forked from NethermindEth/starknet.go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
merkle.go
101 lines (93 loc) · 2.27 KB
/
merkle.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package caigo
import (
"fmt"
"math/big"
)
type FixedSizeMerkleTree struct {
Leaves []*big.Int
Branches [][]*big.Int
Root *big.Int
}
func NewFixedSizeMerkleTree(leaves ...*big.Int) (*FixedSizeMerkleTree, error) {
mt := &FixedSizeMerkleTree{
Leaves: leaves,
Branches: [][]*big.Int{},
}
root, err := mt.build(leaves)
if err != nil {
return nil, err
}
mt.Root = root
return mt, err
}
func MerkleHash(x, y *big.Int) (*big.Int, error) {
if x.Cmp(y) <= 0 {
return Curve.HashElements([]*big.Int{x, y})
}
return Curve.HashElements([]*big.Int{y, x})
}
func (mt *FixedSizeMerkleTree) build(leaves []*big.Int) (*big.Int, error) {
if len(leaves) == 1 {
return leaves[0], nil
}
mt.Branches = append(mt.Branches, leaves)
newLeaves := []*big.Int{}
for i := 0; i < len(leaves); i += 2 {
if i+1 == len(leaves) {
hash, err := MerkleHash(leaves[i], big.NewInt(0))
if err != nil {
return nil, err
}
newLeaves = append(newLeaves, hash)
break
}
hash, err := MerkleHash(leaves[i], leaves[i+1])
if err != nil {
return nil, err
}
newLeaves = append(newLeaves, hash)
}
return mt.build(newLeaves)
}
func (mt *FixedSizeMerkleTree) Proof(leaf *big.Int) ([]*big.Int, error) {
return mt.recursiveProof(leaf, 0, []*big.Int{})
}
func (mt *FixedSizeMerkleTree) recursiveProof(leaf *big.Int, branchIndex int, hashPath []*big.Int) ([]*big.Int, error) {
if branchIndex >= len(mt.Branches) {
return hashPath, nil
}
branch := mt.Branches[branchIndex]
index := -1
for k, v := range branch {
if v.Cmp(leaf) == 0 {
index = k
break
}
}
if index == -1 {
return nil, fmt.Errorf("key 0x%s not found in branch", leaf.Text(16))
}
nextProof := big.NewInt(0)
if index%2 == 0 && index < len(branch) {
nextProof = branch[index+1]
}
if index%2 != 0 {
nextProof = branch[index-1]
}
newLeaf, err := MerkleHash(leaf, nextProof)
if err != nil {
return nil, fmt.Errorf("nextproof error: %v", err)
}
newHashPath := append(hashPath, nextProof)
return mt.recursiveProof(newLeaf, branchIndex+1, newHashPath)
}
func ProofMerklePath(root *big.Int, leaf *big.Int, path []*big.Int) bool {
if len(path) == 0 {
return root.Cmp(leaf) == 0
}
nexLeaf, err := MerkleHash(leaf, path[0])
if err != nil {
return false
}
return ProofMerklePath(root, nexLeaf, path[1:])
}