Skip to content

Commit

Permalink
remove legacy kzg verification, put all initialization on top (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
roberto-bayardo committed Nov 6, 2022
1 parent c702b48 commit 6c556bd
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 104 deletions.
113 changes: 23 additions & 90 deletions crypto/kzg/kzg.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,29 @@ var kzgSetupLagrange []bls.G1Point
// KZG CRS for G1 (only used in tests (for proof creation))
var KzgSetupG1 []bls.G1Point

type JSONTrustedSetup struct {
SetupG1 []bls.G1Point
SetupG2 []bls.G2Point
SetupLagrange []bls.G1Point
}

// Initialize KZG subsystem (load the trusted setup data)
func init() {
var parsedSetup = JSONTrustedSetup{}

// TODO: This is dirty. KZG setup should be loaded using an actual config file directive
err := json.Unmarshal([]byte(KZGSetupStr), &parsedSetup)
if err != nil {
panic(err)
}

kzgSetupG2 = parsedSetup.SetupG2
kzgSetupLagrange = bitReversalPermutation(parsedSetup.SetupLagrange)
KzgSetupG1 = parsedSetup.SetupG1

initDomain()
}

// Convert polynomial in evaluation form to KZG commitment
func BlobToKzg(eval []bls.Fr) *bls.G1Point {
return bls.LinCombG1(kzgSetupLagrange, eval)
Expand Down Expand Up @@ -99,73 +122,6 @@ func (batch *BlobsBatch) Verify() error {
return nil
}

// Verify that the list of `commitments` maps to the list of `blobs`
//
// This is an optimization over the naive approach (found in the EIP) of iteratively checking each blob against each
// commitment. The naive approach requires n*l scalar multiplications where `n` is the number of blobs and `l` is
// FIELD_ELEMENTS_PER_BLOB to compute the commitments for all blobs.
//
// A more efficient approach is to build a linear combination of all blobs and commitments and check all of them in a
// single multi-scalar multiplication.
//
// The MSM would look like this (for three blobs with two field elements each):
// r_0(b0_0*L_0 + b0_1*L_1) + r_1(b1_0*L_0 + b1_1*L_1) + r_2(b2_0*L_0 + b2_1*L_1)
// which we would need to check against the linear combination of commitments: r_0*C_0 + r_1*C_1 + r_2*C_2
// In the above, `r` are the random scalars of the linear combination, `b0` is the zero blob, `L` are the elements
// of the KZG_SETUP_LAGRANGE and `C` are the commitments provided.
//
// By regrouping the above equation around the `L` points we can reduce the length of the MSM further
// (down to just `n` scalar multiplications) by making it look like this:
// (r_0*b0_0 + r_1*b1_0 + r_2*b2_0) * L_0 + (r_0*b0_1 + r_1*b1_1 + r_2*b2_1) * L_1
func VerifyBlobsLegacy(commitments []*bls.G1Point, blobs [][]bls.Fr) error {
// Prepare objects to hold our two MSMs
lPoints := make([]bls.G1Point, params.FieldElementsPerBlob)
lScalars := make([]bls.Fr, params.FieldElementsPerBlob)
rPoints := make([]bls.G1Point, len(commitments))
rScalars := make([]bls.Fr, len(commitments))

// Generate list of random scalars for lincomb
rList := make([]bls.Fr, len(blobs))
for i := 0; i < len(blobs); i++ {
bls.CopyFr(&rList[i], bls.RandomFr())
}

// Build left-side MSM:
// (r_0*b0_0 + r_1*b1_0 + r_2*b2_0) * L_0 + (r_0*b0_1 + r_1*b1_1 + r_2*b2_1) * L_1
for c := 0; c < params.FieldElementsPerBlob; c++ {
var sum bls.Fr
for i := 0; i < len(blobs); i++ {
var tmp bls.Fr

r := rList[i]
blob := blobs[i]

bls.MulModFr(&tmp, &r, &blob[c])
bls.AddModFr(&sum, &sum, &tmp)
}
lScalars[c] = sum
lPoints[c] = kzgSetupLagrange[c]
}

// Build right-side MSM: r_0 * C_0 + r_1 * C_1 + r_2 * C_2 + ...
for i, commitment := range commitments {
rScalars[i] = rList[i]
rPoints[i] = *commitment
}

// Compute both MSMs and check equality
lResult := bls.LinCombG1(lPoints, lScalars)
rResult := bls.LinCombG1(rPoints, rScalars)
if !bls.EqualG1(lResult, rResult) {
return errors.New("VerifyBlobs failed")
}

// TODO: Potential improvement is to unify both MSMs into a single MSM, but you would need to batch-invert the `r`s
// of the right-side MSM to effectively pull them to the left side.

return nil
}

// Bit-reversal permutation helper functions

// Check if `value` is a power of two integer.
Expand Down Expand Up @@ -239,26 +195,3 @@ func ComputeProof(eval []bls.Fr, z *bls.Fr) (*bls.G1Point, error) {
}
return bls.LinCombG1(kzgSetupLagrange, quotientPoly[:]), nil
}

type JSONTrustedSetup struct {
SetupG1 []bls.G1Point
SetupG2 []bls.G2Point
SetupLagrange []bls.G1Point
}

// Initialize KZG subsystem (load the trusted setup data)
func init() {
var parsedSetup = JSONTrustedSetup{}

// TODO: This is dirty. KZG setup should be loaded using an actual config file directive
err := json.Unmarshal([]byte(KZGSetupStr), &parsedSetup)
if err != nil {
panic(err)
}

kzgSetupG2 = parsedSetup.SetupG2
kzgSetupLagrange = bitReversalPermutation(parsedSetup.SetupLagrange)
KzgSetupG1 = parsedSetup.SetupG1

initDomain()
}
14 changes: 0 additions & 14 deletions tests/kzg_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,6 @@ func BenchmarkBlobToKzg(b *testing.B) {
}
}

func BenchmarkVerifyBlobsWithoutKZGProof(b *testing.B) {
var blobs [][]bls.Fr
var commitments []*bls.G1Point
for i := 0; i < 16; i++ {
blob := randomBlob()
blobs = append(blobs, blob)
commitments = append(commitments, kzg.BlobToKzg(blob))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
kzg.VerifyBlobsLegacy(commitments, blobs)
}
}

func BenchmarkVerifyBlobs(b *testing.B) {
blobs := make([]types.Blob, params.MaxBlobsPerBlock)
var commitments []types.KZGCommitment
Expand Down

0 comments on commit 6c556bd

Please sign in to comment.