mirror of
https://github.com/vocdoni/arbo.git
synced 2026-01-09 13:57:54 -05:00
Update Snapshot & Root approach to get the root always from the db, except in the cases that the tree is a snapshot, in which the root will be in memory. In this way, when a snapshot is performed and the original tree gets modifyed, the snapshot will still point to the old root. Also, the root obtained from the db, uses also the db.ReadTx, so if the root is being modifyied in the current tx (db.WriteTx), when getting the root it will be return the lastest version that is in the tx but not yet in the db.
92 lines
2.3 KiB
Go
92 lines
2.3 KiB
Go
package arbo
|
|
|
|
import (
|
|
"encoding/json"
|
|
)
|
|
|
|
// CircomVerifierProof contains the needed data to check a Circom Verifier Proof
|
|
// inside a circom circuit. CircomVerifierProof allow to verify through a
|
|
// zkSNARK proof the inclusion/exclusion of a leaf in a tree.
|
|
type CircomVerifierProof struct {
|
|
Root []byte `json:"root"`
|
|
Siblings [][]byte `json:"siblings"`
|
|
OldKey []byte `json:"oldKey"`
|
|
OldValue []byte `json:"oldValue"`
|
|
IsOld0 bool `json:"isOld0"`
|
|
Key []byte `json:"key"`
|
|
Value []byte `json:"value"`
|
|
Fnc int `json:"fnc"` // 0: inclusion, 1: non inclusion
|
|
}
|
|
|
|
// MarshalJSON implements the JSON marshaler
|
|
func (cvp CircomVerifierProof) MarshalJSON() ([]byte, error) {
|
|
m := make(map[string]interface{})
|
|
|
|
m["root"] = BytesToBigInt(cvp.Root).String()
|
|
m["siblings"] = siblingsToStringArray(cvp.Siblings)
|
|
m["oldKey"] = BytesToBigInt(cvp.OldKey).String()
|
|
m["oldValue"] = BytesToBigInt(cvp.OldValue).String()
|
|
if cvp.IsOld0 {
|
|
m["isOld0"] = "1"
|
|
} else {
|
|
m["isOld0"] = "0"
|
|
}
|
|
m["key"] = BytesToBigInt(cvp.Key).String()
|
|
m["value"] = BytesToBigInt(cvp.Value).String()
|
|
m["fnc"] = cvp.Fnc
|
|
|
|
return json.Marshal(m)
|
|
}
|
|
|
|
func siblingsToStringArray(s [][]byte) []string {
|
|
var r []string
|
|
for i := 0; i < len(s); i++ {
|
|
r = append(r, BytesToBigInt(s[i]).String())
|
|
}
|
|
return r
|
|
}
|
|
|
|
// FillMissingEmptySiblings adds the empty values to the array of siblings for
|
|
// the Tree number of max levels
|
|
func (t *Tree) FillMissingEmptySiblings(s [][]byte) [][]byte {
|
|
for i := len(s); i < t.maxLevels; i++ {
|
|
s = append(s, emptyValue)
|
|
}
|
|
return s
|
|
}
|
|
|
|
// GenerateCircomVerifierProof generates a CircomVerifierProof for a given key
|
|
// in the Tree
|
|
func (t *Tree) GenerateCircomVerifierProof(k []byte) (*CircomVerifierProof, error) {
|
|
kAux, v, siblings, existence, err := t.GenProof(k)
|
|
if err != nil && err != ErrKeyNotFound {
|
|
return nil, err
|
|
}
|
|
var cp CircomVerifierProof
|
|
cp.Root, err = t.Root()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s, err := UnpackSiblings(t.hashFunction, siblings)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cp.Siblings = t.FillMissingEmptySiblings(s)
|
|
if !existence {
|
|
cp.OldKey = kAux
|
|
cp.OldValue = v
|
|
} else {
|
|
cp.OldKey = emptyValue
|
|
cp.OldValue = emptyValue
|
|
}
|
|
cp.Key = k
|
|
cp.Value = v
|
|
if existence {
|
|
cp.Fnc = 0 // inclusion
|
|
} else {
|
|
cp.Fnc = 1 // non inclusion
|
|
}
|
|
|
|
return &cp, nil
|
|
}
|