Skip to content

Commit

Permalink
feat: fix backstepping to work correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
h5law committed Sep 22, 2023
1 parent a9d07d0 commit d058d81
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 20 deletions.
40 changes: 20 additions & 20 deletions smt.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,56 +393,53 @@ func (smt *SMT) ProveClosest(path []byte) (
proof *SparseMerkleProof, // proof of the key-value pair found
err error, // the error value encountered
) {
workingPath := make([]byte, len(path), len(path))

Check failure on line 396 in smt.go

View workflow job for this annotation

GitHub Actions / Go Tests (1.19)

S1019: should use make([]byte, len(path)) instead (gosimple)
copy(workingPath, path)
var siblings []treeNode
var sib treeNode
var parent treeNode
var parentDepth int
var depthDelta int

node := smt.tree
depth := 0
// continuously traverse the tree until we hit a leaf node
for depth < smt.depth() {
// save current node information as "parent" info
if node != nil {
parent = node
}
// resolve current node
node, err = smt.resolveLazy(node)
if err != nil {
return nil, nil, nil, err
}

Check warning on line 415 in smt.go

View check run for this annotation

Codecov / codecov/patch

smt.go#L414-L415

Added lines #L414 - L415 were not covered by tests
// save current node information as "parent" info
parentDepth = depth
parent = node
// if we hit a nil node we must back-step and try the other child of the
// parent node (left -> right, right -> left)
// if we hit a nil node we backstep to the parent node and flip the path bit
// at the parent depth and select the other child
if node == nil {
parent, err = smt.resolveLazy(parent)
node, err = smt.resolveLazy(parent)
if err != nil {
return nil, nil, nil, err
}

Check warning on line 422 in smt.go

View check run for this annotation

Codecov / codecov/patch

smt.go#L421-L422

Added lines #L421 - L422 were not covered by tests
inner, ok := parent.(*innerNode)
if !ok {
panic("parent not inner node")
}
// trim the last sibling node added as it is no longer relevant
if len(siblings) > 0 {
siblings = siblings[:len(siblings)-1]
}
depth = parentDepth
// flip the path bit at the parent depth and select the other child
if GetPathBit(path, depth) == left {
node = inner.rightChild
} else {
node = inner.leftChild
}
depth -= depthDelta
// flip the path bit at the parent depth
flipPathBit(workingPath, depth)
}
// end traversal when we hit a leaf node
if _, ok := node.(*leafNode); ok {
break
}
if ext, ok := node.(*extensionNode); ok {
length, match := ext.match(path, depth)
length, match := ext.match(workingPath, depth)
if match {
for i := 0; i < length; i++ {
siblings = append(siblings, nil)
}
depth += length
depthDelta = length

Check failure on line 442 in smt.go

View workflow job for this annotation

GitHub Actions / Go Tests (1.19)

ineffectual assignment to depthDelta (ineffassign)
node = ext.child
node, err = smt.resolveLazy(node)
if err != nil {
Expand All @@ -453,13 +450,14 @@ func (smt *SMT) ProveClosest(path []byte) (
}
}
inner := node.(*innerNode)
if GetPathBit(path, depth) == left {
if GetPathBit(workingPath, depth) == left {
node, sib = inner.leftChild, inner.rightChild
} else {
node, sib = inner.rightChild, inner.leftChild
}
siblings = append(siblings, sib)
depth += 1
depthDelta = 1
}

// Retrieve the closest path and value hash if found
Expand Down Expand Up @@ -749,6 +747,8 @@ func (ext *extensionNode) split(path []byte, depth int) (treeNode, *treeNode, in
return head, &b, index
}

// expand returns the inner node that represents the start of the singly
// linked list that this extension node represents
func (ext *extensionNode) expand() treeNode {
last := ext.child
for i := ext.pathEnd() - 1; i >= ext.pathStart(); i-- {
Expand Down
7 changes: 7 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ func setPathBit(data []byte, position int) {
data[position/8] = byte(n)
}

// flipPathBit flips the bit at an offset from the most significant bit
func flipPathBit(data []byte, position int) {
n := int(data[position/8]) // get index of byte containing the position
n ^= 1 << (8 - 1 - uint(position)%8) // XOR the bit within the byte at the position
data[position/8] = byte(n)
}

func countSetBits(data []byte) int {
count := 0
for i := 0; i < len(data)*8; i++ {
Expand Down

0 comments on commit d058d81

Please sign in to comment.