Skip to content

Commit

Permalink
move more low-level kzg stuff into kzg_new (#48)
Browse files Browse the repository at this point in the history
* start using custom types from the 4844 spec

* move ComputePowers into kzg_new

* 1) move BlobsToKZGCommitment functionality into kzg_new and make it more closely follow the spec.

2) Remove the BlobsBatch stuff which seems only to be for legacy benchmarking.

* Replace kzg-related data_blob.go type methods Parse, ComputeCommitment, and
Point, so we can move methods that depend on them into the kzg package.

* Remove ComputeCommitments which is unused.

* Add BytesToBLSField go kzg_new, use it instead of hashToFr
  • Loading branch information
roberto-bayardo authored Nov 10, 2022
1 parent e8e85fe commit 9ea1faa
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 227 deletions.
125 changes: 25 additions & 100 deletions core/types/data_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"io"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
Expand Down Expand Up @@ -58,12 +57,8 @@ func (p *KZGCommitment) UnmarshalText(text []byte) error {
return hexutil.UnmarshalFixedText("KZGCommitment", text, p[:])
}

func (p *KZGCommitment) Point() (*bls.G1Point, error) {
return bls.FromCompressedG1(p[:])
}

func (c KZGCommitment) ComputeVersionedHash() common.Hash {
return kzg.KZGToVersionedHash(c)
return common.Hash(kzg.KZGToVersionedHash(kzg.KZGCommitment(c)))
}

// Compressed BLS12-381 G1 element
Expand Down Expand Up @@ -108,10 +103,6 @@ func (p *KZGProof) UnmarshalText(text []byte) error {
return hexutil.UnmarshalFixedText("KZGProof", text, p[:])
}

func (p *KZGProof) Point() (*bls.G1Point, error) {
return bls.FromCompressedG1(p[:])
}

type BLSFieldElement [32]byte

func (p BLSFieldElement) MarshalText() ([]byte, error) {
Expand Down Expand Up @@ -165,18 +156,15 @@ func (blob *Blob) HashTreeRoot(hFn tree.HashFn) tree.Root {
}, params.FieldElementsPerBlob)
}

