Skip to content

Commit

Permalink
Make GetProofItems capable of resolving hashed nodes (#377)
Browse files Browse the repository at this point in the history
* GetProofItems is now able to resolve HashedNodes

* quell linter
  • Loading branch information
gballet authored Aug 29, 2023
1 parent cdd8a92 commit 1261831
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 43 deletions.
2 changes: 1 addition & 1 deletion empty.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (Empty) Commitment() *Point {
return &id
}

func (Empty) GetProofItems(keylist) (*ProofElements, []byte, [][]byte, error) {
func (Empty) GetProofItems(keylist, NodeResolverFn) (*ProofElements, []byte, [][]byte, error) {
return nil, nil, nil, errors.New("trying to produce a commitment for an empty subtree")
}

Expand Down
2 changes: 1 addition & 1 deletion empty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func TestEmptyFuncs(t *testing.T) {
t.Fatal("commitment and commit mismatch")
}

if _, _, _, err := e.GetProofItems(nil); err == nil {
if _, _, _, err := e.GetProofItems(nil, nil); err == nil {
t.Fatal("get proof items should error")
}

Expand Down
2 changes: 1 addition & 1 deletion hashednode.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (HashedNode) Commitment() *Point {
panic("can not get commitment of a hash node")
}

func (HashedNode) GetProofItems(keylist) (*ProofElements, []byte, [][]byte, error) {
func (HashedNode) GetProofItems(keylist, NodeResolverFn) (*ProofElements, []byte, [][]byte, error) {
return nil, nil, nil, errors.New("can not get the full path, and there is no proof of absence")
}

Expand Down
2 changes: 1 addition & 1 deletion hashednode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func TestHashedNodeFuncs(t *testing.T) {
if v != nil {
t.Fatal("non-nil get from a hashed node")
}
if _, _, _, err := e.GetProofItems(nil); err == nil {
if _, _, _, err := e.GetProofItems(nil, nil); err == nil {
t.Fatal("got nil error when getting proof items from a hashed node")
}
if _, err := e.Serialize(); err != errSerializeHashedNode {
Expand Down
8 changes: 4 additions & 4 deletions proof_ipa.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ type StemStateDiff struct {

type StateDiff []StemStateDiff

func GetCommitmentsForMultiproof(root VerkleNode, keys [][]byte) (*ProofElements, []byte, [][]byte, error) {
func GetCommitmentsForMultiproof(root VerkleNode, keys [][]byte, resolver NodeResolverFn) (*ProofElements, []byte, [][]byte, error) {
sort.Sort(keylist(keys))
return root.GetProofItems(keylist(keys))
return root.GetProofItems(keylist(keys), resolver)
}

func MakeVerkleMultiProof(root VerkleNode, keys [][]byte) (*Proof, []*Point, []byte, []*Fr, error) {
func MakeVerkleMultiProof(root VerkleNode, keys [][]byte, resolver NodeResolverFn) (*Proof, []*Point, []byte, []*Fr, error) {
// go-ipa won't accept no key as an input, catch this corner case
// and return an empty result.
if len(keys) == 0 {
Expand All @@ -89,7 +89,7 @@ func MakeVerkleMultiProof(root VerkleNode, keys [][]byte) (*Proof, []*Point, []b
tr := common.NewTranscript("vt")
root.Commit()

pe, es, poas, err := GetCommitmentsForMultiproof(root, keys)
pe, es, poas, err := GetCommitmentsForMultiproof(root, keys, resolver)
if err != nil {
return nil, nil, nil, nil, err
}
Expand Down
48 changes: 24 additions & 24 deletions proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestProofVerifyTwoLeaves(t *testing.T) {
root.Insert(ffx32KeyTest, zeroKeyTest, nil)
root.Commit()

proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{ffx32KeyTest})
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{ffx32KeyTest}, nil)

cfg := GetConfig()
if !VerifyVerkleProof(proof, cis, zis, yis, cfg) {
Expand All @@ -65,7 +65,7 @@ func TestProofVerifyMultipleLeaves(t *testing.T) {
root.Insert(key, fourtyKeyTest, nil)
}

proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{keys[0]})
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{keys[0]}, nil)

cfg := GetConfig()
if !VerifyVerkleProof(proof, cis, zis, yis, cfg) {
Expand All @@ -87,9 +87,9 @@ func TestMultiProofVerifyMultipleLeaves(t *testing.T) {
root.Insert(key, fourtyKeyTest, nil)
}

proof, _, _, _, _ := MakeVerkleMultiProof(root, keys[0:2])
proof, _, _, _, _ := MakeVerkleMultiProof(root, keys[0:2], nil)

pe, _, _, err := GetCommitmentsForMultiproof(root, keys[0:2])
pe, _, _, err := GetCommitmentsForMultiproof(root, keys[0:2], nil)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -123,9 +123,9 @@ func TestMultiProofVerifyMultipleLeavesWithAbsentStem(t *testing.T) {
absent[3] = 1 // and the stem differs
keys = append(keys, absent)

proof, _, _, _, _ := MakeVerkleMultiProof(root, keys)
proof, _, _, _, _ := MakeVerkleMultiProof(root, keys, nil)

pe, _, isabsent, err := GetCommitmentsForMultiproof(root, keys)
pe, _, isabsent, err := GetCommitmentsForMultiproof(root, keys, nil)
if err != nil {
t.Fatal(err)
}
Expand All @@ -152,9 +152,9 @@ func TestMultiProofVerifyMultipleLeavesCommitmentRedundancy(t *testing.T) {
keys[1] = oneKeyTest
root.Insert(keys[1], fourtyKeyTest, nil)

proof, _, _, _, _ := MakeVerkleMultiProof(root, keys)
proof, _, _, _, _ := MakeVerkleMultiProof(root, keys, nil)

pe, _, _, err := GetCommitmentsForMultiproof(root, keys)
pe, _, _, err := GetCommitmentsForMultiproof(root, keys, nil)
if err != nil {
t.Fatal(err)
}
Expand All @@ -171,7 +171,7 @@ func TestProofOfAbsenceInternalVerify(t *testing.T) {
root.Insert(zeroKeyTest, zeroKeyTest, nil)
root.Insert(oneKeyTest, zeroKeyTest, nil)

proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{ffx32KeyTest})
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{ffx32KeyTest}, nil)

cfg := GetConfig()
if !VerifyVerkleProof(proof, cis, zis, yis, cfg) {
Expand All @@ -186,7 +186,7 @@ func TestProofOfAbsenceLeafVerify(t *testing.T) {
root.Insert(zeroKeyTest, zeroKeyTest, nil)
root.Insert(ffx32KeyTest, zeroKeyTest, nil)

proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{oneKeyTest})
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{oneKeyTest}, nil)

cfg := GetConfig()
if !VerifyVerkleProof(proof, cis, zis, yis, cfg) {
Expand All @@ -205,7 +205,7 @@ func TestProofOfAbsenceLeafVerifyOtherSuffix(t *testing.T) {
return ret
}()

proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{key})
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{key}, nil)

cfg := GetConfig()
if !VerifyVerkleProof(proof, cis, zis, yis, cfg) {
Expand All @@ -224,7 +224,7 @@ func TestProofOfAbsenceStemVerify(t *testing.T) {
return ret
}()

proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{key})
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{key}, nil)

cfg := GetConfig()
if !VerifyVerkleProof(proof, cis, zis, yis, cfg) {
Expand All @@ -246,7 +246,7 @@ func BenchmarkProofCalculation(b *testing.B) {
b.ReportAllocs()

for i := 0; i < b.N; i++ {
MakeVerkleMultiProof(root, [][]byte{keys[len(keys)/2]})
MakeVerkleMultiProof(root, [][]byte{keys[len(keys)/2]}, nil)
}
}

Expand All @@ -261,7 +261,7 @@ func BenchmarkProofVerification(b *testing.B) {
}

root.Commit()
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{keys[len(keys)/2]})
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{keys[len(keys)/2]}, nil)

b.ResetTimer()
b.ReportAllocs()
Expand All @@ -286,7 +286,7 @@ func TestProofSerializationNoAbsentStem(t *testing.T) {
root.Insert(key, fourtyKeyTest, nil)
}

proof, _, _, _, _ := MakeVerkleMultiProof(root, [][]byte{keys[0]})
proof, _, _, _, _ := MakeVerkleMultiProof(root, [][]byte{keys[0]}, nil)

vp, statediff, err := SerializeProof(proof)
if err != nil {
Expand Down Expand Up @@ -322,7 +322,7 @@ func TestProofSerializationWithAbsentStem(t *testing.T) {
absentkey[2] = 2
absentkey[3] = 1

proof, _, _, _, _ := MakeVerkleMultiProof(root, [][]byte{absentkey[:]})
proof, _, _, _, _ := MakeVerkleMultiProof(root, [][]byte{absentkey[:]}, nil)

vp, statediff, err := SerializeProof(proof)
if err != nil {
Expand Down Expand Up @@ -360,7 +360,7 @@ func TestProofDeserialize(t *testing.T) {
absentkey[2] = 2
absentkey[3] = 1

proof, _, _, _, _ := MakeVerkleMultiProof(root, [][]byte{absentkey[:]})
proof, _, _, _, _ := MakeVerkleMultiProof(root, [][]byte{absentkey[:]}, nil)

vp, statediff, err := SerializeProof(proof)
if err != nil {
Expand All @@ -373,7 +373,7 @@ func TestProofDeserialize(t *testing.T) {
}
_ = deserialized

pe, _, _, err := root.GetProofItems(keylist{absentkey[:]})
pe, _, _, err := root.GetProofItems(keylist{absentkey[:]}, nil)
if err != nil {
t.Fatal(err)
}
Expand All @@ -390,7 +390,7 @@ func TestProofOfAbsenceEdgeCase(t *testing.T) {
root.Commit()

ret, _ := hex.DecodeString("0303030303030303030303030303030303030303030303030303030303030303")
proof, cs, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{ret})
proof, cs, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{ret}, nil)
cfg := GetConfig()
if !VerifyVerkleProof(proof, cs, zis, yis, cfg) {
t.Fatal("could not verify proof")
Expand All @@ -409,7 +409,7 @@ func TestProofOfAbsenceOtherMultipleLeaves(t *testing.T) {

ret1, _ := hex.DecodeString("0303030303030303030303030303030303030303030303030303030303030300")
ret2, _ := hex.DecodeString("0303030303030303030303030303030303030303030303030303030303030301")
proof, cs, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{ret1, ret2})
proof, cs, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{ret1, ret2}, nil)
cfg := GetConfig()
if !VerifyVerkleProof(proof, cs, zis, yis, cfg) {
t.Fatal("could not verify proof")
Expand All @@ -430,7 +430,7 @@ func TestProofOfAbsenceNoneMultipleStems(t *testing.T) {

ret1, _ := hex.DecodeString("0303030303030303030303030303030303030303030303030303030303030300")
ret2, _ := hex.DecodeString("0303030303030303030303030303030303030303030303030303030303030200")
proof, cs, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{ret1, ret2})
proof, cs, zis, yis, _ := MakeVerkleMultiProof(root, [][]byte{ret1, ret2}, nil)
cfg := GetConfig()
if !VerifyVerkleProof(proof, cs, zis, yis, cfg) {
t.Fatal("could not verify proof")
Expand Down Expand Up @@ -611,7 +611,7 @@ func TestStatelessDeserialize(t *testing.T) {
root.Insert(k, fourtyKeyTest, nil)
}

proof, _, _, _, _ := MakeVerkleMultiProof(root, keylist{zeroKeyTest, fourtyKeyTest})
proof, _, _, _, _ := MakeVerkleMultiProof(root, keylist{zeroKeyTest, fourtyKeyTest}, nil)

serialized, statediff, err := SerializeProof(proof)
if err != nil {
Expand Down Expand Up @@ -650,7 +650,7 @@ func TestStatelessDeserializeMissingChildNode(t *testing.T) {
root.Insert(k, fourtyKeyTest, nil)
}

proof, _, _, _, _ := MakeVerkleMultiProof(root, keylist{zeroKeyTest, fourtyKeyTest})
proof, _, _, _, _ := MakeVerkleMultiProof(root, keylist{zeroKeyTest, fourtyKeyTest}, nil)

serialized, statediff, err := SerializeProof(proof)
if err != nil {
Expand Down Expand Up @@ -688,7 +688,7 @@ func TestStatelessDeserializeDepth2(t *testing.T) {
root.Insert(k, fourtyKeyTest, nil)
}

proof, _, _, _, _ := MakeVerkleMultiProof(root, keylist{zeroKeyTest, key1})
proof, _, _, _, _ := MakeVerkleMultiProof(root, keylist{zeroKeyTest, key1}, nil)

serialized, statediff, err := SerializeProof(proof)
if err != nil {
Expand Down
23 changes: 18 additions & 5 deletions tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ type VerkleNode interface {
// returns them breadth-first. On top of that, it returns
// one "extension status" per stem, and an alternate stem
// if the key is missing but another stem has been found.
GetProofItems(keylist) (*ProofElements, []byte, [][]byte, error)
GetProofItems(keylist, NodeResolverFn) (*ProofElements, []byte, [][]byte, error)

// Serialize encodes the node to RLP.
Serialize() ([]byte, error)
Expand Down Expand Up @@ -772,7 +772,7 @@ func groupKeys(keys keylist, depth byte) []keylist {
return groups
}

func (n *InternalNode) GetProofItems(keys keylist) (*ProofElements, []byte, [][]byte, error) {
func (n *InternalNode) GetProofItems(keys keylist, resolver NodeResolverFn) (*ProofElements, []byte, [][]byte, error) {
var (
groups = groupKeys(keys, n.depth)
pe = &ProofElements{
Expand All @@ -794,7 +794,20 @@ func (n *InternalNode) GetProofItems(keys keylist) (*ProofElements, []byte, [][]
for i, child := range n.children {
fiPtrs[i] = &fi[i]
if child != nil {
points[i] = child.Commitment()
var c VerkleNode
if _, ok := child.(HashedNode); ok {
serialized, err := resolver(keys[0][:n.depth+1])
if err != nil {
return nil, nil, nil, err
}
c, err = ParseNode(serialized, n.depth+1)
if err != nil {
return nil, nil, nil, err
}
} else {
c = child
}
points[i] = c.Commitment()
} else {
// TODO: add a test case to cover this scenario.
points[i] = new(Point)
Expand Down Expand Up @@ -841,7 +854,7 @@ func (n *InternalNode) GetProofItems(keys keylist) (*ProofElements, []byte, [][]
continue
}

pec, es, other, err := n.children[childIdx].GetProofItems(group)
pec, es, other, err := n.children[childIdx].GetProofItems(group, resolver)
if err != nil {
// TODO: add a test case to cover this scenario.
return nil, nil, nil, err
Expand Down Expand Up @@ -1278,7 +1291,7 @@ func leafToComms(poly []Fr, val []byte) error {
return nil
}

func (n *LeafNode) GetProofItems(keys keylist) (*ProofElements, []byte, [][]byte, error) {
func (n *LeafNode) GetProofItems(keys keylist, _ NodeResolverFn) (*ProofElements, []byte, [][]byte, error) {
var (
poly [NodeWidth]Fr // top-level polynomial
pe = &ProofElements{
Expand Down
8 changes: 4 additions & 4 deletions tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,7 @@ func TestEmptyCommitment(t *testing.T) {
root := New()
root.Insert(zeroKeyTest, zeroKeyTest, nil)
root.Commit()
pe, _, _, err := root.GetProofItems(keylist{ffx32KeyTest})
pe, _, _, err := root.GetProofItems(keylist{ffx32KeyTest}, nil)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -937,7 +937,7 @@ func TestGetProofItemsNoPoaIfStemPresent(t *testing.T) {
key1, _ := hex.DecodeString("ffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
key2, _ := hex.DecodeString("ffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff")

_, esses, poas, err := root.GetProofItems(keylist{key1, key2, ffx32KeyTest})
_, esses, poas, err := root.GetProofItems(keylist{key1, key2, ffx32KeyTest}, nil)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -1180,7 +1180,7 @@ func TestRustBanderwagonBlock48(t *testing.T) {

r := tree.Commit()

proof, cis, zis, yis, _ := MakeVerkleMultiProof(tree, keys)
proof, cis, zis, yis, _ := MakeVerkleMultiProof(tree, keys, nil)
vp, statediff, err := SerializeProof(proof)
if err != nil {
t.Fatal(err)
Expand All @@ -1201,7 +1201,7 @@ func TestRustBanderwagonBlock48(t *testing.T) {
if err != nil {
t.Fatal(err)
}
pe, _, _, err := droot.GetProofItems(keys)
pe, _, _, err := droot.GetProofItems(keys, nil)
if err != nil {
t.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion unknown.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (UnknownNode) Commitment() *Point {
return &id
}

func (UnknownNode) GetProofItems(keylist) (*ProofElements, []byte, [][]byte, error) {
func (UnknownNode) GetProofItems(keylist, NodeResolverFn) (*ProofElements, []byte, [][]byte, error) {
return nil, nil, nil, errors.New("can't generate proof items for unknown node")
}

Expand Down
2 changes: 1 addition & 1 deletion unknown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestUnknownFuncs(t *testing.T) {
if comm := un.Commitment(); !comm.Equal(&identity) {
t.Errorf("got %v, want identity", comm)
}
if _, _, _, err := un.GetProofItems(nil); err == nil {
if _, _, _, err := un.GetProofItems(nil, nil); err == nil {
t.Errorf("got nil error when getting proof items from a hashed node")
}
if _, err := un.Serialize(); err == nil {
Expand Down

0 comments on commit 1261831

Please sign in to comment.