Skip to content

Commit a5e6a15

Browse files
signer/core/apitypes: add cell proofs (#32910)
Adds support for cell proofs in blob transactions in the signer --------- Co-authored-by: Gary Rong <garyrong0905@gmail.com>
1 parent cb97c48 commit a5e6a15

File tree

2 files changed

+218
-15
lines changed

2 files changed

+218
-15
lines changed

signer/core/apitypes/types.go

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ type SendTxArgs struct {
108108
BlobHashes []common.Hash `json:"blobVersionedHashes,omitempty"`
109109

110110
// For BlobTxType transactions with blob sidecar
111+
BlobVersion byte `json:"blobVersion,omitempty"`
111112
Blobs []kzg4844.Blob `json:"blobs,omitempty"`
112113
Commitments []kzg4844.Commitment `json:"commitments,omitempty"`
113114
Proofs []kzg4844.Proof `json:"proofs,omitempty"`
@@ -235,37 +236,58 @@ func (args *SendTxArgs) validateTxSidecar() error {
235236
if args.Commitments != nil && len(args.Commitments) != n {
236237
return fmt.Errorf("number of blobs and commitments mismatch (have=%d, want=%d)", len(args.Commitments), n)
237238
}
238-
if args.Proofs != nil && len(args.Proofs) != n {
239-
return fmt.Errorf("number of blobs and proofs mismatch (have=%d, want=%d)", len(args.Proofs), n)
240-
}
241239
if args.BlobHashes != nil && len(args.BlobHashes) != n {
242240
return fmt.Errorf("number of blobs and hashes mismatch (have=%d, want=%d)", len(args.BlobHashes), n)
243241
}
244-
242+
if args.Proofs != nil {
243+
if len(args.Proofs) == n {
244+
// v1 transaction
245+
for i, b := range args.Blobs {
246+
if err := kzg4844.VerifyBlobProof(&b, args.Commitments[i], args.Proofs[i]); err != nil {
247+
return fmt.Errorf("failed to verify blob proof: %v", err)
248+
}
249+
}
250+
} else if len(args.Proofs) == n*kzg4844.CellProofsPerBlob {
251+
// v2 transaction
252+
if err := kzg4844.VerifyCellProofs(args.Blobs, args.Commitments, args.Proofs); err != nil {
253+
return fmt.Errorf("failed to verify blob proof: %v", err)
254+
}
255+
} else {
256+
return fmt.Errorf("number of proofs and blobs mismatch (have=%d, want=%d or %d)", len(args.Proofs), n, n*kzg4844.CellProofsPerBlob)
257+
}
258+
}
245259
if args.Commitments == nil {
246260
// Generate commitment and proof.
247261
commitments := make([]kzg4844.Commitment, n)
248-
proofs := make([]kzg4844.Proof, n)
249262
for i, b := range args.Blobs {
250263
c, err := kzg4844.BlobToCommitment(&b)
251264
if err != nil {
252265
return fmt.Errorf("blobs[%d]: error computing commitment: %v", i, err)
253266
}
254267
commitments[i] = c
255-
p, err := kzg4844.ComputeBlobProof(&b, c)
256-
if err != nil {
257-
return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err)
268+
}
269+
var proofs []kzg4844.Proof
270+
if args.BlobVersion == types.BlobSidecarVersion1 {
271+
proofs = make([]kzg4844.Proof, 0, n*kzg4844.CellProofsPerBlob)
272+
for i, b := range args.Blobs {
273+
p, err := kzg4844.ComputeCellProofs(&b)
274+
if err != nil {
275+
return fmt.Errorf("blobs[%d]: error computing cell proof: %v", i, err)
276+
}
277+
proofs = append(proofs, p...)
278+
}
279+
} else {
280+
proofs = make([]kzg4844.Proof, 0, n)
281+
for i, b := range args.Blobs {
282+
p, err := kzg4844.ComputeBlobProof(&b, commitments[i])
283+
if err != nil {
284+
return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err)
285+
}
286+
proofs = append(proofs, p)
258287
}
259-
proofs[i] = p
260288
}
261289
args.Commitments = commitments
262290
args.Proofs = proofs
263-
} else {
264-
for i, b := range args.Blobs {
265-
if err := kzg4844.VerifyBlobProof(&b, args.Commitments[i], args.Proofs[i]); err != nil {
266-
return fmt.Errorf("failed to verify blob proof: %v", err)
267-
}
268-
}
269291
}
270292

271293
hashes := make([]common.Hash, n)

signer/core/apitypes/types_test.go

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package apitypes
1818

1919
import (
20+
"crypto/rand"
2021
"crypto/sha256"
2122
"encoding/json"
2223
"testing"
@@ -229,3 +230,183 @@ func TestType_TypeName(t *testing.T) {
229230
}
230231
}
231232
}
233+
234+
func TestValidateTxSidecar(t *testing.T) {
235+
t.Parallel()
236+
237+
// Helper function to create a test blob and its commitment/proof
238+
createTestBlob := func() (kzg4844.Blob, kzg4844.Commitment, kzg4844.Proof, common.Hash) {
239+
b := make([]byte, 31)
240+
rand.Read(b)
241+
var blob kzg4844.Blob
242+
for i := range b {
243+
blob[i+1] = b[i]
244+
}
245+
commitment, err := kzg4844.BlobToCommitment(&blob)
246+
if err != nil {
247+
t.Fatal(err)
248+
}
249+
proof, err := kzg4844.ComputeBlobProof(&blob, commitment)
250+
if err != nil {
251+
t.Fatal(err)
252+
}
253+
hash := kzg4844.CalcBlobHashV1(sha256.New(), &commitment)
254+
return blob, commitment, proof, hash
255+
}
256+
257+
// Helper function to create test cell proofs for v1 transactions
258+
createTestCellProofs := func(blob kzg4844.Blob) []kzg4844.Proof {
259+
cellProofs, err := kzg4844.ComputeCellProofs(&blob)
260+
if err != nil {
261+
t.Fatal(err)
262+
}
263+
return cellProofs
264+
}
265+
266+
blob1, commitment1, proof1, hash1 := createTestBlob()
267+
blob2, commitment2, proof2, hash2 := createTestBlob()
268+
269+
tests := []struct {
270+
name string
271+
args SendTxArgs
272+
wantErr bool
273+
}{
274+
{
275+
name: "no blobs - should pass",
276+
args: SendTxArgs{},
277+
wantErr: false,
278+
},
279+
{
280+
name: "valid blobs with commitments and proofs",
281+
args: SendTxArgs{
282+
Blobs: []kzg4844.Blob{blob1, blob2},
283+
Commitments: []kzg4844.Commitment{commitment1, commitment2},
284+
Proofs: []kzg4844.Proof{proof1, proof2},
285+
BlobHashes: []common.Hash{hash1, hash2},
286+
},
287+
wantErr: false,
288+
},
289+
{
290+
name: "valid blobs without commitments/proofs - should generate them",
291+
args: SendTxArgs{
292+
Blobs: []kzg4844.Blob{blob1},
293+
},
294+
wantErr: false,
295+
},
296+
{
297+
name: "valid blobs with v1 cell proofs",
298+
args: SendTxArgs{
299+
Blobs: []kzg4844.Blob{blob1},
300+
Commitments: []kzg4844.Commitment{commitment1},
301+
Proofs: createTestCellProofs(blob1),
302+
BlobHashes: []common.Hash{hash1},
303+
},
304+
wantErr: false,
305+
},
306+
{
307+
name: "blobs with v1 version flag - should generate cell proofs",
308+
args: SendTxArgs{
309+
Blobs: []kzg4844.Blob{blob1},
310+
BlobVersion: types.BlobSidecarVersion1,
311+
},
312+
wantErr: false,
313+
},
314+
{
315+
name: "proofs provided but commitments not",
316+
args: SendTxArgs{
317+
Blobs: []kzg4844.Blob{blob1},
318+
Proofs: []kzg4844.Proof{proof1},
319+
},
320+
wantErr: true,
321+
},
322+
{
323+
name: "commitments provided but proofs not",
324+
args: SendTxArgs{
325+
Blobs: []kzg4844.Blob{blob1},
326+
Commitments: []kzg4844.Commitment{commitment1},
327+
},
328+
wantErr: true,
329+
},
330+
{
331+
name: "mismatch between blobs and commitments",
332+
args: SendTxArgs{
333+
Blobs: []kzg4844.Blob{blob1, blob2},
334+
Commitments: []kzg4844.Commitment{commitment1}, // Only one commitment for two blobs
335+
Proofs: []kzg4844.Proof{proof1},
336+
},
337+
wantErr: true,
338+
},
339+
{
340+
name: "mismatch between blobs and hashes",
341+
args: SendTxArgs{
342+
Blobs: []kzg4844.Blob{blob1, blob2},
343+
Commitments: []kzg4844.Commitment{commitment1, commitment2},
344+
Proofs: []kzg4844.Proof{proof1, proof2},
345+
BlobHashes: []common.Hash{hash1}, // Only one hash for two blobs
346+
},
347+
wantErr: true,
348+
},
349+
{
350+
name: "wrong number of proofs",
351+
args: SendTxArgs{
352+
Blobs: []kzg4844.Blob{blob1, blob2},
353+
Commitments: []kzg4844.Commitment{commitment1, commitment2},
354+
Proofs: []kzg4844.Proof{proof1, proof2, proof1}, // 3 proofs for 2 blobs
355+
},
356+
wantErr: true,
357+
},
358+
{
359+
name: "invalid blob hash",
360+
args: SendTxArgs{
361+
Blobs: []kzg4844.Blob{blob1},
362+
Commitments: []kzg4844.Commitment{commitment1},
363+
Proofs: []kzg4844.Proof{proof1},
364+
BlobHashes: []common.Hash{hash2}, // Wrong hash
365+
},
366+
wantErr: true,
367+
},
368+
{
369+
name: "invalid proof",
370+
args: SendTxArgs{
371+
BlobVersion: types.BlobSidecarVersion1,
372+
Blobs: []kzg4844.Blob{blob1},
373+
Commitments: []kzg4844.Commitment{commitment1},
374+
Proofs: []kzg4844.Proof{proof1, proof2}, // wrong proof
375+
BlobHashes: []common.Hash{hash1},
376+
},
377+
wantErr: true,
378+
},
379+
}
380+
381+
for _, tt := range tests {
382+
t.Run(tt.name, func(t *testing.T) {
383+
// Make a copy to avoid modifying the original test case
384+
args := tt.args
385+
err := args.validateTxSidecar()
386+
387+
if tt.wantErr {
388+
if err == nil {
389+
t.Errorf("validateTxSidecar() expected error but got none")
390+
return
391+
}
392+
} else {
393+
if err != nil {
394+
t.Errorf("validateTxSidecar() unexpected error = %v", err)
395+
}
396+
397+
// For successful cases, verify that commitments and proofs were generated if they weren't provided
398+
if len(args.Blobs) > 0 {
399+
if args.Commitments == nil || len(args.Commitments) != len(args.Blobs) {
400+
t.Errorf("validateTxSidecar() should have generated commitments")
401+
}
402+
if args.Proofs == nil || (len(args.Proofs) != len(args.Blobs) && len(args.Proofs) != len(args.Blobs)*kzg4844.CellProofsPerBlob) {
403+
t.Errorf("validateTxSidecar() should have generated proofs")
404+
}
405+
if args.BlobHashes == nil || len(args.BlobHashes) != len(args.Blobs) {
406+
t.Errorf("validateTxSidecar() should have generated blob hashes")
407+
}
408+
}
409+
}
410+
})
411+
}
412+
}

0 commit comments

Comments
 (0)