[Java binding] Add test vectors for `verifyKzgProof`

This commit is contained in:
Stefan Bratanov 2022-12-15 09:38:41 +02:00
parent 1768321fc3
commit 17fe743fa3
7 changed files with 176 additions and 27 deletions

View File

@ -1,18 +1,21 @@
# Build Shared Library
# Java binding
## Prerequisites
## Build shared library
### Prerequisites
* Follow the instructions in the [README.md](../../README.md) to build blst.
* `JAVA_HOME` environment variable is set to a JDK with an `include` folder containing a `jni.h`
file.
## Build
### Build
```bash
make build
```
This will install the library in `src/main/resources/ethereum/ckzg4844/lib` with a folder structure
This will install the shared library in `src/main/resources/ethereum/ckzg4844/lib` with a folder
structure
and name according to the preset selected (mainnet or minimal) and your OS.
All variables which could be passed to the `make` command and the defaults can be found in
@ -27,8 +30,14 @@ make test
## Benchmark
JMH is used for benchmarking.
See [CKZG4844JNIBenchmark.java](src/jmh/java/ethereum/ckzg4844/CKZG4844JNIBenchmark.java) for more information.
See [CKZG4844JNIBenchmark.java](src/jmh/java/ethereum/ckzg4844/CKZG4844JNIBenchmark.java) for more
information.
```bash
make benchmark
```
## Library
The library which uses this binding and publishes a package to a public maven repo
is [jc-kzg-4844](https://github.com/ConsenSys/jc-kzg-4844).

View File

@ -21,6 +21,7 @@ dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-params:${junitVersion}")
testFixturesImplementation("org.apache.tuweni:tuweni-units:2.3.1")
testFixturesImplementation("com.fasterxml.jackson.core:jackson-databind:2.14.1")
}

View File

@ -64,6 +64,24 @@ public class CKZG4844JNIBenchmark {
}
}
@State(Scope.Benchmark)
public static class VerifyKzgProofState {
private byte[] commitment;
private byte[] z;
private byte[] y;
private byte[] proof;
@Setup
public void setUp() {
final VerifyKzgProofParameters parameters = TestUtils.getVerifyKzgProofTestVectors().get(2);
commitment = parameters.getCommitment();
z = parameters.getZ();
y = parameters.getY();
proof = parameters.getProof();
}
}
@Setup
public void setUp() {
CKZG4844JNI.loadTrustedSetup("../../src/trusted_setup.txt");
@ -90,4 +108,10 @@ public class CKZG4844JNIBenchmark {
state.proof);
}
@Benchmark
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public boolean verifyKzgProof(final VerifyKzgProofState state) {
return CKZG4844JNI.verifyKzgProof(state.commitment, state.z, state.y, state.proof);
}
}

View File

