diff --git a/gradle/versions.gradle b/gradle/versions.gradle
index 1aa6f769ebb..d09d39cc709 100644
--- a/gradle/versions.gradle
+++ b/gradle/versions.gradle
@@ -41,6 +41,7 @@ dependencyManagement {
dependency 'io.libp2p:jvm-libp2p-minimal:0.10.0-RELEASE'
dependency 'tech.pegasys:jblst:0.3.8'
+ dependency 'tech.pegasys:jc-kzg-4844:develop'
dependency 'org.hdrhistogram:HdrHistogram:2.1.12'
diff --git a/infrastructure/kzg/build.gradle b/infrastructure/kzg/build.gradle
index 152af374394..60280534149 100644
--- a/infrastructure/kzg/build.gradle
+++ b/infrastructure/kzg/build.gradle
@@ -1,12 +1,8 @@
-repositories {
- maven { url "https://artifacts.consensys.net/public/maven/maven/" }
-}
-
dependencies {
+ implementation project(':infrastructure:io')
+
implementation 'org.apache.tuweni:tuweni-bytes'
implementation 'org.apache.tuweni:tuweni-ssz'
- implementation("tech.pegasys:jc-kzg-4844:develop")
+ implementation 'tech.pegasys:jc-kzg-4844'
implementation 'commons-io:commons-io'
-
- implementation project(":infrastructure:io")
}
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 3673b829a1d..c89584fb9b8 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
@@ -13,119 +13,66 @@
package tech.pegasys.teku.kzg;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.net.URISyntaxException;
import java.net.URL;
-import java.nio.file.Paths;
import java.util.List;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
-import tech.pegasys.teku.infrastructure.io.resource.ResourceLoader;
-import tech.pegasys.teku.kzg.impl.KZG4844;
-import tech.pegasys.teku.kzg.impl.KzgException;
-import tech.pegasys.teku.kzg.impl.ckzg.CkzgLoader;
/**
- * Implements the standard KZG functions needed for the EIP-4844 specification.
- *
- *
This package strives to implement the KZG standard as used in the Eth2 specification and is
- * the entry-point for all KZG operations in Teku. Do not rely on any of the classes used by this
- * one conforming to the specification or standard.
+ * This interface specifies all the KZG functions needed for the EIP-4844 specification and is the
+ * entry-point for all KZG operations in Teku.
*/
-public final class KZG {
- private static final Logger LOG = LogManager.getLogger();
- private static final String FILE_SCHEME = "file";
-
- private static KZG4844 kzgImpl;
-
- static {
- resetKzgImplementation();
- }
-
- public static void setKzgImplementation(final KZG4844 kzgImpl) {
- KZG.kzgImpl = kzgImpl;
- }
-
- public static void resetKzgImplementation() {
- if (CkzgLoader.INSTANCE.isPresent()) {
- kzgImpl = CkzgLoader.INSTANCE.get();
- LOG.info("KZG: loaded CKZG library");
- } else {
- throw new KzgException("Failed to load CKZG library.");
- }
- }
-
- public static KZG4844 getKzgImpl() {
- return kzgImpl;
- }
-
- public static void resetTrustedSetup() {
- try {
- kzgImpl.resetTrustedSetup();
- } catch (final KzgException ex) {
- LOG.trace("Trying to reset KZG trusted setup which is not loaded");
- }
- }
-
- public static void loadTrustedSetup(final URL url) {
- final String filePath;
- try {
- filePath = copyResourceToTempFileIfNeeded(url);
- } catch (final IOException ex) {
- throw new KzgException(
- String.format("Failed to copy trusted setup '%s' to temporary file", url), ex);
- }
- kzgImpl.loadTrustedSetup(filePath);
- }
-
- public static KZGProof computeAggregateKzgProof(final List blobs) {
- return kzgImpl.computeAggregateKzgProof(blobs);
- }
-
- public static boolean verifyAggregateKzgProof(
- final List blobs, final List kzgCommitments, final KZGProof kzgProof) {
- return kzgImpl.verifyAggregateKzgProof(blobs, kzgCommitments, kzgProof);
- }
-
- public static KZGCommitment blobToKzgCommitment(final Bytes blob) {
- return kzgImpl.blobToKzgCommitment(blob);
- }
-
- public static boolean verifyKzgProof(
- final KZGCommitment kzgCommitment,
- final Bytes32 z,
- final Bytes32 y,
- final KZGProof kzgProof) {
- return kzgImpl.verifyKzgProof(kzgCommitment, z, y, kzgProof);
- }
-
- private static String copyResourceToTempFileIfNeeded(final URL url) throws IOException {
- try {
- if (url.toURI().getScheme().equals(FILE_SCHEME)) {
- // Platform-agnostic safe way to get path
- return Paths.get(url.toURI()).toFile().getPath();
- }
- } catch (final URISyntaxException ex) {
- throw new KzgException(String.format("%s is incorrect file path", url), ex);
- }
-
- final Bytes resource =
- ResourceLoader.urlOrFile("application/octet-stream")
- .loadBytes(url.toExternalForm())
- .orElseThrow(() -> new FileNotFoundException("Not found"));
-
- File temp = File.createTempFile("resource", ".tmp");
- temp.deleteOnExit();
-
- try (final FileOutputStream out = new FileOutputStream(temp)) {
- out.write(resource.toArray());
- }
-
- return temp.getAbsolutePath();
- }
+public interface KZG {
+
+ KZG NOOP =
+ new KZG() {
+ @Override
+ public void loadTrustedSetup(final URL trustedSetup) throws KZGException {}
+
+ @Override
+ public void freeTrustedSetup() throws KZGException {}
+
+ @Override
+ public KZGProof computeAggregateKzgProof(final List blobs) throws KZGException {
+ return KZGProof.infinity();
+ }
+
+ @Override
+ public boolean verifyAggregateKzgProof(
+ final List blobs,
+ final List kzgCommitments,
+ final KZGProof kzgProof)
+ throws KZGException {
+ return true;
+ }
+
+ @Override
+ public KZGCommitment blobToKzgCommitment(final Bytes blob) throws KZGException {
+ return KZGCommitment.infinity();
+ }
+
+ @Override
+ public boolean verifyKzgProof(
+ final KZGCommitment kzgCommitment,
+ final Bytes32 z,
+ final Bytes32 y,
+ final KZGProof kzgProof)
+ throws KZGException {
+ return true;
+ }
+ };
+
+ void loadTrustedSetup(URL trustedSetup) throws KZGException;
+
+ void freeTrustedSetup() throws KZGException;
+
+ KZGProof computeAggregateKzgProof(List blobs) throws KZGException;
+
+ boolean verifyAggregateKzgProof(
+ List blobs, List kzgCommitments, KZGProof kzgProof) throws KZGException;
+
+ KZGCommitment blobToKzgCommitment(Bytes blob) throws KZGException;
+
+ boolean verifyKzgProof(KZGCommitment kzgCommitment, Bytes32 z, Bytes32 y, KZGProof kzgProof)
+ throws KZGException;
}
diff --git a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZGCommitment.java b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZGCommitment.java
index a1c41568712..fea3c0fd971 100644
--- a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZGCommitment.java
+++ b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZGCommitment.java
@@ -47,11 +47,14 @@ public static KZGCommitment fromSSZBytes(final Bytes bytes) {
reader -> new KZGCommitment(Bytes48.wrap(reader.readFixedBytes(KZG_COMMITMENT_SIZE))));
}
- public static KZGCommitment fromBytesCompressed(final Bytes48 bytes)
- throws IllegalArgumentException {
+ public static KZGCommitment fromBytesCompressed(final Bytes48 bytes) {
return new KZGCommitment(bytes);
}
+ public static KZGCommitment fromArray(final byte[] bytes) {
+ return fromBytesCompressed(Bytes48.wrap(bytes));
+ }
+
private final Bytes48 bytesCompressed;
public KZGCommitment(final Bytes48 bytesCompressed) {
@@ -71,6 +74,10 @@ public Bytes48 getBytesCompressed() {
return bytesCompressed;
}
+ public byte[] toArray() {
+ return bytesCompressed.toArray();
+ }
+
public String toAbbreviatedString() {
return getBytesCompressed().toUnprefixedHexString().substring(0, 7);
}
@@ -98,7 +105,7 @@ public boolean equals(final Object obj) {
return false;
}
- KZGCommitment other = (KZGCommitment) obj;
+ final KZGCommitment other = (KZGCommitment) obj;
return Objects.equals(this.getBytesCompressed(), other.getBytesCompressed());
}
diff --git a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/impl/KzgException.java b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZGException.java
similarity index 76%
rename from infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/impl/KzgException.java
rename to infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZGException.java
index f5569929f2c..760e6eeb9fc 100644
--- a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/impl/KzgException.java
+++ b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZGException.java
@@ -11,15 +11,15 @@
* specific language governing permissions and limitations under the License.
*/
-package tech.pegasys.teku.kzg.impl;
+package tech.pegasys.teku.kzg;
-public class KzgException extends IllegalArgumentException {
+public class KZGException extends RuntimeException {
- public KzgException(String message) {
+ public KZGException(final String message) {
super(message);
}
- public KzgException(String message, Throwable cause) {
+ public KZGException(final String message, final Throwable cause) {
super(message, cause);
}
}
diff --git a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZGProof.java b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZGProof.java
index 1683acb269d..a9a0310c36b 100644
--- a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZGProof.java
+++ b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/KZGProof.java
@@ -50,6 +50,10 @@ public static KZGProof fromBytesCompressed(final Bytes48 bytes) throws IllegalAr
return new KZGProof(bytes);
}
+ public static KZGProof fromArray(final byte[] bytes) {
+ return fromBytesCompressed(Bytes48.wrap(bytes));
+ }
+
private final Bytes48 bytesCompressed;
public KZGProof(final Bytes48 bytesCompressed) {
@@ -57,9 +61,9 @@ public KZGProof(final Bytes48 bytesCompressed) {
}
/**
- * Returns the SSZ serialization of the compressed form of the commitment
+ * Returns the SSZ serialization of the compressed form of the proof
*
- * @return the serialization of the compressed form of the commitment.
+ * @return the serialization of the compressed form of the proof.
*/
public Bytes toSSZBytes() {
return SSZ.encode(writer -> writer.writeFixedBytes(getBytesCompressed()));
@@ -69,6 +73,10 @@ public Bytes48 getBytesCompressed() {
return bytesCompressed;
}
+ public byte[] toArray() {
+ return bytesCompressed.toArray();
+ }
+
public String toAbbreviatedString() {
return getBytesCompressed().toUnprefixedHexString().substring(0, 7);
}
@@ -96,7 +104,7 @@ public boolean equals(final Object obj) {
return false;
}
- KZGProof other = (KZGProof) obj;
+ final KZGProof other = (KZGProof) obj;
return Objects.equals(this.getBytesCompressed(), other.getBytesCompressed());
}
diff --git a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/ckzg4844/CKZG4844.java b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/ckzg4844/CKZG4844.java
new file mode 100644
index 00000000000..76032f52ef3
--- /dev/null
+++ b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/ckzg4844/CKZG4844.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright ConsenSys Software Inc., 2022
+ *
+ * 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.ckzg4844;
+
+import ethereum.ckzg4844.CKzg4844JNI;
+import java.net.URL;
+import java.util.List;
+import java.util.stream.Stream;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.tuweni.bytes.Bytes;
+import org.apache.tuweni.bytes.Bytes32;
+import tech.pegasys.teku.kzg.KZG;
+import tech.pegasys.teku.kzg.KZGCommitment;
+import tech.pegasys.teku.kzg.KZGException;
+import tech.pegasys.teku.kzg.KZGProof;
+
+/**
+ * Wrapper around jc-kzg-4844
+ *
+ * This class should be a singleton
+ */
+public final class CKZG4844 implements KZG {
+
+ private static final Logger LOG = LogManager.getLogger();
+
+ private static CKZG4844 instance;
+
+ public static synchronized CKZG4844 createOrGetInstance() {
+ if (instance == null) {
+ instance = new CKZG4844();
+ }
+ return instance;
+ }
+
+ private CKZG4844() {
+ try {
+ LOG.debug("Loaded C-KZG-4844 library");
+ } catch (final Exception ex) {
+ throw new KZGException("Failed to load C-KZG-4844 library", ex);
+ }
+ }
+
+ @Override
+ public void loadTrustedSetup(final URL trustedSetup) throws KZGException {
+ try {
+ final String file = CKZG4844Utils.copyTrustedSetupToTempFileIfNeeded(trustedSetup);
+ CKzg4844JNI.loadTrustedSetup(file);
+ LOG.debug("Loaded trusted setup from {}", file);
+ } catch (final Exception ex) {
+ throw new KZGException("Failed to load trusted setup from " + trustedSetup, ex);
+ }
+ }
+
+ @Override
+ public void freeTrustedSetup() throws KZGException {
+ try {
+ CKzg4844JNI.freeTrustedSetup();
+ } catch (final Exception ex) {
+ throw new KZGException("Failed to free trusted setup", ex);
+ }
+ }
+
+ @Override
+ public KZGProof computeAggregateKzgProof(final List blobs) throws KZGException {
+ try {
+ final byte[] blobsBytes = CKZG4844Utils.flattenBytesListToArray(blobs);
+ final byte[] proof = CKzg4844JNI.computeAggregateKzgProof(blobsBytes, blobs.size());
+ return KZGProof.fromArray(proof);
+ } catch (final Exception ex) {
+ throw new KZGException("Failed to compute aggregated KZG proof for blobs", ex);
+ }
+ }
+
+ @Override
+ public boolean verifyAggregateKzgProof(
+ final List blobs, final List kzgCommitments, final KZGProof kzgProof)
+ throws KZGException {
+ try {
+ final byte[] blobsBytes = CKZG4844Utils.flattenBytesListToArray(blobs);
+ final Stream commitmentsBytesStream =
+ kzgCommitments.stream().map(KZGCommitment::getBytesCompressed);
+ final byte[] commitmentsBytes =
+ CKZG4844Utils.flattenBytesStreamToArray(commitmentsBytesStream);
+ return CKzg4844JNI.verifyAggregateKzgProof(
+ blobsBytes, commitmentsBytes, blobs.size(), kzgProof.toArray());
+ } catch (final Exception ex) {
+ throw new KZGException(
+ "Failed to verify blobs and commitments against KZG proof " + kzgProof, ex);
+ }
+ }
+
+ @Override
+ public KZGCommitment blobToKzgCommitment(final Bytes blob) throws KZGException {
+ try {
+ final byte[] commitmentBytes = CKzg4844JNI.blobToKzgCommitment(blob.toArray());
+ return KZGCommitment.fromArray(commitmentBytes);
+ } catch (final Exception ex) {
+ throw new KZGException("Failed to produce KZG commitment from blob", ex);
+ }
+ }
+
+ @Override
+ public boolean verifyKzgProof(
+ final KZGCommitment kzgCommitment, final Bytes32 z, final Bytes32 y, final KZGProof kzgProof)
+ throws KZGException {
+ try {
+ return CKzg4844JNI.verifyKzgProof(
+ kzgCommitment.toArray(), z.toArray(), y.toArray(), kzgProof.toArray());
+ } catch (final Exception ex) {
+ throw new KZGException(
+ String.format(
+ "Failed to verify KZG commitment %s against KZG proof %s", kzgCommitment, kzgProof),
+ ex);
+ }
+ }
+}
diff --git a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/ckzg4844/CKZG4844Utils.java b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/ckzg4844/CKZG4844Utils.java
new file mode 100644
index 00000000000..e627b31079c
--- /dev/null
+++ b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/ckzg4844/CKZG4844Utils.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright ConsenSys Software Inc., 2022
+ *
+ * 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.ckzg4844;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.List;
+import java.util.stream.Stream;
+import org.apache.tuweni.bytes.Bytes;
+import tech.pegasys.teku.infrastructure.io.resource.ResourceLoader;
+
+class CKZG4844Utils {
+
+ private static final String FILE_SCHEME = "file";
+
+ public static byte[] flattenBytesListToArray(final List bytes) {
+ return flattenBytesStreamToArray(bytes.stream());
+ }
+
+ public static byte[] flattenBytesStreamToArray(final Stream bytes) {
+ return bytes.reduce(Bytes::wrap).orElse(Bytes.EMPTY).toArray();
+ }
+
+ public static String copyTrustedSetupToTempFileIfNeeded(final URL trustedSetup)
+ throws IOException {
+ try {
+ if (trustedSetup.toURI().getScheme().equals(FILE_SCHEME)) {
+ // Platform-agnostic safe way to get path
+ return Paths.get(trustedSetup.toURI()).toFile().getPath();
+ }
+ } catch (final URISyntaxException ex) {
+ throw new IllegalArgumentException(trustedSetup + " is incorrect file path", ex);
+ }
+
+ final InputStream resource =
+ ResourceLoader.urlOrFile("application/octet-stream")
+ .load(trustedSetup.toExternalForm())
+ .orElseThrow(() -> new FileNotFoundException(trustedSetup + " is not found"));
+
+ final Path temp = Files.createTempFile("trusted_setup", ".tmp");
+ temp.toFile().deleteOnExit();
+ Files.copy(resource, temp, StandardCopyOption.REPLACE_EXISTING);
+
+ return temp.toFile().getAbsolutePath();
+ }
+}
diff --git a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/impl/KZG4844.java b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/impl/KZG4844.java
deleted file mode 100644
index 32209dd8735..00000000000
--- a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/impl/KZG4844.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright ConsenSys Software Inc., 2022
- *
- * 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.impl;
-
-import java.util.List;
-import org.apache.tuweni.bytes.Bytes;
-import org.apache.tuweni.bytes.Bytes32;
-import tech.pegasys.teku.kzg.KZGCommitment;
-import tech.pegasys.teku.kzg.KZGProof;
-
-public interface KZG4844 {
-
- /**
- * Free the current trusted setup
- *
- * @throws KzgException if no trusted setup has been loaded.
- */
- void resetTrustedSetup() throws KzgException;
-
- /**
- * Loads the trusted setup from a file. Once loaded, the same setup will be used for all the
- * calls. To load a new setup, reset the current one by calling {@link #resetTrustedSetup()} and
- * then load the new one. If no trusted setup has been loaded, all other API calls will throw an
- * exception.
- *
- * @param path a path to a trusted setup file in filesystem
- * @throws KzgException if file not found or arguments from file are incorrect
- */
- void loadTrustedSetup(String path) throws KzgException;
-
- /**
- * Calculates aggregated proof for the given blobs
- *
- * @param blobs Blobs
- * @return the aggregated proof
- */
- KZGProof computeAggregateKzgProof(List blobs) throws KzgException;
-
- /**
- * Verify aggregated proof and commitments for the given blobs
- *
- * @param blobs Blobs
- * @param kzgCommitments KZG Commitments
- * @param kzgProof The proof that needs verifying
- * @return true if the proof is valid and false otherwise
- */
- boolean verifyAggregateKzgProof(
- List blobs, List kzgCommitments, KZGProof kzgProof) throws KzgException;
-
- /**
- * Calculates commitment for a given blob
- *
- * @param blob Blob
- * @return the commitment
- */
- KZGCommitment blobToKzgCommitment(Bytes blob) throws KzgException;
-
- /**
- * Verify the proof by point evaluation for the given commitment
- *
- * @param kzgCommitment KZG Commitment
- * @param z Z
- * @param y Y
- * @param kzgProof The proof that needs verifying
- * @return true if the proof is valid and false otherwise
- */
- boolean verifyKzgProof(KZGCommitment kzgCommitment, Bytes32 z, Bytes32 y, KZGProof kzgProof)
- throws KzgException;
-}
diff --git a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/impl/ckzg/CkzgKZG4844.java b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/impl/ckzg/CkzgKZG4844.java
deleted file mode 100644
index 369521561d7..00000000000
--- a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/impl/ckzg/CkzgKZG4844.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright ConsenSys Software Inc., 2022
- *
- * 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.impl.ckzg;
-
-import ethereum.ckzg4844.CKzg4844JNI;
-import java.util.List;
-import org.apache.tuweni.bytes.Bytes;
-import org.apache.tuweni.bytes.Bytes32;
-import org.apache.tuweni.bytes.Bytes48;
-import tech.pegasys.teku.kzg.KZGCommitment;
-import tech.pegasys.teku.kzg.KZGProof;
-import tech.pegasys.teku.kzg.impl.KZG4844;
-import tech.pegasys.teku.kzg.impl.KzgException;
-
-/**
- * Wrapper around JNI C-KZG library implementing stripped down KZG specification needed for EIP-4844
- */
-public final class CkzgKZG4844 implements KZG4844 {
-
- @Override
- public void resetTrustedSetup() throws KzgException {
- try {
- CKzg4844JNI.freeTrustedSetup();
- } catch (final Exception ex) {
- throw new KzgException("Failed to reset trusted setup", ex);
- }
- }
-
- @Override
- public void loadTrustedSetup(final String path) throws KzgException {
- try {
- CKzg4844JNI.loadTrustedSetup(path);
- } catch (final Exception ex) {
- throw new KzgException(String.format("Failed to load trusted setup: %s", path), ex);
- }
- }
-
- @Override
- public KZGProof computeAggregateKzgProof(final List blobs) throws KzgException {
- try {
- final byte[] result =
- CKzg4844JNI.computeAggregateKzgProof(
- blobs.stream().reduce(Bytes::wrap).orElse(Bytes.EMPTY).toArray(), blobs.size());
- return KZGProof.fromBytesCompressed(Bytes48.wrap(result));
- } catch (final Exception ex) {
- throw new KzgException("Failed to compute aggregated KZG Proof for Blobs", ex);
- }
- }
-
- @Override
- public boolean verifyAggregateKzgProof(
- final List blobs, final List kzgCommitments, final KZGProof kzgProof)
- throws KzgException {
- try {
- return CKzg4844JNI.verifyAggregateKzgProof(
- blobs.stream().reduce(Bytes::wrap).orElse(Bytes.EMPTY).toArray(),
- kzgCommitments.stream()
- .map(kzgCommitment -> (Bytes) kzgCommitment.getBytesCompressed())
- .reduce(Bytes::wrap)
- .orElse(Bytes.EMPTY)
- .toArray(),
- blobs.size(),
- kzgProof.getBytesCompressed().toArray());
- } catch (final Exception ex) {
- throw new KzgException(
- String.format("Failed to verify blobs against KZG Proof %s", kzgProof), ex);
- }
- }
-
- @Override
- public KZGCommitment blobToKzgCommitment(final Bytes blob) throws KzgException {
- try {
- return KZGCommitment.fromBytesCompressed(
- Bytes48.wrap(CKzg4844JNI.blobToKzgCommitment(blob.toArray())));
- } catch (final Exception ex) {
- throw new KzgException("Failed to produce KZG Commitment from Blob", ex);
- }
- }
-
- @Override
- public boolean verifyKzgProof(
- final KZGCommitment kzgCommitment, final Bytes32 z, final Bytes32 y, final KZGProof kzgProof)
- throws KzgException {
- try {
- return CKzg4844JNI.verifyKzgProof(
- kzgCommitment.getBytesCompressed().toArray(),
- z.toArray(),
- y.toArray(),
- kzgProof.getBytesCompressed().toArray());
- } catch (final Exception ex) {
- throw new KzgException(
- String.format(
- "Failed to verify KZG Commitment %s against KZG Proof %s", kzgCommitment, kzgProof),
- ex);
- }
- }
-}
diff --git a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/impl/ckzg/CkzgLoader.java b/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/impl/ckzg/CkzgLoader.java
deleted file mode 100644
index e5d9e4ef319..00000000000
--- a/infrastructure/kzg/src/main/java/tech/pegasys/teku/kzg/impl/ckzg/CkzgLoader.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright ConsenSys Software Inc., 2022
- *
- * 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.impl.ckzg;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.Optional;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import tech.pegasys.teku.kzg.impl.KZG4844;
-
-public final class CkzgLoader {
-
- private static final Logger LOG = LogManager.getLogger();
- public static final Optional INSTANCE = loadCkzg();
-
- private static Optional loadCkzg() {
- try {
- final Class> kzgClass = Class.forName("tech.pegasys.teku.kzg.impl.ckzg.CkzgKZG4844");
- return Optional.of((KZG4844) kzgClass.getDeclaredConstructor().newInstance());
- } catch (final InstantiationException
- | ExceptionInInitializerError
- | InvocationTargetException
- | NoSuchMethodException
- | IllegalAccessException
- | ClassNotFoundException e) {
- LOG.error("Couldn't load native KZG library", e);
- return Optional.empty();
- }
- }
-}
diff --git a/infrastructure/kzg/src/test/java/tech/pegasys/teku/kzg/KZGTest.java b/infrastructure/kzg/src/test/java/tech/pegasys/teku/kzg/KZGTest.java
index 1d3f87429cf..94e74f77c87 100644
--- a/infrastructure/kzg/src/test/java/tech/pegasys/teku/kzg/KZGTest.java
+++ b/infrastructure/kzg/src/test/java/tech/pegasys/teku/kzg/KZGTest.java
@@ -27,11 +27,12 @@
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.Bytes48;
import org.apache.tuweni.units.bigints.UInt256;
-import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
-import tech.pegasys.teku.kzg.impl.KzgException;
+import tech.pegasys.teku.kzg.ckzg4844.CKZG4844;
public final class KZGTest {
+
private static final String MAINNET_TRUSTED_SETUP_TEST = "trusted_setups/test_mainnet.txt";
private static final BigInteger BLS_MODULUS =
new BigInteger(
@@ -40,27 +41,28 @@ public final class KZGTest {
private static final int RANDOM_SEED = 5566;
private static final Random RND = new Random(RANDOM_SEED);
- @BeforeEach
- public void setup() {
- KZG.resetTrustedSetup();
- }
+ private final KZG kzg = CKZG4844.createOrGetInstance();
- @Test
- public void testKzgDoubleResetDoNotThrow() {
- KZG.resetTrustedSetup();
- KZG.resetTrustedSetup();
+ @AfterEach
+ public void cleanUpIfNeeded() {
+ try {
+ kzg.freeTrustedSetup();
+ } catch (final KZGException ex) {
+ // NOOP
+ }
}
@Test
- public void testKzgLoadTrustedSetup() {
+ public void testKzgLoadTrustedSetupTwice_shouldThrowException() {
loadTrustedSetup();
- KZG.resetTrustedSetup();
+ assertThrows(KZGException.class, this::loadTrustedSetup);
}
@Test
- public void testKzgLoadTrustedSetupTwice_shouldThrowException() {
+ public void testKzgFreeTrustedSetupTwice_shouldThrowException() {
loadTrustedSetup();
- assertThrows(KzgException.class, this::loadTrustedSetup);
+ kzg.freeTrustedSetup();
+ assertThrows(KZGException.class, kzg::freeTrustedSetup);
}
@Test
@@ -69,15 +71,15 @@ public void testUsageWithoutLoadedTrustedSetup_shouldThrowException() {
final KZGCommitment kzgCommitment = new KZGCommitment(emptyCommitment);
final KZGProof kzgProof = new KZGProof(emptyCommitment);
assertThrows(
- KzgException.class,
+ KZGException.class,
() ->
- KZG.verifyAggregateKzgProof(
+ kzg.verifyAggregateKzgProof(
Collections.emptyList(), Collections.emptyList(), kzgProof));
- assertThrows(KzgException.class, () -> KZG.blobToKzgCommitment(Bytes.EMPTY));
- assertThrows(KzgException.class, () -> KZG.computeAggregateKzgProof(Collections.emptyList()));
+ assertThrows(KZGException.class, () -> kzg.blobToKzgCommitment(Bytes.EMPTY));
+ assertThrows(KZGException.class, () -> kzg.computeAggregateKzgProof(Collections.emptyList()));
assertThrows(
- KzgException.class,
- () -> KZG.verifyKzgProof(kzgCommitment, Bytes32.ZERO, Bytes32.ZERO, kzgProof));
+ KZGException.class,
+ () -> kzg.verifyKzgProof(kzgCommitment, Bytes32.ZERO, Bytes32.ZERO, kzgProof));
}
@Test
@@ -89,15 +91,15 @@ public void testVerifyKzgProof() {
.mapToObj(__ -> getSampleBlob())
.collect(Collectors.toList());
final List kzgCommitments =
- blobs.stream().map(KZG::blobToKzgCommitment).collect(Collectors.toList());
- final KZGProof kzgProof = KZG.computeAggregateKzgProof(blobs);
- assertThat(KZG.verifyAggregateKzgProof(blobs, kzgCommitments, kzgProof)).isTrue();
+ blobs.stream().map(kzg::blobToKzgCommitment).collect(Collectors.toList());
+ final KZGProof kzgProof = kzg.computeAggregateKzgProof(blobs);
+ assertThat(kzg.verifyAggregateKzgProof(blobs, kzgCommitments, kzgProof)).isTrue();
assertThat(
- KZG.verifyAggregateKzgProof(
+ kzg.verifyAggregateKzgProof(
blobs.subList(0, 2), kzgCommitments.subList(0, 2), kzgProof))
.isFalse();
- final KZGProof invalidProof = KZG.computeAggregateKzgProof(blobs.subList(0, 2));
- assertThat(KZG.verifyAggregateKzgProof(blobs, kzgCommitments, invalidProof)).isFalse();
+ final KZGProof invalidProof = kzg.computeAggregateKzgProof(blobs.subList(0, 2));
+ assertThat(kzg.verifyAggregateKzgProof(blobs, kzgCommitments, invalidProof)).isFalse();
}
@Test
@@ -106,19 +108,19 @@ public void testVerifyPointEvaluationPrecompile() {
final Bytes48 emptyCommitment = Bytes48.rightPad(Bytes.fromHexString("c0"));
final KZGCommitment kzgCommitment = new KZGCommitment(emptyCommitment);
final KZGProof kzgProof = new KZGProof(emptyCommitment);
- assertThat(KZG.verifyKzgProof(kzgCommitment, Bytes32.ZERO, Bytes32.ZERO, kzgProof)).isTrue();
- assertThat(KZG.computeAggregateKzgProof(Collections.emptyList())).isEqualTo(kzgProof);
+ assertThat(kzg.verifyKzgProof(kzgCommitment, Bytes32.ZERO, Bytes32.ZERO, kzgProof)).isTrue();
+ assertThat(kzg.computeAggregateKzgProof(Collections.emptyList())).isEqualTo(kzgProof);
assertThat(
- KZG.blobToKzgCommitment(Bytes.wrap(new byte[FIELD_ELEMENTS_PER_BLOB * Bytes32.SIZE])))
+ kzg.blobToKzgCommitment(Bytes.wrap(new byte[FIELD_ELEMENTS_PER_BLOB * Bytes32.SIZE])))
.isEqualTo(kzgCommitment);
assertThat(
- KZG.verifyAggregateKzgProof(Collections.emptyList(), Collections.emptyList(), kzgProof))
+ kzg.verifyAggregateKzgProof(Collections.emptyList(), Collections.emptyList(), kzgProof))
.isTrue();
}
private void loadTrustedSetup() {
- final URL resourceUrl = KZGTest.class.getResource(MAINNET_TRUSTED_SETUP_TEST);
- KZG.loadTrustedSetup(resourceUrl);
+ final URL trustedSetup = KZGTest.class.getResource(MAINNET_TRUSTED_SETUP_TEST);
+ kzg.loadTrustedSetup(trustedSetup);
}
private BigInteger randomBigIntegerInModulus(final BigInteger modulus, final Random rnd) {
@@ -135,6 +137,6 @@ private Bytes getSampleBlob() {
.mapToObj(__ -> randomBigIntegerInModulus(BLS_MODULUS, RND))
.map(bi -> (Bytes) UInt256.valueOf(bi).toBytes())
.reduce(Bytes::wrap)
- .get();
+ .orElse(Bytes.EMPTY);
}
}