func (blob *Blob) ComputeCommitment() (commitment KZGCommitment, ok bool) {
// Convert a blob to kzg.Blob
func (blob *Blob) ToKZGBlob() (kzg.Blob, bool) {
frs := make([]bls.Fr, len(blob))
for i, elem := range blob {
if !bls.FrFrom32(&frs[i], elem) {
return KZGCommitment{}, false
return []bls.Fr{}, false
}
}
// data is presented in eval form
commitmentG1 := kzg.BlobToKzg(frs)
var out KZGCommitment
copy(out[:], bls.ToCompressedG1(commitmentG1))
return out, true
return kzg.Blob(frs), true
}

func (blob *Blob) MarshalText() ([]byte, error) {
Expand Down Expand Up @@ -219,33 +207,8 @@ func (blob *Blob) UnmarshalText(text []byte) error {
return nil
}

// Parse blob into Fr elements array
func (blob *Blob) Parse() (out []bls.Fr, err error) {
out = make([]bls.Fr, params.FieldElementsPerBlob)
for i, chunk := range blob {
ok := bls.FrFrom32(&out[i], chunk)
if !ok {
return nil, errors.New("internal error commitments")
}
}
return out, nil
}

type BlobKzgs []KZGCommitment

// Extract the crypto material underlying these commitments
func (li BlobKzgs) Parse() ([]*bls.G1Point, error) {
out := make([]*bls.G1Point, len(li))
for i, c := range li {
p, err := c.Point()
if err != nil {
return nil, fmt.Errorf("failed to parse commitment %d: %v", i, err)
}
out[i] = p
}
return out, nil
}

func (li *BlobKzgs) Deserialize(dr *codec.DecodingReader) error {
return dr.List(func() codec.Deserializable {
i := len(*li)
Expand Down Expand Up @@ -283,16 +246,16 @@ func (li BlobKzgs) copy() BlobKzgs {
type Blobs []Blob

// Extract the crypto material underlying these blobs
func (blobs Blobs) Parse() ([][]bls.Fr, error) {
func (blobs Blobs) toKZGBlobSequence() ([][]bls.Fr, bool) {
out := make([][]bls.Fr, len(blobs))
for i, b := range blobs {
blob, err := b.Parse()
if err != nil {
return nil, fmt.Errorf("failed to parse blob %d: %v", i, err)
blob, ok := b.ToKZGBlob()
if !ok {
return nil, false
}
out[i] = blob
}
return out, nil
return out, true
}

func (a *Blobs) Deserialize(dr *codec.DecodingReader) error {
Expand Down Expand Up @@ -333,31 +296,17 @@ func (blobs Blobs) copy() Blobs {
return cpy
}

// Return KZG commitments and versioned hashes that correspond to these blobs
func (blobs Blobs) ComputeCommitments() (commitments []KZGCommitment, versionedHashes []common.Hash, ok bool) {
commitments = make([]KZGCommitment, len(blobs))
versionedHashes = make([]common.Hash, len(blobs))
for i, blob := range blobs {
commitments[i], ok = blob.ComputeCommitment()
if !ok {
return nil, nil, false
}
versionedHashes[i] = commitments[i].ComputeVersionedHash()
}
return commitments, versionedHashes, true
}

// Return KZG commitments, versioned hashes and the aggregated KZG proof that correspond to these blobs
func (blobs Blobs) ComputeCommitmentsAndAggregatedProof() (commitments []KZGCommitment, versionedHashes []common.Hash, aggregatedProof KZGProof, err error) {
commitments = make([]KZGCommitment, len(blobs))
versionedHashes = make([]common.Hash, len(blobs))
for i, blob := range blobs {
var ok bool
commitments[i], ok = blob.ComputeCommitment()
frs, ok := blob.ToKZGBlob()
if !ok {
return nil, nil, KZGProof{}, errors.New("invalid blob for commitment")
}
versionedHashes[i] = commitments[i].ComputeVersionedHash()
commitments[i] = KZGCommitment(kzg.BlobToKZGCommitment(frs))
versionedHashes[i] = common.Hash(kzg.KZGToVersionedHash(kzg.KZGCommitment(commitments[i])))
}

var kzgProof KZGProof
Expand All @@ -378,13 +327,12 @@ func (blobs Blobs) ComputeCommitmentsAndAggregatedProof() (commitments []KZGComm
if err != nil {
return nil, nil, KZGProof{}, err
}
var z bls.Fr
hashToFr(&z, sum)
z := kzg.BytesToBLSField(sum)

var y bls.Fr
kzg.EvaluatePolyInEvaluationForm(&y, aggregatePoly[:], &z)
kzg.EvaluatePolyInEvaluationForm(&y, aggregatePoly[:], z)

aggProofG1, err := kzg.ComputeProof(aggregatePoly, &z)
aggProofG1, err := kzg.ComputeProof(aggregatePoly, z)
if err != nil {
return nil, nil, KZGProof{}, err
}
Expand Down Expand Up @@ -515,17 +463,16 @@ func (b *BlobTxWrapData) verifyBlobs(inner TxData) error {
if err != nil {
return err
}
var z bls.Fr
hashToFr(&z, sum)
z := kzg.BytesToBLSField(sum)

var y bls.Fr
kzg.EvaluatePolyInEvaluationForm(&y, aggregatePoly[:], &z)
kzg.EvaluatePolyInEvaluationForm(&y, aggregatePoly[:], z)

aggregateProofG1, err := b.KzgAggregatedProof.Point()
aggregateProofG1, err := bls.FromCompressedG1(b.KzgAggregatedProof[:])
if err != nil {
return fmt.Errorf("aggregate proof parse error: %v", err)
}
if !kzg.VerifyKZGProofFromPoints(aggregateCommitmentG1, &z, &y, aggregateProofG1) {
if !kzg.VerifyKZGProofFromPoints(aggregateCommitmentG1, z, &y, aggregateProofG1) {
return errors.New("failed to verify kzg")
}
return nil
Expand Down Expand Up @@ -568,39 +515,27 @@ func (b *BlobTxWrapData) encodeTyped(w io.Writer, txdata TxData) error {
return EncodeSSZ(w, &wrapped)
}

func computePowers(r *bls.Fr, n int) []bls.Fr {
var currentPower bls.Fr
bls.AsFr(&currentPower, 1)
powers := make([]bls.Fr, n)
for i := range powers {
powers[i] = currentPower
bls.MulModFr(&currentPower, &currentPower, r)
}
return powers
}

func computeAggregateKzgCommitment(blobs Blobs, commitments []KZGCommitment) ([]bls.Fr, *bls.G1Point, error) {
// create challenges
sum, err := sszHash(&BlobsAndCommitments{blobs, commitments})
if err != nil {
return nil, nil, err
}
var r bls.Fr
hashToFr(&r, sum)
r := kzg.BytesToBLSField(sum)

powers := computePowers(&r, len(blobs))
powers := kzg.ComputePowers(r, len(blobs))

commitmentsG1 := make([]bls.G1Point, len(commitments))
for i := 0; i < len(commitmentsG1); i++ {
p, _ := commitments[i].Point()
p, _ := bls.FromCompressedG1(commitments[i][:])
bls.CopyG1(&commitmentsG1[i], p)
}
aggregateCommitmentG1 := bls.LinCombG1(commitmentsG1, powers)
var aggregateCommitment KZGCommitment
copy(aggregateCommitment[:], bls.ToCompressedG1(aggregateCommitmentG1))

polys, err := blobs.Parse()
if err != nil {
polys, ok := blobs.toKZGBlobSequence()
if !ok {
return nil, nil, err
}
aggregatePoly, err := bls.PolyLinComb(polys, powers)
Expand All @@ -609,13 +544,3 @@ func computeAggregateKzgCommitment(blobs Blobs, commitments []KZGCommitment) ([]
}
return aggregatePoly, aggregateCommitmentG1, nil
}

func hashToFr(out *bls.Fr, h [32]byte) {
// re-interpret as little-endian
var b [32]byte = h
for i := 0; i < 16; i++ {
b[31-i], b[i] = b[i], b[31-i]
}
zB := new(big.Int).Mod(new(big.Int).SetBytes(b[:]), kzg.BLSModulus)
_ = kzg.BigToFr(out, zB)
}
64 changes: 0 additions & 64 deletions crypto/kzg/kzg.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ package kzg
import (
"encoding/json"
"errors"
"fmt"
"math/big"
"math/bits"
"sync"

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

Expand Down Expand Up @@ -45,68 +43,6 @@ func init() {
initDomain()
}

// Convert polynomial in evaluation form to KZG commitment
func BlobToKzg(eval []bls.Fr) *bls.G1Point {
return bls.LinCombG1(kzgSetupLagrange, eval)
}

type BlobsBatch struct {
sync.Mutex
init bool
aggregateCommitment bls.G1Point
aggregateBlob [params.FieldElementsPerBlob]bls.Fr
}

func (batch *BlobsBatch) Join(commitments []*bls.G1Point, blobs [][]bls.Fr) error {
batch.Lock()
defer batch.Unlock()
if len(commitments) != len(blobs) {
return fmt.Errorf("expected commitments len %d to equal blobs len %d", len(commitments), len(blobs))
}
if !batch.init && len(commitments) > 0 {
batch.init = true
bls.CopyG1(&batch.aggregateCommitment, commitments[0])
copy(batch.aggregateBlob[:], blobs[0])
commitments = commitments[1:]
blobs = blobs[1:]
}
for i, commit := range commitments {
batch.join(commit, blobs[i])
}
return nil
}

func (batch *BlobsBatch) join(commitment *bls.G1Point, blob []bls.Fr) {
// we multiply the input we are joining with a random scalar, so we can add it to the aggregate safely
randomScalar := bls.RandomFr()

// TODO: instead of computing the lin-comb of the commitments on the go, we could buffer
// the random scalar and commitment, and run a LinCombG1 over all of them during Verify()
var tmpG1 bls.G1Point
bls.MulG1(&tmpG1, commitment, randomScalar)
bls.AddG1(&batch.aggregateCommitment, &batch.aggregateCommitment, &tmpG1)

var tmpFr bls.Fr
for i := 0; i < params.FieldElementsPerBlob; i++ {
bls.MulModFr(&tmpFr, &blob[i], randomScalar)
bls.AddModFr(&batch.aggregateBlob[i], &batch.aggregateBlob[i], &tmpFr)
}
}

func (batch *BlobsBatch) Verify() error {
batch.Lock()
defer batch.Unlock()
if !batch.init {
return nil // empty batch
}
// Compute both MSMs and check equality
lResult := bls.LinCombG1(kzgSetupLagrange, batch.aggregateBlob[:])
if !bls.EqualG1(lResult, &batch.aggregateCommitment) {
return errors.New("BlobsBatch failed to Verify")
}
return nil
}

// Bit-reversal permutation helper functions

// Check if `value` is a power of two integer.
Expand Down
Loading

0 comments on commit 9ea1faa

Please sign in to comment.