From 4dda77c540d996b96774446b05ab0bccf675aa5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gamenik?= Date: Fri, 1 Aug 2025 16:40:56 +0200 Subject: [PATCH] support semantic hashing list --- core/txpool/blobpool/blobpool_test.go | 29 +++++++++++++++++++++ core/types/tx_blob.go | 14 ++++------- crypto/kzg4844/kzg4844.go | 36 +++++++++++++++++++++++++++ eth/catalyst/api.go | 8 +++--- internal/ethapi/transaction_args.go | 6 +---- signer/core/apitypes/types.go | 6 +---- 6 files changed, 76 insertions(+), 23 deletions(-) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 422c35f6d2..bba8c15288 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -1675,6 +1675,35 @@ func TestAdd(t *testing.T) { } } +func TestCommitmentList(t *testing.T) { + var liste []kzg4844.Commitment + for i := 0; i < 4; i++ { + blob := &kzg4844.Blob{byte(i)} + commit, _ := kzg4844.BlobToCommitment(blob) + liste = append(liste, commit) + } + output := make([]common.Hash, 4) + + kzg4844.CalcBlobHashListV1(liste, output) + + if output[0][0] != 1 || output[0][1] != 6 || + output[0][30] != 64 || output[0][31] != 20 { + t.Errorf("Hash 1 is different") + } + if output[1][0] != 1 || output[1][1] != 90 || + output[1][30] != 47 || output[1][31] != 104 { + t.Errorf("Hash 2 is different") + } + if output[2][0] != 1 || output[2][1] != 129 || + output[2][30] != 50 || output[2][31] != 12 { + t.Errorf("Hash 3 is different") + } + if output[3][0] != 1 || output[3][1] != 53 || + output[3][30] != 101 || output[3][31] != 224 { + t.Errorf("Hash 4 is different") + } +} + // fakeBilly is a billy.Database implementation which just drops data on the floor. type fakeBilly struct { billy.Database diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go index bbfd3c98db..dc0392eb6b 100644 --- a/core/types/tx_blob.go +++ b/core/types/tx_blob.go @@ -18,7 +18,6 @@ package types import ( "bytes" - "crypto/sha256" "errors" "fmt" "math/big" @@ -87,11 +86,8 @@ func NewBlobTxSidecar(version byte, blobs []kzg4844.Blob, commitments []kzg4844. // BlobHashes computes the blob hashes of the given blobs. func (sc *BlobTxSidecar) BlobHashes() []common.Hash { - hasher := sha256.New() h := make([]common.Hash, len(sc.Commitments)) - for i := range sc.Blobs { - h[i] = kzg4844.CalcBlobHashV1(hasher, &sc.Commitments[i]) - } + kzg4844.CalcBlobHashListV1(sc.Commitments, h) return h } @@ -153,11 +149,11 @@ func (sc *BlobTxSidecar) ValidateBlobCommitmentHashes(hashes []common.Hash) erro if len(sc.Commitments) != len(hashes) { return fmt.Errorf("invalid number of %d blob commitments compared to %d blob hashes", len(sc.Commitments), len(hashes)) } - hasher := sha256.New() + var listComputed = make([]common.Hash, len(hashes)) + kzg4844.CalcBlobHashListV1(sc.Commitments, listComputed) for i, vhash := range hashes { - computed := kzg4844.CalcBlobHashV1(hasher, &sc.Commitments[i]) - if vhash != computed { - return fmt.Errorf("blob %d: computed hash %#x mismatches transaction one %#x", i, computed, vhash) + if vhash != listComputed[i] { + return fmt.Errorf("blob %d: computed hash %#x mismatches transaction one %#x", i, listComputed[i], vhash) } } return nil diff --git a/crypto/kzg4844/kzg4844.go b/crypto/kzg4844/kzg4844.go index baf9c9655b..d6412e7b8a 100644 --- a/crypto/kzg4844/kzg4844.go +++ b/crypto/kzg4844/kzg4844.go @@ -18,12 +18,15 @@ package kzg4844 import ( + "crypto/sha256" "embed" "errors" "hash" "reflect" + "sync" "sync/atomic" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ) @@ -185,6 +188,39 @@ func CalcBlobHashV1(hasher hash.Hash, commit *Commitment) (vh [32]byte) { return vh } +// CalcBlobHashListV1 calculates the 'versioned blob hash' of a list of commitment with 2 go routines. +func CalcBlobHashListV1(list []Commitment, output []common.Hash) { + if len(list) != len(output) { + panic("wrong output size") + } + if len(list) == 0 { + return + } + hasher1 := sha256.New() + if len(list) == 1 { + output[0] = CalcBlobHashV1(hasher1, &list[0]) + return + } + var wg sync.WaitGroup + wg.Add(2) + go calcBlobHashListPartV1(list, output, &wg, hasher1, 0) + hasher2 := sha256.New() + go calcBlobHashListPartV1(list, output, &wg, hasher2, 1) + wg.Wait() +} + +// calcs hashes of all odd or all even parts of the list +func calcBlobHashListPartV1(list []Commitment, output []common.Hash, wg *sync.WaitGroup, hasher hash.Hash, where int) { + defer wg.Done() + for ; where < len(list); where += 2 { + hasher.Reset() + var commitment *Commitment = &list[where] + hasher.Write(commitment[:]) + hasher.Sum(output[where][:0]) + output[where][0] = 0x01 // version + } +} + // IsValidVersionedHash checks that h is a structurally-valid versioned blob hash. func IsValidVersionedHash(h []byte) bool { return len(h) == 32 && h[0] == 0x01 diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index f91896cc6e..8634936425 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -18,7 +18,6 @@ package catalyst import ( - "crypto/sha256" "errors" "fmt" "strconv" @@ -496,7 +495,6 @@ func (api *ConsensusAPI) GetBlobsV1(hashes []common.Hash) ([]*engine.BlobAndProo } var ( res = make([]*engine.BlobAndProofV1, len(hashes)) - hasher = sha256.New() index = make(map[common.Hash]int) sidecars = api.eth.BlobTxPool().GetBlobs(hashes) ) @@ -509,8 +507,10 @@ func (api *ConsensusAPI) GetBlobsV1(hashes []common.Hash) ([]*engine.BlobAndProo // already filled continue } - for cIdx, commitment := range sidecar.Commitments { - computed := kzg4844.CalcBlobHashV1(hasher, &commitment) + var listComputed = make([]common.Hash, len(sidecar.Commitments)) + kzg4844.CalcBlobHashListV1(sidecar.Commitments, listComputed) + for cIdx, _ := range sidecar.Commitments { + computed := listComputed[cIdx] if idx, ok := index[computed]; ok { res[idx] = &engine.BlobAndProofV1{ Blob: sidecar.Blobs[cIdx][:], diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 6b094721e4..0a2007d015 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -19,7 +19,6 @@ package ethapi import ( "bytes" "context" - "crypto/sha256" "errors" "fmt" "math" @@ -341,10 +340,7 @@ func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context) error { } hashes := make([]common.Hash, n) - hasher := sha256.New() - for i, c := range args.Commitments { - hashes[i] = kzg4844.CalcBlobHashV1(hasher, &c) - } + kzg4844.CalcBlobHashListV1(args.Commitments, hashes) if args.BlobHashes != nil { for i, h := range hashes { if h != args.BlobHashes[i] { diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index b5fd5a2854..f096ee67eb 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -18,7 +18,6 @@ package apitypes import ( "bytes" - "crypto/sha256" "encoding/json" "errors" "fmt" @@ -266,10 +265,7 @@ func (args *SendTxArgs) validateTxSidecar() error { } hashes := make([]common.Hash, n) - hasher := sha256.New() - for i, c := range args.Commitments { - hashes[i] = kzg4844.CalcBlobHashV1(hasher, &c) - } + kzg4844.CalcBlobHashListV1(args.Commitments, hashes) if args.BlobHashes != nil { for i, h := range hashes { if h != args.BlobHashes[i] {