Skip to content

Commit

Permalink
dirty commit
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasmenendez committed Nov 18, 2024
1 parent d1ee77b commit cde7748
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 46 deletions.
67 changes: 42 additions & 25 deletions arbo/mimc_bls12_377/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,23 @@ 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 {
return 0, err
}
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:
Expand All @@ -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
}
49 changes: 28 additions & 21 deletions arbo/mimc_bls12_377/verifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -21,29 +18,34 @@ 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 {
return CheckProof(api, circuit.Key, circuit.Value, circuit.Root, circuit.Siblings[:])
}

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)
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -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
Expand Down

0 comments on commit cde7748

Please sign in to comment.