Skip to content

Commit

Permalink
last optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasmenendez committed Nov 6, 2024
1 parent 23b36d3 commit 35eff8e
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 25 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ A set of custom circuits writted in [Gnark](https://github.com/ConsenSys/gnark)
3. Arbo (by [@arnaucube](https://github.com/arnaucube)) proof checker from [@vocdoni/arbo](https://github.com/vocdoni/vocdoni-node/tree/main/tree/arbo) ([source code](./arbo))
- This is compatible with the SMT Verifier.


**SMT Verifier vs. Arbo**

| | SMT Verifier | Arbo |
|:---:|---:|---:|
| *Inputs* | 4 | 5 |
| *Constrains* | 42316 | 39396 (🏆) |
| *Solver time* | 169.192292ms | 162.1965ms (🏆) |
| *Constrains* | 42316 | 41373 (🏆) |
| *Solver time* | 169.192292ms (🏆) | 560.808916ms |


---
Expand Down
45 changes: 23 additions & 22 deletions arbo/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,20 @@ func prevLevel(api frontend.API, leaf, ipath, valid, sibling frontend.Variable)
return api.Select(valid, intermediateLeafKey, leaf)
}

// isLessThanConstant function returns if the variable is less than the constant
// provided. It calculates the difference between the constant and the variable,
// gets the binary representation of it and returns the most significant bit,
// which is the sign bit (1 if the difference is negative, 0 otherwise).
func isLessThanConstant(api frontend.API, v frontend.Variable, c int) frontend.Variable {
bitsize := api.Compiler().FieldBitLen()
delta := api.Sub(frontend.Variable(c), v)
bits := api.ToBinary(delta, bitsize)
return bits[bitsize-1]
// strictCmp function compares a and b and returns:
//
// 1 a != b
// 0 a == b
func strictCmp(api frontend.API, a, b frontend.Variable) frontend.Variable {
return api.Select(api.IsZero(api.Sub(a, b)), 0, 1)
}

// validSiblings function creates a binary map with the slots where a valid
// sibling is located in the siblings list. This function helps to skip
// unnecessary iterations when walking through the merkle tree.
func validSiblings(api frontend.API, siblings []frontend.Variable, nsibling frontend.Variable) []frontend.Variable {
valid := make([]frontend.Variable, len(siblings))
for i := 0; i < len(siblings); i++ {
valid[i] = isLessThanConstant(api, nsibling, i)
}
return valid
// 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.
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)
}

// CheckProof receives the parameters of a proof of Arbo to recalculate the
Expand All @@ -46,18 +40,25 @@ func CheckProof(api frontend.API, key, value, root, nsiblings frontend.Variable,
// of provided siblings
api.AssertIsLessOrEqual(nsiblings, len(siblings))
// get a map with the valid siblings
valid := validSiblings(api, siblings, nsiblings)
// valid := validSiblings(api, siblings, nsiblings)
// 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, api.Compiler().FieldBitLen())
// calculate the value leaf to start with it to rebuild the tree
// leafValue = H(key | value | 1)
leafValue := poseidon.Hash(api, key, value, 1)
// calculate the root and compare it with the provided one
currentLevel := leafValue
prevLeaf := leafValue
currentLeaf := leafValue
prevSibling := frontend.Variable(0)
for i := len(siblings) - 1; i >= 0; i-- {
currentLevel = prevLevel(api, currentLevel, path[i], valid[i], siblings[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 = prevLevel(api, currentLeaf, path[i], valid, siblings[i])
}
api.AssertIsEqual(currentLevel, root)
api.AssertIsEqual(currentLeaf, root)
return nil
}
3 changes: 3 additions & 0 deletions arbo/verifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"math/big"
"testing"
"time"

"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend"
Expand Down Expand Up @@ -84,7 +85,9 @@ func successInputs(t *testing.T, n int) testVerifierCircuit {

func TestVerifier(t *testing.T) {
p := profile.Start()
now := time.Now()
_, _ = frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &testVerifierCircuit{})
fmt.Println("elapsed", time.Since(now))
p.Stop()
fmt.Println("constrains", p.NbConstraints())

Expand Down

0 comments on commit 35eff8e

Please sign in to comment.