Skip to content

Commit

Permalink
Use slices instead of pointers to arrays to pass blobs by reference
Browse files Browse the repository at this point in the history
  • Loading branch information
yperbasis committed Jan 30, 2025
1 parent 8b10b21 commit ce13be6
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 54 deletions.
20 changes: 10 additions & 10 deletions api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,23 @@ func TestNonCanonicalSmoke(t *testing.T) {
blobGood := GetRandBlob(123456789)
blobBad := GetRandBlob(123456789)
unreducedScalar := nonCanonicalScalar(123445)
modifyBlob(blobBad, unreducedScalar, 0)
modifyBlob(blobBad[:], unreducedScalar, 0)

commitment, err := ctx.BlobToKZGCommitment(blobGood, NumGoRoutines)
commitment, err := ctx.BlobToKZGCommitment(blobGood[:], NumGoRoutines)
require.NoError(t, err)
_, err = ctx.BlobToKZGCommitment(blobBad, NumGoRoutines)
_, err = ctx.BlobToKZGCommitment(blobBad[:], NumGoRoutines)
require.Error(t, err, "expected an error as we gave a non-canonical blob")

inputPointGood := GetRandFieldElement(123)
inputPointBad := createScalarNonCanonical(inputPointGood)
proof, claimedValueGood, err := ctx.ComputeKZGProof(blobGood, inputPointGood, NumGoRoutines)
proof, claimedValueGood, err := ctx.ComputeKZGProof(blobGood[:], inputPointGood, NumGoRoutines)
require.NoError(t, err)
claimedValueBad := createScalarNonCanonical(claimedValueGood)

_, _, err = ctx.ComputeKZGProof(blobGood, inputPointBad, NumGoRoutines)
_, _, err = ctx.ComputeKZGProof(blobGood[:], inputPointBad, NumGoRoutines)
require.Error(t, err, "expected an error since input point was not canonical")

_, _, err = ctx.ComputeKZGProof(blobBad, inputPointGood, NumGoRoutines)
_, _, err = ctx.ComputeKZGProof(blobBad[:], inputPointGood, NumGoRoutines)
require.Error(t, err, "expected an error since blob was not canonical")

err = ctx.VerifyKZGProof(commitment, inputPointGood, claimedValueGood, proof)
Expand All @@ -68,19 +68,19 @@ func TestNonCanonicalSmoke(t *testing.T) {
err = ctx.VerifyKZGProof(commitment, inputPointBad, claimedValueGood, proof)
require.Error(t, err, "expected an error since input point was not canonical")

blobProof, err := ctx.ComputeBlobKZGProof(blobBad, commitment, NumGoRoutines)
blobProof, err := ctx.ComputeBlobKZGProof(blobBad[:], commitment, NumGoRoutines)
require.Error(t, err, "expected an error since blob was not canonical")

err = ctx.VerifyBlobKZGProof(blobBad, commitment, blobProof)
err = ctx.VerifyBlobKZGProof(blobBad[:], commitment, blobProof)
require.Error(t, err, "expected an error since blob was not canonical")

err = ctx.VerifyBlobKZGProofBatch([]*gokzg4844.Blob{blobBad}, []gokzg4844.KZGCommitment{commitment}, []gokzg4844.KZGProof{blobProof})
err = ctx.VerifyBlobKZGProofBatch([]gokzg4844.BlobRef{blobBad[:]}, []gokzg4844.KZGCommitment{commitment}, []gokzg4844.KZGProof{blobProof})
require.Error(t, err, "expected an error since blob was not canonical")
}

// Below are helper methods which allow us to change a serialized element into
// its non-canonical counterpart by adding the modulus
func modifyBlob(blob *gokzg4844.Blob, newValue gokzg4844.Scalar, index int) {
func modifyBlob(blob gokzg4844.BlobRef, newValue gokzg4844.Scalar, index int) {
copy(blob[index:index+gokzg4844.SerializedScalarSize], newValue[:])
}

Expand Down
16 changes: 8 additions & 8 deletions bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,31 +35,31 @@ func GetRandFieldElement(seed int64) [32]byte {
return gokzg4844.SerializeScalar(r)
}

func GetRandBlob(seed int64) *gokzg4844.Blob {
func GetRandBlob(seed int64) gokzg4844.Blob {
var blob gokzg4844.Blob
bytesPerBlob := gokzg4844.ScalarsPerBlob * gokzg4844.SerializedScalarSize
for i := 0; i < bytesPerBlob; i += gokzg4844.SerializedScalarSize {
fieldElementBytes := GetRandFieldElement(seed + int64(i))
copy(blob[i:i+gokzg4844.SerializedScalarSize], fieldElementBytes[:])
}
return &blob
return blob
}

func Benchmark(b *testing.B) {
const length = 64
blobs := make([]*gokzg4844.Blob, length)
blobs := make([]gokzg4844.BlobRef, length)
commitments := make([]gokzg4844.KZGCommitment, length)
proofs := make([]gokzg4844.KZGProof, length)
fields := make([]gokzg4844.Scalar, length)

for i := 0; i < length; i++ {
blob := GetRandBlob(int64(i))
commitment, err := ctx.BlobToKZGCommitment(blob, NumGoRoutines)
commitment, err := ctx.BlobToKZGCommitment(blob[:], NumGoRoutines)
require.NoError(b, err)
proof, err := ctx.ComputeBlobKZGProof(blob, commitment, NumGoRoutines)
proof, err := ctx.ComputeBlobKZGProof(blob[:], commitment, NumGoRoutines)
require.NoError(b, err)

blobs[i] = blob
blobs[i] = blob[:]
commitments[i] = commitment
proofs[i] = proof
fields[i] = GetRandFieldElement(int64(i))
Expand Down Expand Up @@ -126,7 +126,7 @@ func Benchmark(b *testing.B) {
func BenchmarkDeserializeBlob(b *testing.B) {
var (
blob = GetRandBlob(int64(13))
first, err = gokzg4844.DeserializeBlob(blob)
first, err = gokzg4844.DeserializeBlob(blob[:])
second kzg.Polynomial
)
if err != nil {
Expand All @@ -135,7 +135,7 @@ func BenchmarkDeserializeBlob(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for n := 0; n < b.N; n++ {
second, err = gokzg4844.DeserializeBlob(blob)
second, err = gokzg4844.DeserializeBlob(blob[:])
if err != nil {
b.Fatal(err)
}
Expand Down
20 changes: 10 additions & 10 deletions consensus_specs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func TestBlobToKZGCommitment(t *testing.T) {
require.False(t, testCaseValid)
return
}
gotCommitment, err := ctx.BlobToKZGCommitment(blob, NumGoRoutines)
gotCommitment, err := ctx.BlobToKZGCommitment(blob[:], NumGoRoutines)
if err != nil {
require.False(t, testCaseValid)
return
Expand Down Expand Up @@ -98,7 +98,7 @@ func TestComputeKZGProof(t *testing.T) {
require.False(t, testCaseValid)
return
}
proof, outputPoint, err := ctx.ComputeKZGProof(blob, inputPoint, NumGoRoutines)
proof, outputPoint, err := ctx.ComputeKZGProof(blob[:], inputPoint, NumGoRoutines)
if err != nil {
require.False(t, testCaseValid)
return
Expand Down Expand Up @@ -148,7 +148,7 @@ func TestComputeBlobKZGProof(t *testing.T) {
require.False(t, testCaseValid)
return
}
proof, err := ctx.ComputeBlobKZGProof(blob, commitment, NumGoRoutines)
proof, err := ctx.ComputeBlobKZGProof(blob[:], commitment, NumGoRoutines)
if err != nil {
require.False(t, testCaseValid)
return
Expand Down Expand Up @@ -265,7 +265,7 @@ func TestVerifyBlobKZGProof(t *testing.T) {
return
}

err = ctx.VerifyBlobKZGProof(blob, commitment, proof)
err = ctx.VerifyBlobKZGProof(blob[:], commitment, proof)

// Test specifically distinguish between the test failing
// because of the pairing check and failing because of
Expand Down Expand Up @@ -306,14 +306,14 @@ func TestVerifyBlobKZGProofBatch(t *testing.T) {
require.NoError(t, err)
testCaseValid := test.ProofIsValid != nil

var blobs []*gokzg4844.Blob
var blobs []gokzg4844.BlobRef
for _, b := range test.Input.Blobs {
blob, err := hexStrToBlob(b)
if err != nil {
require.False(t, testCaseValid)
return
}
blobs = append(blobs, blob)
blobs = append(blobs, blob[:])
}

var commitments []gokzg4844.KZGCommitment
Expand Down Expand Up @@ -355,18 +355,18 @@ func TestVerifyBlobKZGProofBatch(t *testing.T) {
}
}

func hexStrToBlob(hexStr string) (*gokzg4844.Blob, error) {
func hexStrToBlob(hexStr string) (gokzg4844.Blob, error) {
var blob gokzg4844.Blob
byts, err := hexStrToBytes(hexStr)
if err != nil {
return nil, err
return blob, err
}

if len(blob) != len(byts) {
return nil, fmt.Errorf("blob does not have the correct length, %d ", len(byts))
return blob, fmt.Errorf("blob does not have the correct length, %d ", len(byts))
}
copy(blob[:], byts)
return &blob, nil
return blob, nil
}

func hexStrToScalar(hexStr string) (gokzg4844.Scalar, error) {
Expand Down
18 changes: 9 additions & 9 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,39 @@ var ctx, _ = gokzg4844.NewContext4096Secure()

func TestBlobProveVerifyRandomPointIntegration(t *testing.T) {
blob := GetRandBlob(123)
commitment, err := ctx.BlobToKZGCommitment(blob, NumGoRoutines)
commitment, err := ctx.BlobToKZGCommitment(blob[:], NumGoRoutines)
require.NoError(t, err)
proof, err := ctx.ComputeBlobKZGProof(blob, commitment, NumGoRoutines)
proof, err := ctx.ComputeBlobKZGProof(blob[:], commitment, NumGoRoutines)
require.NoError(t, err)
err = ctx.VerifyBlobKZGProof(blob, commitment, proof)
err = ctx.VerifyBlobKZGProof(blob[:], commitment, proof)
require.NoError(t, err)
}

func TestBlobProveVerifySpecifiedPointIntegration(t *testing.T) {
blob := GetRandBlob(123)
commitment, err := ctx.BlobToKZGCommitment(blob, NumGoRoutines)
commitment, err := ctx.BlobToKZGCommitment(blob[:], NumGoRoutines)
require.NoError(t, err)
inputPoint := GetRandFieldElement(123)
proof, claimedValue, err := ctx.ComputeKZGProof(blob, inputPoint, NumGoRoutines)
proof, claimedValue, err := ctx.ComputeKZGProof(blob[:], inputPoint, NumGoRoutines)
require.NoError(t, err)
err = ctx.VerifyKZGProof(commitment, inputPoint, claimedValue, proof)
require.NoError(t, err)
}

func TestBlobProveVerifyBatchIntegration(t *testing.T) {
batchSize := 5
blobs := make([]*gokzg4844.Blob, batchSize)
blobs := make([]gokzg4844.BlobRef, batchSize)
commitments := make([]gokzg4844.KZGCommitment, batchSize)
proofs := make([]gokzg4844.KZGProof, batchSize)

for i := 0; i < batchSize; i++ {
blob := GetRandBlob(int64(i))
commitment, err := ctx.BlobToKZGCommitment(blob, NumGoRoutines)
commitment, err := ctx.BlobToKZGCommitment(blob[:], NumGoRoutines)
require.NoError(t, err)
proof, err := ctx.ComputeBlobKZGProof(blob, commitment, NumGoRoutines)
proof, err := ctx.ComputeBlobKZGProof(blob[:], commitment, NumGoRoutines)
require.NoError(t, err)

blobs[i] = blob
blobs[i] = blob[:]
commitments[i] = commitment
proofs[i] = proof
}
Expand Down
4 changes: 2 additions & 2 deletions fiatshamir.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ const DomSepProtocol = "FSBLOBVERIFY_V1_"
// [compute_challenge]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#compute_challenge
//
// [hash_to_bls_field]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#hash_to_bls_field
func computeChallenge(blob *Blob, commitment KZGCommitment) fr.Element {
func computeChallenge(blob BlobRef, commitment KZGCommitment) fr.Element {
h := sha256.New()
h.Write([]byte(DomSepProtocol))
h.Write(u64ToByteArray16(ScalarsPerBlob))
h.Write(blob[:])
h.Write(blob)
h.Write(commitment[:])

digest := h.Sum(nil)
Expand Down
8 changes: 4 additions & 4 deletions fiatshamir_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (
// If the way computeChallenge is computed is updated
// then this test will fail
func TestComputeChallengeInterop(t *testing.T) {
blob := &Blob{}
blob := Blob{}
commitment := SerializeG1Point(bls12381.G1Affine{})
challenge := computeChallenge(blob, KZGCommitment(commitment))
challenge := computeChallenge(blob[:], KZGCommitment(commitment))
expected := []byte{
0x04, 0xb7, 0xb2, 0x2a, 0xf6, 0x3d, 0x2b, 0x2f,
0x1c, 0xed, 0x8d, 0x55, 0x05, 0x60, 0xe5, 0xd1,
Expand All @@ -38,7 +38,7 @@ func TestTo16Bytes(t *testing.T) {

func BenchmarkComputeChallenge(b *testing.B) {
var (
blob = &Blob{}
blob = Blob{}
commitment = SerializeG1Point(bls12381.G1Affine{})
challenge fr.Element
want = []byte{
Expand All @@ -51,7 +51,7 @@ func BenchmarkComputeChallenge(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for n := 0; n < b.N; n++ {
challenge = computeChallenge(blob, KZGCommitment(commitment))
challenge = computeChallenge(blob[:], KZGCommitment(commitment))
}
have := SerializeScalar(challenge)
require.Equal(b, want, have[:])
Expand Down
6 changes: 3 additions & 3 deletions prove.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
// value to a negative number or 0 will make it default to the number of CPUs.
//
// [blob_to_kzg_commitment]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#blob_to_kzg_commitment
func (c *Context) BlobToKZGCommitment(blob *Blob, numGoRoutines int) (KZGCommitment, error) {
func (c *Context) BlobToKZGCommitment(blob BlobRef, numGoRoutines int) (KZGCommitment, error) {
// 1. Deserialization
//
// Deserialize blob into polynomial
Expand Down Expand Up @@ -43,7 +43,7 @@ func (c *Context) BlobToKZGCommitment(blob *Blob, numGoRoutines int) (KZGCommitm
// value to a negative number or 0 will make it default to the number of CPUs.
//
// [compute_blob_kzg_proof]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#compute_blob_kzg_proof
func (c *Context) ComputeBlobKZGProof(blob *Blob, blobCommitment KZGCommitment, numGoRoutines int) (KZGProof, error) {
func (c *Context) ComputeBlobKZGProof(blob BlobRef, blobCommitment KZGCommitment, numGoRoutines int) (KZGProof, error) {
// 1. Deserialization
//
polynomial, err := DeserializeBlob(blob)
Expand Down Expand Up @@ -82,7 +82,7 @@ func (c *Context) ComputeBlobKZGProof(blob *Blob, blobCommitment KZGCommitment,
// value to a negative number or 0 will make it default to the number of CPUs.
//
// [compute_kzg_proof]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#compute_kzg_proof
func (c *Context) ComputeKZGProof(blob *Blob, inputPointBytes Scalar, numGoRoutines int) (KZGProof, Scalar, error) {
func (c *Context) ComputeKZGProof(blob BlobRef, inputPointBytes Scalar, numGoRoutines int) (KZGProof, Scalar, error) {
// 1. Deserialization
//
polynomial, err := DeserializeBlob(blob)
Expand Down
10 changes: 7 additions & 3 deletions serialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ type (
// [Blob]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#custom-types
Blob [ScalarsPerBlob * SerializedScalarSize]byte

// Auxiliary type to pass blobs by reference (fast) rather than value (slow).
// The slice MUST be of the same length as a Blob, i.e. ScalarsPerBlob * SerializedScalarSize
BlobRef []byte

// KZGProof is a serialized commitment to the quotient polynomial.
//
// It matches [KZGProof] in the spec.
Expand Down Expand Up @@ -107,7 +111,7 @@ func DeserializeKZGProof(proof KZGProof) (bls12381.G1Affine, error) {
// 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) {
func DeserializeBlob(blob BlobRef) (kzg.Polynomial, error) {
poly := make(kzg.Polynomial, ScalarsPerBlob)
for i := 0; i < ScalarsPerBlob; i++ {
chunk := blob[i*SerializedScalarSize : (i+1)*SerializedScalarSize]
Expand Down Expand Up @@ -140,12 +144,12 @@ func SerializeScalar(element fr.Element) Scalar {
//
// 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 {
func SerializePoly(poly kzg.Polynomial) Blob {
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
return blob
}
4 changes: 2 additions & 2 deletions serialization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ func TestSerializePolyRoundTrip(t *testing.T) {
blobA := gokzg4844.SerializePoly(expectedPolyA)
blobB := gokzg4844.SerializePoly(expectedPolyB)

gotPolyA, err := gokzg4844.DeserializeBlob(blobA)
gotPolyA, err := gokzg4844.DeserializeBlob(blobA[:])
if err != nil {
t.Error(err)
}
gotPolyB, err := gokzg4844.DeserializeBlob(blobB)
gotPolyB, err := gokzg4844.DeserializeBlob(blobB[:])
if err != nil {
t.Error(err)
}
Expand Down
6 changes: 3 additions & 3 deletions verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (c *Context) VerifyKZGProof(blobCommitment KZGCommitment, inputPointBytes,
// VerifyBlobKZGProof implements [verify_blob_kzg_proof].
//
// [verify_blob_kzg_proof]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#verify_blob_kzg_proof
func (c *Context) VerifyBlobKZGProof(blob *Blob, blobCommitment KZGCommitment, kzgProof KZGProof) error {
func (c *Context) VerifyBlobKZGProof(blob BlobRef, blobCommitment KZGCommitment, kzgProof KZGProof) error {
// 1. Deserialize
//
polynomial, err := DeserializeBlob(blob)
Expand Down Expand Up @@ -85,7 +85,7 @@ func (c *Context) VerifyBlobKZGProof(blob *Blob, blobCommitment KZGCommitment, k
// VerifyBlobKZGProofBatch implements [verify_blob_kzg_proof_batch].
//
// [verify_blob_kzg_proof_batch]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#verify_blob_kzg_proof_batch
func (c *Context) VerifyBlobKZGProofBatch(blobs []*Blob, polynomialCommitments []KZGCommitment, kzgProofs []KZGProof) error {
func (c *Context) VerifyBlobKZGProofBatch(blobs []BlobRef, polynomialCommitments []KZGCommitment, kzgProofs []KZGProof) error {
// 1. Check that all components in the batch have the same size
//
blobsLen := len(blobs)
Expand Down Expand Up @@ -149,7 +149,7 @@ func (c *Context) VerifyBlobKZGProofBatch(blobs []*Blob, polynomialCommitments [
// go-routines in a more intricate way than done below for large batches.
//
// [verify_blob_kzg_proof_batch]: https://github.com/ethereum/consensus-specs/blob/017a8495f7671f5fff2075a9bfc9238c1a0982f8/specs/deneb/polynomial-commitments.md#verify_blob_kzg_proof_batch
func (c *Context) VerifyBlobKZGProofBatchPar(blobs []*Blob, commitments []KZGCommitment, proofs []KZGProof) error {
func (c *Context) VerifyBlobKZGProofBatchPar(blobs []BlobRef, commitments []KZGCommitment, proofs []KZGProof) error {
// 1. Check that all components in the batch have the same size
if len(commitments) != len(blobs) || len(proofs) != len(blobs) {
return ErrBatchLengthCheck
Expand Down

0 comments on commit ce13be6

Please sign in to comment.