Skip to content

Commit 6cbb79e

Browse files
pure bytes API for VerifyKZGProof per 3097, and move kzg_new back into kzg.go now that updates are near complete
1 parent 0cc40fe commit 6cbb79e

File tree

5 files changed

+267
-266
lines changed

5 files changed

+267
-266
lines changed

crypto/kzg/kzg.go

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,25 @@
77
package kzg
88

99
import (
10+
"crypto/sha256"
1011
"encoding/json"
12+
"errors"
13+
"fmt"
14+
"math/big"
1115
"math/bits"
1216

17+
"github.com/ethereum/go-ethereum/params"
1318
"github.com/protolambda/go-kzg/bls"
19+
"github.com/protolambda/ztyp/codec"
1420
)
1521

22+
const (
23+
FIAT_SHAMIR_PROTOCOL_DOMAIN = "FSBLOBVERIFY_V1_"
24+
)
25+
26+
type Polynomial []bls.Fr
27+
type Polynomials [][]bls.Fr
28+
1629
// KZG CRS for G2
1730
var kzgSetupG2 []bls.G2Point
1831

@@ -73,3 +86,219 @@ func bitReversalPermutation(l []bls.G1Point) []bls.G1Point {
7386

7487
return out
7588
}
89+
90+
// VerifyKZGProof implements verify_kzg_proof from the EIP-4844 consensus spec,
91+
// only with the byte inputs already parsed into points & field elements.
92+
func VerifyKZGProofFromPoints(polynomialKZG *bls.G1Point, z *bls.Fr, y *bls.Fr, kzgProof *bls.G1Point) bool {
93+
var zG2 bls.G2Point
94+
bls.MulG2(&zG2, &bls.GenG2, z)
95+
var yG1 bls.G1Point
96+
bls.MulG1(&yG1, &bls.GenG1, y)
97+
98+
var xMinusZ bls.G2Point
99+
bls.SubG2(&xMinusZ, &kzgSetupG2[1], &zG2)
100+
var pMinusY bls.G1Point
101+
bls.SubG1(&pMinusY, polynomialKZG, &yG1)
102+
103+
return bls.PairingsVerify(&pMinusY, &bls.GenG2, kzgProof, &xMinusZ)
104+
}
105+
106+
// VerifyAggregateKZGProof implements verify_aggregate_kzg_proof from the EIP-4844 consensus spec,
107+
// only operating on blobs that have already been converted into polynomials.
108+
func VerifyAggregateKZGProofFromPolynomials(blobs Polynomials, expectedKZGCommitments KZGCommitmentSequence, kzgAggregatedProof KZGProof) (bool, error) {
109+
aggregatedPoly, aggregatedPolyCommitment, evaluationChallenge, err :=
110+
ComputeAggregatedPolyAndCommitment(blobs, expectedKZGCommitments)
111+
if err != nil {
112+
return false, err
113+
}
114+
y := EvaluatePolynomialInEvaluationForm(aggregatedPoly, evaluationChallenge)
115+
kzgProofG1, err := bls.FromCompressedG1(kzgAggregatedProof[:])
116+
if err != nil {
117+
return false, fmt.Errorf("failed to decode kzgProof: %v", err)
118+
}
119+
return VerifyKZGProofFromPoints(aggregatedPolyCommitment, evaluationChallenge, y, kzgProofG1), nil
120+
}
121+
122+
// ComputePowers implements compute_powers from the EIP-4844 consensus spec:
123+
// https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#compute_powers
124+
func ComputePowers(r *bls.Fr, n int) []bls.Fr {
125+
var currentPower bls.Fr
126+
bls.AsFr(&currentPower, 1)
127+
powers := make([]bls.Fr, n)
128+
for i := range powers {
129+
powers[i] = currentPower
130+
bls.MulModFr(&currentPower, &currentPower, r)
131+
}
132+
return powers
133+
}
134+
135+
func PolynomialToKZGCommitment(eval Polynomial) KZGCommitment {
136+
g1 := bls.LinCombG1(kzgSetupLagrange, []bls.Fr(eval))
137+
var out KZGCommitment
138+
copy(out[:], bls.ToCompressedG1(g1))
139+
return out
140+
}
141+
142+
// BytesToBLSField implements bytes_to_bls_field from the EIP-4844 consensus spec:
143+
// https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#bytes_to_bls_field
144+
func BytesToBLSField(h [32]byte) *bls.Fr {
145+
// re-interpret as little-endian
146+
var b [32]byte = h
147+
for i := 0; i < 16; i++ {
148+
b[31-i], b[i] = b[i], b[31-i]
149+
}
150+
zB := new(big.Int).Mod(new(big.Int).SetBytes(b[:]), BLSModulus)
151+
out := new(bls.Fr)
152+
BigToFr(out, zB)
153+
return out
154+
}
155+
156+
// ComputeAggregatedPolyAndcommitment implements compute_aggregated_poly_and_commitment from the EIP-4844 consensus spec:
157+
// https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#compute_aggregated_poly_and_commitment
158+
func ComputeAggregatedPolyAndCommitment(blobs Polynomials, commitments KZGCommitmentSequence) ([]bls.Fr, *bls.G1Point, *bls.Fr, error) {
159+
// create challenges
160+
r, err := HashToBLSField(blobs, commitments)
161+
powers := ComputePowers(r, len(blobs))
162+
if len(powers) == 0 {
163+
return nil, nil, nil, errors.New("powers can't be 0 length")
164+
}
165+
166+
var evaluationChallenge bls.Fr
167+
bls.MulModFr(&evaluationChallenge, r, &powers[len(powers)-1])
168+
169+
aggregatedPoly, err := bls.PolyLinComb(blobs, powers)
170+
if err != nil {
171+
return nil, nil, nil, err
172+
}
173+
174+
l := commitments.Len()
175+
commitmentsG1 := make([]bls.G1Point, l)
176+
for i := 0; i < l; i++ {
177+
c := commitments.At(i)
178+
p, err := bls.FromCompressedG1(c[:])
179+
if err != nil {
180+
return nil, nil, nil, err
181+
}
182+
bls.CopyG1(&commitmentsG1[i], p)
183+
}
184+
aggregatedCommitmentG1 := bls.LinCombG1(commitmentsG1, powers)
185+
return aggregatedPoly, aggregatedCommitmentG1, &evaluationChallenge, nil
186+
}
187+
188+
type commitmentSequenceImpl []KZGCommitment
189+
190+
func (s commitmentSequenceImpl) At(i int) KZGCommitment {
191+
return s[i]
192+
}
193+
194+
func (s commitmentSequenceImpl) Len() int {
195+
return len(s)
196+
}
197+
198+
// ComputeAggregateKZGProofFromPolynomials implements compute_aggregate_kzg_proof from the EIP-4844
199+
// consensus spec, only operating over blobs that are already parsed into a polynomial.
200+
func ComputeAggregateKZGProofFromPolynomials(blobs Polynomials) (KZGProof, error) {
201+
commitments := make(commitmentSequenceImpl, len(blobs))
202+
for i, b := range blobs {
203+
commitments[i] = PolynomialToKZGCommitment(Polynomial(b))
204+
}
205+
aggregatedPoly, _, evaluationChallenge, err := ComputeAggregatedPolyAndCommitment(blobs, commitments)
206+
if err != nil {
207+
return KZGProof{}, err
208+
}
209+
return ComputeKZGProof(aggregatedPoly, evaluationChallenge)
210+
}
211+
212+
// ComputeAggregateKZGProof implements compute_kzg_proof from the EIP-4844 consensus spec:
213+
// https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#compute_kzg_proof
214+
func ComputeKZGProof(polynomial []bls.Fr, z *bls.Fr) (KZGProof, error) {
215+
y := EvaluatePolynomialInEvaluationForm(polynomial, z)
216+
polynomialShifted := make([]bls.Fr, len(polynomial))
217+
for i := range polynomial {
218+
bls.SubModFr(&polynomialShifted[i], &polynomial[i], y)
219+
}
220+
denominatorPoly := make([]bls.Fr, len(polynomial))
221+
if len(polynomial) != len(Domain) {
222+
return KZGProof{}, errors.New("polynomial has invalid length")
223+
}
224+
for i := range polynomial {
225+
if bls.EqualFr(&DomainFr[i], z) {
226+
return KZGProof{}, errors.New("invalid z challenge")
227+
}
228+
bls.SubModFr(&denominatorPoly[i], &DomainFr[i], z)
229+
}
230+
quotientPolynomial := make([]bls.Fr, len(polynomial))
231+
for i := range polynomial {
232+
bls.DivModFr(&quotientPolynomial[i], &polynomialShifted[i], &denominatorPoly[i])
233+
}
234+
rG1 := bls.LinCombG1(kzgSetupLagrange, quotientPolynomial)
235+
var proof KZGProof
236+
copy(proof[:], bls.ToCompressedG1(rG1))
237+
return proof, nil
238+
}
239+
240+
// EvaluatePolynomialInEvaluationForm implements evaluate_polynomial_in_evaluation_form from the EIP-4844 consensus spec:
241+
// https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#evaluate_polynomial_in_evaluation_form
242+
func EvaluatePolynomialInEvaluationForm(poly []bls.Fr, x *bls.Fr) *bls.Fr {
243+
var result bls.Fr
244+
bls.EvaluatePolyInEvaluationForm(&result, poly, x, DomainFr, 0)
245+
return &result
246+
}
247+
248+
// HashToBLSField implements hash_to_bls_field from the EIP-4844 consensus specs:
249+
// https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#hash_to_bls_field
250+
func HashToBLSField(polys Polynomials, comms KZGCommitmentSequence) (*bls.Fr, error) {
251+
sha := sha256.New()
252+
w := codec.NewEncodingWriter(sha)
253+
if err := w.Write([]byte(FIAT_SHAMIR_PROTOCOL_DOMAIN)); err != nil {
254+
return nil, err
255+
}
256+
if err := w.WriteUint64(params.FieldElementsPerBlob); err != nil {
257+
return nil, err
258+
}
259+
if err := w.WriteUint64(uint64(len(polys))); err != nil {
260+
return nil, err
261+
}
262+
for _, poly := range polys {
263+
for _, fe := range poly {
264+
b32 := bls.FrTo32(&fe)
265+
if err := w.Write(b32[:]); err != nil {
266+
return nil, err
267+
}
268+
}
269+
}
270+
l := comms.Len()
271+
for i := 0; i < l; i++ {
272+
c := comms.At(i)
273+
if err := w.Write(c[:]); err != nil {
274+
return nil, err
275+
}
276+
}
277+
var hash [32]byte
278+
copy(hash[:], sha.Sum(nil))
279+
return BytesToBLSField(hash), nil
280+
}
281+
282+
func BlobToPolynomial(b Blob) (Polynomial, bool) {
283+
l := b.Len()
284+
frs := make(Polynomial, l)
285+
for i := 0; i < l; i++ {
286+
if !bls.FrFrom32(&frs[i], b.At(i)) {
287+
return []bls.Fr{}, false
288+
}
289+
}
290+
return frs, true
291+
}
292+
293+
func BlobsToPolynomials(blobs BlobSequence) ([][]bls.Fr, bool) {
294+
l := blobs.Len()
295+
out := make(Polynomials, l)
296+
for i := 0; i < l; i++ {
297+
blob, ok := BlobToPolynomial(blobs.At(i))
298+
if !ok {
299+
return nil, false
300+
}
301+
out[i] = blob
302+
}
303+
return out, true
304+
}

