support semantic hashing list

This commit is contained in:
Jürgen Gamenik 2025-08-01 16:40:56 +02:00
parent 32d537cd58
commit 4dda77c540
6 changed files with 76 additions and 23 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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][:],

View file

@ -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] {

View file

@ -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] {