Browse Source

Add Proof generation

circomproofs
arnaucube 3 years ago
parent
commit
6254619875
1 changed files with 130 additions and 0 deletions
  1. +130
    -0
      merkletree.go

+ 130
- 0
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
}

Loading…
Cancel
Save