diff --git a/eth-reference-tests/build.gradle b/eth-reference-tests/build.gradle index b6c65513dc5..94073b33220 100644 --- a/eth-reference-tests/build.gradle +++ b/eth-reference-tests/build.gradle @@ -17,6 +17,7 @@ dependencies { referenceTestImplementation project(':infrastructure:async') referenceTestImplementation project(':infrastructure:io') referenceTestImplementation testFixtures(project(':infrastructure:async')) + referenceTestImplementation testFixtures(project(':infrastructure:kzg')) referenceTestImplementation testFixtures(project(':infrastructure:metrics')) referenceTestImplementation project(':infrastructure:time') referenceTestImplementation project(':data:dataexchange') diff --git a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/KzgRetriever.java b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/KzgRetriever.java index a21514a1cb5..c0fa4b1e76b 100644 --- a/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/KzgRetriever.java +++ b/eth-reference-tests/src/referenceTest/java/tech/pegasys/teku/reference/KzgRetriever.java @@ -16,6 +16,7 @@ import com.google.common.collect.Maps; import java.util.Map; import tech.pegasys.teku.kzg.KZG; +import tech.pegasys.teku.kzg.NoOpKZG; import tech.pegasys.teku.networks.Eth2NetworkConfiguration; import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.SpecMilestone; @@ -29,7 +30,7 @@ public static KZG getKzgWithLoadedTrustedSetup(final Spec spec, final String net || spec.isMilestoneSupported(SpecMilestone.ELECTRA)) { return getKzgWithLoadedTrustedSetup(network); } - return KZG.NOOP; + return NoOpKZG.INSTANCE; } public static KZG getKzgWithLoadedTrustedSetup(final String network) { diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannelStub.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannelStub.java index 7e9af041716..00ded9246f6 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannelStub.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannelStub.java @@ -126,7 +126,7 @@ public ExecutionLayerChannelStub( // trusted setup loading will be handled by the BeaconChainController kzg = KZG.getInstance(false); } else { - kzg = KZG.NOOP; + kzg = KZG.DISABLED; } this.blobsUtil = new BlobsUtil(spec, kzg); } diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/ChainBuilder.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/ChainBuilder.java index 829c64f3ebf..bc3eeabdac2 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/ChainBuilder.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/ChainBuilder.java @@ -41,9 +41,9 @@ import tech.pegasys.teku.infrastructure.async.SyncAsyncRunner; import tech.pegasys.teku.infrastructure.ssz.SszList; import tech.pegasys.teku.infrastructure.unsigned.UInt64; -import tech.pegasys.teku.kzg.KZG; import tech.pegasys.teku.kzg.KZGCommitment; import tech.pegasys.teku.kzg.KZGProof; +import tech.pegasys.teku.kzg.NoOpKZG; import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.SpecMilestone; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.Blob; @@ -111,7 +111,7 @@ private ChainBuilder( final Optional maybeEarliestBlobSidecarSlot) { this.spec = spec; this.validatorKeys = validatorKeys; - this.blobsUtil = new BlobsUtil(spec, KZG.NOOP); + this.blobsUtil = new BlobsUtil(spec, NoOpKZG.INSTANCE); this.attestationGenerator = new AttestationGenerator(spec, validatorKeys); this.attesterSlashingGenerator = new AttesterSlashingGenerator(spec, validatorKeys); this.proposerSlashingGenerator = new ProposerSlashingGenerator(spec, validatorKeys); diff --git a/gradle/versions.gradle b/gradle/versions.gradle index f5e690f1bd0..a7bfc507482 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -35,7 +35,7 @@ dependencyManagement { dependency 'io.libp2p:jvm-libp2p:1.2.2-RELEASE' dependency 'tech.pegasys:jblst:0.3.12' dependency 'io.consensys.protocols:jc-kzg-4844:2.1.1' - dependency 'io.github.crate-crypto:java-eth-kzg:0.5.2' + dependency 'io.github.crate-crypto:java-eth-kzg:0.5.4' dependency 'org.hdrhistogram:HdrHistogram:2.2.2' diff --git a/infrastructure/kzg/build.gradle b/infrastructure/kzg/build.gradle index 66a8b08f7fc..d074cfd9d17 100644 --- a/infrastructure/kzg/build.gradle +++ b/infrastructure/kzg/build.gradle @@ -9,4 +9,5 @@ dependencies { implementation 'commons-io:commons-io' testFixturesImplementation 'com.google.guava:guava' + testFixturesImplementation 'io.consensys.tuweni:tuweni-bytes' } diff --git a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/CKZG4844.java b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/CKZG4844.java index ca973616fea..feef1cc7ba0 100644 --- a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/CKZG4844.java +++ b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/CKZG4844.java @@ -155,6 +155,16 @@ public KZGProof computeBlobKzgProof(final Bytes blob, final KZGCommitment kzgCom } } + @Override + public List computeCells(final Bytes blob) throws KZGException { + try { + final byte[] cells = CKZG4844JNI.computeCells(blob.toArrayUnsafe()); + return KZGCell.splitBytes(Bytes.wrap(cells)); + } catch (final Exception ex) { + throw new KZGException("Failed to compute KZG cells for blob " + blob.toShortHexString(), ex); + } + } + @Override public List computeCellsAndProofs(final Bytes blob) { final CellsAndProofs cellsAndProofs = diff --git a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZG.java b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZG.java index 86e86507f7d..2472b42f3c5 100644 --- a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZG.java +++ b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZG.java @@ -16,7 +16,6 @@ import java.math.BigInteger; import java.util.List; import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes48; /** * This interface specifies all the KZG functions needed for the Deneb specification and is the @@ -35,7 +34,7 @@ static KZG getInstance(final boolean rustKzgEnabled) { return rustKzgEnabled ? RustWithCKZG.getInstance() : CKZG4844.getInstance(); } - KZG NOOP = + KZG DISABLED = new KZG() { @Override @@ -48,7 +47,7 @@ public void freeTrustedSetup() throws KZGException {} public boolean verifyBlobKzgProof( final Bytes blob, final KZGCommitment kzgCommitment, final KZGProof kzgProof) throws KZGException { - return true; + throw new UnsupportedOperationException("KZG is disabled"); } @Override @@ -57,23 +56,28 @@ public boolean verifyBlobKzgProofBatch( final List kzgCommitments, final List kzgProofs) throws KZGException { - return true; + throw new UnsupportedOperationException("KZG is disabled"); } @Override public KZGCommitment blobToKzgCommitment(final Bytes blob) throws KZGException { - return KZGCommitment.fromBytesCompressed(Bytes48.ZERO); + throw new UnsupportedOperationException("KZG is disabled"); } @Override public KZGProof computeBlobKzgProof(final Bytes blob, final KZGCommitment kzgCommitment) throws KZGException { - return KZGProof.fromBytesCompressed(Bytes48.ZERO); + throw new UnsupportedOperationException("KZG is disabled"); + } + + @Override + public List computeCells(Bytes blob) { + throw new UnsupportedOperationException("KZG is disabled"); } @Override public List computeCellsAndProofs(Bytes blob) { - throw new RuntimeException("Not implemented"); + throw new UnsupportedOperationException("KZG is disabled"); } @Override @@ -81,12 +85,12 @@ public boolean verifyCellProofBatch( List commitments, List cellWithIDs, List proofs) { - return false; + throw new UnsupportedOperationException("KZG is disabled"); } @Override public List recoverCellsAndProofs(List cells) { - throw new RuntimeException("Not implemented"); + throw new UnsupportedOperationException("KZG is disabled"); } }; @@ -107,6 +111,9 @@ boolean verifyBlobKzgProofBatch( // Fulu PeerDAS methods + List computeCells(Bytes blob); + + @Deprecated(since = "Use computeCells instead, computeCellsAndProof is not for production") List computeCellsAndProofs(Bytes blob); boolean verifyCellProofBatch( diff --git a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/RustKZG.java b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/RustKZG.java index 53489af8b81..51c532487ee 100644 --- a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/RustKZG.java +++ b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/RustKZG.java @@ -14,6 +14,7 @@ package tech.pegasys.teku.kzg; import com.google.common.collect.Streams; +import ethereum.cryptography.Cells; import ethereum.cryptography.CellsAndProofs; import ethereum.cryptography.LibEthKZG; import java.util.Arrays; @@ -102,6 +103,12 @@ public KZGProof computeBlobKzgProof(final Bytes blob, final KZGCommitment kzgCom throw new RuntimeException("LibPeerDASKZG library doesn't support computeBlobKzgProof"); } + @Override + public List computeCells(final Bytes blob) { + final Cells cells = library.computeCells(blob.toArrayUnsafe()); + return KZGCell.splitBytes(Bytes.wrap(cells.toBytes())); + } + @Override public List computeCellsAndProofs(final Bytes blob) { final CellsAndProofs cellsAndProofs = library.computeCellsAndKZGProofs(blob.toArrayUnsafe()); diff --git a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/RustWithCKZG.java b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/RustWithCKZG.java index 972a5e7693a..1dd47803855 100644 --- a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/RustWithCKZG.java +++ b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/RustWithCKZG.java @@ -28,7 +28,7 @@ final class RustWithCKZG implements KZG { private static RustWithCKZG instance; private final CKZG4844 ckzg4844Delegate; - private final RustKZG rustKzgDelegeate; + private final RustKZG rustKzgDelegate; static synchronized RustWithCKZG getInstance() { if (instance == null) { @@ -39,13 +39,13 @@ static synchronized RustWithCKZG getInstance() { private RustWithCKZG() { this.ckzg4844Delegate = CKZG4844.getInstance(); - this.rustKzgDelegeate = RustKZG.getInstance(); + this.rustKzgDelegate = RustKZG.getInstance(); } @Override public synchronized void loadTrustedSetup(final String trustedSetupFile) throws KZGException { ckzg4844Delegate.loadTrustedSetup(trustedSetupFile); - rustKzgDelegeate.loadTrustedSetup(trustedSetupFile); + rustKzgDelegate.loadTrustedSetup(trustedSetupFile); } @Override @@ -58,7 +58,7 @@ public synchronized void freeTrustedSetup() throws KZGException { } KZGException rustKzgDelegateException = null; try { - rustKzgDelegeate.freeTrustedSetup(); + rustKzgDelegate.freeTrustedSetup(); } catch (final KZGException ex) { rustKzgDelegateException = ex; } @@ -102,9 +102,14 @@ public KZGProof computeBlobKzgProof(final Bytes blob, final KZGCommitment kzgCom return ckzg4844Delegate.computeBlobKzgProof(blob, kzgCommitment); } + @Override + public List computeCells(final Bytes blob) { + return rustKzgDelegate.computeCells(blob); + } + @Override public List computeCellsAndProofs(final Bytes blob) { - return rustKzgDelegeate.computeCellsAndProofs(blob); + return rustKzgDelegate.computeCellsAndProofs(blob); } @Override @@ -112,11 +117,11 @@ public boolean verifyCellProofBatch( final List commitments, final List cellWithIds, final List proofs) { - return rustKzgDelegeate.verifyCellProofBatch(commitments, cellWithIds, proofs); + return rustKzgDelegate.verifyCellProofBatch(commitments, cellWithIds, proofs); } @Override public List recoverCellsAndProofs(final List cells) { - return rustKzgDelegeate.recoverCellsAndProofs(cells); + return rustKzgDelegate.recoverCellsAndProofs(cells); } } diff --git a/infrastructure/kzg/src/test/java/tech/pegasys/teku/kzg/KZGAbstractTest.java b/infrastructure/kzg/src/test/java/tech/pegasys/teku/kzg/KZGAbstractTest.java index 6bb2cde9432..d449fec49dd 100644 --- a/infrastructure/kzg/src/test/java/tech/pegasys/teku/kzg/KZGAbstractTest.java +++ b/infrastructure/kzg/src/test/java/tech/pegasys/teku/kzg/KZGAbstractTest.java @@ -300,6 +300,14 @@ public void testComputeRecoverCellsAndProofs() { assertThat(recoveredCells).isEqualTo(cellAndProofs); } + @Test + public void testComputeCellsAndProofsEqualsComputeCells() { + Bytes blob = getSampleBlob(); + List cellAndProofs = kzg.computeCellsAndProofs(blob); + List cells = kzg.computeCells(blob); + assertThat(cells).isEqualTo(cellAndProofs.stream().map(KZGCellAndProof::cell).toList()); + } + private List getSampleBlobs(final int count) { return IntStream.range(0, count).mapToObj(__ -> getSampleBlob()).collect(Collectors.toList()); } diff --git a/infrastructure/kzg/src/testFixtures/java/tech/pegasys/teku/kzg/NoOpKZG.java b/infrastructure/kzg/src/testFixtures/java/tech/pegasys/teku/kzg/NoOpKZG.java new file mode 100644 index 00000000000..c0f71a46f2a --- /dev/null +++ b/infrastructure/kzg/src/testFixtures/java/tech/pegasys/teku/kzg/NoOpKZG.java @@ -0,0 +1,84 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.kzg; + +import java.util.List; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes48; + +public class NoOpKZG implements KZG { + + public static final NoOpKZG INSTANCE = new NoOpKZG(); + + @Override + public void loadTrustedSetup(final String trustedSetupFile) throws KZGException { + // DO NOTHING + } + + @Override + public void freeTrustedSetup() throws KZGException { + // DO NOTHING + } + + @Override + public boolean verifyCellProofBatch( + final List commitments, + final List cellWithIDs, + final List proofs) { + return true; + } + + @Override + public List recoverCellsAndProofs(final List cells) { + return List.of(); + } + + @Override + @Deprecated(since = "Use computeCells instead, computeCellsAndProof is not for production") + public List computeCellsAndProofs(final Bytes blob) { + return List.of(); + } + + @Override + public List computeCells(final Bytes blob) { + return List.of(); + } + + @Override + public KZGProof computeBlobKzgProof(final Bytes blob, final KZGCommitment kzgCommitment) + throws KZGException { + return KZGProof.fromBytesCompressed(Bytes48.ZERO); + } + + @Override + public KZGCommitment blobToKzgCommitment(final Bytes blob) throws KZGException { + return KZGCommitment.fromBytesCompressed(Bytes48.ZERO); + } + + @Override + public boolean verifyBlobKzgProofBatch( + final List blobs, + final List kzgCommitments, + final List kzgProofs) + throws KZGException { + return true; + } + + @Override + public boolean verifyBlobKzgProof( + final Bytes blob, final KZGCommitment kzgCommitment, final KZGProof kzgProof) + throws KZGException { + return true; + } +} diff --git a/networking/eth2/build.gradle b/networking/eth2/build.gradle index d975bc73fba..13f9dad2d2f 100644 --- a/networking/eth2/build.gradle +++ b/networking/eth2/build.gradle @@ -48,6 +48,7 @@ dependencies { testFixturesImplementation testFixtures(project(':infrastructure:async')) testFixturesImplementation project(':infrastructure:bytes') testFixturesImplementation testFixtures(project(':infrastructure:events')) + testFixturesImplementation testFixtures(project(':infrastructure:kzg')) testFixturesImplementation testFixtures(project(':infrastructure:metrics')) testFixturesImplementation testFixtures(project(':infrastructure:time')) testFixturesImplementation testFixtures(project(':storage')) diff --git a/networking/eth2/src/testFixtures/java/tech/pegasys/teku/networking/eth2/Eth2P2PNetworkFactory.java b/networking/eth2/src/testFixtures/java/tech/pegasys/teku/networking/eth2/Eth2P2PNetworkFactory.java index f2e66ed2cb2..652b65587a4 100644 --- a/networking/eth2/src/testFixtures/java/tech/pegasys/teku/networking/eth2/Eth2P2PNetworkFactory.java +++ b/networking/eth2/src/testFixtures/java/tech/pegasys/teku/networking/eth2/Eth2P2PNetworkFactory.java @@ -44,7 +44,7 @@ import tech.pegasys.teku.infrastructure.subscribers.Subscribers; import tech.pegasys.teku.infrastructure.time.StubTimeProvider; import tech.pegasys.teku.infrastructure.time.TimeProvider; -import tech.pegasys.teku.kzg.KZG; +import tech.pegasys.teku.kzg.NoOpKZG; import tech.pegasys.teku.network.p2p.jvmlibp2p.PrivateKeyGenerator; import tech.pegasys.teku.networking.eth2.gossip.config.GossipConfigurator; import tech.pegasys.teku.networking.eth2.gossip.encoding.GossipEncoding; @@ -230,7 +230,7 @@ protected Eth2P2PNetwork buildNetwork(final P2PConfig config) { P2PConfig.DEFAULT_PEER_BLOB_SIDECARS_RATE_LIMIT, P2PConfig.DEFAULT_PEER_REQUEST_LIMIT, spec, - KZG.NOOP, + NoOpKZG.INSTANCE, (__) -> Optional.empty()); List> rpcMethods = diff --git a/services/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/BeaconChainController.java b/services/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/BeaconChainController.java index 9d6157fc87b..fbf4dab4c6f 100644 --- a/services/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/BeaconChainController.java +++ b/services/beaconchain/src/main/java/tech/pegasys/teku/services/beaconchain/BeaconChainController.java @@ -571,7 +571,7 @@ protected void initKzg() { "Trusted setup should be configured when Deneb is enabled")); kzg.loadTrustedSetup(trustedSetupFile); } else { - kzg = KZG.NOOP; + kzg = KZG.DISABLED; } }