Skip to content

Commit e8e85fe

Browse files
make verify_kzg_proof apis more closely mimic the specs (#46)
1 parent bca26b3 commit e8e85fe

File tree

5 files changed

+100
-86
lines changed

5 files changed

+100
-86
lines changed

core/types/data_blob.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99

1010
"github.com/ethereum/go-ethereum/common"
1111
"github.com/ethereum/go-ethereum/common/hexutil"
12-
"github.com/ethereum/go-ethereum/crypto"
1312
"github.com/ethereum/go-ethereum/crypto/kzg"
1413
"github.com/ethereum/go-ethereum/params"
1514
"github.com/protolambda/go-kzg/bls"
@@ -63,10 +62,8 @@ func (p *KZGCommitment) Point() (*bls.G1Point, error) {
6362
return bls.FromCompressedG1(p[:])
6463
}
6564

66-
func (kzg KZGCommitment) ComputeVersionedHash() common.Hash {
67-
h := crypto.Keccak256Hash(kzg[:])
68-
h[0] = params.BlobCommitmentVersionKZG
69-
return h
65+
func (c KZGCommitment) ComputeVersionedHash() common.Hash {
66+
return kzg.KZGToVersionedHash(c)
7067
}
7168

7269
// Compressed BLS12-381 G1 element
@@ -528,7 +525,7 @@ func (b *BlobTxWrapData) verifyBlobs(inner TxData) error {
528525
if err != nil {
529526
return fmt.Errorf("aggregate proof parse error: %v", err)
530527
}
531-
if !kzg.VerifyKzgProof(aggregateCommitmentG1, &z, &y, aggregateProofG1) {
528+
if !kzg.VerifyKZGProofFromPoints(aggregateCommitmentG1, &z, &y, aggregateProofG1) {
532529
return errors.New("failed to verify kzg")
533530
}
534531
return nil

core/vm/contracts.go

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import (
2222
"errors"
2323
"math/big"
2424

25-
"github.com/ethereum/go-ethereum/core/types"
26-
2725
"github.com/ethereum/go-ethereum/common"
2826
"github.com/ethereum/go-ethereum/common/math"
2927
"github.com/ethereum/go-ethereum/crypto"
@@ -33,7 +31,6 @@ import (
3331
"github.com/ethereum/go-ethereum/crypto/kzg"
3432
"github.com/ethereum/go-ethereum/params"
3533
big2 "github.com/holiman/big"
36-
"github.com/protolambda/go-kzg/bls"
3734
"golang.org/x/crypto/ripemd160"
3835
)
3936

@@ -1077,70 +1074,11 @@ func (c *bls12381MapG2) Run(input []byte) ([]byte, error) {
10771074
// to check if a value is part of a blob at a specific point with a KZG proof.
10781075
type pointEvaluation struct{}
10791076

1080-
var (
1081-
errPointEvaluationInputLength = errors.New("invalid input length")
1082-
errPointEvaluationInvalidVersionedHash = errors.New("invalid versioned hash")
1083-
errPointEvaluationInvalidX = errors.New("invalid evaluation point")
1084-
errPointEvaluationInvalidY = errors.New("invalid expected output")
1085-
errPointEvaluationInvalidKzg = errors.New("invalid data kzg")
1086-
errPointEvaluationInvalidProof = errors.New("invalid proof")
1087-
errPointEvaluationMismatchVersionedHash = errors.New("mismatched versioned hash")
1088-
errPointEvaluationBadProof = errors.New("bad proof")
1089-
)
1090-
10911077
// RequiredGas returns the gas required to execute the pre-compiled contract.
10921078
func (c *pointEvaluation) RequiredGas(input []byte) uint64 {
10931079
return params.PointEvaluationGas
10941080
}
10951081

10961082
func (c *pointEvaluation) Run(input []byte) ([]byte, error) {
1097-
if len(input) != 192 {
1098-
return nil, errPointEvaluationInputLength
1099-
}
1100-
1101-
var versionedHash common.Hash
1102-
copy(versionedHash[:], input[:32])
1103-
// XXX Should we version check the hash?
1104-
if versionedHash[0] != params.BlobCommitmentVersionKZG {
1105-
return nil, errPointEvaluationInvalidVersionedHash
1106-
}
1107-
1108-
var x bls.Fr
1109-
var data [32]byte
1110-
copy(data[:], input[32:64])
1111-
ok := bls.FrFrom32(&x, data)
1112-
if !ok {
1113-
return nil, errPointEvaluationInvalidX
1114-
}
1115-
1116-
var y bls.Fr
1117-
copy(data[:], input[64:96])
1118-
ok = bls.FrFrom32(&y, data)
1119-
if !ok {
1120-
return nil, errPointEvaluationInvalidY
1121-
}
1122-
1123-
var commitment types.KZGCommitment
1124-
copy(commitment[:], input[96:144])
1125-
if commitment.ComputeVersionedHash() != versionedHash {
1126-
return nil, errPointEvaluationMismatchVersionedHash
1127-
}
1128-
1129-
parsedCommitment, err := commitment.Point()
1130-
if err != nil {
1131-
return nil, errPointEvaluationInvalidKzg
1132-
}
1133-
1134-
var proof types.KZGCommitment
1135-
copy(proof[:], input[144:192])
1136-
parsedProof, err := proof.Point()
1137-
if err != nil {
1138-
return nil, errPointEvaluationInvalidProof
1139-
}
1140-
1141-
if !kzg.VerifyKzgProof(parsedCommitment, &x, &y, parsedProof) {
1142-
return nil, errPointEvaluationBadProof
1143-
}
1144-
1145-
return []byte{}, nil
1083+
return kzg.PointEvaluationPrecompile(input)
11461084
}

crypto/kzg/kzg.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,21 +50,6 @@ func BlobToKzg(eval []bls.Fr) *bls.G1Point {
5050
return bls.LinCombG1(kzgSetupLagrange, eval)
5151
}
5252

53-
// Verify a KZG proof
54-
func VerifyKzgProof(commitment *bls.G1Point, x *bls.Fr, y *bls.Fr, proof *bls.G1Point) bool {
55-
// Verify the pairing equation
56-
var xG2 bls.G2Point
57-
bls.MulG2(&xG2, &bls.GenG2, x)
58-
var sMinuxX bls.G2Point
59-
bls.SubG2(&sMinuxX, &kzgSetupG2[1], &xG2)
60-
var yG1 bls.G1Point
61-
bls.MulG1(&yG1, &bls.GenG1, y)
62-
var commitmentMinusY bls.G1Point
63-
bls.SubG1(&commitmentMinusY, commitment, &yG1)
64-
65-
return bls.PairingsVerify(&commitmentMinusY, &bls.GenG2, proof, &sMinuxX)
66-
}
67-
6853
type BlobsBatch struct {
6954
sync.Mutex
7055
init bool

crypto/kzg/kzg_new.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package kzg
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
7+
"github.com/protolambda/go-kzg/bls"
8+
9+
"github.com/ethereum/go-ethereum/crypto"
10+
"github.com/ethereum/go-ethereum/params"
11+
)
12+
13+
// VerifyKZGProof implements verify_kzg_proof from the EIP-4844 consensus spec:
14+
// https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#verify_kzg_proof
15+
func VerifyKZGProof(polynomialKZG [48]byte, z *bls.Fr, y *bls.Fr, kzgProof [48]byte) (bool, error) {
16+
polynomialKZGG1, err := bls.FromCompressedG1(polynomialKZG[:])
17+
if err != nil {
18+
return false, fmt.Errorf("failed to decode polynomialKZG: %v", err)
19+
}
20+
kzgProofG1, err := bls.FromCompressedG1(kzgProof[:])
21+
if err != nil {
22+
return false, fmt.Errorf("failed to decode kzgProof: %v", err)
23+
}
24+
return VerifyKZGProofFromPoints(polynomialKZGG1, z, y, kzgProofG1), nil
25+
}
26+
27+
func VerifyKZGProofFromPoints(polynomialKZG *bls.G1Point, z *bls.Fr, y *bls.Fr, kzgProof *bls.G1Point) bool {
28+
var zG2 bls.G2Point
29+
bls.MulG2(&zG2, &bls.GenG2, z)
30+
var yG1 bls.G1Point
31+
bls.MulG1(&yG1, &bls.GenG1, y)
32+
33+
var xMinusZ bls.G2Point
34+
bls.SubG2(&xMinusZ, &kzgSetupG2[1], &zG2)
35+
var pMinusY bls.G1Point
36+
bls.SubG1(&pMinusY, polynomialKZG, &yG1)
37+
38+
return bls.PairingsVerify(&pMinusY, &bls.GenG2, kzgProof, &xMinusZ)
39+
}
40+
41+
// KZGToVersionedHash implements kzg_to_versioned_hash from EIP-4844
42+
func KZGToVersionedHash(kzg [48]byte) [32]byte {
43+
h := crypto.Keccak256Hash(kzg[:])
44+
h[0] = params.BlobCommitmentVersionKZG
45+
return h
46+
}
47+
48+
// PointEvaluationPrecompile implements point_evaluation_precompile from EIP-4844
49+
func PointEvaluationPrecompile(input []byte) ([]byte, error) {
50+
if len(input) != 192 {
51+
return nil, errors.New("invalid input length")
52+
}
53+
54+
// versioned hash: first 32 bytes
55+
var versionedHash [32]byte
56+
copy(versionedHash[:], input[:32])
57+
58+
var x, y [32]byte
59+
// Evaluation point: next 32 bytes
60+
copy(x[:], input[32:64])
61+
// Expected output: next 32 bytes
62+
copy(y[:], input[64:96])
63+
64+
// successfully converting x and y to bls.Fr confirms they are < MODULUS per the spec
65+
var xFr, yFr bls.Fr
66+
ok := bls.FrFrom32(&xFr, x)
67+
if !ok {
68+
return nil, errors.New("invalid evaluation point")
69+
}
70+
ok = bls.FrFrom32(&yFr, y)
71+
if !ok {
72+
return nil, errors.New("invalid expected output")
73+
}
74+
75+
// input kzg point: next 48 bytes
76+
var dataKZG [48]byte
77+
copy(dataKZG[:], input[96:144])
78+
if KZGToVersionedHash(dataKZG) != versionedHash {
79+
return nil, errors.New("mismatched versioned hash")
80+
}
81+
82+
// Quotient kzg: next 48 bytes
83+
var quotientKZG [48]byte
84+
copy(quotientKZG[:], input[144:192])
85+
86+
ok, err := VerifyKZGProof(dataKZG, &xFr, &yFr, quotientKZG)
87+
if err != nil {
88+
return nil, fmt.Errorf("verify_kzg_proof error: %v", err)
89+
}
90+
if !ok {
91+
return nil, errors.New("failed to verify kzg proof")
92+
}
93+
return []byte{}, nil
94+
}

tests/kzg_bench_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func BenchmarkVerifyBlobs(b *testing.B) {
7676
}
7777
}
7878

79-
func BenchmarkVerifyKzgProof(b *testing.B) {
79+
func BenchmarkVerifyKZGProof(b *testing.B) {
8080
// First let's do some go-kzg preparations to be able to convert polynomial between coefficient and evaluation form
8181
fs := gokzg.NewFFTSettings(uint8(math.Log2(params.FieldElementsPerBlob)))
8282

@@ -109,7 +109,7 @@ func BenchmarkVerifyKzgProof(b *testing.B) {
109109
b.ResetTimer()
110110
for i := 0; i < b.N; i++ {
111111
// Verify kzg proof
112-
if kzg.VerifyKzgProof(commitment, &xFr, &value, proof) != true {
112+
if kzg.VerifyKZGProofFromPoints(commitment, &xFr, &value, proof) != true {
113113
b.Fatal("failed proof verification")
114114
}
115115
}

0 commit comments

Comments
 (0)