217 lines
8.2 KiB
Go
217 lines
8.2 KiB
Go
package goethkzg
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381"
|
|
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
|
|
"github.com/crate-crypto/go-eth-kzg/internal/kzg"
|
|
"github.com/crate-crypto/go-eth-kzg/internal/utils"
|
|
)
|
|
|
|
// CompressedG1Size is the number of bytes needed to represent a group element in G1 when compressed.
|
|
const CompressedG1Size = 48
|
|
|
|
// CompressedG2Size is the number of bytes needed to represent a group element in G2 when compressed.
|
|
const CompressedG2Size = 96
|
|
|
|
// SerializedScalarSize is the number of bytes needed to represent a field element corresponding to the order of the G1
|
|
// group.
|
|
//
|
|
// It matches [BYTES_PER_FIELD_ELEMENT] in the spec.
|
|
//
|
|
// [BYTES_PER_FIELD_ELEMENT]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#constants
|
|
const SerializedScalarSize = 32
|
|
|
|
// ScalarsPerBlob is the number of serialized scalars in a blob.
|
|
//
|
|
// It matches [FIELD_ELEMENTS_PER_BLOB] in the spec.
|
|
//
|
|
// Note: These scalars are not guaranteed to be valid (a value less than [BLS_MODULUS]). If any of the scalars in a blob
|
|
// are invalid (non-canonical), an error will be returned on deserialization.
|
|
//
|
|
// [BLS_MODULUS]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#constants
|
|
// [FIELD_ELEMENTS_PER_BLOB]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#blob
|
|
const ScalarsPerBlob = 4096
|
|
|
|
// BytesPerCell is the number of bytes in a `Cell`.
|
|
const BytesPerCell = scalarsPerCell * SerializedScalarSize
|
|
|
|
// The number of cells in an extended blob.
|
|
const CellsPerExtBlob = 128
|
|
|
|
// scalarsPerCell is the number of scalars in a cell.
|
|
const scalarsPerCell = 64
|
|
|
|
// expansionFactor is the factor by which the number of
|
|
// scalars in a blob is expanded to create an extended blob.
|
|
const expansionFactor = 2
|
|
|
|
// scalarsPerExtBlob is the number of scalars in an extended blob.
|
|
//
|
|
// An extended blob is a blob that has been evaluated at more points than is needed
|
|
// to uniquely determine the polynomial its corresponding polynomial.
|
|
const scalarsPerExtBlob = expansionFactor * ScalarsPerBlob
|
|
|
|
type (
|
|
// G1Point matches [G1Point] in the spec.
|
|
//
|
|
// [G1Point]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#custom-types
|
|
G1Point [CompressedG1Size]byte
|
|
|
|
// G2Point matches [G2Point] in the spec.
|
|
//
|
|
// [G2Point]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#custom-types
|
|
G2Point [CompressedG2Size]byte
|
|
|
|
// Scalar matches [BLSFieldElement] in the spec.
|
|
//
|
|
// [BLSFieldElement]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#custom-types
|
|
Scalar [SerializedScalarSize]byte
|
|
|
|
// Blob is a flattened representation of a serialized polynomial.
|
|
//
|
|
// It matches [Blob] in the spec.
|
|
//
|
|
// [Blob]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#custom-types
|
|
Blob [ScalarsPerBlob * SerializedScalarSize]byte
|
|
|
|
// KZGProof is a serialized commitment to the quotient polynomial.
|
|
//
|
|
// It matches [KZGProof] in the spec.
|
|
//
|
|
// [KZGProof]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#custom-types
|
|
KZGProof G1Point
|
|
|
|
// KZGCommitment is a serialized commitment to a polynomial.
|
|
//
|
|
// It matches [KZGCommitment] in the spec.
|
|
//
|
|
// [KZGCommitment]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#custom-types
|
|
KZGCommitment G1Point
|
|
|
|
// Cell is a serialized version of a set of evaluations to a polynomial
|
|
Cell [BytesPerCell]byte
|
|
)
|
|
|
|
// SerializeG1Point converts a [bls12381.G1Affine] to [G1Point].
|
|
func SerializeG1Point(affine bls12381.G1Affine) G1Point {
|
|
return affine.Bytes()
|
|
}
|
|
|
|
// deserializeG1Point converts a [G1Point] to the internal [bls12381.G1Affine] type. It will return an error if the
|
|
// point is not on the group or if the point is not in the correct subgroup.
|
|
//
|
|
// It implements [validate_kzg_g1].
|
|
//
|
|
// [validate_kzg_g1]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#validate_kzg_g1
|
|
func deserializeG1Point(serPoint G1Point) (bls12381.G1Affine, error) {
|
|
var point bls12381.G1Affine
|
|
_, err := point.SetBytes(serPoint[:])
|
|
if err != nil {
|
|
return bls12381.G1Affine{}, err
|
|
}
|
|
return point, nil
|
|
}
|
|
|
|
// DeserializeKZGCommitment implements [bytes_to_kzg_commitment].
|
|
//
|
|
// [bytes_to_kzg_commitment]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#bytes_to_kzg_commitment
|
|
func DeserializeKZGCommitment(commitment KZGCommitment) (bls12381.G1Affine, error) {
|
|
return deserializeG1Point(G1Point(commitment))
|
|
}
|
|
|
|
// DeserializeKZGProof implements [bytes_to_kzg_proof].
|
|
//
|
|
// [bytes_to_kzg_proof]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#bytes_to_kzg_proof
|
|
func DeserializeKZGProof(proof KZGProof) (bls12381.G1Affine, error) {
|
|
return deserializeG1Point(G1Point(proof))
|
|
}
|
|
|
|
// DeserializeBlob implements [blob_to_polynomial].
|
|
//
|
|
// [blob_to_polynomial]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#blob_to_polynomial
|
|
func DeserializeBlob(blob *Blob) (kzg.Polynomial, error) {
|
|
if blob == nil {
|
|
return nil, ErrDeserializeNilInput
|
|
}
|
|
poly := make(kzg.Polynomial, ScalarsPerBlob)
|
|
for i := 0; i < ScalarsPerBlob; i++ {
|
|
chunk := blob[i*SerializedScalarSize : (i+1)*SerializedScalarSize]
|
|
if err := poly[i].SetBytesCanonical(chunk); err != nil {
|
|
return nil, ErrNonCanonicalScalar
|
|
}
|
|
}
|
|
return poly, nil
|
|
}
|
|
|
|
// DeserializeScalar implements [bytes_to_bls_field].
|
|
//
|
|
// Note: Returns an error if the scalar is not in the range [0, p-1] (inclusive) where `p` is the prime associated with the scalar field.
|
|
//
|
|
// [bytes_to_bls_field]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#bytes_to_bls_field
|
|
func DeserializeScalar(serScalar Scalar) (fr.Element, error) {
|
|
scalar, err := utils.ReduceCanonicalBigEndian(serScalar[:])
|
|
if err != nil {
|
|
return fr.Element{}, ErrNonCanonicalScalar
|
|
}
|
|
return scalar, nil
|
|
}
|
|
|
|
// SerializeScalar converts a [fr.Element] to [Scalar].
|
|
func SerializeScalar(element fr.Element) Scalar {
|
|
return element.Bytes()
|
|
}
|
|
|
|
// SerializePoly converts a [kzg.Polynomial] to [Blob].
|
|
//
|
|
// Note: This method is never used in the API because we always expect a byte array and will never receive deserialized
|
|
// field elements. We include it so that upstream fuzzers do not need to reimplement it.
|
|
func SerializePoly(poly kzg.Polynomial) *Blob {
|
|
if len(poly) != ScalarsPerBlob {
|
|
panic(fmt.Sprintf("expected polynomial to have size %d but it has size %d", ScalarsPerBlob, len(poly)))
|
|
}
|
|
var blob Blob
|
|
for i := 0; i < ScalarsPerBlob; i++ {
|
|
chunk := blob[i*SerializedScalarSize : (i+1)*SerializedScalarSize]
|
|
serScalar := SerializeScalar(poly[i])
|
|
copy(chunk, serScalar[:])
|
|
}
|
|
return &blob
|
|
}
|
|
|
|
// serializeEvaluations converts an array of scalars of size `scalarsPerCell` to [Cell].
|
|
func serializeEvaluations(evals *[scalarsPerCell]fr.Element) *Cell {
|
|
var cell Cell
|
|
|
|
for i := 0; i < scalarsPerCell; i++ {
|
|
chunk := cell[i*SerializedScalarSize : (i+1)*SerializedScalarSize]
|
|
serScalar := SerializeScalar(evals[i])
|
|
copy(chunk, serScalar[:])
|
|
}
|
|
|
|
return &cell
|
|
}
|
|
|
|
func deserializeCell(cell *Cell) ([]fr.Element, error) {
|
|
if cell == nil {
|
|
return nil, ErrDeserializeNilInput
|
|
}
|
|
evals := make([]fr.Element, scalarsPerCell)
|
|
|
|
for i := 0; i < scalarsPerCell; i++ {
|
|
chunk := cell[i*SerializedScalarSize : (i+1)*SerializedScalarSize]
|
|
|
|
chunk_arr := [SerializedScalarSize]byte{}
|
|
copy(chunk_arr[:], chunk)
|
|
|
|
eval, err := DeserializeScalar(chunk_arr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
evals[i] = eval
|
|
}
|
|
|
|
return evals, nil
|
|
}
|