Skip to content

Commit eca7921

Browse files
committed
implement cow on leaves
Signed-off-by: Ignacio Hagopian <[email protected]>
1 parent a649f3c commit eca7921

File tree

4 files changed

+115
-57
lines changed

4 files changed

+115
-57
lines changed

proof_test.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import (
3434
)
3535

3636
func TestProofVerifyTwoLeaves(t *testing.T) {
37+
cfg := GetConfig()
38+
3739
root := New()
3840
root.Insert(zeroKeyTest, zeroKeyTest, nil)
3941
root.Insert(oneKeyTest, zeroKeyTest, nil)
@@ -42,7 +44,6 @@ func TestProofVerifyTwoLeaves(t *testing.T) {
4244

4345
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{ffx32KeyTest}, map[string][]byte{string(ffx32KeyTest): zeroKeyTest})
4446

45-
cfg := GetConfig()
4647
if !VerifyVerkleProof(proof, cis, zis, yis, cfg) {
4748
t.Fatalf("could not verify verkle proof: %s", ToDot(root))
4849
}
@@ -176,6 +177,7 @@ func TestProofOfAbsenceLeafVerify(t *testing.T) {
176177
t.Fatal("could not verify verkle proof")
177178
}
178179
}
180+
179181
func TestProofOfAbsenceLeafVerifyOtherSuffix(t *testing.T) {
180182
root := New()
181183
root.Insert(zeroKeyTest, zeroKeyTest, nil)
@@ -212,6 +214,7 @@ func TestProofOfAbsenceStemVerify(t *testing.T) {
212214
}
213215

214216
func BenchmarkProofCalculation(b *testing.B) {
217+
_ = GetConfig()
215218
keys := make([][]byte, 100000)
216219
root := New()
217220
for i := 0; i < 100000; i++ {
@@ -220,6 +223,7 @@ func BenchmarkProofCalculation(b *testing.B) {
220223
keys[i] = key
221224
root.Insert(key, zeroKeyTest, nil)
222225
}
226+
root.Commit()
223227

224228
b.ResetTimer()
225229
b.ReportAllocs()
@@ -370,7 +374,6 @@ func TestProofDeserialize(t *testing.T) {
370374
}
371375

372376
func TestProofDeserializeErrors(t *testing.T) {
373-
374377
deserialized, err := DeserializeProof([]byte{0}, nil)
375378
if err == nil {
376379
t.Fatal("deserializing invalid proof didn't cause an error")

stateless_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func TestStatelessChildren(t *testing.T) {
4848
t.Fatal("invalid list length")
4949
}
5050

51-
var emptycount = 0
51+
emptycount := 0
5252
for _, v := range list {
5353
if _, ok := v.(Empty); ok {
5454
emptycount++
@@ -377,6 +377,7 @@ func TestStatelessDeserializeDepth2(t *testing.T) {
377377
}
378378

379379
func TestStatelessGetProofItems(t *testing.T) {
380+
_ = GetConfig()
380381
insertedKeys := [][]byte{zeroKeyTest, oneKeyTest, ffx32KeyTest}
381382
provenKeys := [][]byte{zeroKeyTest, fourtyKeyTest}
382383

tree.go

+98-50
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"bytes"
3030
"errors"
3131
"fmt"
32+
"sync"
3233

3334
"github.com/crate-crypto/go-ipa/banderwagon"
3435
)
@@ -187,6 +188,7 @@ type (
187188

188189
commitment *Point
189190
c1, c2 *Point
191+
cow map[byte][]byte
190192

191193
depth byte
192194
}
@@ -219,23 +221,6 @@ func NewLeafNode(stem []byte, values [][]byte) *LeafNode {
219221
c2: Generator(),
220222
}
221223

222-
// Initialize the commitment with the extension tree
223-
// marker and the stem.
224-
cfg := GetConfig()
225-
count := 0
226-
var poly, c1poly, c2poly [256]Fr
227-
poly[0].SetUint64(1)
228-
StemFromBytes(&poly[1], leaf.stem)
229-
230-
count = fillSuffixTreePoly(c1poly[:], values[:128])
231-
leaf.c1 = cfg.CommitToPoly(c1poly[:], 256-count)
232-
toFr(&poly[2], leaf.c1)
233-
count = fillSuffixTreePoly(c2poly[:], values[128:])
234-
leaf.c2 = cfg.CommitToPoly(c2poly[:], 256-count)
235-
toFr(&poly[3], leaf.c2)
236-
237-
leaf.commitment = cfg.CommitToPoly(poly[:], 252)
238-
239224
return leaf
240225
}
241226

@@ -844,7 +829,7 @@ func (n *LeafNode) updateC(index byte, c *Point, oldc *Fr) {
844829
n.commitment.Add(n.commitment, &diff)
845830
}
846831

847-
func (n *LeafNode) updateCn(index byte, value []byte, c *Point) {
832+
func (n *LeafNode) updateCn(index byte, oldValue []byte, c *Point) {
848833
var (
849834
old, newH [2]Fr
850835
diff Point
@@ -857,8 +842,8 @@ func (n *LeafNode) updateCn(index byte, value []byte, c *Point) {
857842
// do not include it. The result should be the same,
858843
// but the computation time should be faster as one doesn't need to
859844
// compute 1 - 1 mod N.
860-
leafToComms(old[:], n.values[index])
861-
leafToComms(newH[:], value)
845+
leafToComms(old[:], oldValue)
846+
leafToComms(newH[:], n.values[index])
862847

863848
newH[0].Sub(&newH[0], &old[0])
864849
poly[2*(index%128)] = newH[0]
@@ -873,42 +858,36 @@ func (n *LeafNode) updateCn(index byte, value []byte, c *Point) {
873858
}
874859

875860
func (n *LeafNode) updateLeaf(index byte, value []byte) {
876-
c, oldc := n.getOldCn(index)
877-
878-
n.updateCn(index, value, c)
861+
// If we haven't calculated a commitment for this node, we don't need to create the cow map since all the
862+
// previous values are empty. If we already have a calculated commitment, then we track new values in
863+
// cow so we can do diff-updating in the next Commit().
864+
if n.commitment != nil {
865+
// If cow was never setup, then initialize the map.
866+
if n.cow == nil {
867+
n.cow = make(map[byte][]byte)
868+
}
879869

880-
n.updateC(index, c, oldc)
870+
// If we are touching an value in an index for the first time,
871+
// we save the original value for future use to update commitments.
872+
if _, ok := n.cow[index]; !ok {
873+
if n.values[index] == nil {
874+
n.cow[index] = nil
875+
} else {
876+
n.cow[index] = make([]byte, 32)
877+
copy(n.cow[index], n.values[index])
878+
}
879+
}
880+
}
881881

882882
n.values[index] = value
883883
}
884884

885885
func (n *LeafNode) updateMultipleLeaves(values [][]byte) {
886-
var c1, c2 *Point
887-
var old1, old2 *Fr
888-
for i, v := range values {
889-
if len(v) != 0 && !bytes.Equal(v, n.values[i]) {
890-
if i < 128 {
891-
if c1 == nil {
892-
c1, old1 = n.getOldCn(byte(i))
893-
}
894-
n.updateCn(byte(i), v, c1)
895-
} else {
896-
if c2 == nil {
897-
c2, old2 = n.getOldCn(byte(i))
898-
}
899-
n.updateCn(byte(i), v, c2)
900-
}
901-
902-
n.values[i] = v
886+
for i := range values {
887+
if values[i] != nil {
888+
n.updateLeaf(byte(i), values[i])
903889
}
904890
}
905-
906-
if c1 != nil {
907-
n.updateC(0, c1, old1)
908-
}
909-
if c2 != nil {
910-
n.updateC(128, c2, old2)
911-
}
912891
}
913892

914893
func (n *LeafNode) InsertOrdered(key []byte, value []byte, _ NodeFlushFn) error {
@@ -957,8 +936,77 @@ func (n *LeafNode) Commitment() *Point {
957936
return n.commitment
958937
}
959938

960-
func (n *LeafNode) Commit() *Point {
961-
return n.commitment
939+
var frPool = sync.Pool{
940+
New: func() any {
941+
ret := make([]Fr, NodeWidth)
942+
return &ret
943+
},
944+
}
945+
946+
func (leaf *LeafNode) Commit() *Point {
947+
// If we've never calculated a commitment for this leaf node, we calculate the commitment
948+
// in a single shot considering all the values.
949+
if leaf.commitment == nil {
950+
// Initialize the commitment with the extension tree
951+
// marker and the stem.
952+
count := 0
953+
c1polyp := frPool.Get().(*[]Fr)
954+
c1poly := *c1polyp
955+
defer func() {
956+
for i := 0; i < 256; i++ {
957+
c1poly[i] = Fr{}
958+
}
959+
frPool.Put(c1polyp)
960+
}()
961+
962+
count = fillSuffixTreePoly(c1poly, leaf.values[:128])
963+
leaf.c1 = cfg.CommitToPoly(c1poly, 256-count)
964+
965+
for i := 0; i < 256; i++ {
966+
c1poly[i] = Fr{}
967+
}
968+
count = fillSuffixTreePoly(c1poly, leaf.values[128:])
969+
leaf.c2 = cfg.CommitToPoly(c1poly, 256-count)
970+
971+
for i := 0; i < 256; i++ {
972+
c1poly[i] = Fr{}
973+
}
974+
c1poly[0].SetUint64(1)
975+
StemFromBytes(&c1poly[1], leaf.stem)
976+
977+
toFrMultiple([]*Fr{&c1poly[2], &c1poly[3]}, []*Point{leaf.c1, leaf.c2})
978+
leaf.commitment = cfg.CommitToPoly(c1poly, 252)
979+
980+
} else if len(leaf.cow) != 0 {
981+
// If we've already have a calculated commitment, and there're touched leaf values, we do a diff update.
982+
var c1, c2 *Point
983+
var old1, old2 *Fr
984+
for i, oldValue := range leaf.cow {
985+
if !bytes.Equal(oldValue, leaf.values[i]) {
986+
if i < 128 {
987+
if c1 == nil {
988+
c1, old1 = leaf.getOldCn(i)
989+
}
990+
leaf.updateCn(i, oldValue, c1)
991+
} else {
992+
if c2 == nil {
993+
c2, old2 = leaf.getOldCn(i)
994+
}
995+
leaf.updateCn(i, oldValue, c2)
996+
}
997+
}
998+
}
999+
1000+
if c1 != nil {
1001+
leaf.updateC(0, c1, old1)
1002+
}
1003+
if c2 != nil {
1004+
leaf.updateC(128, c2, old2)
1005+
}
1006+
leaf.cow = nil
1007+
}
1008+
1009+
return leaf.commitment
9621010
}
9631011

9641012
// fillSuffixTreePoly takes one of the two suffix tree and

tree_test.go

+10-4
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,17 @@ import (
3333
"errors"
3434
"fmt"
3535
mRand "math/rand"
36+
"os"
3637
"sort"
3738
"testing"
3839
"time"
3940
)
4041

42+
func TestMain(m *testing.M) {
43+
_ = GetConfig()
44+
os.Exit(m.Run())
45+
}
46+
4147
// a 32 byte value, as expected in the tree structure
4248
var testValue = []byte("0123456789abcdef0123456789abcdef")
4349

@@ -106,7 +112,6 @@ func TestInsertTwoLeavesLastLevel(t *testing.T) {
106112
if !bytes.Equal(leaf.values[0], testValue) {
107113
t.Fatalf("did not find correct value in trie %x != %x", testValue, leaf.values[0])
108114
}
109-
110115
}
111116

112117
func TestGetTwoLeaves(t *testing.T) {
@@ -413,6 +418,7 @@ func TestDeleteUnequalPath(t *testing.T) {
413418
t.Fatalf("didn't catch the deletion of non-existing key, err =%v", err)
414419
}
415420
}
421+
416422
func TestDeleteResolve(t *testing.T) {
417423
key1, _ := hex.DecodeString("0105000000000000000000000000000000000000000000000000000000000000")
418424
key2, _ := hex.DecodeString("0107000000000000000000000000000000000000000000000000000000000000")
@@ -719,7 +725,7 @@ func isLeafEqual(a, b *LeafNode) bool {
719725

720726
func TestGetResolveFromHash(t *testing.T) {
721727
var count uint
722-
var dummyError = errors.New("dummy")
728+
dummyError := errors.New("dummy")
723729
var serialized []byte
724730
getter := func([]byte) ([]byte, error) {
725731
count++
@@ -813,7 +819,7 @@ func TestInsertIntoHashedNode(t *testing.T) {
813819
t.Fatalf("error detecting a decoding error after resolution: %v", err)
814820
}
815821

816-
var randomResolverError = errors.New("'clef' was mispronounced")
822+
randomResolverError := errors.New("'clef' was mispronounced")
817823
// Check that the proper error is raised if the resolver returns an error
818824
erroringResolver := func(h []byte) ([]byte, error) {
819825
return nil, randomResolverError
@@ -879,9 +885,9 @@ func TestLeafToCommsLessThan16(*testing.T) {
879885
}
880886

881887
func TestGetProofItemsNoPoaIfStemPresent(t *testing.T) {
882-
883888
root := New()
884889
root.Insert(ffx32KeyTest, zeroKeyTest, nil)
890+
root.Commit()
885891

886892
// insert two keys that differ from the inserted stem
887893
// by one byte.

0 commit comments

Comments
 (0)