From cde7748474f46f33df39dde661534a4e13a6b6d3 Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Mon, 18 Nov 2024 08:49:45 +0100 Subject: [PATCH] dirty commit --- arbo/mimc_bls12_377/verifier.go | 67 +++++++++++++++++----------- arbo/mimc_bls12_377/verifier_test.go | 49 +++++++++++--------- 2 files changed, 70 insertions(+), 46 deletions(-) diff --git a/arbo/mimc_bls12_377/verifier.go b/arbo/mimc_bls12_377/verifier.go index 068c0e3..610090f 100644 --- a/arbo/mimc_bls12_377/verifier.go +++ b/arbo/mimc_bls12_377/verifier.go @@ -5,12 +5,14 @@ import ( "github.com/consensys/gnark/std/hash/mimc" ) -// prevLevel function calculates the previous level of the merkle tree given the -// current leaf, the current path bit of the leaf, the validity of the sibling -// and the sibling itself. -func prevLevel(api frontend.API, leaf, ipath, valid, sibling frontend.Variable) (frontend.Variable, error) { - // l, r = path == 1 ? sibling, current : current, sibling - l, r := api.Select(ipath, sibling, leaf), api.Select(ipath, leaf, sibling) +// intermediateLeafKey function calculates the intermediate leaf key of the +// path position provided. The leaf key is calculated by hashing the sibling +// and the key provided. The position of the sibling and the key is decided by +// the path position. If the current sibling is not valid, the method will +// return the key provided. +func intermediateLeafKey(api frontend.API, ipath, valid, key, sibling frontend.Variable) (frontend.Variable, error) { + // l, r = path == 1 ? sibling, key : key, sibling + l, r := api.Select(ipath, sibling, key), api.Select(ipath, key, sibling) // intermediateLeafKey = H(l | r) hash, err := mimc.NewMiMC(api) if err != nil { @@ -18,8 +20,8 @@ func prevLevel(api frontend.API, leaf, ipath, valid, sibling frontend.Variable) } hash.Write(l, r) intermediateLeafKey := hash.Sum() - // newCurrent = valid == 1 ? current : intermediateLeafKey - return api.Select(valid, intermediateLeafKey, leaf), nil + // newCurrent = valid == 1 ? intermediateLeafKey : key + return api.Select(valid, intermediateLeafKey, key), nil } // strictCmp function compares a and b and returns: @@ -31,44 +33,59 @@ func strictCmp(api frontend.API, a, b frontend.Variable) frontend.Variable { } // isValid function returns 1 if the the sibling provided is a valid sibling or -// 0 otherwise. To check if the sibling is valid, its leaf value and it must be -// different from the previous leaf value and the previous sibling. +// 0 otherwise. To check if the sibling is valid, its leaf key and it must be +// different from the previous leaf key and the previous sibling. func isValid(api frontend.API, sibling, prevSibling, leaf, prevLeaf frontend.Variable) frontend.Variable { cmp1, cmp2 := strictCmp(api, leaf, prevLeaf), strictCmp(api, sibling, prevSibling) return api.Select(api.Or(cmp1, cmp2), 1, 0) } +func swapEndianness(api frontend.API, b frontend.Variable, l int) frontend.Variable { + bits := api.ToBinary(b, l) + swapped := make([]frontend.Variable, l) + for i := 0; i < l; i++ { + swapped[len(bits)-1-i] = bits[i] + } + return api.FromBinary(swapped) +} + // CheckProof receives the parameters of a proof of Arbo to recalculate the // root with them and compare it with the provided one, verifiying the proof. func CheckProof(api frontend.API, key, value, root frontend.Variable, siblings []frontend.Variable) error { // calculate the path from the provided key to decide which leaf is the // correct one in every level of the tree path := api.ToBinary(key, len(siblings)) - // calculate the value leaf to start with it to rebuild the tree - // leafValue = H(key | value | 1) + for i := 0; i < len(path); i++ { + api.Println("gnark", i, path[i]) + } + api.Println(swapEndianness(api, key, len(siblings))) + // calculate the current leaf key to start with it to rebuild the tree + // leafKey = H(key | value | 1) hash, err := mimc.NewMiMC(api) if err != nil { return err } hash.Write(key, value, 1) - leafValue := hash.Sum() - api.Println("[gnark] leafKey", key) - api.Println("[gnark] leafValue", leafValue) - // calculate the root and compare it with the provided one - prevLeaf := leafValue - currentLeaf := leafValue - prevSibling := frontend.Variable(0) + leafKey := hash.Sum() + api.Println("gnark leafKey", leafKey) + // calculate the root iterating through the siblings in inverse order, + // calculating the intermediate leaf key based on the path and the validity + // of the current sibling + prevKey := leafKey // init prevKey with computed leafKey + lastKey := leafKey // init lastKey with computed leafKey + prevSibling := frontend.Variable(0) // init prevSibling with 0 for i := len(siblings) - 1; i >= 0; i-- { // check if the sibling is valid - valid := isValid(api, siblings[i], prevSibling, currentLeaf, prevLeaf) - prevLeaf = currentLeaf - prevSibling = siblings[i] - // compute the next leaf value - currentLeaf, err = prevLevel(api, currentLeaf, path[i], valid, siblings[i]) + valid := isValid(api, siblings[i], prevSibling, lastKey, prevKey) + prevKey = lastKey // update prevKey to the lastKey + prevSibling = siblings[i] // update prevSibling to the current sibling + // compute the intermediate leaf key and update the lastKey + lastKey, err = intermediateLeafKey(api, path[i], valid, lastKey, siblings[i]) if err != nil { return err } + // api.Println("gnark", i, path[i], prevKey, prevSibling, lastKey) } - api.AssertIsEqual(currentLeaf, root) + api.AssertIsEqual(lastKey, root) return nil } diff --git a/arbo/mimc_bls12_377/verifier_test.go b/arbo/mimc_bls12_377/verifier_test.go index 9f0ecd2..2308f19 100644 --- a/arbo/mimc_bls12_377/verifier_test.go +++ b/arbo/mimc_bls12_377/verifier_test.go @@ -6,13 +6,10 @@ import ( "math/big" "os" "testing" - "time" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/profile" "github.com/consensys/gnark/test" arbotree "github.com/vocdoni/arbo" "go.vocdoni.io/dvote/db" @@ -21,11 +18,16 @@ import ( "go.vocdoni.io/dvote/util" ) +const ( + n_siblings = 32 + k_len = n_siblings / 8 +) + type testVerifierCircuit struct { Root frontend.Variable Key frontend.Variable Value frontend.Variable - Siblings [160]frontend.Variable + Siblings [n_siblings]frontend.Variable } func (circuit *testVerifierCircuit) Define(api frontend.API) error { @@ -33,17 +35,17 @@ func (circuit *testVerifierCircuit) Define(api frontend.API) error { } func TestVerifier(t *testing.T) { - p := profile.Start() - now := time.Now() - _, _ = frontend.Compile(ecc.BLS12_377.ScalarField(), r1cs.NewBuilder, &testVerifierCircuit{}) - fmt.Println("elapsed", time.Since(now)) - p.Stop() - fmt.Println("constrains", p.NbConstraints()) + // p := profile.Start() + // now := time.Now() + // _, _ = frontend.Compile(ecc.BLS12_377.ScalarField(), r1cs.NewBuilder, &testVerifierCircuit{}) + // fmt.Println("elapsed", time.Since(now)) + // p.Stop() + // fmt.Println("constrains", p.NbConstraints()) assert := test.NewAssert(t) // inputs := successInputs(t, 10) - inputs, err := generateCensusProof(10, util.RandomBytes(20), big.NewInt(10).Bytes()) + inputs, err := generateCensusProof(10, util.RandomBytes(k_len), big.NewInt(10).Bytes()) if err != nil { t.Fatal(err) } @@ -78,7 +80,7 @@ func generateCensusProof(n int, k, v []byte) (testVerifierCircuit, error) { } tree, err := arbotree.NewTree(arbotree.Config{ Database: database, - MaxLevels: 160, + MaxLevels: n_siblings, HashFunction: arbotree.HashFunctionMiMC_BLS12_377, }) if err != nil { @@ -89,13 +91,9 @@ func generateCensusProof(n int, k, v []byte) (testVerifierCircuit, error) { if err = tree.Add(k, v); err != nil { return testVerifierCircuit{}, err } - h := tree.HashFunction() - r, _ := h.Hash(k, v, []byte{1}) - log.Println("[go] leafKey", new(big.Int).SetBytes(k)) - log.Println("[go] leafValue", new(big.Int).SetBytes(r)) // add random addresses for i := 1; i < n; i++ { - rk := BigToFF(new(big.Int).SetBytes(util.RandomBytes(20))).Bytes() + rk := BigToFF(new(big.Int).SetBytes(util.RandomBytes(k_len))).Bytes() rv := new(big.Int).SetBytes(util.RandomBytes(8)).Bytes() if err = tree.Add(rk, rv); err != nil { return testVerifierCircuit{}, err @@ -113,8 +111,9 @@ func generateCensusProof(n int, k, v []byte) (testVerifierCircuit, error) { if err != nil { return testVerifierCircuit{}, err } - paddedSiblings := [160]frontend.Variable{} - for i := 0; i < 160; i++ { + fmt.Println("validSiblings", len(unpackedSiblings)) + paddedSiblings := [n_siblings]frontend.Variable{} + for i := 0; i < n_siblings; i++ { if i < len(unpackedSiblings) { paddedSiblings[i] = arbo.BytesLEToBigInt(unpackedSiblings[i]) } else { @@ -125,9 +124,17 @@ func generateCensusProof(n int, k, v []byte) (testVerifierCircuit, error) { if err != nil { return testVerifierCircuit{}, err } + verified, err := arbotree.CheckProof(tree.HashFunction(), k, v, root, siblings) + if !verified { + return testVerifierCircuit{}, fmt.Errorf("error verifying the proof") + } + if err != nil { + return testVerifierCircuit{}, err + } + log.Println(new(big.Int).SetBytes(k).String()) return testVerifierCircuit{ - Root: root, - Key: k, + Root: new(big.Int).SetBytes(root), + Key: arbo.BytesLEToBigInt(k), Value: new(big.Int).SetBytes(v), Siblings: paddedSiblings, }, nil