@ -8,7 +8,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import ethereum.ckzg4844.CKZG4844JNI.Preset;
import java.util.Optional;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class CKZG4844JNITest {
@ -64,22 +67,12 @@ public class CKZG4844JNITest {
}
@Test
public void verifiesPointEvaluationPrecompile() {
loadTrustedSetup();
final byte[] commitment = new byte[CKZG4844JNI.BYTES_PER_COMMITMENT];
commitment[0] = (byte) 0xc0;
final byte[] z = new byte[32];
final byte[] y = new byte[32];
final byte[] proof = new byte[CKZG4844JNI.BYTES_PER_PROOF];
proof[0] = (byte) 0xc0;
assertTrue(CKZG4844JNI.verifyKzgProof(commitment, z, y, proof));
CKZG4844JNI.freeTrustedSetup();
@ParameterizedTest(name = "{index}")
@MethodSource("getVerifyKzgProofTestVectors")
public void testVerifyKzgProof(final VerifyKzgProofParameters parameters) {
assertTrue(
CKZG4844JNI.verifyKzgProof(parameters.getCommitment(), parameters.getZ(), parameters.getY(),
parameters.getProof()));
}
@Test
@ -119,7 +112,8 @@ public class CKZG4844JNITest {
loadTrustedSetup();
final RuntimeException exception = assertThrows(RuntimeException.class, this::loadTrustedSetup);
final RuntimeException exception = assertThrows(RuntimeException.class,
CKZG4844JNITest::loadTrustedSetup);
assertEquals("Trusted Setup is already loaded. Free it before loading a new one.",
exception.getMessage());
@ -142,11 +136,17 @@ public class CKZG4844JNITest {
assertEquals("Trusted Setup is not loaded.", exception.getMessage());
}
private void loadTrustedSetup() {
private static void loadTrustedSetup() {
if (PRESET.equals(Preset.MINIMAL)) {
CKZG4844JNI.loadTrustedSetup("../../src/trusted_setup_4.txt");
} else {
CKZG4844JNI.loadTrustedSetup("../../src/trusted_setup.txt");
}
}
private static Stream<VerifyKzgProofParameters> getVerifyKzgProofTestVectors() {
loadTrustedSetup();
return TestUtils.getVerifyKzgProofTestVectors().stream()
.onClose(CKZG4844JNI::freeTrustedSetup);
}
}

View File

@ -1,15 +1,28 @@
package ethereum.ckzg4844;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
public class TestUtils {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final Random RANDOM = new Random();
public static byte[] flatten(final byte[]... bytes) {
@ -21,8 +34,8 @@ public class TestUtils {
public static byte[] createRandomBlob() {
final byte[][] blob = IntStream.range(0, CKZG4844JNI.getFieldElementsPerBlob())
.mapToObj(__ -> randomBlsFieldElement())
.map(blsFieldElement -> blsFieldElement.toArray(ByteOrder.LITTLE_ENDIAN))
.mapToObj(__ -> randomBLSFieldElement())
.map(fieldElement -> fieldElement.toArray(ByteOrder.LITTLE_ENDIAN))
.toArray(byte[][]::new);
return flatten(blob);
}
@ -47,12 +60,47 @@ public class TestUtils {
return flatten(commitments);
}
private static UInt256 randomBlsFieldElement() {
/**
* Generated using <a
* href="https://github.com/crate-crypto/proto-danksharding-fuzzy-test/">proto-danksharding-fuzzy-test</a>
*/
public static List<VerifyKzgProofParameters> getVerifyKzgProofTestVectors() {
final JsonNode jsonNode;
try (InputStream testVectors = readResource("test-vectors/public_verify_kzg_proof.json")) {
jsonNode = OBJECT_MAPPER.readTree(testVectors);
} catch (final IOException ex) {
throw new UncheckedIOException(ex);
}
final ArrayNode testCases = (ArrayNode) jsonNode.get("TestCases");
final Stream.Builder<VerifyKzgProofParameters> testVectors = Stream.builder();
testVectors.add(VerifyKzgProofParameters.ZERO);
IntStream.range(0,
jsonNode.get("NumTestCases").asInt())
.mapToObj(i -> {
final JsonNode testCase = testCases.get(i);
final Bytes32 z = Bytes32.fromHexString(testCase.get("InputPoint").asText());
final Bytes32 y = Bytes32.fromHexString(testCase.get("ClaimedValue").asText());
final Bytes commitment = Bytes.fromHexString(testCase.get("Commitment").asText(),
CKZG4844JNI.BYTES_PER_COMMITMENT);
final Bytes proof = Bytes.fromHexString(testCase.get("Proof").asText(),
CKZG4844JNI.BYTES_PER_PROOF);
return new VerifyKzgProofParameters(commitment.toArray(), z.toArray(), y.toArray(),
proof.toArray());
})
.forEach(testVectors::add);
return testVectors.build().collect(Collectors.toList());
}
private static UInt256 randomBLSFieldElement() {
final BigInteger attempt = new BigInteger(CKZG4844JNI.BLS_MODULUS.bitLength(), RANDOM);
if (attempt.compareTo(CKZG4844JNI.BLS_MODULUS) < 0) {
return UInt256.valueOf(attempt);
}
return randomBlsFieldElement();
return randomBLSFieldElement();
}
private static InputStream readResource(final String resource) {
return Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
}
}

View File

@ -0,0 +1,46 @@
package ethereum.ckzg4844;
public class VerifyKzgProofParameters {
public static final VerifyKzgProofParameters ZERO;
static {
final byte[] commitment = new byte[CKZG4844JNI.BYTES_PER_COMMITMENT];
commitment[0] = (byte) 0xc0;
final byte[] z = new byte[32];
final byte[] y = new byte[32];
final byte[] proof = new byte[CKZG4844JNI.BYTES_PER_PROOF];
proof[0] = (byte) 0xc0;
ZERO = new VerifyKzgProofParameters(commitment, z, y, proof);
}
private final byte[] commitment;
private final byte[] z;
private final byte[] y;
private final byte[] proof;
public VerifyKzgProofParameters(final byte[] commitment, final byte[] z, final byte[] y,
final byte[] proof) {
this.commitment = commitment;
this.z = z;
this.y = y;
this.proof = proof;
}
public byte[] getCommitment() {
return commitment;
}
public byte[] getZ() {
return z;
}
public byte[] getY() {
return y;
}
public byte[] getProof() {
return proof;
}
}

File diff suppressed because one or more lines are too long