Java bindings improvements

This commit is contained in:
Stefan Bratanov 2022-11-25 13:28:03 +00:00
parent 438ebf874b
commit ec7eae4815
6 changed files with 155 additions and 65 deletions

View File

@ -1,7 +1,7 @@
INCLUDE_DIRS = ../../src ../../blst/bindings
ifeq ($(OS),Windows_NT)
CLANG_EXECUTABLE=gcc
CLANG_EXECUTABLE=clang
GRADLE_COMMAND=gradlew
CLANG_FLAGS=-shared
JNI_INCLUDE_FOLDER=win32
@ -37,4 +37,3 @@ build:
test:
${GRADLE_COMMAND} clean test

View File

@ -2,15 +2,15 @@
## Prerequisites
* Follow the instructions in the [README.md](../../README.md) to install blst and build the C-KZG code.
* `JAVA_HOME` environment variable is set to a JDK with an `include` folder containing a jni.h file.
* Follow the instructions in the [README.md](../../README.md) to install blst and build the C-KZG library.
* `JAVA_HOME` environment variable is set to a JDK with an `include` folder containing a `jni.h` file.
## Build
```bash
make build
```
This will install the library in the `src/main/resources/lib` folder according to your OS
This will install the library in the `src/main/resources/lib` folder with a name according to your OS
## Test
```bash

View File

@ -22,7 +22,7 @@ void throw_exception(JNIEnv *env, const char *message)
(*env)->ThrowNew(env, Exception, message);
}
JNIEXPORT void JNICALL Java_CKzg4844JNI_loadTrustedSetup(JNIEnv *env, jclass thisCls, jstring file)
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_loadTrustedSetup(JNIEnv *env, jclass thisCls, jstring file)
{
if (settings != NULL)
{
@ -61,7 +61,7 @@ JNIEXPORT void JNICALL Java_CKzg4844JNI_loadTrustedSetup(JNIEnv *env, jclass thi
(*env)->ReleaseStringUTFChars(env, file, file_native);
}
JNIEXPORT void JNICALL Java_CKzg4844JNI_freeTrustedSetup(JNIEnv *env, jclass thisCls)
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_freeTrustedSetup(JNIEnv *env, jclass thisCls)
{
if (settings == NULL)
{
@ -72,7 +72,7 @@ JNIEXPORT void JNICALL Java_CKzg4844JNI_freeTrustedSetup(JNIEnv *env, jclass thi
reset_trusted_setup();
}
JNIEXPORT jbyteArray JNICALL Java_CKzg4844JNI_computeAggregateKzgProof(JNIEnv *env, jclass thisCls, jbyteArray blobs, jlong count)
JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_computeAggregateKzgProof(JNIEnv *env, jclass thisCls, jbyteArray blobs, jlong count)
{
if (settings == NULL)
{
@ -104,7 +104,7 @@ JNIEXPORT jbyteArray JNICALL Java_CKzg4844JNI_computeAggregateKzgProof(JNIEnv *e
return proof;
}
JNIEXPORT jboolean JNICALL Java_CKzg4844JNI_verifyAggregateKzgProof(JNIEnv *env, jclass thisCls, jbyteArray blobs, jbyteArray commitments, jlong count, jbyteArray proof)
JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_verifyAggregateKzgProof(JNIEnv *env, jclass thisCls, jbyteArray blobs, jbyteArray commitments, jlong count, jbyteArray proof)
{
if (settings == NULL)
{
@ -163,7 +163,7 @@ JNIEXPORT jboolean JNICALL Java_CKzg4844JNI_verifyAggregateKzgProof(JNIEnv *env,
return (jboolean)out;
}
JNIEXPORT jbyteArray JNICALL Java_CKzg4844JNI_blobToKzgCommitment(JNIEnv *env, jclass thisCls, jbyteArray blob)
JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_blobToKzgCommitment(JNIEnv *env, jclass thisCls, jbyteArray blob)
{
if (settings == NULL)
{
@ -186,7 +186,7 @@ JNIEXPORT jbyteArray JNICALL Java_CKzg4844JNI_blobToKzgCommitment(JNIEnv *env, j
return commitment;
}
JNIEXPORT jboolean JNICALL Java_CKzg4844JNI_verifyKzgProof(JNIEnv *env, jclass thisCls, jbyteArray commitment, jbyteArray z, jbyteArray y, jbyteArray proof)
JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_verifyKzgProof(JNIEnv *env, jclass thisCls, jbyteArray commitment, jbyteArray z, jbyteArray y, jbyteArray proof)
{
if (settings == NULL)
{

View File

@ -1,59 +1,54 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class CKzg4844JNI */
/* Header for class ethereum_ckzg4844_CKzg4844JNI */
#ifndef _Included_CKzg4844JNI
#define _Included_CKzg4844JNI
#ifndef _Included_ethereum_ckzg4844_CKzg4844JNI
#define _Included_ethereum_ckzg4844_CKzg4844JNI
#ifdef __cplusplus
extern "C" {
extern "C"
{
#endif
/*
* Class: CKzg4844JNI
* Class: ethereum_ckzg4844_CKzg4844JNI
* Method: loadTrustedSetup
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_CKzg4844JNI_loadTrustedSetup
(JNIEnv *, jclass, jstring);
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_loadTrustedSetup(JNIEnv *, jclass, jstring);
/*
* Class: CKzg4844JNI
* Class: ethereum_ckzg4844_CKzg4844JNI
* Method: freeTrustedSetup
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_CKzg4844JNI_freeTrustedSetup
(JNIEnv *, jclass);
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_freeTrustedSetup(JNIEnv *, jclass);
/*
* Class: CKzg4844JNI
* Class: ethereum_ckzg4844_CKzg4844JNI
* Method: computeAggregateKzgProof
* Signature: ([BJ)[B
*/
JNIEXPORT jbyteArray JNICALL Java_CKzg4844JNI_computeAggregateKzgProof
(JNIEnv *, jclass, jbyteArray, jlong);
JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_computeAggregateKzgProof(JNIEnv *, jclass, jbyteArray, jlong);
/*
* Class: CKzg4844JNI
* Class: ethereum_ckzg4844_CKzg4844JNI
* Method: verifyAggregateKzgProof
* Signature: ([B[BJ[B)Z
*/
JNIEXPORT jboolean JNICALL Java_CKzg4844JNI_verifyAggregateKzgProof
(JNIEnv *, jclass, jbyteArray, jbyteArray, jlong, jbyteArray);
JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_verifyAggregateKzgProof(JNIEnv *, jclass, jbyteArray, jbyteArray, jlong, jbyteArray);
/*
* Class: CKzg4844JNI
* Class: ethereum_ckzg4844_CKzg4844JNI
* Method: blobToKzgCommitment
* Signature: ([B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_CKzg4844JNI_blobToKzgCommitment
(JNIEnv *, jclass, jbyteArray);
JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_blobToKzgCommitment(JNIEnv *, jclass, jbyteArray);
/*
* Class: CKzg4844JNI
* Class: ethereum_ckzg4844_CKzg4844JNI
* Method: verifyKzgProof
* Signature: ([B[B[B[B)Z
*/
JNIEXPORT jboolean JNICALL Java_CKzg4844JNI_verifyKzgProof
(JNIEnv *, jclass, jbyteArray, jbyteArray, jbyteArray, jbyteArray);
JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_verifyKzgProof(JNIEnv *, jclass, jbyteArray, jbyteArray, jbyteArray, jbyteArray);
#ifdef __cplusplus
}

View File

@ -1,3 +1,5 @@
package ethereum.ckzg4844;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
@ -10,7 +12,8 @@ public class CKzg4844JNI {
private static final String PLATFORM_NATIVE_LIBRARY_NAME = System.mapLibraryName(LIBRARY_NAME);
static {
InputStream libraryResource = CKzg4844JNI.class.getResourceAsStream(
InputStream libraryResource = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(
"lib/" + PLATFORM_NATIVE_LIBRARY_NAME);
if (libraryResource == null) {
try {
@ -39,17 +42,60 @@ public class CKzg4844JNI {
public static int BYTES_PER_FIELD_ELEMENT = 32;
public static int BYTES_PER_BLOB = FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT;
/**
* Loads the trusted setup from a file. Once loaded, the same setup will be used for all the
* native calls. To load a new setup, free the current one by calling {@link #freeTrustedSetup()}
* and then load the new one. If no trusted setup has been loaded, all the native calls will throw
* an exception.
*
* @param file A path to a trusted setup file
*/
public static native void loadTrustedSetup(String file);
/**
* Free the current trusted setup. This method will throw an exception if no trusted setup has
* been loaded.
*/
public static native void freeTrustedSetup();
/**
* Calculates aggregated proof for the given blobs
*
* @param blobs blobs as flattened bytes
* @param count the count of the blobs
* @return the aggregated proof
*/
public static native byte[] computeAggregateKzgProof(byte[] blobs, long count);
/**
* Verify aggregated proof and commitments for the given blobs
*
* @param blobs blobs as flattened bytes
* @param commitments commitments as flattened bytes
* @param count the count of the blobs (should be same as the count of the commitments)
* @param proof the proof that needs verifying
* @return true if the proof is valid and false otherwise
*/
public static native boolean verifyAggregateKzgProof(byte[] blobs, byte[] commitments, long count,
byte[] proof);
/**
* Calculates commitment for a given blob
*
* @param blob blob bytes
* @return the commitment
*/
public static native byte[] blobToKzgCommitment(byte[] blob);
/**
* Verify the proof by point evaluation for the given commitment
*
* @param commitment commitment bytes
* @param z Z
* @param y Y
* @param proof the proof that needs verifying
* @return true if the proof is valid and false otherwise
*/
public static native boolean verifyKzgProof(byte[] commitment, byte[] z, byte[] y, byte[] proof);
}

View File

@ -1,3 +1,5 @@
package ethereum.ckzg4844;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
@ -6,6 +8,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Random;
import java.util.stream.IntStream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
public class CKZg4844JNITest {
@ -26,7 +30,6 @@ public class CKZg4844JNITest {
assertEquals(CKzg4844JNI.BYTES_PER_COMMITMENT, commitment.length);
assertEquals(CKzg4844JNI.BYTES_PER_COMMITMENT, commitment2.length);
// flatten blobs and commitments
final byte[] blobs = flatten(blob, blob2);
final byte[] commitments = flatten(commitment, commitment2);
@ -36,7 +39,7 @@ public class CKZg4844JNITest {
assertTrue(CKzg4844JNI.verifyAggregateKzgProof(blobs, commitments, 2, proof));
final byte[] fakeProof = createRandomProof();
final byte[] fakeProof = createRandomProof(2);
assertFalse(CKzg4844JNI.verifyAggregateKzgProof(blobs, commitments, 2, fakeProof));
CKzg4844JNI.freeTrustedSetup();
@ -61,6 +64,37 @@ public class CKZg4844JNITest {
}
@Disabled("Use for manually testing performance.")
@Test
public void testPerformance() {
loadTrustedSetup();
final int count = 100;
final byte[] blobs = createRandomBlobs(count);
final byte[] commitments = getCommitmentsForBlobs(blobs, count);
long startTime = System.currentTimeMillis();
final byte[] proof = CKzg4844JNI.computeAggregateKzgProof(blobs, count);
long endTime = System.currentTimeMillis();
System.out.printf("Computing aggregate proof for %d blobs took %d milliseconds%n", count,
endTime - startTime);
startTime = System.currentTimeMillis();
boolean proofValidity = CKzg4844JNI.verifyAggregateKzgProof(blobs, commitments, count, proof);
endTime = System.currentTimeMillis();
assertTrue(proofValidity);
System.out.printf("Verifying aggregate proof for %d blobs took %d milliseconds%n", count,
endTime - startTime);
CKzg4844JNI.freeTrustedSetup();
}
@Test
public void throwsIfMethodIsUsedWithoutLoadingTrustedSetup() {
@ -82,6 +116,7 @@ public class CKZg4844JNITest {
exception.getMessage());
CKzg4844JNI.freeTrustedSetup();
}
@Test
@ -108,12 +143,27 @@ public class CKZg4844JNITest {
return blob;
}
private byte[] createRandomProof() {
final byte[] blob = createRandomBlob();
return CKzg4844JNI.computeAggregateKzgProof(blob, 1);
private byte[] createRandomBlobs(final int count) {
final byte[][] blobs = IntStream.rangeClosed(1, count).mapToObj(__ -> createRandomBlob())
.toArray(byte[][]::new);
return flatten(blobs);
}
private byte[] flatten(byte[]... bytes) {
private byte[] createRandomProof(final int count) {
return CKzg4844JNI.computeAggregateKzgProof(createRandomBlobs(count), count);
}
private byte[] getCommitmentsForBlobs(final byte[] blobs, final int count) {
final byte[][] commitments = new byte[count][];
IntStream.range(0, count).forEach(i -> {
final byte[] blob = Arrays.copyOfRange(blobs, i * CKzg4844JNI.BYTES_PER_BLOB,
(i + 1) * CKzg4844JNI.BYTES_PER_BLOB);
commitments[i] = CKzg4844JNI.blobToKzgCommitment(blob);
});
return flatten(commitments);
}
private byte[] flatten(final byte[]... bytes) {
final int capacity = Arrays.stream(bytes).mapToInt(b -> b.length).sum();
final ByteBuffer buffer = ByteBuffer.allocate(capacity);
Arrays.stream(bytes).forEach(buffer::put);