Skip to content

Commit

Permalink
Rename hyper pruning package
Browse files Browse the repository at this point in the history
Co-authored-by: Gabriel Díaz <g.diaz.lopezllave@bbva.com>
  • Loading branch information
aalda and gdiazlo committed Feb 25, 2019
1 parent 03693e2 commit 17e27a9
Show file tree
Hide file tree
Showing 24 changed files with 1,517 additions and 2,987 deletions.
6 changes: 3 additions & 3 deletions balloon/hyper2/proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"bytes"

"github.com/bbva/qed/balloon/hyper2/navigation"
"github.com/bbva/qed/balloon/hyper2/pruning2"
"github.com/bbva/qed/balloon/hyper2/pruning"
"github.com/bbva/qed/hashing"
"github.com/bbva/qed/log"
)
Expand Down Expand Up @@ -53,8 +53,8 @@ func (p QueryProof) Verify(key []byte, expectedRootHash hashing.Digest) (valid b
}

// build a stack of operations and then interpret it to recompute the root hash
ops := pruning2.PruneToVerify(key, p.Value, p.hasher.Len()-uint16(len(p.AuditPath)))
ctx := &pruning2.Context{
ops := pruning.PruneToVerify(key, p.Value, p.hasher.Len()-uint16(len(p.AuditPath)))
ctx := &pruning.Context{
Hasher: p.hasher,
AuditPath: p.AuditPath,
}
Expand Down
18 changes: 17 additions & 1 deletion balloon/hyper2/pruning/batch.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
Copyright 2018 Banco Bilbao Vizcaya Argentaria, S.A.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package pruning

import (
Expand Down Expand Up @@ -35,7 +51,7 @@ func (b BatchNode) String() string {
}

func (b BatchNode) HasLeafAt(i int8) bool {
return b.Batch[i][b.nodeSize] == byte(1)
return len(b.Batch[i]) > 0 && b.Batch[i][b.nodeSize] == byte(1)
}

func (b BatchNode) AddHashAt(i int8, value []byte) {
Expand Down
191 changes: 93 additions & 98 deletions balloon/hyper2/pruning/insert.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
Copyright 2018 Banco Bilbao Vizcaya Argentaria, S.A.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package pruning

import (
Expand Down Expand Up @@ -43,93 +59,79 @@ func (l Leaves) Split(index []byte) (left, right Leaves) {
return l[:splitIndex], l[splitIndex:]
}

type TraverseBatch func(pos *navigation.Position, leaves Leaves, batch *BatchNode, iBatch int8) (Operation, error)
type TraverseBatch func(pos navigation.Position, leaves Leaves, batch *BatchNode, iBatch int8, ops *OperationsStack)

func PruneToInsert(index []byte, value []byte, cacheHeightLimit uint16, batches BatchLoader) (Operation, error) {
func PruneToInsert(index []byte, value []byte, cacheHeightLimit uint16, batches BatchLoader) *OperationsStack {

var traverse, traverseThroughCache, traverseAfterCache TraverseBatch

traverse = func(pos *navigation.Position, leaves Leaves, batch *BatchNode, iBatch int8) (Operation, error) {

var err error
traverse = func(pos navigation.Position, leaves Leaves, batch *BatchNode, iBatch int8, ops *OperationsStack) {
if batch == nil {
batch, err = batches.Load(pos)
if err != nil {
return nil, err
}
batch = batches.Load(pos)
}

if pos.Height > cacheHeightLimit {
return traverseThroughCache(pos, leaves, batch, iBatch)
traverseThroughCache(pos, leaves, batch, iBatch, ops)
} else {
traverseAfterCache(pos, leaves, batch, iBatch, ops)
}
return traverseAfterCache(pos, leaves, batch, iBatch)

}

traverseThroughCache = func(pos *navigation.Position, leaves Leaves, batch *BatchNode, iBatch int8) (Operation, error) {
traverseThroughCache = func(pos navigation.Position, leaves Leaves, batch *BatchNode, iBatch int8, ops *OperationsStack) {

if len(leaves) == 0 { // discarded branch
if batch.HasElementAt(iBatch) {
return NewUseProvidedOp(pos, batch, iBatch), nil
ops.Push(getProvidedHash(pos, iBatch, batch))
} else {
ops.Push(getDefaultHash(pos))
}
return NewGetDefaultOp(pos), nil
return
}

// at the end of a batch tree
if iBatch > 0 && pos.Height%4 == 0 {
op, err := traverse(pos, leaves, nil, 0)
if err != nil {
return nil, err
}
return NewPutBatchOp(op, batch), nil
traverse(pos, leaves, nil, 0, ops)
ops.Push(updateBatchNode(pos, iBatch, batch))
return
}

// on an internal node of the subtree

// we found a node in our path
if batch.HasElementAt(iBatch) {
// we found a shortcut leaf in our path
if batch.HasLeafAt(iBatch) {
// push down leaf
key, value := batch.GetLeafKVAt(iBatch)
leaves = leaves.InsertSorted(Leaf{key, value})
batch.ResetElementAt(iBatch)
batch.ResetElementAt(2*iBatch + 1)
batch.ResetElementAt(2*iBatch + 2)
return traverse(pos, leaves, batch, iBatch)
}
// we found a node in our path and it is a shortcut leaf
if batch.HasLeafAt(iBatch) {
// push down leaf
key, value := batch.GetLeafKVAt(iBatch)
leaves = leaves.InsertSorted(Leaf{key, value})
batch.ResetElementAt(iBatch)
batch.ResetElementAt(2*iBatch + 1)
batch.ResetElementAt(2*iBatch + 2)
traverseThroughCache(pos, leaves, batch, iBatch, ops)
return
}

// on an internal node with more than one leaf

rightPos := pos.Right()
leftPos := pos.Left()
leftLeaves, rightLeaves := leaves.Split(rightPos.Index)

left, err := traverse(&leftPos, leftLeaves, batch, 2*iBatch+1)
if err != nil {
return nil, err
}
right, err := traverse(&rightPos, rightLeaves, batch, 2*iBatch+2)
if err != nil {
return nil, err
}
traverseThroughCache(pos.Left(), leftLeaves, batch, 2*iBatch+1, ops)
traverseThroughCache(rightPos, rightLeaves, batch, 2*iBatch+2, ops)

op := NewInnerHashOp(pos, batch, iBatch, left, right)
ops.PushAll(innerHash(pos), updateBatchNode(pos, iBatch, batch))
if iBatch == 0 { // it's the root of the batch tree
return NewPutBatchOp(op, batch), nil
ops.Push(putInCache(pos, batch))
}
return op, nil

}

traverseAfterCache = func(pos *navigation.Position, leaves Leaves, batch *BatchNode, iBatch int8) (Operation, error) {
traverseAfterCache = func(pos navigation.Position, leaves Leaves, batch *BatchNode, iBatch int8, ops *OperationsStack) {

if len(leaves) == 0 { // discarded branch
if batch.HasElementAt(iBatch) {
return NewUseProvidedOp(pos, batch, iBatch), nil
ops.Push(getProvidedHash(pos, iBatch, batch))
} else {
ops.Push(getDefaultHash(pos))
}
return NewGetDefaultOp(pos), nil
return
}

// at the end of the main tree
Expand All @@ -140,92 +142,85 @@ func PruneToInsert(index []byte, value []byte, cacheHeightLimit uint16, batches
}
// create or update the leaf with a new shortcut
newBatch := NewEmptyBatchNode(len(pos.Index))
shortcut := NewMutateBatchOp(
NewShortcutLeafOp(pos, newBatch, 0, leaves[0].Index, leaves[0].Value),
newBatch,
ops.PushAll(
leafHash(pos, leaves[0].Value),
updateBatchShortcut(pos, 0, newBatch, leaves[0].Index, leaves[0].Value),
mutateBatch(pos, newBatch),
updateBatchNode(pos, iBatch, batch),
)
return NewLeafOp(pos, batch, iBatch, shortcut), nil
return
}

// at the end of a subtree
if iBatch > 0 && pos.Height%4 == 0 {
if len(leaves) > 1 {
// with more than one leaf to insert -> it's impossible to be a shortcut leaf
op, err := traverse(pos, leaves, nil, 0)
if err != nil {
return nil, err
}
return NewLeafOp(pos, batch, iBatch, op), nil
traverse(pos, leaves, nil, 0, ops)
ops.Push(updateBatchNode(pos, iBatch, batch))
return
}
// with only one leaf to insert -> add a new shortcut leaf or continue traversing
// with only one leaf to insert -> continue traversing
if batch.HasElementAt(iBatch) {
// continue traversing
op, err := traverse(pos, leaves, nil, 0)
if err != nil {
return nil, err
}
return NewLeafOp(pos, batch, iBatch, op), nil
traverse(pos, leaves, nil, 0, ops)
ops.Push(updateBatchNode(pos, iBatch, batch))
return
}
// nil value (no previous node stored) so create a new shortcut batch
newBatch := NewEmptyBatchNode(len(pos.Index))
shortcut := NewMutateBatchOp(
NewShortcutLeafOp(pos, newBatch, 0, leaves[0].Index, leaves[0].Value),
newBatch,
ops.PushAll(
leafHash(pos, leaves[0].Value),
updateBatchShortcut(pos, 0, newBatch, leaves[0].Index, leaves[0].Value),
mutateBatch(pos, newBatch),
updateBatchNode(pos, iBatch, batch),
)
return NewLeafOp(pos, batch, iBatch, shortcut), nil
return
}

// on an internal node with only one leaf to insert

if len(leaves) == 1 {
// we found a nil in our path -> create a shortcut leaf
if !batch.HasElementAt(iBatch) {
shortcut := NewShortcutLeafOp(pos, batch, iBatch, leaves[0].Index, leaves[0].Value)
if pos.Height%4 == 0 { // at the root or at leaf of the subtree
return NewMutateBatchOp(shortcut, NewEmptyBatchNode(len(pos.Index))), nil
ops.PushAll(
leafHash(pos, leaves[0].Value),
updateBatchShortcut(pos, iBatch, batch, leaves[0].Index, leaves[0].Value),
)
if pos.Height%4 == 0 { // at the root or at a leaf of the subtree (not necessary to check iBatch)
ops.Push(mutateBatch(pos, batch))
}
return shortcut, nil
return
}

// we found a node in our path
if batch.HasElementAt(iBatch) {
// we found a shortcut leaf in our path
if batch.HasLeafAt(iBatch) {
// push down leaf
key, value := batch.GetLeafKVAt(iBatch)
leaves = leaves.InsertSorted(Leaf{key, value})
batch.ResetElementAt(iBatch)
batch.ResetElementAt(2*iBatch + 1)
batch.ResetElementAt(2*iBatch + 2)
return traverse(pos, leaves, batch, iBatch)
}
// we found a node in our path and itis a shortcut leaf
if batch.HasLeafAt(iBatch) {
// push down leaf
key, value := batch.GetLeafKVAt(iBatch)
leaves = leaves.InsertSorted(Leaf{key, value})
batch.ResetElementAt(iBatch)
batch.ResetElementAt(2*iBatch + 1)
batch.ResetElementAt(2*iBatch + 2)
traverseAfterCache(pos, leaves, batch, iBatch, ops)
return
}
}

// on an internal node with more than one leaf
rightPos := pos.Right()
leftPos := pos.Left()
leftLeaves, rightLeaves := leaves.Split(rightPos.Index)

left, err := traverse(&leftPos, leftLeaves, batch, 2*iBatch+1)
if err != nil {
return nil, err
}
right, err := traverse(&rightPos, rightLeaves, batch, 2*iBatch+2)
if err != nil {
return nil, err
}
traverseAfterCache(pos.Left(), leftLeaves, batch, 2*iBatch+1, ops)
traverseAfterCache(rightPos, rightLeaves, batch, 2*iBatch+2, ops)

op := NewInnerHashOp(pos, batch, iBatch, left, right)
ops.PushAll(innerHash(pos), updateBatchNode(pos, iBatch, batch))
if iBatch == 0 { // at root node -> mutate batch
return NewMutateBatchOp(op, batch), nil
ops.Push(mutateBatch(pos, batch))
}
return op, nil

}

ops := NewOperationsStack()
leaves := make(Leaves, 0)
leaves = leaves.InsertSorted(Leaf{index, value})
root := navigation.NewRootPosition(uint16(len(index) * 8))
return traverse(&root, leaves, nil, 0)
traverse(navigation.NewRootPosition(uint16(len(index)*8)), leaves, nil, 0, ops)
return ops
}
Loading

0 comments on commit 17e27a9

Please sign in to comment.