diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 3e52933a900..76bfd22a236 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -123,6 +123,11 @@ type BlobAndProofV1 struct { Proof hexutil.Bytes `json:"proof"` } +type BlobAndProofV2 struct { + Blob hexutil.Bytes `json:"blob"` + CellProofs []hexutil.Bytes `json:"proofs"` +} + // JSON type overrides for ExecutionPayloadEnvelope. type executionPayloadEnvelopeMarshaling struct { BlockValue *hexutil.Big @@ -331,7 +336,9 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types. for j := range sidecar.Blobs { bundle.Blobs = append(bundle.Blobs, hexutil.Bytes(sidecar.Blobs[j][:])) bundle.Commitments = append(bundle.Commitments, hexutil.Bytes(sidecar.Commitments[j][:])) - bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:])) + } + for _, proof := range sidecar.Proofs { + bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(proof[:])) } } diff --git a/beacon/engine/types_test.go b/beacon/engine/types_test.go new file mode 100644 index 00000000000..7ffdf4e8182 --- /dev/null +++ b/beacon/engine/types_test.go @@ -0,0 +1,56 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package engine + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto/kzg4844" +) + +func TestBlobs(t *testing.T) { + var ( + emptyBlob = new(kzg4844.Blob) + emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob) + emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit) + emptyCellProof, _ = kzg4844.ComputeCells(emptyBlob) + ) + header := types.Header{} + block := types.NewBlock(&header, &types.Body{}, nil, nil) + + sidecarWithoutCellProofs := &types.BlobTxSidecar{ + Blobs: []kzg4844.Blob{*emptyBlob}, + Commitments: []kzg4844.Commitment{emptyBlobCommit}, + Proofs: []kzg4844.Proof{emptyBlobProof}, + } + env := BlockToExecutableData(block, common.Big0, []*types.BlobTxSidecar{sidecarWithoutCellProofs}, nil) + if len(env.BlobsBundle.Proofs) != 1 { + t.Fatalf("Expect 1 proof in blobs bundle, got %v", len(env.BlobsBundle.Proofs)) + } + + sidecarWithCellProofs := &types.BlobTxSidecar{ + Blobs: []kzg4844.Blob{*emptyBlob}, + Commitments: []kzg4844.Commitment{emptyBlobCommit}, + Proofs: emptyCellProof, + } + env = BlockToExecutableData(block, common.Big0, []*types.BlobTxSidecar{sidecarWithCellProofs}, nil) + if len(env.BlobsBundle.Proofs) != 128 { + t.Fatalf("Expect 128 proofs in blobs bundle, got %v", len(env.BlobsBundle.Proofs)) + } +} diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index 32b34f4e53d..1c0c651964b 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -23,7 +23,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/params/forks" ) var ( @@ -81,38 +80,49 @@ func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTim // CalcBlobFee calculates the blobfee from the header's excess blob gas field. func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int { - var frac uint64 - switch config.LatestFork(header.Time) { - case forks.Osaka: - frac = config.BlobScheduleConfig.Osaka.UpdateFraction - case forks.Prague: - frac = config.BlobScheduleConfig.Prague.UpdateFraction - case forks.Cancun: - frac = config.BlobScheduleConfig.Cancun.UpdateFraction - default: + blobConfig := latestBlobConfig(config, header.Time) + if blobConfig == nil { panic("calculating blob fee on unsupported fork") } - return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(*header.ExcessBlobGas), new(big.Int).SetUint64(frac)) + return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(*header.ExcessBlobGas), new(big.Int).SetUint64(blobConfig.UpdateFraction)) } // MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp. func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { - if cfg.BlobScheduleConfig == nil { + blobConfig := latestBlobConfig(cfg, time) + if blobConfig == nil { return 0 } + return blobConfig.Max +} + +func latestBlobConfig(cfg *params.ChainConfig, time uint64) *params.BlobConfig { + if cfg.BlobScheduleConfig == nil { + return nil + } var ( london = cfg.LondonBlock s = cfg.BlobScheduleConfig ) switch { + case cfg.IsBPO5(london, time) && s.BPO5 != nil: + return s.BPO5 + case cfg.IsBPO4(london, time) && s.BPO4 != nil: + return s.BPO4 + case cfg.IsBPO3(london, time) && s.BPO3 != nil: + return s.BPO3 + case cfg.IsBPO2(london, time) && s.BPO2 != nil: + return s.BPO2 + case cfg.IsBPO1(london, time) && s.BPO1 != nil: + return s.BPO1 case cfg.IsOsaka(london, time) && s.Osaka != nil: - return s.Osaka.Max + return s.Osaka case cfg.IsPrague(london, time) && s.Prague != nil: - return s.Prague.Max + return s.Prague case cfg.IsCancun(london, time) && s.Cancun != nil: - return s.Cancun.Max + return s.Cancun default: - return 0 + return nil } } @@ -129,6 +139,16 @@ func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int { return 0 } switch { + case s.BPO5 != nil: + return s.BPO5.Max + case s.BPO4 != nil: + return s.BPO4.Max + case s.BPO3 != nil: + return s.BPO3.Max + case s.BPO2 != nil: + return s.BPO2.Max + case s.BPO1 != nil: + return s.BPO1.Max case s.Osaka != nil: return s.Osaka.Max case s.Prague != nil: @@ -142,23 +162,11 @@ func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int { // targetBlobsPerBlock returns the target number of blobs in a block at the given timestamp. func targetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int { - if cfg.BlobScheduleConfig == nil { - return 0 - } - var ( - london = cfg.LondonBlock - s = cfg.BlobScheduleConfig - ) - switch { - case cfg.IsOsaka(london, time) && s.Osaka != nil: - return s.Osaka.Target - case cfg.IsPrague(london, time) && s.Prague != nil: - return s.Prague.Target - case cfg.IsCancun(london, time) && s.Cancun != nil: - return s.Cancun.Target - default: + blobConfig := latestBlobConfig(cfg, time) + if blobConfig == nil { return 0 } + return blobConfig.Target } // fakeExponential approximates factor * e ** (numerator / denominator) using diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index e506da228d9..2c50809716f 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -36,7 +36,6 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -1295,27 +1294,13 @@ func (p *BlobPool) GetMetadata(hash common.Hash) *txpool.TxMetadata { } } -// GetBlobs returns a number of blobs are proofs for the given versioned hashes. +// GetBlobs returns a number of blobs and proofs for the given versioned hashes. // This is a utility method for the engine API, enabling consensus clients to // retrieve blobs from the pools directly instead of the network. -func (p *BlobPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) { - // Create a map of the blob hash to indices for faster fills - var ( - blobs = make([]*kzg4844.Blob, len(vhashes)) - proofs = make([]*kzg4844.Proof, len(vhashes)) - ) - index := make(map[common.Hash]int) - for i, vhash := range vhashes { - index[vhash] = i - } - // Iterate over the blob hashes, pulling transactions that fill it. Take care - // to also fill anything else the transaction might include (probably will). - for i, vhash := range vhashes { - // If already filled by a previous fetch, skip - if blobs[i] != nil { - continue - } - // Unfilled, retrieve the datastore item (in a short lock) +func (p *BlobPool) GetBlobs(vhashes []common.Hash) []*types.BlobTxSidecar { + sidecars := make([]*types.BlobTxSidecar, len(vhashes)) + for idx, vhash := range vhashes { + // Retrieve the datastore item (in a short lock) p.lock.RLock() id, exists := p.lookup.storeidOfBlob(vhash) if !exists { @@ -1335,16 +1320,22 @@ func (p *BlobPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844. log.Error("Blobs corrupted for traced transaction", "id", id, "err", err) continue } - // Fill anything requested, not just the current versioned hash - sidecar := item.BlobTxSidecar() - for j, blobhash := range item.BlobHashes() { - if idx, ok := index[blobhash]; ok { - blobs[idx] = &sidecar.Blobs[j] - proofs[idx] = &sidecar.Proofs[j] - } + sidecars[idx] = item.BlobTxSidecar() + } + return sidecars +} + +func (p *BlobPool) HasBlobs(vhashes []common.Hash) bool { + for _, vhash := range vhashes { + // Retrieve the datastore item (in a short lock) + p.lock.RLock() + _, exists := p.lookup.storeidOfBlob(vhash) + p.lock.RUnlock() + if !exists { + return false } } - return blobs, proofs + return true } // Add inserts a set of blob transactions into the pool if they pass validation (both diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 0a323179a6a..060b241e251 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -417,8 +417,23 @@ func verifyBlobRetrievals(t *testing.T, pool *BlobPool) { for i := range testBlobVHashes { copy(hashes[i][:], testBlobVHashes[i][:]) } - blobs, proofs := pool.GetBlobs(hashes) - + sidecars := pool.GetBlobs(hashes) + var blobs []*kzg4844.Blob + var proofs []*kzg4844.Proof + for idx, sidecar := range sidecars { + if sidecar == nil { + blobs = append(blobs, nil) + proofs = append(proofs, nil) + continue + } + blobHashes := sidecar.BlobHashes() + for i, hash := range blobHashes { + if hash == hashes[idx] { + blobs = append(blobs, &sidecar.Blobs[i]) + proofs = append(proofs, &sidecar.Proofs[i]) + } + } + } // Cross validate what we received vs what we wanted if len(blobs) != len(hashes) || len(proofs) != len(hashes) { t.Errorf("retrieved blobs/proofs size mismatch: have %d/%d, want %d", len(blobs), len(proofs), len(hashes)) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 0223b456e65..ac7eccce7d1 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -35,7 +35,6 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -1065,8 +1064,14 @@ func (pool *LegacyPool) GetMetadata(hash common.Hash) *txpool.TxMetadata { // GetBlobs is not supported by the legacy transaction pool, it is just here to // implement the txpool.SubPool interface. -func (pool *LegacyPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) { - return nil, nil +func (pool *LegacyPool) GetBlobs(vhashes []common.Hash) []*types.BlobTxSidecar { + return nil +} + +// HasBlobs is not supported by the legacy transaction pool, it is just here to +// implement the txpool.SubPool interface. +func (pool *LegacyPool) HasBlobs(vhashes []common.Hash) bool { + return false } // Has returns an indicator whether txpool has a transaction cached with the diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go index 8cfc14f1640..90f1d5d9e51 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -23,7 +23,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/event" "github.com/holiman/uint256" ) @@ -136,7 +135,11 @@ type SubPool interface { // GetBlobs returns a number of blobs are proofs for the given versioned hashes. // This is a utility method for the engine API, enabling consensus clients to // retrieve blobs from the pools directly instead of the network. - GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) + GetBlobs(vhashes []common.Hash) []*types.BlobTxSidecar + + // HasBlobs returns true if all blobs corresponding to the versioned hashes + // are in the sub pool. + HasBlobs(vhashes []common.Hash) bool // ValidateTxBasics checks whether a transaction is valid according to the consensus // rules, but does not check state-dependent validation such as sufficient balance. diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index cc8f74c1b8e..666fdddcdb7 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -26,7 +26,6 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -311,17 +310,42 @@ func (p *TxPool) GetMetadata(hash common.Hash) *TxMetadata { // GetBlobs returns a number of blobs are proofs for the given versioned hashes. // This is a utility method for the engine API, enabling consensus clients to // retrieve blobs from the pools directly instead of the network. -func (p *TxPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) { +func (p *TxPool) GetBlobs(vhashes []common.Hash) []*types.BlobTxSidecar { for _, subpool := range p.subpools { // It's an ugly to assume that only one pool will be capable of returning - // anything meaningful for this call, but anythingh else requires merging + // anything meaningful for this call, but anything else requires merging // partial responses and that's too annoying to do until we get a second // blobpool (probably never). - if blobs, proofs := subpool.GetBlobs(vhashes); blobs != nil { - return blobs, proofs + if sidecars := subpool.GetBlobs(vhashes); sidecars != nil { + return sidecars } } - return nil, nil + return nil +} + +// HasBlobs will return true if all the vhashes are available in the same subpool. +func (p *TxPool) HasBlobs(vhashes []common.Hash) bool { + for _, subpool := range p.subpools { + // It's an ugly to assume that only one pool will be capable of returning + // anything meaningful for this call, but anything else requires merging + // partial responses and that's too annoying to do until we get a second + // blobpool (probably never). + if subpool.HasBlobs(vhashes) { + return true + } + } + return false +} + +// ValidateTxBasics checks whether a transaction is valid according to the consensus +// rules, but does not check state-dependent validation such as sufficient balance. +func (p *TxPool) ValidateTxBasics(tx *types.Transaction) error { + for _, subpool := range p.subpools { + if subpool.Filter(tx) { + return subpool.ValidateTxBasics(tx) + } + } + return fmt.Errorf("%w: received type %d", core.ErrTxTypeNotSupported, tx.Type()) } // Add enqueues a batch of transactions into the pool if they are valid. Due diff --git a/core/txpool/validation.go b/core/txpool/validation.go index e370f2ce84f..ab6d93af8da 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -152,9 +152,16 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types if len(hashes) > maxBlobs { return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), maxBlobs) } - // Ensure commitments, proofs and hashes are valid - if err := validateBlobSidecar(hashes, sidecar); err != nil { - return err + if opts.Config.IsOsaka(head.Number, head.Time) { + // Ensure commitments, cell proofs and hashes are valid + if err := validateBlobSidecarOsaka(hashes, sidecar); err != nil { + return err + } + } else { + // Ensure commitments, proofs and hashes are valid + if err := validateBlobSidecar(hashes, sidecar); err != nil { + return err + } } } if tx.Type() == types.SetCodeTxType { @@ -166,6 +173,9 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types } func validateBlobSidecar(hashes []common.Hash, sidecar *types.BlobTxSidecar) error { + if sidecar.Version != 0 { + return fmt.Errorf("invalid sidecar version pre-osaka: %v", sidecar.Version) + } if len(sidecar.Blobs) != len(hashes) { return fmt.Errorf("invalid number of %d blobs compared to %d blob hashes", len(sidecar.Blobs), len(hashes)) } @@ -185,6 +195,35 @@ func validateBlobSidecar(hashes []common.Hash, sidecar *types.BlobTxSidecar) err return nil } +func validateBlobSidecarOsaka(hashes []common.Hash, sidecar *types.BlobTxSidecar) error { + if sidecar.Version != 1 { + return fmt.Errorf("invalid sidecar version post-osaka: %v", sidecar.Version) + } + if len(sidecar.Blobs) != len(hashes) { + return fmt.Errorf("invalid number of %d blobs compared to %d blob hashes", len(sidecar.Blobs), len(hashes)) + } + if len(sidecar.Commitments) != len(hashes) { + return fmt.Errorf("invalid number of %d commitments compared to %d blob hashes", len(sidecar.Commitments), len(hashes)) + } + if len(sidecar.Proofs) != len(hashes)*kzg4844.CellProofsPerBlob { + return fmt.Errorf("invalid number of %d blob proofs expected %d", len(sidecar.Proofs), len(hashes)*kzg4844.CellProofsPerBlob) + } + if err := sidecar.ValidateBlobCommitmentHashes(hashes); err != nil { + return err + } + // Blob commitments match with the hashes in the transaction, verify the + // blobs themselves via KZG + var blobs []*kzg4844.Blob + for _, blob := range sidecar.Blobs { + blobs = append(blobs, &blob) + } + + if err := kzg4844.VerifyCellProofs(blobs, sidecar.Commitments, sidecar.Proofs); err != nil { + return err + } + return nil +} + // ValidationOptionsWithState define certain differences between stateful transaction // validation across the different pools without having to duplicate those checks. type ValidationOptionsWithState struct { diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go index 9b1d53958fe..73832c7d308 100644 --- a/core/types/tx_blob.go +++ b/core/types/tx_blob.go @@ -55,6 +55,7 @@ type BlobTx struct { // BlobTxSidecar contains the blobs of a blob transaction. type BlobTxSidecar struct { + Version byte // Version Blobs []kzg4844.Blob // Blobs needed by the blob pool Commitments []kzg4844.Commitment // Commitments needed by the blob pool Proofs []kzg4844.Proof // Proofs needed by the blob pool @@ -70,6 +71,20 @@ func (sc *BlobTxSidecar) BlobHashes() []common.Hash { return h } +// CellProofsAt returns the cell proofs for blob with index idx. +func (sc *BlobTxSidecar) CellProofsAt(idx int) []kzg4844.Proof { + var cellProofs []kzg4844.Proof + for i := range kzg4844.CellProofsPerBlob { + index := idx*kzg4844.CellProofsPerBlob + i + if index > len(sc.Proofs) { + return nil + } + proof := sc.Proofs[index] + cellProofs = append(cellProofs, proof) + } + return cellProofs +} + // encodedSize computes the RLP size of the sidecar elements. This does NOT return the // encoded size of the BlobTxSidecar, it's just a helper for tx.Size(). func (sc *BlobTxSidecar) encodedSize() uint64 { @@ -110,6 +125,14 @@ type blobTxWithBlobs struct { Proofs []kzg4844.Proof } +type versionedBlobTxWithBlobs struct { + BlobTx *BlobTx + Version byte + Blobs []kzg4844.Blob + Commitments []kzg4844.Commitment + Proofs []kzg4844.Proof +} + // copy creates a deep copy of the transaction data and initializes all fields. func (tx *BlobTx) copy() TxData { cpy := &BlobTx{ @@ -218,6 +241,17 @@ func (tx *BlobTx) encode(b *bytes.Buffer) error { if tx.Sidecar == nil { return rlp.Encode(b, tx) } + // Encode a cell proof transaction + if tx.Sidecar.Version != 0 { + inner := &versionedBlobTxWithBlobs{ + BlobTx: tx, + Version: tx.Sidecar.Version, + Blobs: tx.Sidecar.Blobs, + Commitments: tx.Sidecar.Commitments, + Proofs: tx.Sidecar.Proofs, + } + return rlp.Encode(b, inner) + } inner := &blobTxWithBlobs{ BlobTx: tx, Blobs: tx.Sidecar.Blobs, @@ -246,13 +280,23 @@ func (tx *BlobTx) decode(input []byte) error { if firstElemKind != rlp.List { return rlp.DecodeBytes(input, tx) } - // It's a tx with blobs. - var inner blobTxWithBlobs + + // It's a tx with blobs. Try to decode it as version 0. + var inner versionedBlobTxWithBlobs if err := rlp.DecodeBytes(input, &inner); err != nil { - return err + var innerV0 blobTxWithBlobs + if err := rlp.DecodeBytes(input, &innerV0); err != nil { + return err + } + inner.BlobTx = innerV0.BlobTx + inner.Version = 0 + inner.Blobs = innerV0.Blobs + inner.Commitments = innerV0.Commitments + inner.Proofs = innerV0.Proofs } *tx = *inner.BlobTx tx.Sidecar = &BlobTxSidecar{ + Version: inner.Version, Blobs: inner.Blobs, Commitments: inner.Commitments, Proofs: inner.Proofs, diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 784b4108026..1513665b303 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -66,7 +66,7 @@ var PrecompiledContractsByzantium = PrecompiledContracts{ common.BytesToAddress([]byte{0x2}): &sha256hash{}, common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, common.BytesToAddress([]byte{0x4}): &dataCopy{}, - common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false}, + common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false, eip7823: false, eip7883: false}, common.BytesToAddress([]byte{0x6}): &bn256AddByzantium{}, common.BytesToAddress([]byte{0x7}): &bn256ScalarMulByzantium{}, common.BytesToAddress([]byte{0x8}): &bn256PairingByzantium{}, @@ -79,7 +79,7 @@ var PrecompiledContractsIstanbul = PrecompiledContracts{ common.BytesToAddress([]byte{0x2}): &sha256hash{}, common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, common.BytesToAddress([]byte{0x4}): &dataCopy{}, - common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false}, + common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false, eip7823: false, eip7883: false}, common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{}, common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{}, common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{}, @@ -93,7 +93,7 @@ var PrecompiledContractsBerlin = PrecompiledContracts{ common.BytesToAddress([]byte{0x2}): &sha256hash{}, common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, common.BytesToAddress([]byte{0x4}): &dataCopy{}, - common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true}, + common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true, eip7823: false, eip7883: false}, common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{}, common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{}, common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{}, @@ -107,7 +107,7 @@ var PrecompiledContractsCancun = PrecompiledContracts{ common.BytesToAddress([]byte{0x2}): &sha256hash{}, common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, common.BytesToAddress([]byte{0x4}): &dataCopy{}, - common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true}, + common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true, eip7823: false, eip7883: false}, common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{}, common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{}, common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{}, @@ -122,7 +122,7 @@ var PrecompiledContractsPrague = PrecompiledContracts{ common.BytesToAddress([]byte{0x02}): &sha256hash{}, common.BytesToAddress([]byte{0x03}): &ripemd160hash{}, common.BytesToAddress([]byte{0x04}): &dataCopy{}, - common.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true}, + common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true, eip7823: false, eip7883: false}, common.BytesToAddress([]byte{0x06}): &bn256AddIstanbul{}, common.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{}, common.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{}, @@ -141,6 +141,28 @@ var PrecompiledContractsBLS = PrecompiledContractsPrague var PrecompiledContractsVerkle = PrecompiledContractsBerlin +// PrecompiledContractsOsaka contains the set of pre-compiled Ethereum +// contracts used in the Osaka release. +var PrecompiledContractsOsaka = PrecompiledContracts{ + common.BytesToAddress([]byte{0x01}): &ecrecover{}, + common.BytesToAddress([]byte{0x02}): &sha256hash{}, + common.BytesToAddress([]byte{0x03}): &ripemd160hash{}, + common.BytesToAddress([]byte{0x04}): &dataCopy{}, + common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true, eip7823: true, eip7883: true}, + common.BytesToAddress([]byte{0x06}): &bn256AddIstanbul{}, + common.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{}, + common.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{}, + common.BytesToAddress([]byte{0x09}): &blake2F{}, + common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{}, + common.BytesToAddress([]byte{0x0b}): &bls12381G1Add{}, + common.BytesToAddress([]byte{0x0c}): &bls12381G1MultiExp{}, + common.BytesToAddress([]byte{0x0d}): &bls12381G2Add{}, + common.BytesToAddress([]byte{0x0e}): &bls12381G2MultiExp{}, + common.BytesToAddress([]byte{0x0f}): &bls12381Pairing{}, + common.BytesToAddress([]byte{0x10}): &bls12381MapG1{}, + common.BytesToAddress([]byte{0x11}): &bls12381MapG2{}, +} + var ( PrecompiledAddressesPrague []common.Address PrecompiledAddressesCancun []common.Address @@ -175,6 +197,8 @@ func activePrecompiledContracts(rules params.Rules) PrecompiledContracts { switch { case rules.IsVerkle: return PrecompiledContractsVerkle + case rules.IsOsaka: + return PrecompiledContractsOsaka case rules.IsPrague: return PrecompiledContractsPrague case rules.IsCancun: @@ -317,6 +341,8 @@ func (c *dataCopy) Run(in []byte) ([]byte, error) { // bigModExp implements a native big integer exponential modular operation. type bigModExp struct { eip2565 bool + eip7823 bool + eip7883 bool } var ( @@ -392,7 +418,11 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { adjExpLen := new(big.Int) if expLen.Cmp(big32) > 0 { adjExpLen.Sub(expLen, big32) - adjExpLen.Lsh(adjExpLen, 3) + if c.eip7883 { + adjExpLen.Lsh(adjExpLen, 4) + } else { + adjExpLen.Lsh(adjExpLen, 3) + } } adjExpLen.Add(adjExpLen, big.NewInt(int64(msb))) // Calculate the gas cost of the operation @@ -402,6 +432,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { } else { gas.Set(modLen) } + maxLen := new(big.Int).Set(gas) if c.eip2565 { // EIP-2565 has three changes // 1. Different multComplexity (inlined here) @@ -415,6 +446,14 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { gas.Rsh(gas, 3) gas.Mul(gas, gas) + var minPrice uint64 = 200 + if c.eip7883 { + minPrice = 500 + if maxLen.Cmp(big32) > 0 { + gas.Mul(gas, big.NewInt(2)) + } + } + if adjExpLen.Cmp(big1) > 0 { gas.Mul(gas, adjExpLen) } @@ -423,9 +462,9 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { if gas.BitLen() > 64 { return math.MaxUint64 } - // 3. Minimum price of 200 gas - if gas.Uint64() < 200 { - return 200 + + if gas.Uint64() < minPrice { + return minPrice } return gas.Uint64() } @@ -463,6 +502,9 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) { mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) v []byte ) + if c.eip7823 && max(max(baseLen, expLen), modLen) > 1024 { + return nil, fmt.Errorf("one or more of base/exponent/modulus length exceeded 1024 bytes") + } switch { case mod.BitLen() == 0: // Modulo 0 is undefined, return zero diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index b627f2ada50..a441f6c0f60 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -50,8 +50,9 @@ var allPrecompiles = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{2}): &sha256hash{}, common.BytesToAddress([]byte{3}): &ripemd160hash{}, common.BytesToAddress([]byte{4}): &dataCopy{}, - common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false}, - common.BytesToAddress([]byte{0xf5}): &bigModExp{eip2565: true}, + common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false, eip7883: false}, + common.BytesToAddress([]byte{0xf5}): &bigModExp{eip2565: true, eip7883: false}, + common.BytesToAddress([]byte{0xf6}): &bigModExp{eip2565: true, eip7883: true}, common.BytesToAddress([]byte{6}): &bn256AddIstanbul{}, common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{}, common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, @@ -238,6 +239,9 @@ func BenchmarkPrecompiledModExp(b *testing.B) { benchJson("modexp", "05", b) } func TestPrecompiledModExpEip2565(t *testing.T) { testJson("modexp_eip2565", "f5", t) } func BenchmarkPrecompiledModExpEip2565(b *testing.B) { benchJson("modexp_eip2565", "f5", b) } +func TestPrecompiledModExpEip7883(t *testing.T) { testJson("modexp_eip7883", "f6", t) } +func BenchmarkPrecompiledModExpEip7883(b *testing.B) { benchJson("modexp_eip7883", "f6", b) } + // Tests the sample inputs from the elliptic curve addition EIP 213. func TestPrecompiledBn256Add(t *testing.T) { testJson("bn256Add", "06", t) } func BenchmarkPrecompiledBn256Add(b *testing.B) { benchJson("bn256Add", "06", b) } diff --git a/core/vm/testdata/precompiles/modexp_eip7883.json b/core/vm/testdata/precompiles/modexp_eip7883.json new file mode 100644 index 00000000000..62cedda66ff --- /dev/null +++ b/core/vm/testdata/precompiles/modexp_eip7883.json @@ -0,0 +1,107 @@ +[ + { + "Input": "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb502fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + "Expected": "60008f1614cc01dcfb6bfb09c625cf90b47d4468db81b5f8b7a39d42f332eab9b2da8f2d95311648a8f243f4bb13cfb3d8f7f2a3c014122ebb3ed41b02783adc", + "Name": "nagydani-1-square", + "Gas": 500, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb503fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + "Expected": "4834a46ba565db27903b1c720c9d593e84e4cbd6ad2e64b31885d944f68cd801f92225a8961c952ddf2797fa4701b330c85c4b363798100b921a1a22a46a7fec", + "Name": "nagydani-1-qube", + "Gas": 500, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5010001fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b", + "Expected": "c36d804180c35d4426b57b50c5bfcca5c01856d104564cd513b461d3c8b8409128a5573e416d0ebe38f5f736766d9dc27143e4da981dfa4d67f7dc474cbee6d2", + "Name": "nagydani-1-pow0x10001", + "Gas": 682, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5102e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + "Expected": "981dd99c3b113fae3e3eaa9435c0dc96779a23c12a53d1084b4f67b0b053a27560f627b873e3f16ad78f28c94f14b6392def26e4d8896c5e3c984e50fa0b3aa44f1da78b913187c6128baa9340b1e9c9a0fd02cb78885e72576da4a8f7e5a113e173a7a2889fde9d407bd9f06eb05bc8fc7b4229377a32941a02bf4edcc06d70", + "Name": "nagydani-2-square", + "Gas": 500, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5103e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + "Expected": "d89ceb68c32da4f6364978d62aaa40d7b09b59ec61eb3c0159c87ec3a91037f7dc6967594e530a69d049b64adfa39c8fa208ea970cfe4b7bcd359d345744405afe1cbf761647e32b3184c7fbe87cee8c6c7ff3b378faba6c68b83b6889cb40f1603ee68c56b4c03d48c595c826c041112dc941878f8c5be828154afd4a16311f", + "Name": "nagydani-2-qube", + "Gas": 500, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51010001e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + "Expected": "ad85e8ef13fd1dd46eae44af8b91ad1ccae5b7a1c92944f92a19f21b0b658139e0cabe9c1f679507c2de354bf2c91ebd965d1e633978a830d517d2f6f8dd5fd58065d58559de7e2334a878f8ec6992d9b9e77430d4764e863d77c0f87beede8f2f7f2ab2e7222f85cc9d98b8467f4bb72e87ef2882423ebdb6daf02dddac6db2", + "Name": "nagydani-2-pow0x10001", + "Gas": 2730, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb02d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + "Expected": "affc7507ea6d84751ec6b3f0d7b99dbcc263f33330e450d1b3ff0bc3d0874320bf4edd57debd587306988157958cb3cfd369cc0c9c198706f635c9e0f15d047df5cb44d03e2727f26b083c4ad8485080e1293f171c1ed52aef5993a5815c35108e848c951cf1e334490b4a539a139e57b68f44fee583306f5b85ffa57206b3ee5660458858534e5386b9584af3c7f67806e84c189d695e5eb96e1272d06ec2df5dc5fabc6e94b793718c60c36be0a4d031fc84cd658aa72294b2e16fc240aef70cb9e591248e38bd49c5a554d1afa01f38dab72733092f7555334bbef6c8c430119840492380aa95fa025dcf699f0a39669d812b0c6946b6091e6e235337b6f8", + "Name": "nagydani-3-square", + "Gas": 682, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb03d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + "Expected": "1b280ecd6a6bf906b806d527c2a831e23b238f89da48449003a88ac3ac7150d6a5e9e6b3be4054c7da11dd1e470ec29a606f5115801b5bf53bc1900271d7c3ff3cd5ed790d1c219a9800437a689f2388ba1a11d68f6a8e5b74e9a3b1fac6ee85fc6afbac599f93c391f5dc82a759e3c6c0ab45ce3f5d25d9b0c1bf94cf701ea6466fc9a478dacc5754e593172b5111eeba88557048bceae401337cd4c1182ad9f700852bc8c99933a193f0b94cf1aedbefc48be3bc93ef5cb276d7c2d5462ac8bb0c8fe8923a1db2afe1c6b90d59c534994a6a633f0ead1d638fdc293486bb634ff2c8ec9e7297c04241a61c37e3ae95b11d53343d4ba2b4cc33d2cfa7eb705e", + "Name": "nagydani-3-qube", + "Gas": 682, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb010001d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + "Expected": "37843d7c67920b5f177372fa56e2a09117df585f81df8b300fba245b1175f488c99476019857198ed459ed8d9799c377330e49f4180c4bf8e8f66240c64f65ede93d601f957b95b83efdee1e1bfde74169ff77002eaf078c71815a9220c80b2e3b3ff22c2f358111d816ebf83c2999026b6de50bfc711ff68705d2f40b753424aefc9f70f08d908b5a20276ad613b4ab4309a3ea72f0c17ea9df6b3367d44fb3acab11c333909e02e81ea2ed404a712d3ea96bba87461720e2d98723e7acd0520ac1a5212dbedcd8dc0c1abf61d4719e319ff4758a774790b8d463cdfe131d1b2dcfee52d002694e98e720cb6ae7ccea353bc503269ba35f0f63bf8d7b672a76", + "Name": "nagydani-3-pow0x10001", + "Gas": 10922, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8102df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + "Expected": "8a5aea5f50dcc03dc7a7a272b5aeebc040554dbc1ffe36753c4fc75f7ed5f6c2cc0de3a922bf96c78bf0643a73025ad21f45a4a5cadd717612c511ab2bff1190fe5f1ae05ba9f8fe3624de1de2a817da6072ddcdb933b50216811dbe6a9ca79d3a3c6b3a476b079fd0d05f04fb154e2dd3e5cb83b148a006f2bcbf0042efb2ae7b916ea81b27aac25c3bf9a8b6d35440062ad8eae34a83f3ffa2cc7b40346b62174a4422584f72f95316f6b2bee9ff232ba9739301c97c99a9ded26c45d72676eb856ad6ecc81d36a6de36d7f9dafafee11baa43a4b0d5e4ecffa7b9b7dcefd58c397dd373e6db4acd2b2c02717712e6289bed7c813b670c4a0c6735aa7f3b0f1ce556eae9fcc94b501b2c8781ba50a8c6220e8246371c3c7359fe4ef9da786ca7d98256754ca4e496be0a9174bedbecb384bdf470779186d6a833f068d2838a88d90ef3ad48ff963b67c39cc5a3ee123baf7bf3125f64e77af7f30e105d72c4b9b5b237ed251e4c122c6d8c1405e736299c3afd6db16a28c6a9cfa68241e53de4cd388271fe534a6a9b0dbea6171d170db1b89858468885d08fecbd54c8e471c3e25d48e97ba450b96d0d87e00ac732aaa0d3ce4309c1064bd8a4c0808a97e0143e43a24cfa847635125cd41c13e0574487963e9d725c01375db99c31da67b4cf65eff555f0c0ac416c727ff8d438ad7c42030551d68c2e7adda0abb1ca7c10", + "Name": "nagydani-4-square", + "Gas": 2730, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8103df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + "Expected": "5a2664252aba2d6e19d9600da582cdd1f09d7a890ac48e6b8da15ae7c6ff1856fc67a841ac2314d283ffa3ca81a0ecf7c27d89ef91a5a893297928f5da0245c99645676b481b7e20a566ee6a4f2481942bee191deec5544600bb2441fd0fb19e2ee7d801ad8911c6b7750affec367a4b29a22942c0f5f4744a4e77a8b654da2a82571037099e9c6d930794efe5cdca73c7b6c0844e386bdca8ea01b3d7807146bb81365e2cdc6475f8c23e0ff84463126189dc9789f72bbce2e3d2d114d728a272f1345122de23df54c922ec7a16e5c2a8f84da8871482bd258c20a7c09bbcd64c7a96a51029bbfe848736a6ba7bf9d931a9b7de0bcaf3635034d4958b20ae9ab3a95a147b0421dd5f7ebff46c971010ebfc4adbbe0ad94d5498c853e7142c450d8c71de4b2f84edbf8acd2e16d00c8115b150b1c30e553dbb82635e781379fe2a56360420ff7e9f70cc64c00aba7e26ed13c7c19622865ae07248daced36416080f35f8cc157a857ed70ea4f347f17d1bee80fa038abd6e39b1ba06b97264388b21364f7c56e192d4b62d9b161405f32ab1e2594e86243e56fcf2cb30d21adef15b9940f91af681da24328c883d892670c6aa47940867a81830a82b82716895db810df1b834640abefb7db2092dd92912cb9a735175bc447be40a503cf22dfe565b4ed7a3293ca0dfd63a507430b323ee248ec82e843b673c97ad730728cebc", + "Name": "nagydani-4-qube", + "Gas": 2730, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81010001df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + "Expected": "bed8b970c4a34849fc6926b08e40e20b21c15ed68d18f228904878d4370b56322d0da5789da0318768a374758e6375bfe4641fca5285ec7171828922160f48f5ca7efbfee4d5148612c38ad683ae4e3c3a053d2b7c098cf2b34f2cb19146eadd53c86b2d7ccf3d83b2c370bfb840913ee3879b1057a6b4e07e110b6bcd5e958bc71a14798c91d518cc70abee264b0d25a4110962a764b364ac0b0dd1ee8abc8426d775ec0f22b7e47b32576afaf1b5a48f64573ed1c5c29f50ab412188d9685307323d990802b81dacc06c6e05a1e901830ba9fcc67688dc29c5e27bde0a6e845ca925f5454b6fb3747edfaa2a5820838fb759eadf57f7cb5cec57fc213ddd8a4298fa079c3c0f472b07fb15aa6a7f0a3780bd296ff6a62e58ef443870b02260bd4fd2bbc98255674b8e1f1f9f8d33c7170b0ebbea4523b695911abbf26e41885344823bd0587115fdd83b721a4e8457a31c9a84b3d3520a07e0e35df7f48e5a9d534d0ec7feef1ff74de6a11e7f93eab95175b6ce22c68d78a642ad642837897ec11349205d8593ac19300207572c38d29ca5dfa03bc14cdbc32153c80e5cc3e739403d34c75915e49beb43094cc6dcafb3665b305ddec9286934ae66ec6b777ca528728c851318eb0f207b39f1caaf96db6eeead6b55ed08f451939314577d42bcc9f97c0b52d0234f88fd07e4c1d7780fdebc025cfffcb572cb27a8c33963", + "Name": "nagydani-4-pow0x10001", + "Gas": 43690, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf02e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + "Expected": "d61fe4e3f32ac260915b5b03b78a86d11bfc41d973fce5b0cc59035cf8289a8a2e3878ea15fa46565b0d806e2f85b53873ea20ed653869b688adf83f3ef444535bf91598ff7e80f334fb782539b92f39f55310cc4b35349ab7b278346eda9bc37c0d8acd3557fae38197f412f8d9e57ce6a76b7205c23564cab06e5615be7c6f05c3d05ec690cba91da5e89d55b152ff8dd2157dc5458190025cf94b1ad98f7cbe64e9482faba95e6b33844afc640892872b44a9932096508f4a782a4805323808f23e54b6ff9b841dbfa87db3505ae4f687972c18ea0f0d0af89d36c1c2a5b14560c153c3fee406f5cf15cfd1c0bb45d767426d465f2f14c158495069d0c5955a00150707862ecaae30624ebacdd8ac33e4e6aab3ff90b6ba445a84689386b9e945d01823a65874444316e83767290fcff630d2477f49d5d8ffdd200e08ee1274270f86ed14c687895f6caf5ce528bd970c20d2408a9ba66216324c6a011ac4999098362dbd98a038129a2d40c8da6ab88318aa3046cb660327cc44236d9e5d2163bd0959062195c51ed93d0088b6f92051fc99050ece2538749165976233697ab4b610385366e5ce0b02ad6b61c168ecfbedcdf74278a38de340fd7a5fead8e588e294795f9b011e2e60377a89e25c90e145397cdeabc60fd32444a6b7642a611a83c464d8b8976666351b4865c37b02e6dc21dbcdf5f930341707b618cc0f03c3122646b3385c9df9f2ec730eec9d49e7dfc9153b6e6289da8c4f0ebea9ccc1b751948e3bb7171c9e4d57423b0eeeb79095c030cb52677b3f7e0b45c30f645391f3f9c957afa549c4e0b2465b03c67993cd200b1af01035962edbc4c9e89b31c82ac121987d6529dafdeef67a132dc04b6dc68e77f22862040b75e2ceb9ff16da0fca534e6db7bd12fa7b7f51b6c08c1e23dfcdb7acbd2da0b51c87ffbced065a612e9b1c8bba9b7e2d8d7a2f04fcc4aaf355b60d764879a76b5e16762d5f2f55d585d0c8e82df6940960cddfb72c91dfa71f6b4e1c6ca25dfc39a878e998a663c04fe29d5e83b9586d047b4d7ff70a9f0d44f127e7d741685ca75f11629128d916a0ffef4be586a30c4b70389cc746e84ebf177c01ee8a4511cfbb9d1ecf7f7b33c7dd8177896e10bbc82f838dcd6db7ac67de62bf46b6a640fb580c5d1d2708f3862e3d2b645d0d18e49ef088053e3a220adc0e033c2afcfe61c90e32151152eb3caaf746c5e377d541cafc6cbb0cc0fa48b5caf1728f2e1957f5addfc234f1a9d89e40d49356c9172d0561a695fce6dab1d412321bbf407f63766ffd7b6b3d79bcfa07991c5a9709849c1008689e3b47c50d613980bec239fb64185249d055b30375ccb4354d71fe4d05648fbf6c80634dfc3575f2f24abb714c1e4c95e8896763bf4316e954c7ad19e5780ab7a040ca6fb9271f90a8b22ae738daf6cb", + "Name": "nagydani-5-square", + "Gas": 10922, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf03e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + "Expected": "5f9c70ec884926a89461056ad20ac4c30155e817f807e4d3f5bb743d789c83386762435c3627773fa77da5144451f2a8aad8adba88e0b669f5377c5e9bad70e45c86fe952b613f015a9953b8a5de5eaee4566acf98d41e327d93a35bd5cef4607d025e58951167957df4ff9b1627649d3943805472e5e293d3efb687cfd1e503faafeb2840a3e3b3f85d016051a58e1c9498aab72e63b748d834b31eb05d85dcde65e27834e266b85c75cc4ec0135135e0601cb93eeeb6e0010c8ceb65c4c319623c5e573a2c8c9fbbf7df68a930beb412d3f4dfd146175484f45d7afaa0d2e60684af9b34730f7c8438465ad3e1d0c3237336722f2aa51095bd5759f4b8ab4dda111b684aa3dac62a761722e7ae43495b7709933512c81c4e3c9133a51f7ce9f2b51fcec064f65779666960b4e45df3900f54311f5613e8012dd1b8efd359eda31a778264c72aa8bb419d862734d769076bce2810011989a45374e5c5d8729fec21427f0bf397eacbb4220f603cf463a4b0c94efd858ffd9768cd60d6ce68d755e0fbad007ce5c2223d70c7018345a102e4ab3c60a13a9e7794303156d4c2063e919f2153c13961fb324c80b240742f47773a7a8e25b3e3fb19b00ce839346c6eb3c732fbc6b888df0b1fe0a3d07b053a2e9402c267b2d62f794d8a2840526e3ade15ce2264496ccd7519571dfde47f7a4bb16292241c20b2be59f3f8fb4f6383f232d838c5a22d8c95b6834d9d2ca493f5a505ebe8899503b0e8f9b19e6e2dd81c1628b80016d02097e0134de51054c4e7674824d4d758760fc52377d2cad145e259aa2ffaf54139e1a66b1e0c1c191e32ac59474c6b526f5b3ba07d3e5ec286eddf531fcd5292869be58c9f22ef91026159f7cf9d05ef66b4299f4da48cc1635bf2243051d342d378a22c83390553e873713c0454ce5f3234397111ac3fe3207b86f0ed9fc025c81903e1748103692074f83824fda6341be4f95ff00b0a9a208c267e12fa01825054cc0513629bf3dbb56dc5b90d4316f87654a8be18227978ea0a8a522760cad620d0d14fd38920fb7321314062914275a5f99f677145a6979b156bd82ecd36f23f8e1273cc2759ecc0b2c69d94dad5211d1bed939dd87ed9e07b91d49713a6e16ade0a98aea789f04994e318e4ff2c8a188cd8d43aeb52c6daa3bc29b4af50ea82a247c5cd67b573b34cbadcc0a376d3bbd530d50367b42705d870f2e27a8197ef46070528bfe408360faa2ebb8bf76e9f388572842bcb119f4d84ee34ae31f5cc594f23705a49197b181fb78ed1ec99499c690f843a4d0cf2e226d118e9372271054fbabdcc5c92ae9fefaef0589cd0e722eaf30c1703ec4289c7fd81beaa8a455ccee5298e31e2080c10c366a6fcf56f7d13582ad0bcad037c612b710fc595b70fbefaaca23623b60c6c39b11beb8e5843b6b3dac60f", + "Name": "nagydani-5-qube", + "Gas": 10922, + "NoBenchmark": false + }, + { + "Input": "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf010001e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + "Expected": "5a0eb2bdf0ac1cae8e586689fa16cd4b07dfdedaec8a110ea1fdb059dd5253231b6132987598dfc6e11f86780428982d50cf68f67ae452622c3b336b537ef3298ca645e8f89ee39a26758206a5a3f6409afc709582f95274b57b71fae5c6b74619ae6f089a5393c5b79235d9caf699d23d88fb873f78379690ad8405e34c19f5257d596580c7a6a7206a3712825afe630c76b31cdb4a23e7f0632e10f14f4e282c81a66451a26f8df2a352b5b9f607a7198449d1b926e27036810368e691a74b91c61afa73d9d3b99453e7c8b50fd4f09c039a2f2feb5c419206694c31b92df1d9586140cb3417b38d0c503c7b508cc2ed12e813a1c795e9829eb39ee78eeaf360a169b491a1d4e419574e712402de9d48d54c1ae5e03739b7156615e8267e1fb0a897f067afd11fb33f6e24182d7aaaaa18fe5bc1982f20d6b871e5a398f0f6f718181d31ec225cfa9a0a70124ed9a70031bdf0c1c7829f708b6e17d50419ef361cf77d99c85f44607186c8d683106b8bd38a49b5d0fb503b397a83388c5678dcfcc737499d84512690701ed621a6f0172aecf037184ddf0f2453e4053024018e5ab2e30d6d5363b56e8b41509317c99042f517247474ab3abc848e00a07f69c254f46f2a05cf6ed84e5cc906a518fdcfdf2c61ce731f24c5264f1a25fc04934dc28aec112134dd523f70115074ca34e3807aa4cb925147f3a0ce152d323bd8c675ace446d0fd1ae30c4b57f0eb2c23884bc18f0964c0114796c5b6d080c3d89175665fbf63a6381a6a9da39ad070b645c8bb1779506da14439a9f5b5d481954764ea114fac688930bc68534d403cff4210673b6a6ff7ae416b7cd41404c3d3f282fcd193b86d0f54d0006c2a503b40d5c3930da980565b8f9630e9493a79d1c03e74e5f93ac8e4dc1a901ec5e3b3e57049124c7b72ea345aa359e782285d9e6a5c144a378111dd02c40855ff9c2be9b48425cb0b2fd62dc8678fd151121cf26a65e917d65d8e0dacfae108eb5508b601fb8ffa370be1f9a8b749a2d12eeab81f41079de87e2d777994fa4d28188c579ad327f9957fb7bdecec5c680844dd43cb57cf87aeb763c003e65011f73f8c63442df39a92b946a6bd968a1c1e4d5fa7d88476a68bd8e20e5b70a99259c7d3f85fb1b65cd2e93972e6264e74ebf289b8b6979b9b68a85cd5b360c1987f87235c3c845d62489e33acf85d53fa3561fe3a3aee18924588d9c6eba4edb7a4d106b31173e42929f6f0c48c80ce6a72d54eca7c0fe870068b7a7c89c63cdda593f5b32d3cb4ea8a32c39f00ab449155757172d66763ed9527019d6de6c9f2416aa6203f4d11c9ebee1e1d3845099e55504446448027212616167eb36035726daa7698b075286f5379cd3e93cb3e0cf4f9cb8d017facbb5550ed32d5ec5400ae57e47e2bf78d1eaeff9480cc765ceff39db500", + "Name": "nagydani-5-pow0x10001", + "Gas": 174762, + "NoBenchmark": false + } +] diff --git a/crypto/kzg4844/kzg4844.go b/crypto/kzg4844/kzg4844.go index 0a2478cea00..6637a589c62 100644 --- a/crypto/kzg4844/kzg4844.go +++ b/crypto/kzg4844/kzg4844.go @@ -34,6 +34,8 @@ var ( blobT = reflect.TypeOf(Blob{}) commitmentT = reflect.TypeOf(Commitment{}) proofT = reflect.TypeOf(Proof{}) + + CellProofsPerBlob = 128 ) // Blob represents a 4844 data blob. @@ -84,6 +86,10 @@ type Claim [32]byte // useCKZG controls whether the cryptography should use the Go or C backend. var useCKZG atomic.Bool +func init() { + UseCKZG(true) +} + // UseCKZG can be called to switch the default Go implementation of KZG to the C // library if for some reason the user wishes to do so (e.g. consensus bug in one // or the other). @@ -149,6 +155,16 @@ func VerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error { return gokzgVerifyBlobProof(blob, commitment, proof) } +// VerifyCellProofs verifies a batch of proofs corresponding to the blobs and commitments. +// Expects length of blobs and commitments to be equal. +// Expects length of proofs be 128 * length of blobs. +func VerifyCellProofs(blobs []*Blob, commitments []Commitment, proofs []Proof) error { + if useCKZG.Load() { + return ckzgVerifyCellProofBatch(blobs, commitments, proofs) + } + return gokzgVerifyCellProofBatch(blobs, commitments, proofs) +} + // ComputeCellProofs returns the KZG cell proofs that are used to verify the blob against // the commitment. // @@ -177,3 +193,10 @@ func CalcBlobHashV1(hasher hash.Hash, commit *Commitment) (vh [32]byte) { func IsValidVersionedHash(h []byte) bool { return len(h) == 32 && h[0] == 0x01 } + +func ComputeCells(blob *Blob) ([]Proof, error) { + if useCKZG.Load() { + return ckzgComputeCellProofs(blob) + } + return gokzgComputeCellProofs(blob) +} diff --git a/crypto/kzg4844/kzg4844_ckzg_cgo.go b/crypto/kzg4844/kzg4844_ckzg_cgo.go index 49a7046fe0d..2404a1a9a52 100644 --- a/crypto/kzg4844/kzg4844_ckzg_cgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_cgo.go @@ -149,3 +149,44 @@ func ckzgComputeCellProofs(blob *Blob) ([]Proof, error) { } return p, nil } + +// ckzgVerifyCellProofs verifies that the blob data corresponds to the provided commitment. +func ckzgVerifyCellProofBatch(blobs []*Blob, commitments []Commitment, cellProofs []Proof) error { + ckzgIniter.Do(ckzgInit) + var ( + proofs = make([]ckzg4844.Bytes48, len(cellProofs)) + commits = make([]ckzg4844.Bytes48, 0, len(cellProofs)) + cellIndices = make([]uint64, 0, len(cellProofs)) + cells = make([]ckzg4844.Cell, 0, len(cellProofs)) + ) + // Copy over the cell proofs + for i, proof := range cellProofs { + proofs[i] = (ckzg4844.Bytes48)(proof) + } + // Blow up the commitments to be the same length as the proofs + for _, commitment := range commitments { + for range gokzg4844.CellsPerExtBlob { + commits = append(commits, (ckzg4844.Bytes48)(commitment)) + } + } + // Compute the cells and cell indices + for _, blob := range blobs { + cellsI, err := ckzg4844.ComputeCells((*ckzg4844.Blob)(blob)) + if err != nil { + return err + } + cells = append(cells, cellsI[:]...) + for idx := range len(cellsI) { + cellIndices = append(cellIndices, uint64(idx)) + } + } + + valid, err := ckzg4844.VerifyCellKZGProofBatch(commits, cellIndices, cells, proofs) + if err != nil { + return err + } + if !valid { + return errors.New("invalid proof") + } + return nil +} diff --git a/crypto/kzg4844/kzg4844_ckzg_nocgo.go b/crypto/kzg4844/kzg4844_ckzg_nocgo.go index 6f4bd3b8236..3b12e1c2ad0 100644 --- a/crypto/kzg4844/kzg4844_ckzg_nocgo.go +++ b/crypto/kzg4844/kzg4844_ckzg_nocgo.go @@ -61,6 +61,11 @@ func ckzgVerifyBlobProof(blob *Blob, commitment Commitment, proof Proof) error { panic("unsupported platform") } +// ckzgVerifyCellProofBatch verifies that the blob data corresponds to the provided commitment. +func ckzgVerifyCellProofBatch(blobs []*Blob, commitments []Commitment, proof []Proof) error { + panic("unsupported platform") +} + // ckzgComputeCellProofs returns the KZG cell proofs that are used to verify the blob against // the commitment. // diff --git a/crypto/kzg4844/kzg4844_gokzg.go b/crypto/kzg4844/kzg4844_gokzg.go index 46a38a89136..9fbd6f654af 100644 --- a/crypto/kzg4844/kzg4844_gokzg.go +++ b/crypto/kzg4844/kzg4844_gokzg.go @@ -114,3 +114,37 @@ func gokzgComputeCellProofs(blob *Blob) ([]Proof, error) { } return p, nil } + +// gokzgVerifyCellProofs verifies that the blob data corresponds to the provided commitment. +func gokzgVerifyCellProofBatch(blobs []*Blob, commitments []Commitment, cellProofs []Proof) error { + gokzgIniter.Do(gokzgInit) + + var ( + proofs = make([]gokzg4844.KZGProof, len(cellProofs)) + commits = make([]gokzg4844.KZGCommitment, 0, len(cellProofs)) + cellIndices = make([]uint64, 0, len(cellProofs)) + cells = make([]*gokzg4844.Cell, 0, len(cellProofs)) + ) + // Copy over the cell proofs + for i, proof := range cellProofs { + proofs[i] = gokzg4844.KZGProof(proof) + } + // Blow up the commitments to be the same length as the proofs + for _, commitment := range commitments { + for range gokzg4844.CellsPerExtBlob { + commits = append(commits, gokzg4844.KZGCommitment(commitment)) + } + } + // Compute the cell and cell indices + for _, blob := range blobs { + cellsI, err := context.ComputeCells((*gokzg4844.Blob)(blob), 2) + if err != nil { + return err + } + cells = append(cells, cellsI[:]...) + for idx := range len(cellsI) { + cellIndices = append(cellIndices, uint64(idx)) + } + } + return context.VerifyCellKZGProofBatch(commits, cellIndices, cells[:], proofs) +} diff --git a/crypto/kzg4844/kzg4844_test.go b/crypto/kzg4844/kzg4844_test.go index 7fa261e523e..61ef350f20e 100644 --- a/crypto/kzg4844/kzg4844_test.go +++ b/crypto/kzg4844/kzg4844_test.go @@ -193,3 +193,39 @@ func benchmarkVerifyBlobProof(b *testing.B, ckzg bool) { VerifyBlobProof(blob, commitment, proof) } } + +func TestCKZGCells(t *testing.T) { testKZGCells(t, true) } +func TestGoKZGCells(t *testing.T) { testKZGCells(t, false) } +func testKZGCells(t *testing.T, ckzg bool) { + if ckzg && !ckzgAvailable { + t.Skip("CKZG unavailable in this test build") + } + defer func(old bool) { useCKZG.Store(old) }(useCKZG.Load()) + useCKZG.Store(ckzg) + + blob1 := randBlob() + blob2 := randBlob() + + commitment1, err := BlobToCommitment(blob1) + if err != nil { + t.Fatalf("failed to create KZG commitment from blob: %v", err) + } + commitment2, err := BlobToCommitment(blob2) + if err != nil { + t.Fatalf("failed to create KZG commitment from blob: %v", err) + } + + proofs1, err := ComputeCellProofs(blob1) + if err != nil { + t.Fatalf("failed to create KZG proof at point: %v", err) + } + + proofs2, err := ComputeCellProofs(blob2) + if err != nil { + t.Fatalf("failed to create KZG proof at point: %v", err) + } + proofs := append(proofs1, proofs2...) + if err := VerifyCellProofs([]*Blob{blob1, blob2}, []Commitment{commitment1, commitment2}, proofs); err != nil { + t.Fatalf("failed to verify KZG proof at point: %v", err) + } +} diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index b5f035b6d2d..d5e3bc7b59d 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -18,6 +18,7 @@ package catalyst import ( + "crypto/sha256" "errors" "fmt" "strconv" @@ -29,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/version" @@ -91,7 +93,9 @@ var caps = []string{ "engine_getPayloadV2", "engine_getPayloadV3", "engine_getPayloadV4", + "engine_getPayloadV5", "engine_getBlobsV1", + "engine_getBlobsV2", "engine_newPayloadV1", "engine_newPayloadV2", "engine_newPayloadV3", @@ -231,7 +235,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, pa return engine.STATUS_INVALID, attributesErr("missing withdrawals") case params.BeaconRoot == nil: return engine.STATUS_INVALID, attributesErr("missing beacon root") - case !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague): + case !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague, forks.Osaka): return engine.STATUS_INVALID, unsupportedForkErr("fcuV3 must only be called for cancun or prague payloads") } } @@ -456,6 +460,14 @@ func (api *ConsensusAPI) GetPayloadV4(payloadID engine.PayloadID) (*engine.Execu return api.getPayload(payloadID, false) } +// GetPayloadV4 returns a cached payload by id. +func (api *ConsensusAPI) GetPayloadV5(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { + if !payloadID.Is(engine.PayloadV3) { + return nil, engine.UnsupportedFork + } + return api.getPayload(payloadID, false) +} + func (api *ConsensusAPI) getPayload(payloadID engine.PayloadID, full bool) (*engine.ExecutionPayloadEnvelope, error) { log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID) data := api.localBlocks.get(payloadID, full) @@ -470,14 +482,82 @@ func (api *ConsensusAPI) GetBlobsV1(hashes []common.Hash) ([]*engine.BlobAndProo if len(hashes) > 128 { return nil, engine.TooLargeRequest.With(fmt.Errorf("requested blob count too large: %v", len(hashes))) } - res := make([]*engine.BlobAndProofV1, len(hashes)) + var ( + res = make([]*engine.BlobAndProofV1, len(hashes)) + hasher = sha256.New() + index = make(map[common.Hash]int) + sidecars = api.eth.TxPool().GetBlobs(hashes) + ) - blobs, proofs := api.eth.TxPool().GetBlobs(hashes) - for i := 0; i < len(blobs); i++ { - if blobs[i] != nil { - res[i] = &engine.BlobAndProofV1{ - Blob: (*blobs[i])[:], - Proof: (*proofs[i])[:], + for i, hash := range hashes { + index[hash] = i + } + for i, sidecar := range sidecars { + if res[i] != nil || sidecar == nil { + // already filled + continue + } + for cIdx, commitment := range sidecar.Commitments { + computed := kzg4844.CalcBlobHashV1(hasher, &commitment) + if idx, ok := index[computed]; ok { + res[idx] = &engine.BlobAndProofV1{ + Blob: sidecar.Blobs[cIdx][:], + Proof: sidecar.Proofs[cIdx][:], + } + } + } + } + return res, nil +} + +// GetBlobsV2 returns a blob from the transaction pool. +func (api *ConsensusAPI) GetBlobsV2(hashes []common.Hash) ([]*engine.BlobAndProofV2, error) { + if len(hashes) > 128 { + return nil, engine.TooLargeRequest.With(fmt.Errorf("requested blob count too large: %v", len(hashes))) + } + + // Optimization: check first if all blobs are available, if not, return empty response + if !api.eth.TxPool().HasBlobs(hashes) { + return nil, nil + } + + // pull up the blob hashes + var ( + res = make([]*engine.BlobAndProofV2, len(hashes)) + index = make(map[common.Hash][]int) + sidecars = api.eth.TxPool().GetBlobs(hashes) + ) + + for i, hash := range hashes { + index[hash] = append(index[hash], i) + } + for i, sidecar := range sidecars { + if res[i] != nil { + // already filled + continue + } + if sidecar == nil { + // not found, return empty response + return nil, nil + } + if sidecar.Version != 1 { + log.Info("GetBlobs queried V0 transaction: index %v, blobhashes %v", index, sidecar.BlobHashes()) + return nil, nil + } + blobHashes := sidecar.BlobHashes() + for bIdx, hash := range blobHashes { + if idxes, ok := index[hash]; ok { + proofs := sidecar.CellProofsAt(bIdx) + var cellProofs []hexutil.Bytes + for _, proof := range proofs { + cellProofs = append(cellProofs, proof[:]) + } + for _, idx := range idxes { + res[idx] = &engine.BlobAndProofV2{ + Blob: sidecar.Blobs[bIdx][:], + CellProofs: cellProofs, + } + } } } } @@ -550,7 +630,7 @@ func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHas return invalidStatus, paramsErr("nil beaconRoot post-cancun") case executionRequests == nil: return invalidStatus, paramsErr("nil executionRequests post-prague") - case !api.checkFork(params.Timestamp, forks.Prague): + case !api.checkFork(params.Timestamp, forks.Prague, forks.Osaka): return invalidStatus, unsupportedForkErr("newPayloadV3 must only be called for cancun payloads") } requests := convertRequests(executionRequests) diff --git a/miner/worker.go b/miner/worker.go index d80cb8913ba..b480e91e21b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -390,6 +391,25 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran continue } + // Make sure all transactions after osaka have cell proofs + if miner.chainConfig.IsOsaka(env.header.Number, env.header.Time) { + if sidecar := tx.BlobTxSidecar(); sidecar != nil { + if sidecar.Version == 0 { + log.Warn("Encountered Version 0 transaction post-Osaka, recompute proofs", "hash", ltx.Hash) + sidecar.Proofs = make([]kzg4844.Proof, 0) + for _, blob := range sidecar.Blobs { + cellProofs, err := kzg4844.ComputeCells(&blob) + if err != nil { + panic(err) + } + sidecar.Proofs = append(sidecar.Proofs, cellProofs...) + } + //txs.Pop() + //continue + } + } + } + // Error may be ignored here. The error has already been checked // during transaction acceptance in the transaction pool. from, _ := types.Sender(env.signer, tx) diff --git a/params/config.go b/params/config.go index 2e825ffcd56..a64ee78bec1 100644 --- a/params/config.go +++ b/params/config.go @@ -410,6 +410,11 @@ type ChainConfig struct { PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague) OsakaTime *uint64 `json:"osakaTime,omitempty"` // Osaka switch time (nil = no fork, 0 = already on osaka) VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle) + BPO1Time *uint64 `json:"bpo1Time,omitempty"` // BPO1 switch time (nil = no fork, 0 = already on bpo1) + BPO2Time *uint64 `json:"bpo2Time,omitempty"` // BPO2 switch time (nil = no fork, 0 = already on bpo2) + BPO3Time *uint64 `json:"bpo3Time,omitempty"` // BPO3 switch time (nil = no fork, 0 = already on bpo3) + BPO4Time *uint64 `json:"bpo4Time,omitempty"` // BPO4 switch time (nil = no fork, 0 = already on bpo4) + BPO5Time *uint64 `json:"bpo5Time,omitempty"` // BPO5 switch time (nil = no fork, 0 = already on bpo5) // TerminalTotalDifficulty is the amount of total difficulty reached by // the network that triggers the consensus upgrade. @@ -530,6 +535,21 @@ func (c *ChainConfig) Description() string { if c.VerkleTime != nil { banner += fmt.Sprintf(" - Verkle: @%-10v\n", *c.VerkleTime) } + if c.BPO1Time != nil { + banner += fmt.Sprintf(" - BPO1: @%-10v\n", *c.BPO1Time) + } + if c.BPO2Time != nil { + banner += fmt.Sprintf(" - BPO2: @%-10v\n", *c.BPO2Time) + } + if c.BPO3Time != nil { + banner += fmt.Sprintf(" - BPO3: @%-10v\n", *c.BPO3Time) + } + if c.BPO4Time != nil { + banner += fmt.Sprintf(" - BPO4: @%-10v\n", *c.BPO4Time) + } + if c.BPO5Time != nil { + banner += fmt.Sprintf(" - BPO5: @%-10v\n", *c.BPO5Time) + } return banner } @@ -546,6 +566,11 @@ type BlobScheduleConfig struct { Prague *BlobConfig `json:"prague,omitempty"` Osaka *BlobConfig `json:"osaka,omitempty"` Verkle *BlobConfig `json:"verkle,omitempty"` + BPO1 *BlobConfig `json:"bpo1,omitempty"` + BPO2 *BlobConfig `json:"bpo2,omitempty"` + BPO3 *BlobConfig `json:"bpo3,omitempty"` + BPO4 *BlobConfig `json:"bpo4,omitempty"` + BPO5 *BlobConfig `json:"bpo5,omitempty"` } // IsHomestead returns whether num is either equal to the homestead block or greater. @@ -653,6 +678,31 @@ func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time) } +// IsBPO1 returns whether time is either equal to the BPO1 fork time or greater. +func (c *ChainConfig) IsBPO1(num *big.Int, time uint64) bool { + return c.IsLondon(num) && isTimestampForked(c.BPO1Time, time) +} + +// IsBPO2 returns whether time is either equal to the BPO2 fork time or greater. +func (c *ChainConfig) IsBPO2(num *big.Int, time uint64) bool { + return c.IsLondon(num) && isTimestampForked(c.BPO2Time, time) +} + +// IsBPO3 returns whether time is either equal to the BPO3 fork time or greater. +func (c *ChainConfig) IsBPO3(num *big.Int, time uint64) bool { + return c.IsLondon(num) && isTimestampForked(c.BPO3Time, time) +} + +// IsBPO4 returns whether time is either equal to the BPO4 fork time or greater. +func (c *ChainConfig) IsBPO4(num *big.Int, time uint64) bool { + return c.IsLondon(num) && isTimestampForked(c.BPO4Time, time) +} + +// IsBPO5 returns whether time is either equal to the BPO5 fork time or greater. +func (c *ChainConfig) IsBPO5(num *big.Int, time uint64) bool { + return c.IsLondon(num) && isTimestampForked(c.BPO5Time, time) +} + // IsVerkleGenesis checks whether the verkle fork is activated at the genesis block. // // Verkle mode is considered enabled if the verkle fork time is configured, @@ -777,6 +827,11 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "cancun", timestamp: c.CancunTime, config: bsc.Cancun}, {name: "prague", timestamp: c.PragueTime, config: bsc.Prague}, {name: "osaka", timestamp: c.OsakaTime, config: bsc.Osaka}, + {name: "bpo1", timestamp: c.BPO1Time, config: bsc.BPO1}, + {name: "bpo2", timestamp: c.BPO2Time, config: bsc.BPO2}, + {name: "bpo3", timestamp: c.BPO3Time, config: bsc.BPO3}, + {name: "bpo4", timestamp: c.BPO4Time, config: bsc.BPO4}, + {name: "bpo5", timestamp: c.BPO5Time, config: bsc.BPO5}, } { if cur.config != nil { if err := cur.config.validate(); err != nil {