diff --git a/proof_ipa.go b/proof_ipa.go index 3f7af94..e540163 100644 --- a/proof_ipa.go +++ b/proof_ipa.go @@ -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) } @@ -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) + 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) +} diff --git a/proof_test.go b/proof_test.go index 8486551..5ee7680 100644 --- a/proof_test.go +++ b/proof_test.go @@ -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)) } } @@ -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)) } } @@ -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") } } @@ -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") } } @@ -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") } } @@ -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") } } @@ -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") } } @@ -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") } } @@ -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") } } @@ -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") } } @@ -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) } } @@ -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") } } @@ -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") } } @@ -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") } @@ -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") } @@ -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)) } @@ -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)) } }) @@ -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) } @@ -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) } diff --git a/tree_test.go b/tree_test.go index 594d6a7..d84581b 100644 --- a/tree_test.go +++ b/tree_test.go @@ -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") } @@ -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") } } @@ -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()