diff --git a/node/crypto/proof_tree.go b/node/crypto/proof_tree.go index 884006a..c1911f6 100644 --- a/node/crypto/proof_tree.go +++ b/node/crypto/proof_tree.go @@ -4,12 +4,18 @@ import ( "bytes" "crypto/sha512" "encoding/binary" + "encoding/gob" "errors" "fmt" rbls48581 "source.quilibrium.com/quilibrium/monorepo/bls48581" ) +func init() { + gob.Register(&VectorCommitmentLeafNode{}) + gob.Register(&VectorCommitmentBranchNode{}) +} + const ( BranchNodes = 1024 BranchBits = 10 // log2(1024) @@ -21,39 +27,39 @@ type VectorCommitmentNode interface { } type VectorCommitmentLeafNode struct { - key []byte - value []byte - commitment []byte + Key []byte + Value []byte + Commitment []byte } type VectorCommitmentBranchNode struct { - prefix []int - children [BranchNodes]VectorCommitmentNode - commitment []byte + Prefix []int + Children [BranchNodes]VectorCommitmentNode + Commitment []byte } func (n *VectorCommitmentLeafNode) Commit() []byte { - if n.commitment == nil { + if n.Commitment == nil { h := sha512.New() h.Write([]byte{0}) - h.Write(n.key) - h.Write(n.value) - n.commitment = h.Sum(nil) + h.Write(n.Key) + h.Write(n.Value) + n.Commitment = h.Sum(nil) } - return n.commitment + return n.Commitment } func (n *VectorCommitmentBranchNode) Commit() []byte { - if n.commitment == nil { + if n.Commitment == nil { data := []byte{} - for _, child := range n.children { + for _, child := range n.Children { if child != nil { out := child.Commit() switch c := child.(type) { case *VectorCommitmentBranchNode: h := sha512.New() h.Write([]byte{1}) - for _, p := range c.prefix { + for _, p := range c.Prefix { h.Write(binary.BigEndian.AppendUint32([]byte{}, uint32(p))) } h.Write(out) @@ -67,23 +73,23 @@ func (n *VectorCommitmentBranchNode) Commit() []byte { } } - n.commitment = rbls48581.CommitRaw(data, 1024) + n.Commitment = rbls48581.CommitRaw(data, 1024) } - return n.commitment + return n.Commitment } func (n *VectorCommitmentBranchNode) Verify(index int, proof []byte) bool { data := []byte{} - if n.commitment == nil { - for _, child := range n.children { + if n.Commitment == nil { + for _, child := range n.Children { if child != nil { out := child.Commit() switch c := child.(type) { case *VectorCommitmentBranchNode: h := sha512.New() h.Write([]byte{1}) - for _, p := range c.prefix { + for _, p := range c.Prefix { h.Write(binary.BigEndian.AppendUint32([]byte{}, uint32(p))) } h.Write(out) @@ -97,17 +103,17 @@ func (n *VectorCommitmentBranchNode) Verify(index int, proof []byte) bool { } } - n.commitment = rbls48581.CommitRaw(data, 1024) + n.Commitment = rbls48581.CommitRaw(data, 1024) data = data[64*index : 64*(index+1)] } else { - child := n.children[index] + child := n.Children[index] if child != nil { out := child.Commit() switch c := child.(type) { case *VectorCommitmentBranchNode: h := sha512.New() h.Write([]byte{1}) - for _, p := range c.prefix { + for _, p := range c.Prefix { h.Write(binary.BigEndian.AppendUint32([]byte{}, uint32(p))) } h.Write(out) @@ -121,19 +127,19 @@ func (n *VectorCommitmentBranchNode) Verify(index int, proof []byte) bool { } } - return rbls48581.VerifyRaw(data, n.commitment, uint64(index), proof, 1024) + return rbls48581.VerifyRaw(data, n.Commitment, uint64(index), proof, 1024) } func (n *VectorCommitmentBranchNode) Prove(index int) []byte { data := []byte{} - for _, child := range n.children { + for _, child := range n.Children { if child != nil { out := child.Commit() switch c := child.(type) { case *VectorCommitmentBranchNode: h := sha512.New() h.Write([]byte{1}) - for _, p := range c.prefix { + for _, p := range c.Prefix { h.Write(binary.BigEndian.AppendUint32([]byte{}, uint32(p))) } h.Write(out) @@ -151,7 +157,7 @@ func (n *VectorCommitmentBranchNode) Prove(index int) []byte { } type VectorCommitmentTree struct { - root VectorCommitmentNode + Root VectorCommitmentNode } // getNextNibble returns the next BranchBits bits from the key starting at pos @@ -212,60 +218,60 @@ func (t *VectorCommitmentTree) Insert(key, value []byte) error { var insert func(node VectorCommitmentNode, depth int) VectorCommitmentNode insert = func(node VectorCommitmentNode, depth int) VectorCommitmentNode { if node == nil { - return &VectorCommitmentLeafNode{key: key, value: value} + return &VectorCommitmentLeafNode{Key: key, Value: value} } switch n := node.(type) { case *VectorCommitmentLeafNode: - if bytes.Equal(n.key, key) { - n.value = value - n.commitment = nil + if bytes.Equal(n.Key, key) { + n.Value = value + n.Commitment = nil return n } // Get common prefix nibbles and divergence point - sharedNibbles, divergeDepth := getNibblesUntilDiverge(n.key, key, depth) + sharedNibbles, divergeDepth := getNibblesUntilDiverge(n.Key, key, depth) // Create single branch node with shared prefix branch := &VectorCommitmentBranchNode{ - prefix: sharedNibbles, + Prefix: sharedNibbles, } // Add both leaves at their final positions - finalOldNibble := getNextNibble(n.key, divergeDepth) + finalOldNibble := getNextNibble(n.Key, divergeDepth) finalNewNibble := getNextNibble(key, divergeDepth) - branch.children[finalOldNibble] = n - branch.children[finalNewNibble] = &VectorCommitmentLeafNode{key: key, value: value} + branch.Children[finalOldNibble] = n + branch.Children[finalNewNibble] = &VectorCommitmentLeafNode{Key: key, Value: value} return branch case *VectorCommitmentBranchNode: - if len(n.prefix) > 0 { + if len(n.Prefix) > 0 { // Check if the new key matches the prefix - for i, expectedNibble := range n.prefix { + for i, expectedNibble := range n.Prefix { actualNibble := getNextNibble(key, depth+i*BranchBits) if actualNibble != expectedNibble { // Create new branch with shared prefix subset newBranch := &VectorCommitmentBranchNode{ - prefix: n.prefix[:i], + Prefix: n.Prefix[:i], } // Position old branch and new leaf - newBranch.children[expectedNibble] = n - n.prefix = n.prefix[i+1:] // remove shared prefix from old branch - newBranch.children[actualNibble] = &VectorCommitmentLeafNode{key: key, value: value} + newBranch.Children[expectedNibble] = n + n.Prefix = n.Prefix[i+1:] // remove shared prefix from old branch + newBranch.Children[actualNibble] = &VectorCommitmentLeafNode{Key: key, Value: value} return newBranch } } // Key matches prefix, continue with final nibble - finalNibble := getNextNibble(key, depth+len(n.prefix)*BranchBits) - n.children[finalNibble] = insert(n.children[finalNibble], depth+len(n.prefix)*BranchBits+BranchBits) - n.commitment = nil + finalNibble := getNextNibble(key, depth+len(n.Prefix)*BranchBits) + n.Children[finalNibble] = insert(n.Children[finalNibble], depth+len(n.Prefix)*BranchBits+BranchBits) + n.Commitment = nil return n } else { // Simple branch without prefix nibble := getNextNibble(key, depth) - n.children[nibble] = insert(n.children[nibble], depth+BranchBits) - n.commitment = nil + n.Children[nibble] = insert(n.Children[nibble], depth+BranchBits) + n.Commitment = nil return n } } @@ -273,7 +279,7 @@ func (t *VectorCommitmentTree) Insert(key, value []byte) error { return nil } - t.root = insert(t.root, 0) + t.Root = insert(t.Root, 0) return nil } @@ -294,33 +300,33 @@ func (t *VectorCommitmentTree) Verify(key []byte, proofs [][]byte) bool { switch n := node.(type) { case *VectorCommitmentLeafNode: - if bytes.Equal(n.key, key) { - return bytes.Equal(n.value, proofs[0]) + if bytes.Equal(n.Key, key) { + return bytes.Equal(n.Value, proofs[0]) } return false case *VectorCommitmentBranchNode: // Check prefix match - for i, expectedNibble := range n.prefix { + for i, expectedNibble := range n.Prefix { if getNextNibble(key, depth+i*BranchBits) != expectedNibble { return false } } // Get final nibble after prefix - finalNibble := getNextNibble(key, depth+len(n.prefix)*BranchBits) + finalNibble := getNextNibble(key, depth+len(n.Prefix)*BranchBits) if !n.Verify(finalNibble, proofs[0]) { return false } - return verify(n.children[finalNibble], proofs[1:], depth+len(n.prefix)*BranchBits+BranchBits) + return verify(n.Children[finalNibble], proofs[1:], depth+len(n.Prefix)*BranchBits+BranchBits) } return false } - return verify(t.root, proofs, 0) + return verify(t.Root, proofs, 0) } func (t *VectorCommitmentTree) Prove(key []byte) [][]byte { @@ -336,31 +342,31 @@ func (t *VectorCommitmentTree) Prove(key []byte) [][]byte { switch n := node.(type) { case *VectorCommitmentLeafNode: - if bytes.Equal(n.key, key) { - return [][]byte{n.value} + if bytes.Equal(n.Key, key) { + return [][]byte{n.Value} } return nil case *VectorCommitmentBranchNode: // Check prefix match - for i, expectedNibble := range n.prefix { + for i, expectedNibble := range n.Prefix { if getNextNibble(key, depth+i*BranchBits) != expectedNibble { return nil } } // Get final nibble after prefix - finalNibble := getNextNibble(key, depth+len(n.prefix)*BranchBits) + finalNibble := getNextNibble(key, depth+len(n.Prefix)*BranchBits) proofs := [][]byte{n.Prove(finalNibble)} - return append(proofs, prove(n.children[finalNibble], depth+len(n.prefix)*BranchBits+BranchBits)...) + return append(proofs, prove(n.Children[finalNibble], depth+len(n.Prefix)*BranchBits+BranchBits)...) } return nil } - return prove(t.root, 0) + return prove(t.Root, 0) } // Get retrieves a value from the tree by key @@ -377,27 +383,27 @@ func (t *VectorCommitmentTree) Get(key []byte) ([]byte, error) { switch n := node.(type) { case *VectorCommitmentLeafNode: - if bytes.Equal(n.key, key) { - return n.value + if bytes.Equal(n.Key, key) { + return n.Value } return nil case *VectorCommitmentBranchNode: // Check prefix match - for i, expectedNibble := range n.prefix { + for i, expectedNibble := range n.Prefix { if getNextNibble(key, depth+i*BranchBits) != expectedNibble { return nil } } // Get final nibble after prefix - finalNibble := getNextNibble(key, depth+len(n.prefix)*BranchBits) - return get(n.children[finalNibble], depth+len(n.prefix)*BranchBits+BranchBits) + finalNibble := getNextNibble(key, depth+len(n.Prefix)*BranchBits) + return get(n.Children[finalNibble], depth+len(n.Prefix)*BranchBits+BranchBits) } return nil } - value := get(t.root, 0) + value := get(t.Root, 0) if value == nil { return nil, errors.New("key not found") } @@ -418,14 +424,14 @@ func (t *VectorCommitmentTree) Delete(key []byte) error { switch n := node.(type) { case *VectorCommitmentLeafNode: - if bytes.Equal(n.key, key) { + if bytes.Equal(n.Key, key) { return nil } return n case *VectorCommitmentBranchNode: // Check prefix match - for i, expectedNibble := range n.prefix { + for i, expectedNibble := range n.Prefix { currentNibble := getNextNibble(key, depth+i*BranchBits) if currentNibble != expectedNibble { return n // Key doesn't match prefix, nothing to delete @@ -433,15 +439,15 @@ func (t *VectorCommitmentTree) Delete(key []byte) error { } // Delete at final position after prefix - finalNibble := getNextNibble(key, depth+len(n.prefix)*BranchBits) - n.children[finalNibble] = delete(n.children[finalNibble], depth+len(n.prefix)*BranchBits+BranchBits) - n.commitment = nil + finalNibble := getNextNibble(key, depth+len(n.Prefix)*BranchBits) + n.Children[finalNibble] = delete(n.Children[finalNibble], depth+len(n.Prefix)*BranchBits+BranchBits) + n.Commitment = nil // Count remaining children childCount := 0 var lastChild VectorCommitmentNode var lastIndex int - for i, child := range n.children { + for i, child := range n.Children { if child != nil { childCount++ lastChild = child @@ -454,14 +460,14 @@ func (t *VectorCommitmentTree) Delete(key []byte) error { } else if childCount == 1 { // If the only child is a leaf, keep structure if its path matches if leaf, ok := lastChild.(*VectorCommitmentLeafNode); ok { - if lastIndex == getLastNibble(leaf.key, len(n.prefix)) { + if lastIndex == getLastNibble(leaf.Key, len(n.Prefix)) { return n } return leaf } // If it's a branch, merge the prefixes if branch, ok := lastChild.(*VectorCommitmentBranchNode); ok { - branch.prefix = append(n.prefix, branch.prefix...) + branch.Prefix = append(n.Prefix, branch.Prefix...) return branch } } @@ -471,16 +477,16 @@ func (t *VectorCommitmentTree) Delete(key []byte) error { return nil } - t.root = delete(t.root, 0) + t.Root = delete(t.Root, 0) return nil } -// Root returns the root hash of the tree -func (t *VectorCommitmentTree) Root() []byte { - if t.root == nil { +// Commit returns the root of the tree +func (t *VectorCommitmentTree) Commit() []byte { + if t.Root == nil { return make([]byte, 64) } - return t.root.Commit() + return t.Root.Commit() } func debugNode(node VectorCommitmentNode, depth int, prefix string) { @@ -490,10 +496,10 @@ func debugNode(node VectorCommitmentNode, depth int, prefix string) { switch n := node.(type) { case *VectorCommitmentLeafNode: - fmt.Printf("%sLeaf: key=%x value=%x\n", prefix, n.key, n.value) + fmt.Printf("%sLeaf: key=%x value=%x\n", prefix, n.Key, n.Value) case *VectorCommitmentBranchNode: - fmt.Printf("%sBranch %v:\n", prefix, n.prefix) - for i, child := range n.children { + fmt.Printf("%sBranch %v:\n", prefix, n.Prefix) + for i, child := range n.Children { if child != nil { fmt.Printf("%s [%d]:\n", prefix, i) debugNode(child, depth+1, prefix+" ")