crypto/kzg/kzg_bytes.go

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ func PointEvaluationPrecompile(input []byte) ([]byte, error) {
3535
if len(input) != 192 {
3636
return nil, errors.New("invalid input length")
3737
}
38-
3938
// versioned hash: first 32 bytes
4039
var versionedHash [32]byte
4140
copy(versionedHash[:], input[:32])
@@ -46,17 +45,6 @@ func PointEvaluationPrecompile(input []byte) ([]byte, error) {
4645
// Expected output: next 32 bytes
4746
copy(y[:], input[64:96])
4847

49-
// successfully converting x and y to bls.Fr confirms they are < MODULUS per the spec
50-
var xFr, yFr bls.Fr
51-
ok := bls.FrFrom32(&xFr, x)
52-
if !ok {
53-
return nil, errors.New("invalid evaluation point")
54-
}
55-
ok = bls.FrFrom32(&yFr, y)
56-
if !ok {
57-
return nil, errors.New("invalid expected output")
58-
}
59-
6048
// input kzg point: next 48 bytes
6149
var dataKZG [48]byte
6250
copy(dataKZG[:], input[96:144])
@@ -68,7 +56,7 @@ func PointEvaluationPrecompile(input []byte) ([]byte, error) {
6856
var quotientKZG [48]byte
6957
copy(quotientKZG[:], input[144:192])
7058

71-
ok, err := VerifyKZGProof(KZGCommitment(dataKZG), &xFr, &yFr, KZGProof(quotientKZG))
59+
ok, err := VerifyKZGProof(KZGCommitment(dataKZG), x, y, KZGProof(quotientKZG))
7260
if err != nil {
7361
return nil, fmt.Errorf("verify_kzg_proof error: %v", err)
7462
}
@@ -78,6 +66,30 @@ func PointEvaluationPrecompile(input []byte) ([]byte, error) {
7866
return []byte{}, nil
7967
}
8068

69+
// VerifyKZGProof implements verify_kzg_proof from the EIP-4844 consensus spec:
70+
// https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#verify_kzg_proof
71+
func VerifyKZGProof(polynomialKZG KZGCommitment, z, y [32]byte, kzgProof KZGProof) (bool, error) {
72+
// successfully converting z and y to bls.Fr confirms they are < MODULUS per the spec
73+
var zFr, yFr bls.Fr
74+
ok := bls.FrFrom32(&yFr, z)
75+
if !ok {
76+
return false, errors.New("invalid evaluation point")
77+
}
78+
ok = bls.FrFrom32(&yFr, y)
79+
if !ok {
80+
return false, errors.New("invalid expected output")
81+
}
82+
polynomialKZGG1, err := bls.FromCompressedG1(polynomialKZG[:])
83+
if err != nil {
84+
return false, fmt.Errorf("failed to decode polynomialKZG: %v", err)
85+
}
86+
kzgProofG1, err := bls.FromCompressedG1(kzgProof[:])
87+
if err != nil {
88+
return false, fmt.Errorf("failed to decode kzgProof: %v", err)
89+
}
90+
return VerifyKZGProofFromPoints(polynomialKZGG1, &zFr, &yFr, kzgProofG1), nil
91+
}
92+
8193
// KZGToVersionedHash implements kzg_to_versioned_hash from EIP-4844
8294
func KZGToVersionedHash(kzg KZGCommitment) VersionedHash {
8395
h := sha256.Sum256(kzg[:])
@@ -108,7 +120,11 @@ func VerifyAggregateKZGProof(blobs BlobSequence, expectedKZGCommitments KZGCommi
108120
return false, err
109121
}
110122
y := EvaluatePolynomialInEvaluationForm(aggregatedPoly, evaluationChallenge)
111-
return VerifyKZGProof(aggregatedPolyCommitment, evaluationChallenge, y, kzgAggregatedProof)
123+
kzgProofG1, err := bls.FromCompressedG1(kzgAggregatedProof[:])
124+
if err != nil {
125+
return false, fmt.Errorf("failed to decode kzgProof: %v", err)
126+
}
127+
return VerifyKZGProofFromPoints(aggregatedPolyCommitment, evaluationChallenge, y, kzgProofG1), nil
112128
}
113129

114130
// ComputeAggregateKZGProof implements compute_aggregate_kzg_proof from the EIP-4844 consensus spec:

0 commit comments

Comments
 (0)