Skip to content

Commit

Permalink
Move DeserializeAndVerifyVerkleProof to go-verkle (#444)
Browse files Browse the repository at this point in the history
* Move DeserializeAndVerifyVerkleProof to go-verkle

* remove note-to-self

* remove unwanted trace

* remove comment
  • Loading branch information
gballet authored Jul 29, 2024
1 parent f450636 commit 5b4be73
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 26 deletions.
62 changes: 58 additions & 4 deletions proof_ipa.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,21 +202,21 @@ func MakeVerkleMultiProof(preroot, postroot VerkleNode, keys [][]byte, resolver
return proof, pe.Cis, pe.Zis, pe.Yis, nil
}

// VerifyVerkleProofWithPreState takes a proof and a trusted tree root and verifies that the proof is valid.
func VerifyVerkleProofWithPreState(proof *Proof, preroot VerkleNode) error {
// verifyVerkleProofWithPreState takes a proof and a trusted tree root and verifies that the proof is valid.
func verifyVerkleProofWithPreState(proof *Proof, preroot VerkleNode) error {
pe, _, _, _, err := getProofElementsFromTree(preroot, nil, proof.Keys, nil)
if err != nil {
return fmt.Errorf("error getting proof elements: %w", err)
}

if ok, err := VerifyVerkleProof(proof, pe.Cis, pe.Zis, pe.Yis, GetConfig()); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, pe.Cis, pe.Zis, pe.Yis, GetConfig()); !ok || err != nil {
return fmt.Errorf("error verifying proof: verifies=%v, error=%w", ok, err)
}

return nil
}

func VerifyVerkleProof(proof *Proof, Cs []*Point, indices []uint8, ys []*Fr, tc *Config) (bool, error) {
func verifyVerkleProof(proof *Proof, Cs []*Point, indices []uint8, ys []*Fr, tc *Config) (bool, error) {
tr := common.NewTranscript("vt")
return ipa.CheckMultiProof(tr, tc.conf, proof.Multipoint, Cs, ys, indices)
}
Expand Down Expand Up @@ -555,3 +555,57 @@ type bytesSlice []Stem
func (x bytesSlice) Len() int { return len(x) }
func (x bytesSlice) Less(i, j int) bool { return bytes.Compare(x[i], x[j]) < 0 }
func (x bytesSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] }

// Verify is the API function that verifies a verkle proofs as found in a block/execution payload.
func Verify(vp *VerkleProof, preStateRoot []byte, postStateRoot []byte, statediff StateDiff) error {

proof, err := DeserializeProof(vp, statediff)
if err != nil {
return fmt.Errorf("verkle proof deserialization error: %w", err)
}

rootC := new(Point)
rootC.SetBytes(preStateRoot)

Check failure on line 568 in proof_ipa.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `rootC.SetBytes` is not checked (errcheck)
pretree, err := PreStateTreeFromProof(proof, rootC)
if err != nil {
return fmt.Errorf("error rebuilding the pre-tree from proof: %w", err)
}
// TODO this should not be necessary, remove it
// after the new proof generation code has stabilized.
for _, stemdiff := range statediff {
for _, suffixdiff := range stemdiff.SuffixDiffs {
var key [32]byte
copy(key[:31], stemdiff.Stem[:])
key[31] = suffixdiff.Suffix

val, err := pretree.Get(key[:], nil)
if err != nil {
return fmt.Errorf("could not find key %x in tree rebuilt from proof: %w", key, err)
}
if len(val) > 0 {
if !bytes.Equal(val, suffixdiff.CurrentValue[:]) {
return fmt.Errorf("could not find correct value at %x in tree rebuilt from proof: %x != %x", key, val, *suffixdiff.CurrentValue)
}
} else {
if suffixdiff.CurrentValue != nil && len(suffixdiff.CurrentValue) != 0 {
return fmt.Errorf("could not find correct value at %x in tree rebuilt from proof: %x != %x", key, val, *suffixdiff.CurrentValue)
}
}
}
}

// TODO: this is necessary to verify that the post-values are the correct ones.
// But all this can be avoided with a even faster way. The EVM block execution can
// keep track of the written keys, and compare that list with this post-values list.
// This can avoid regenerating the post-tree which is somewhat expensive.
posttree, err := PostStateTreeFromStateDiff(pretree, statediff)
if err != nil {
return fmt.Errorf("error rebuilding the post-tree from proof: %w", err)
}
regeneratedPostTreeRoot := posttree.Commitment().Bytes()
if !bytes.Equal(regeneratedPostTreeRoot[:], postStateRoot) {
return fmt.Errorf("post tree root mismatch: %x != %x", regeneratedPostTreeRoot, postStateRoot)
}

return verifyVerkleProofWithPreState(proof, pretree)
}
38 changes: 19 additions & 19 deletions proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func TestProofEmptyTree(t *testing.T) {

proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, nil, [][]byte{ffx32KeyTest}, nil)
cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
t.Fatalf("could not verify verkle proof: %s", ToDot(root))
}
}
Expand All @@ -67,7 +67,7 @@ func TestProofVerifyTwoLeaves(t *testing.T) {
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, nil, [][]byte{ffx32KeyTest}, nil)

cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
t.Fatalf("could not verify verkle proof: %s", ToDot(root))
}
}
Expand All @@ -94,7 +94,7 @@ func TestProofVerifyMultipleLeaves(t *testing.T) {
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, nil, [][]byte{keys[0]}, nil)

cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
t.Fatal("could not verify verkle proof")
}
}
Expand Down Expand Up @@ -125,7 +125,7 @@ func TestMultiProofVerifyMultipleLeaves(t *testing.T) {
t.Fatal(err)
}
cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, pe.Cis, pe.Zis, pe.Yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, pe.Cis, pe.Zis, pe.Yis, cfg); !ok || err != nil {
t.Fatal("could not verify verkle proof")
}
}
Expand Down Expand Up @@ -172,7 +172,7 @@ func TestMultiProofVerifyMultipleLeavesWithAbsentStem(t *testing.T) {
}

cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, pe.Cis, pe.Zis, pe.Yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, pe.Cis, pe.Zis, pe.Yis, cfg); !ok || err != nil {
t.Fatal("could not verify verkle proof")
}
}
Expand All @@ -199,7 +199,7 @@ func TestMultiProofVerifyMultipleLeavesCommitmentRedundancy(t *testing.T) {
t.Fatal(err)
}
cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, pe.Cis, pe.Zis, pe.Yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, pe.Cis, pe.Zis, pe.Yis, cfg); !ok || err != nil {
t.Fatal("could not verify verkle proof")
}
}
Expand All @@ -219,7 +219,7 @@ func TestProofOfAbsenceInternalVerify(t *testing.T) {
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, nil, [][]byte{ffx32KeyTest}, nil)

cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
t.Fatal("could not verify verkle proof")
}
}
Expand All @@ -239,7 +239,7 @@ func TestProofOfAbsenceLeafVerify(t *testing.T) {
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, nil, [][]byte{oneKeyTest}, nil)

cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
t.Fatal("could not verify verkle proof")
}
}
Expand All @@ -263,7 +263,7 @@ func TestProofOfAbsenceLeafVerifyOtherSuffix(t *testing.T) {
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, nil, [][]byte{key}, nil)

cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
t.Fatal("could not verify verkle proof")
}
}
Expand All @@ -285,7 +285,7 @@ func TestProofOfAbsenceStemVerify(t *testing.T) {
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, nil, [][]byte{key}, nil)

cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
t.Fatal("could not verify verkle proof")
}
}
Expand Down Expand Up @@ -336,7 +336,7 @@ func BenchmarkProofVerification(b *testing.B) {

cfg := GetConfig()
for i := 0; i < b.N; i++ {
if ok, err := VerifyVerkleProof(proof, cis, zis, yis, cfg); err != nil || !ok {
if ok, err := verifyVerkleProof(proof, cis, zis, yis, cfg); err != nil || !ok {
b.Fatal(err)
}
}
Expand Down Expand Up @@ -458,7 +458,7 @@ func TestProofDeserialize(t *testing.T) {
t.Fatal(err)
}
cfg := GetConfig()
if ok, err := VerifyVerkleProof(deserialized, pe.Cis, pe.Zis, pe.Yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(deserialized, pe.Cis, pe.Zis, pe.Yis, cfg); !ok || err != nil {
t.Fatal("could not verify verkle proof")
}
}
Expand All @@ -472,7 +472,7 @@ func TestProofOfAbsenceEdgeCase(t *testing.T) {
ret, _ := hex.DecodeString("0303030303030303030303030303030303030303030303030303030303030303")
proof, cs, zis, yis, _ := MakeVerkleMultiProof(root, nil, [][]byte{ret}, nil)
cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, cs, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cs, zis, yis, cfg); !ok || err != nil {
t.Fatal("could not verify proof")
}
}
Expand All @@ -493,7 +493,7 @@ func TestProofOfAbsenceOtherMultipleLeaves(t *testing.T) {
ret2, _ := hex.DecodeString("0303030303030303030303030303030303030303030303030303030303030301")
proof, cs, zis, yis, _ := MakeVerkleMultiProof(root, nil, [][]byte{ret1, ret2}, nil)
cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, cs, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cs, zis, yis, cfg); !ok || err != nil {
t.Fatal("could not verify proof")
}

Expand Down Expand Up @@ -555,7 +555,7 @@ func TestProofOfAbsenceNoneMultipleStems(t *testing.T) {
ret2, _ := hex.DecodeString("0303030303030303030303030303030303030303030303030303030303030200")
proof, cs, zis, yis, _ := MakeVerkleMultiProof(root, nil, [][]byte{ret1, ret2}, nil)
cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, cs, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cs, zis, yis, cfg); !ok || err != nil {
t.Fatal("could not verify proof")
}

Expand Down Expand Up @@ -1050,7 +1050,7 @@ func TestProofVerificationWithPostState(t *testing.T) { // skipcq: GO-R1005
t.Fatalf("error deserializing proof: %v", err)
}

if err = VerifyVerkleProofWithPreState(dproof, root); err != nil {
if err = verifyVerkleProofWithPreState(dproof, root); err != nil {
t.Fatalf("could not verify verkle proof: %v, original: %s reconstructed: %s", err, ToDot(root), ToDot(postroot))
}

Expand All @@ -1068,7 +1068,7 @@ func TestProofVerificationWithPostState(t *testing.T) { // skipcq: GO-R1005
t.Fatalf("differing root commitments %x != %x", dpostroot.Commitment().Bytes(), postroot.Commitment().Bytes())
}

if err = VerifyVerkleProofWithPreState(dproof, dpreroot); err != nil {
if err = verifyVerkleProofWithPreState(dproof, dpreroot); err != nil {
t.Fatalf("could not verify verkle proof: %v, original: %s reconstructed: %s", err, ToDot(dpreroot), ToDot(dpostroot))
}
})
Expand All @@ -1094,7 +1094,7 @@ func TestGenerateProofWithOnlyAbsentKeys(t *testing.T) {
}

// It must pass.
if ok, err := VerifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
t.Fatalf("original proof didn't verify: %v", err)
}

Expand All @@ -1119,7 +1119,7 @@ func TestGenerateProofWithOnlyAbsentKeys(t *testing.T) {
}

// It must pass.
if ok, err := VerifyVerkleProof(dproof, pe.Cis, pe.Zis, pe.Yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(dproof, pe.Cis, pe.Zis, pe.Yis, cfg); !ok || err != nil {
t.Fatalf("reconstructed proof didn't verify: %v", err)
}

Expand Down
6 changes: 3 additions & 3 deletions tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1310,7 +1310,7 @@ func TestRustBanderwagonBlock48(t *testing.T) {
t.Logf("serialized proof=%v", vp)

cfg := GetConfig()
if ok, err := VerifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
t.Fatal("proof didn't verify")
}

Expand All @@ -1328,7 +1328,7 @@ func TestRustBanderwagonBlock48(t *testing.T) {
t.Fatal(err)
}

if ok, err := VerifyVerkleProof(dproof, pe.Cis, pe.Zis, pe.Yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(dproof, pe.Cis, pe.Zis, pe.Yis, cfg); !ok || err != nil {
t.Fatal("deserialized proof didn't verify")
}
}
Expand Down Expand Up @@ -1775,7 +1775,7 @@ func runRandTest(rt randTest) error {
}
root.Commit()
proof, cis, zis, yis, _ := MakeVerkleMultiProof(root, nil, keys, nil)
if ok, err := VerifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
if ok, err := verifyVerkleProof(proof, cis, zis, yis, cfg); !ok || err != nil {
rt[i].err = fmt.Errorf("could not verify verkle proof: %s, err %v", ToDot(root), err)
}
// TODO: reconsider if we should avoid returning pointers in Hash() and Commit()
Expand Down

0 comments on commit 5b4be73

Please sign in to comment.