Skip to content

Commit d51265c

Browse files
committed
feat(merkle): add builder on merkle trees data structure
1 parent b3e4eee commit d51265c

3 files changed

Lines changed: 531 additions & 77 deletions

File tree

internal/merkle/builder.go

Lines changed: 391 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,391 @@
1+
package merkle
2+
3+
import (
4+
"fmt"
5+
"math/big"
6+
"slices"
7+
8+
"github.com/ethereum/go-ethereum/common"
9+
"github.com/ethereum/go-ethereum/crypto"
10+
)
11+
12+
// MerkleProof: dave/common-rs/merkle/src/tree.rs
13+
type Proof struct {
14+
Pos *big.Int
15+
Node common.Hash
16+
Siblings []common.Hash
17+
}
18+
19+
func Leaf(node common.Hash, pos *big.Int) *Proof {
20+
return &Proof{
21+
Node: node,
22+
Pos: pos,
23+
Siblings: nil,
24+
}
25+
}
26+
27+
func (proof *Proof) BuildRoot() common.Hash {
28+
zero := big.NewInt(0)
29+
two := big.NewInt(2)
30+
rootHash := proof.Node
31+
32+
for i, s := range proof.Siblings {
33+
34+
// ((pos >> i) % 2) == 0
35+
if new(big.Int).Rem(new(big.Int).Rsh(proof.Pos, uint(i)), two).Cmp(zero) == 0 {
36+
rootHash = crypto.Keccak256Hash(rootHash[:], s[:])
37+
} else {
38+
rootHash = crypto.Keccak256Hash(s[:], rootHash[:])
39+
}
40+
}
41+
return rootHash
42+
}
43+
44+
func (proof *Proof) VerifyRoot(other common.Hash) bool {
45+
return proof.BuildRoot() == other
46+
}
47+
48+
func (proof *Proof) PushHash(h common.Hash) {
49+
proof.Siblings = append(proof.Siblings, h)
50+
}
51+
52+
////////////////////////////////////////////////////////////////////////////////
53+
54+
// MerkleTree: dave/common-rs/merkle/src/tree.rs
55+
type Tree struct {
56+
RootHash common.Hash
57+
Height uint32
58+
Subtrees *InnerNode
59+
}
60+
61+
// InnerNode: dave/common-rs/merkle/src/tree.rs
62+
// Emulate the rust enum type with a struct containing both {Pair, Iterated}.
63+
type InnerNode struct {
64+
// Pair
65+
LHS, RHS *Tree
66+
67+
// Iterated
68+
Child *Tree
69+
}
70+
71+
func (inner *InnerNode) Valid() bool {
72+
isPair := (inner.LHS != nil && inner.RHS != nil)
73+
isIterated := inner.Child != nil
74+
return (isPair || isIterated) && !(isPair && isIterated) // xor
75+
}
76+
77+
func (inner *InnerNode) Children() (*Tree, *Tree) {
78+
if !inner.Valid() {
79+
panic(fmt.Sprintf("invalid InnerNode state: %v\n", inner))
80+
}
81+
82+
if inner.Child != nil {
83+
return inner.Child, inner.Child
84+
} else {
85+
return inner.LHS, inner.RHS
86+
}
87+
}
88+
89+
func TreeLeaf(hash common.Hash) *Tree {
90+
return &Tree{
91+
Height: 0,
92+
RootHash: hash,
93+
Subtrees: nil,
94+
}
95+
}
96+
97+
func (tree *Tree) GetRootHash() common.Hash {
98+
return tree.RootHash
99+
}
100+
101+
func (tree *Tree) FindChildByHash(hash common.Hash) *InnerNode {
102+
if inner := tree.Subtrees; inner != nil {
103+
if !inner.Valid() {
104+
panic(fmt.Sprintf("invalid InnerNode state: %v\n", inner))
105+
}
106+
107+
if inner.Child != nil {
108+
child := inner.Child.FindChildByHash(hash)
109+
if child != nil {
110+
return child
111+
}
112+
} else {
113+
lhs := inner.LHS.FindChildByHash(hash)
114+
if lhs != nil {
115+
return lhs
116+
}
117+
118+
rhs := inner.LHS.FindChildByHash(hash)
119+
if rhs != nil {
120+
return rhs
121+
}
122+
}
123+
}
124+
return nil // not found
125+
}
126+
127+
func (tree *Tree) Join(other *Tree) *Tree {
128+
return &Tree{
129+
RootHash: crypto.Keccak256Hash(tree.RootHash[:], other.RootHash[:]),
130+
Height: tree.Height + 1,
131+
Subtrees: &InnerNode{
132+
LHS: tree,
133+
RHS: other,
134+
},
135+
}
136+
}
137+
138+
func (tree *Tree) Iterated(rep uint64) *Tree {
139+
root := tree
140+
for range rep {
141+
root = &Tree{
142+
RootHash: crypto.Keccak256Hash(root.RootHash[:], root.RootHash[:]),
143+
Height: tree.Height + 1,
144+
Subtrees: &InnerNode{
145+
Child: tree,
146+
},
147+
}
148+
}
149+
return root
150+
}
151+
152+
func (tree *Tree) ProveLeaf(index *big.Int) *Proof {
153+
return tree.ProveLeafRec(index)
154+
}
155+
156+
func (tree *Tree) ProveLast() *Proof {
157+
one := big.NewInt(1)
158+
159+
// index = (1 << height) - 1
160+
index := new(big.Int).Sub(
161+
new(big.Int).Lsh(
162+
one,
163+
uint(tree.Height),
164+
),
165+
one,
166+
)
167+
return tree.ProveLeaf(index)
168+
}
169+
170+
func (tree *Tree) ProveLeafRec(index *big.Int) *Proof {
171+
one := big.NewInt(1)
172+
zero := big.NewInt(0)
173+
numLeafs := new(big.Int).Lsh(one, uint(tree.Height))
174+
if numLeafs.Cmp(index) <= 0 {
175+
panic(fmt.Sprintf("index out of bounds: %v, %v", numLeafs, index))
176+
}
177+
178+
subtree := tree.Subtrees
179+
if subtree == nil {
180+
if index.Cmp(zero) != 0 {
181+
panic(fmt.Sprintf("invalid Tree state: %v", tree))
182+
}
183+
if tree.Height != 0 {
184+
panic(fmt.Sprintf("invalid Tree state: %v", tree))
185+
}
186+
return Leaf(tree.RootHash, index)
187+
}
188+
189+
shiftAmount := uint(tree.Height - 1)
190+
isLeftLeaf := new(big.Int).Rsh(index, shiftAmount).Cmp(zero) == 0
191+
192+
// innerIndex = index & !(1 << shiftAmount)
193+
innerIndex := new(big.Int).And(
194+
index,
195+
new(big.Int).Not(
196+
new(big.Int).Lsh(
197+
one,
198+
shiftAmount,
199+
),
200+
),
201+
)
202+
203+
lhs, rhs := subtree.Children()
204+
if isLeftLeaf {
205+
proof := lhs.ProveLeafRec(innerIndex)
206+
proof.PushHash(rhs.RootHash)
207+
proof.Pos = index
208+
return proof
209+
} else {
210+
proof := rhs.ProveLeafRec(innerIndex)
211+
proof.PushHash(lhs.RootHash)
212+
proof.Pos = index
213+
return proof
214+
}
215+
}
216+
217+
////////////////////////////////////////////////////////////////////////////////
218+
219+
// Node: common-rs/merkle/src/tree_builder.rs
220+
type Node struct {
221+
Tree *Tree
222+
AccumulatedCount *big.Int
223+
}
224+
225+
type Builder struct {
226+
Trees []Node
227+
}
228+
229+
func (b *Builder) Height() (uint32, bool) {
230+
n := len(b.Trees)
231+
if n == 0 {
232+
return 0, false
233+
}
234+
return b.Trees[n-1].Tree.Height, true
235+
}
236+
237+
func (b *Builder) Count() (*big.Int, bool) {
238+
n := len(b.Trees)
239+
if n == 0 {
240+
return nil, false
241+
}
242+
return b.Trees[n-1].AccumulatedCount, true
243+
}
244+
245+
func (b *Builder) CanBuild() bool {
246+
n := len(b.Trees)
247+
if n == 0 {
248+
return false
249+
}
250+
return isPow2(b.Trees[n-1].AccumulatedCount)
251+
}
252+
253+
func (b *Builder) Append(leaf *Tree) {
254+
b.AppendRepeated(leaf, big.NewInt(1))
255+
}
256+
257+
func (b *Builder) AppendRepeatedUint64(leaf *Tree, reps uint64) {
258+
b.AppendRepeated(leaf, new(big.Int).SetUint64(reps))
259+
}
260+
261+
func (b *Builder) AppendRepeated(leaf *Tree, reps *big.Int) {
262+
zero := big.NewInt(0)
263+
if reps.Cmp(zero) <= 0 {
264+
panic("invalid repetitions")
265+
}
266+
267+
accumulatedCount := b.CalculateAccumulatedCount(reps)
268+
if height, ok := b.Height(); ok {
269+
if height != leaf.Height {
270+
panic("mismatched tree size")
271+
}
272+
}
273+
b.Trees = append(b.Trees, Node{
274+
Tree: leaf,
275+
AccumulatedCount: accumulatedCount,
276+
})
277+
}
278+
279+
func (b *Builder) Build() *Tree {
280+
if count, ok := b.Count(); ok {
281+
if !isCountPow2(count) {
282+
panic(fmt.Sprintf("builder has %v leafs, which is not a power of two", count))
283+
}
284+
log2Size := countTrailingZeroes(count)
285+
return buildMerkle(b.Trees, log2Size, big.NewInt(0))
286+
} else {
287+
panic("no leafs in the merkle builder")
288+
}
289+
}
290+
291+
func (b *Builder) CalculateAccumulatedCount(reps *big.Int) *big.Int {
292+
n := len(b.Trees)
293+
if n != 0 {
294+
zero := big.NewInt(0)
295+
if reps.Cmp(zero) == 0 {
296+
panic("merkle builder is full")
297+
}
298+
299+
// TODO: warping version
300+
return new(big.Int).Add(reps, b.Trees[n-1].AccumulatedCount)
301+
} else {
302+
return reps
303+
}
304+
}
305+
306+
func buildMerkle(trees []Node, log2Size uint, stride *big.Int) *Tree {
307+
one := big.NewInt(1)
308+
size := new(big.Int).Lsh(one, log2Size) // TODO: warping version
309+
310+
firstTime := new(big.Int).Add(new(big.Int).Mul(stride, size), one)
311+
lastTime := new(big.Int).Mul(new(big.Int).Add(stride, one), size)
312+
313+
firstCell := findCellContaining(trees, firstTime)
314+
lastCell := findCellContaining(trees, lastTime)
315+
316+
if firstCell == lastCell {
317+
tree := trees[firstCell].Tree
318+
iterated := tree.Iterated(uint64(log2Size))
319+
return iterated
320+
}
321+
322+
left := buildMerkle(trees[firstCell:(lastCell+1)],
323+
log2Size - 1,
324+
new(big.Int).Lsh(stride, 1),
325+
)
326+
327+
right := buildMerkle(trees[firstCell:(lastCell+1)],
328+
log2Size - 1,
329+
new(big.Int).Add(new(big.Int).Lsh(stride, 1), one),
330+
)
331+
332+
return left.Join(right)
333+
}
334+
335+
func findCellContaining(trees []Node, elem *big.Int) uint {
336+
one := big.NewInt(1)
337+
left := uint(0)
338+
right := uint(len(trees) - 1)
339+
340+
for ; left < right; {
341+
needle := left + (right - left) / 2
342+
343+
// TODO: wrapping version
344+
x := new(big.Int).Sub(trees[needle].AccumulatedCount, one)
345+
y := new(big.Int).Sub(elem, one)
346+
if x.Cmp(y) < 0 {
347+
left = needle + 1
348+
} else {
349+
right = needle
350+
}
351+
}
352+
return left
353+
}
354+
355+
////////////////////////////////////////////////////////////////////////////////
356+
357+
func isPow2(x *big.Int) bool {
358+
if x.Sign() <= 0 {
359+
return false
360+
}
361+
362+
// x & (x-1) == 0
363+
zero := big.NewInt(0)
364+
one := big.NewInt(1)
365+
return new(big.Int).And(
366+
x,
367+
new(big.Int).Sub(
368+
x,
369+
one,
370+
),
371+
).Cmp(zero) == 0
372+
}
373+
374+
func isCountPow2(x *big.Int) bool {
375+
return x.Cmp(big.NewInt(0)) == 0 || isPow2(x)
376+
}
377+
378+
func countTrailingZeroes(x *big.Int) uint {
379+
count := uint(0)
380+
381+
// each byte from least to most significant
382+
brk: for _, b := range slices.Backward(x.Bytes()) {
383+
for i := range 8 {
384+
if b >> i & 1 != 0 {
385+
break brk
386+
}
387+
count++
388+
}
389+
}
390+
return count
391+
}

0 commit comments

Comments
 (0)