mirror of
https://github.com/arnaucube/go-merkletree-iden3.git
synced 2026-02-07 03:26:46 +01:00
Add Proof generation
This commit is contained in:
130
merkletree.go
130
merkletree.go
@@ -300,3 +300,133 @@ func getPath(numLevels int, k []byte) []bool {
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// NodeAux contains the auxiliary node used in a non-existence proof.
|
||||
type NodeAux struct {
|
||||
Key *Hash
|
||||
Value *Hash
|
||||
}
|
||||
|
||||
// Proof defines the required elements for a MT proof of existence or non-existence.
|
||||
type Proof struct {
|
||||
// existence indicates wether this is a proof of existence or non-existence.
|
||||
Existence bool
|
||||
// depth indicates how deep in the tree the proof goes.
|
||||
depth uint
|
||||
// notempties is a bitmap of non-empty Siblings found in Siblings.
|
||||
notempties [ElemBytesLen - proofFlagsLen]byte
|
||||
// Siblings is a list of non-empty sibling keys.
|
||||
Siblings []*Hash
|
||||
NodeAux *NodeAux
|
||||
}
|
||||
|
||||
// NewProofFromBytes parses a byte array into a Proof.
|
||||
func NewProofFromBytes(bs []byte) (*Proof, error) {
|
||||
if len(bs) < ElemBytesLen {
|
||||
return nil, ErrInvalidProofBytes
|
||||
}
|
||||
p := &Proof{}
|
||||
if (bs[0] & 0x01) == 0 {
|
||||
p.Existence = true
|
||||
}
|
||||
p.depth = uint(bs[1])
|
||||
copy(p.notempties[:], bs[proofFlagsLen:ElemBytesLen])
|
||||
siblingBytes := bs[ElemBytesLen:]
|
||||
sibIdx := 0
|
||||
for i := uint(0); i < p.depth; i++ {
|
||||
if common.TestBitBigEndian(p.notempties[:], i) {
|
||||
if len(siblingBytes) < (sibIdx+1)*ElemBytesLen {
|
||||
return nil, ErrInvalidProofBytes
|
||||
}
|
||||
var sib Hash
|
||||
copy(sib[:], siblingBytes[sibIdx*ElemBytesLen:(sibIdx+1)*ElemBytesLen])
|
||||
p.Siblings = append(p.Siblings, &sib)
|
||||
sibIdx++
|
||||
}
|
||||
}
|
||||
|
||||
if !p.Existence && ((bs[0] & 0x02) != 0) {
|
||||
p.NodeAux = &NodeAux{Key: &Hash{}, Value: &Hash{}}
|
||||
nodeAuxBytes := siblingBytes[len(p.Siblings)*ElemBytesLen:]
|
||||
if len(nodeAuxBytes) != 2*ElemBytesLen {
|
||||
return nil, ErrInvalidProofBytes
|
||||
}
|
||||
copy(p.NodeAux.Key[:], nodeAuxBytes[:ElemBytesLen])
|
||||
copy(p.NodeAux.Value[:], nodeAuxBytes[ElemBytesLen:2*ElemBytesLen])
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Bytes serializes a Proof into a byte array.
|
||||
func (p *Proof) Bytes() []byte {
|
||||
bsLen := proofFlagsLen + len(p.notempties) + ElemBytesLen*len(p.Siblings)
|
||||
if p.NodeAux != nil {
|
||||
bsLen += 2 * ElemBytesLen
|
||||
}
|
||||
bs := make([]byte, bsLen)
|
||||
|
||||
if !p.Existence {
|
||||
bs[0] |= 0x01
|
||||
}
|
||||
bs[1] = byte(p.depth)
|
||||
copy(bs[proofFlagsLen:len(p.notempties)+proofFlagsLen], p.notempties[:])
|
||||
siblingsBytes := bs[len(p.notempties)+proofFlagsLen:]
|
||||
for i, k := range p.Siblings {
|
||||
copy(siblingsBytes[i*ElemBytesLen:(i+1)*ElemBytesLen], k[:])
|
||||
}
|
||||
if p.NodeAux != nil {
|
||||
bs[0] |= 0x02
|
||||
copy(bs[len(bs)-2*ElemBytesLen:], p.NodeAux.Key[:])
|
||||
copy(bs[len(bs)-1*ElemBytesLen:], p.NodeAux.Value[:])
|
||||
}
|
||||
return bs
|
||||
}
|
||||
|
||||
// GenerateProof generates the proof of existence (or non-existence) of an
|
||||
// Entry's hash Index for a Merkle Tree given the root.
|
||||
// If the rootKey is nil, the current merkletree root is used
|
||||
func (mt *MerkleTree) GenerateProof(k *big.Int, rootKey *Hash) (*Proof, error) {
|
||||
p := &Proof{}
|
||||
var siblingKey *Hash
|
||||
|
||||
kHash := NewHashFromBigInt(k)
|
||||
path := getPath(mt.maxLevels, kHash[:])
|
||||
if rootKey == nil {
|
||||
rootKey = mt.Root()
|
||||
}
|
||||
nextKey := rootKey
|
||||
for p.depth = 0; p.depth < uint(mt.maxLevels); p.depth++ {
|
||||
n, err := mt.GetNode(nextKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch n.Type {
|
||||
case NodeTypeEmpty:
|
||||
return p, nil
|
||||
case NodeTypeLeaf:
|
||||
if bytes.Equal(kHash[:], n.Entry[0][:]) {
|
||||
p.Existence = true
|
||||
return p, nil
|
||||
} else {
|
||||
// We found a leaf whose entry didn't match hIndex
|
||||
p.NodeAux = &NodeAux{Key: n.Entry[0], Value: n.Entry[1]}
|
||||
return p, nil
|
||||
}
|
||||
case NodeTypeMiddle:
|
||||
if path[p.depth] {
|
||||
nextKey = n.ChildR
|
||||
siblingKey = n.ChildL
|
||||
} else {
|
||||
nextKey = n.ChildL
|
||||
siblingKey = n.ChildR
|
||||
}
|
||||
default:
|
||||
return nil, ErrInvalidNodeFound
|
||||
}
|
||||
if !bytes.Equal(siblingKey[:], HashZero[:]) {
|
||||
common.SetBitBigEndian(p.notempties[:], uint(p.depth))
|
||||
p.Siblings = append(p.Siblings, siblingKey)
|
||||
}
|
||||
}
|
||||
return nil, ErrEntryIndexNotFound
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user