Skip to content

Commit

Permalink
apples to apples merkle bench with akd
Browse files Browse the repository at this point in the history
  • Loading branch information
sanjit-bhat committed Jan 16, 2025
1 parent fa39292 commit d1a22b8
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 110 deletions.
10 changes: 10 additions & 0 deletions data/25-01-16-pav-akd-seeded-merkle.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
setup:
- merkle tree seeded with 1000 vals.
- add to tree over the bench.
- for GetMemb, only query a single val over bench.
- Put / Get only one elem per iter.
- all setup same for both pav and akd.

format: PutNoProof | PutWithProof | GetMemb | GetNonMemb
pav: 144us | 175us | 31us | 8us
akd: 73us | 90us | 9.8us | 11.8us
174 changes: 64 additions & 110 deletions merkle/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,173 +6,127 @@ import (
"testing"
)

func BenchmarkPut(b *testing.B) {
tr := NewTree()
val := []byte("val")
var seed [32]byte
rnd := rand.NewChaCha8(seed)
label := make([]byte, cryptoffi.HashLen)
var val = []byte("val")

func BenchmarkPutNoProof(b *testing.B) {
tr, rnd, label := newSeededTree(b, 1000)
b.ResetTimer()
for range b.N {
_, err := rnd.Read(label)
if err != nil {
b.Fatal(err)
}
_, _, errb := tr.Put(label, val)
_, errb := tr.putNoProof(label, val)
if errb {
b.Fatal()
}
}
}

func BenchmarkGetMemb(b *testing.B) {
tr := NewTree()
val := []byte("val")
var seed [32]byte
rnd := rand.NewChaCha8(seed)
label := make([]byte, cryptoffi.HashLen)

func BenchmarkPutWithProof(b *testing.B) {
tr, rnd, label := newSeededTree(b, 1000)
b.ResetTimer()
for range b.N {
_, err := rnd.Read(label)
if err != nil {
b.Fatal(err)
}
b.StopTimer()
_, _, errb := tr.Put(label, val)
if errb {
b.Fatal()
}
b.StartTimer()

_, _, _, _, errb = tr.Get(label)
if errb {
b.Fatal()
}
}
}

var mapVal []byte
var proof []byte

func BenchmarkGetNonMembNone(b *testing.B) {
tr := NewTree()
var seed [32]byte
rnd := rand.NewChaCha8(seed)
label := make([]byte, cryptoffi.HashLen)
nonEmpt := 0

tr2 := NewTree()
val := []byte("val")
for i := 0; i < 500; i++ {
_, err := rnd.Read(label)
if err != nil {
b.Fatal(err)
}
_, _, errb := tr2.Put(label, val)
func BenchmarkGetMemb(b *testing.B) {
tr, _, label := newSeededTree(b, 1000)
b.ResetTimer()
for range b.N {
_, _, _, _, errb := tr.Get(label)
if errb {
b.Fatal()
}
}
}

func BenchmarkGetNonMemb(b *testing.B) {
tr, rnd, label := newSeededTree(b, 1000)
b.ResetTimer()
for range b.N {
_, err := rnd.Read(label)
if err != nil {
b.Fatal(err)
}

mapVal0, _, _, proof0, errb := tr.Get(label)
mapVal = mapVal0
proof = proof0
_, _, _, _, errb := tr.Get(label)
if errb {
b.Fatal()
}
depth := uint64(len(proof0)) / hashesPerProofDepth
if depth != 0 {
nonEmpt++
}
}

b.Log(nonEmpt)
}

func BenchmarkGetNonMembSome(b *testing.B) {
tr := NewTree()
val := []byte("val")
func newSeededTree(b *testing.B, sz int) (tr *Tree, rnd *rand.ChaCha8, label []byte) {
tr = NewTree()
var seed [32]byte
rnd := rand.NewChaCha8(seed)
label := make([]byte, cryptoffi.HashLen)
totalDep := 0
total := 0
rnd = rand.NewChaCha8(seed)
label = make([]byte, cryptoffi.HashLen)

for i := 0; i < 500; i++ {
for i := 0; i < sz; i++ {
_, err := rnd.Read(label)
if err != nil {
b.Fatal(err)
}
_, _, errb := tr.Put(label, val)
_, errb := tr.putNoProof(label, val)
if errb {
b.Fatal()
}
}

b.ResetTimer()
for range b.N {
_, err := rnd.Read(label)
if err != nil {
b.Fatal(err)
}

mapVal0, _, _, proof0, errb := tr.Get(label)
mapVal = mapVal0
proof = proof0
if errb {
b.Fatal()
}
depth := len(proof0) / int(hashesPerProofDepth)
totalDep += depth
total++
}

b.Log("avg dep", float32(totalDep)/float32(total), "total", total)
return
}

func BenchmarkGetProofNone(b *testing.B) {
tr := NewTree()
label := make([]byte, cryptoffi.HashLen)

b.ResetTimer()
for range b.N {
proof = tr.ctx.getProof(tr.root, label)
// putNoProof returns the digest and error.
func (t *Tree) putNoProof(label []byte, mapVal []byte) ([]byte, bool) {
if uint64(len(label)) != cryptoffi.HashLen {
return nil, true
}
}

func BenchmarkGetProofSome(b *testing.B) {
tr := NewTree()
root := newInteriorNode()
child0 := newInteriorNode()
tr.root = root
root.children[0] = child0
label := make([]byte, cryptoffi.HashLen)

b.ResetTimer()
for range b.N {
proof = tr.ctx.getProof(tr.root, label)
// make all interior nodes.
var interiors = make([]*node, 0, cryptoffi.HashLen)
if t.root == nil {
t.root = newInteriorNode()
}
}

func BenchmarkMallocUnstable(b *testing.B) {
proofs := make([][]byte, 0, 1_000_000)
for range b.N {
proof := make([]byte, 0, cryptoffi.HashLen*hashesPerProofDepth)
proofs = append(proofs, proof)
interiors = append(interiors, t.root)
n := cryptoffi.HashLen - 1
for depth := uint64(0); depth < n; depth++ {
currNode := interiors[depth]

// XXX: Converting to `uint64` for Goose, since it does not handle the
// implicit conversion from uint8 to int when using `pos` as a slice
// index.
pos := uint64(label[depth])

if currNode.children[pos] == nil {
currNode.children[pos] = newInteriorNode()
}
interiors = append(interiors, currNode.children[pos])
}
}

func BenchmarkMallocWarmup(b *testing.B) {
var proof []byte
for range b.N {
proof = make([]byte, 0, cryptoffi.HashLen*hashesPerProofDepth)
proof = append(proof, 1)
// make leaf node with correct hash.
lastInterior := interiors[cryptoffi.HashLen-1]
// XXX: To deal with goose failing to handle the implicit conversion to int
// when using as a slice index
lastPos := uint64(label[cryptoffi.HashLen-1])
lastInterior.children[lastPos] = &node{mapVal: mapVal, hash: compLeafNodeHash(mapVal)}

// correct hashes of interior nodes, bubbling up.
// +1/-1 offsets for Goosable uint64 loop var.
var loopBuf = make([]byte, 0, numChildren*cryptoffi.HashLen+1)
var depth = cryptoffi.HashLen
for depth >= 1 {
loopBuf = t.ctx.updInteriorHash(loopBuf, interiors[depth-1])
loopBuf = loopBuf[:0]
depth--
}

dig := t.ctx.getHash(t.root)
return dig, false
}

0 comments on commit d1a22b8

Please sign in to comment.