Skip to content

Commit

Permalink
make verify_kzg_proof apis more closely mimic the specs
Browse files Browse the repository at this point in the history
  • Loading branch information
roberto-bayardo committed Nov 9, 2022
1 parent bca26b3 commit b8bf7fd
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 86 deletions.
9 changes: 3 additions & 6 deletions core/types/data_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/kzg"
"github.com/ethereum/go-ethereum/params"
"github.com/protolambda/go-kzg/bls"
Expand Down Expand Up @@ -63,10 +62,8 @@ func (p *KZGCommitment) Point() (*bls.G1Point, error) {
return bls.FromCompressedG1(p[:])
}

func (kzg KZGCommitment) ComputeVersionedHash() common.Hash {
h := crypto.Keccak256Hash(kzg[:])
h[0] = params.BlobCommitmentVersionKZG
return h
func (c KZGCommitment) ComputeVersionedHash() common.Hash {
return kzg.KZGToVersionedHash(c)
}

// Compressed BLS12-381 G1 element
Expand Down Expand Up @@ -528,7 +525,7 @@ func (b *BlobTxWrapData) verifyBlobs(inner TxData) error {
if err != nil {
return fmt.Errorf("aggregate proof parse error: %v", err)
}
if !kzg.VerifyKzgProof(aggregateCommitmentG1, &z, &y, aggregateProofG1) {
if !kzg.VerifyKZGProofFromPoints(aggregateCommitmentG1, &z, &y, aggregateProofG1) {
return errors.New("failed to verify kzg")
}
return nil
Expand Down
64 changes: 1 addition & 63 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import (
"errors"
"math/big"

"github.com/ethereum/go-ethereum/core/types"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
Expand All @@ -33,7 +31,6 @@ import (
"github.com/ethereum/go-ethereum/crypto/kzg"
"github.com/ethereum/go-ethereum/params"
big2 "github.com/holiman/big"
"github.com/protolambda/go-kzg/bls"
"golang.org/x/crypto/ripemd160"
)

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

var (
errPointEvaluationInputLength = errors.New("invalid input length")
errPointEvaluationInvalidVersionedHash = errors.New("invalid versioned hash")
errPointEvaluationInvalidX = errors.New("invalid evaluation point")
errPointEvaluationInvalidY = errors.New("invalid expected output")
errPointEvaluationInvalidKzg = errors.New("invalid data kzg")
errPointEvaluationInvalidProof = errors.New("invalid proof")
errPointEvaluationMismatchVersionedHash = errors.New("mismatched versioned hash")
errPointEvaluationBadProof = errors.New("bad proof")
)

// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *pointEvaluation) RequiredGas(input []byte) uint64 {
return params.PointEvaluationGas
}

func (c *pointEvaluation) Run(input []byte) ([]byte, error) {
if len(input) != 192 {
return nil, errPointEvaluationInputLength
}

var versionedHash common.Hash
copy(versionedHash[:], input[:32])
// XXX Should we version check the hash?
if versionedHash[0] != params.BlobCommitmentVersionKZG {
return nil, errPointEvaluationInvalidVersionedHash
}

var x bls.Fr
var data [32]byte
copy(data[:], input[32:64])
ok := bls.FrFrom32(&x, data)
if !ok {
return nil, errPointEvaluationInvalidX
}

var y bls.Fr
copy(data[:], input[64:96])
ok = bls.FrFrom32(&y, data)
if !ok {
return nil, errPointEvaluationInvalidY
}

var commitment types.KZGCommitment
copy(commitment[:], input[96:144])
if commitment.ComputeVersionedHash() != versionedHash {
return nil, errPointEvaluationMismatchVersionedHash
}

parsedCommitment, err := commitment.Point()
if err != nil {
return nil, errPointEvaluationInvalidKzg
}

var proof types.KZGCommitment
copy(proof[:], input[144:192])
parsedProof, err := proof.Point()
if err != nil {
return nil, errPointEvaluationInvalidProof
}

if !kzg.VerifyKzgProof(parsedCommitment, &x, &y, parsedProof) {
return nil, errPointEvaluationBadProof
}

return []byte{}, nil
return kzg.PointEvaluationPrecompile(input)
}
15 changes: 0 additions & 15 deletions crypto/kzg/kzg.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,6 @@ func BlobToKzg(eval []bls.Fr) *bls.G1Point {
return bls.LinCombG1(kzgSetupLagrange, eval)
}

// Verify a KZG proof
func VerifyKzgProof(commitment *bls.G1Point, x *bls.Fr, y *bls.Fr, proof *bls.G1Point) bool {
// Verify the pairing equation
var xG2 bls.G2Point
bls.MulG2(&xG2, &bls.GenG2, x)
var sMinuxX bls.G2Point
bls.SubG2(&sMinuxX, &kzgSetupG2[1], &xG2)
var yG1 bls.G1Point
bls.MulG1(&yG1, &bls.GenG1, y)
var commitmentMinusY bls.G1Point
bls.SubG1(&commitmentMinusY, commitment, &yG1)

return bls.PairingsVerify(&commitmentMinusY, &bls.GenG2, proof, &sMinuxX)
}

type BlobsBatch struct {
sync.Mutex
init bool
Expand Down
94 changes: 94 additions & 0 deletions crypto/kzg/kzg_new.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package kzg

import (
"errors"
"fmt"

"github.com/protolambda/go-kzg/bls"

"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)

// VerifyKZGProof implements verify_kzg_proof from the EIP-4844 consensus spec:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#verify_kzg_proof
func VerifyKZGProof(polynomialKZG [48]byte, z *bls.Fr, y *bls.Fr, kzgProof [48]byte) (bool, error) {
polynomialKZGG1, err := bls.FromCompressedG1(polynomialKZG[:])
if err != nil {
return false, fmt.Errorf("failed to decode polynomialKZG: %v", err)
}
kzgProofG1, err := bls.FromCompressedG1(kzgProof[:])
if err != nil {
return false, fmt.Errorf("failed to decode kzgProof: %v", err)
}
return VerifyKZGProofFromPoints(polynomialKZGG1, z, y, kzgProofG1), nil
}

func VerifyKZGProofFromPoints(polynomialKZG *bls.G1Point, z *bls.Fr, y *bls.Fr, kzgProof *bls.G1Point) bool {
var zG2 bls.G2Point
bls.MulG2(&zG2, &bls.GenG2, z)
var yG1 bls.G1Point
bls.MulG1(&yG1, &bls.GenG1, y)

var xMinusZ bls.G2Point
bls.SubG2(&xMinusZ, &kzgSetupG2[1], &zG2)
var pMinusY bls.G1Point
bls.SubG1(&pMinusY, polynomialKZG, &yG1)

return bls.PairingsVerify(&pMinusY, &bls.GenG2, kzgProof, &xMinusZ)
}

// KZGToVersionedHash implements kzg_to_versioned_hash from EIP-4844
func KZGToVersionedHash(kzg [48]byte) [32]byte {
h := crypto.Keccak256Hash(kzg[:])
h[0] = params.BlobCommitmentVersionKZG
return h
}

// PointEvaluationPrecompile implements point_evaluation_precompile from EIP-4844
func PointEvaluationPrecompile(input []byte) ([]byte, error) {
if len(input) != 192 {
return nil, errors.New("invalid input length")
}

// versioned hash: first 32 bytes
var versionedHash [32]byte
copy(versionedHash[:], input[:32])

var x, y [32]byte
// Evaluation point: next 32 bytes
copy(x[:], input[32:64])
// Expected output: next 32 bytes
copy(y[:], input[64:96])

// successfully converting x and y to bls.Fr confirms they are < MODULUS per the spec
var xFr, yFr bls.Fr
ok := bls.FrFrom32(&xFr, x)
if !ok {
return nil, errors.New("invalid evaluation point")
}
ok = bls.FrFrom32(&yFr, y)
if !ok {
return nil, errors.New("invalid expected output")
}

// input kzg point: next 48 bytes
var dataKZG [48]byte
copy(dataKZG[:], input[96:144])
if KZGToVersionedHash(dataKZG) != versionedHash {
return nil, errors.New("mismatched versioned hash")
}

// Quotient kzg: next 48 bytes
var quotientKZG [48]byte
copy(quotientKZG[:], input[144:192])

ok, err := VerifyKZGProof(dataKZG, &xFr, &yFr, quotientKZG)
if err != nil {
return nil, fmt.Errorf("verify_kzg_proof error: %v", err)
}
if !ok {
return nil, errors.New("failed to verify kzg proof")
}
return []byte{}, nil
}
4 changes: 2 additions & 2 deletions tests/kzg_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func BenchmarkVerifyBlobs(b *testing.B) {
}
}

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

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

0 comments on commit b8bf7fd

Please sign in to comment.