Skip to content

Commit fa4d349

Browse files
committed
feat: add build root children from proof
1 parent df8aefa commit fa4d349

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

internal/merkle/builder.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package merkle
55

66
import (
7+
"errors"
78
"fmt"
89
"math/big"
910
"slices"
@@ -50,6 +51,33 @@ func (proof *Proof) BuildRoot() common.Hash {
5051
return rootHash
5152
}
5253

54+
func (proof *Proof) BuildRootChildren() (common.Hash, common.Hash, error) {
55+
if len(proof.Siblings) == 0 {
56+
zero := common.Hash{}
57+
return zero, zero, errors.New("Siblings array is empty")
58+
}
59+
two := big.NewInt(2)
60+
height := len(proof.Siblings)
61+
childHash := proof.Node
62+
63+
for i, s := range proof.Siblings[:height-1] {
64+
65+
// ((pos >> i) % 2) == 0
66+
if new(big.Int).Rem(new(big.Int).Rsh(proof.Pos, uint(i)), two).Cmp(zero) == 0 {
67+
childHash = crypto.Keccak256Hash(childHash[:], s[:])
68+
} else {
69+
childHash = crypto.Keccak256Hash(s[:], childHash[:])
70+
}
71+
}
72+
73+
// ((pos >> (height-1)) % 2) == 0
74+
if new(big.Int).Rem(new(big.Int).Rsh(proof.Pos, uint(height-1)), two).Cmp(zero) == 0 {
75+
return childHash, proof.Siblings[height-1], nil
76+
} else {
77+
return proof.Siblings[height-1], childHash, nil
78+
}
79+
}
80+
5381
func (proof *Proof) VerifyRoot(other common.Hash) bool {
5482
return proof.BuildRoot() == other
5583
}
@@ -58,6 +86,15 @@ func (proof *Proof) PushHash(h common.Hash) {
5886
proof.Siblings = append(proof.Siblings, h)
5987
}
6088

89+
func RootChildrenFromProof(leaf common.Hash, siblings []common.Hash, index uint64) (common.Hash, common.Hash, error) {
90+
p := &Proof{
91+
Pos: new(big.Int).SetUint64(index),
92+
Node: leaf,
93+
Siblings: siblings,
94+
}
95+
return p.BuildRootChildren()
96+
}
97+
6198
////////////////////////////////////////////////////////////////////////////////
6299

63100
// MerkleTree: dave/common-rs/merkle/src/tree.rs

internal/merkle/builder_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"testing"
99

1010
"github.com/ethereum/go-ethereum/common"
11+
"github.com/ethereum/go-ethereum/crypto"
1112
"github.com/stretchr/testify/assert"
1213
)
1314

@@ -129,6 +130,54 @@ func TestAppendAndRepeated(t *testing.T) {
129130
assert.Equal(t, tree1, tree2)
130131
}
131132

133+
func TestBuildRootChildren1(t *testing.T) {
134+
p := Proof{
135+
Pos: big.NewInt(1),
136+
Node: common.HexToHash("0x01"),
137+
Siblings: []common.Hash{
138+
common.HexToHash("0x02"),
139+
},
140+
}
141+
rootHash := p.BuildRoot()
142+
lhs, rhs, err := p.BuildRootChildren()
143+
144+
assert.Nil(t, err)
145+
assert.Equal(t, rootHash, crypto.Keccak256Hash(lhs[:], rhs[:]))
146+
}
147+
148+
func TestBuildRootChildren2(t *testing.T) {
149+
p := Proof{
150+
Pos: big.NewInt(1),
151+
Node: common.HexToHash("0x01"),
152+
Siblings: []common.Hash{
153+
common.HexToHash("0x02"),
154+
common.HexToHash("0x03"),
155+
},
156+
}
157+
rootHash := p.BuildRoot()
158+
lhs, rhs, err := p.BuildRootChildren()
159+
160+
assert.Nil(t, err)
161+
assert.Equal(t, rootHash, crypto.Keccak256Hash(lhs[:], rhs[:]))
162+
}
163+
164+
func TestBuildRootChildren3(t *testing.T) {
165+
p := Proof{
166+
Pos: big.NewInt(1),
167+
Node: common.HexToHash("0x01"),
168+
Siblings: []common.Hash{
169+
common.HexToHash("0x02"),
170+
common.HexToHash("0x03"),
171+
common.HexToHash("0x04"),
172+
},
173+
}
174+
rootHash := p.BuildRoot()
175+
lhs, rhs, err := p.BuildRootChildren()
176+
177+
assert.Nil(t, err)
178+
assert.Equal(t, rootHash, crypto.Keccak256Hash(lhs[:], rhs[:]))
179+
}
180+
132181
// repanicked
133182
//func TestBuildNotPow2(t *testing.T) {
134183
// defer recover()

0 commit comments

Comments
 (0)