Java binding - load library based on a preset
This commit is contained in:
parent
78bf846f69
commit
0072efe70a
|
@ -10,7 +10,10 @@ on:
|
|||
|
||||
jobs:
|
||||
test-java-bindings:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
|
@ -19,7 +22,15 @@ jobs:
|
|||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "11"
|
||||
- name: Setup
|
||||
run: cd src && make blst && make all
|
||||
- name: Test
|
||||
run: cd bindings/java && make build test
|
||||
- name: Build blst
|
||||
run: |
|
||||
cd src
|
||||
make blst
|
||||
- name: Build and Test (mainnet preset)
|
||||
run: |
|
||||
cd bindings/java
|
||||
make build test
|
||||
- name: Build and Test (minimal preset)
|
||||
run: |
|
||||
cd bindings/java
|
||||
make PRESET=minimal build test -B
|
||||
|
|
|
@ -4,3 +4,4 @@ bin/
|
|||
.idea/
|
||||
.iml
|
||||
*.o
|
||||
*.log
|
|
@ -1,21 +1,19 @@
|
|||
INCLUDE_DIRS = ../../src ../../blst/bindings
|
||||
|
||||
LIBRARY_FOLDER=src/main/resources/ethereum/ckzg4844/lib
|
||||
|
||||
FIELD_ELEMENTS_PER_BLOB ?= 4096
|
||||
TARGETS=c_kzg_4844_jni.c ../../src/c_kzg_4844.c ../../lib/libblst.a
|
||||
|
||||
CC_FLAGS=
|
||||
OPTIMIZATION_LEVEL=-O2
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
CLANG_EXECUTABLE=clang
|
||||
GRADLE_COMMAND=gradlew
|
||||
CLANG_EXECUTABLE=gcc
|
||||
CLANG_FLAGS=-shared
|
||||
JNI_INCLUDE_FOLDER=win32
|
||||
OS_ARCH=amd64
|
||||
LIBRARY_RESOURCE=ckzg4844jni.dll
|
||||
GRADLE_COMMAND=gradlew
|
||||
else
|
||||
CLANG_EXECUTABLE=clang
|
||||
GRADLE_COMMAND=./gradlew
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
CLANG_FLAGS=-fPIC -shared
|
||||
|
@ -32,18 +30,32 @@ else
|
|||
OS_ARCH=x86_64
|
||||
LIBRARY_RESOURCE=libckzg4844jni.dylib
|
||||
endif
|
||||
GRADLE_COMMAND=./gradlew
|
||||
endif
|
||||
|
||||
PRESET ?= mainnet
|
||||
|
||||
ifeq ($(PRESET),minimal)
|
||||
FIELD_ELEMENTS_PER_BLOB ?= 4
|
||||
else
|
||||
FIELD_ELEMENTS_PER_BLOB ?= 4096
|
||||
endif
|
||||
|
||||
LIBRARY_FOLDER=src/main/resources/ethereum/ckzg4844/lib/${OS_ARCH}/${PRESET}
|
||||
|
||||
ifeq ($(JAVA_HOME),)
|
||||
$(error JAVA_HOME is not set and autodetection failed)
|
||||
endif
|
||||
|
||||
all: build test
|
||||
all: build test benchmark
|
||||
|
||||
build:
|
||||
mkdir -p ${LIBRARY_FOLDER}/${OS_ARCH}
|
||||
${CLANG_EXECUTABLE} ${CC_FLAGS} ${CLANG_FLAGS} -O -Wall ${addprefix -I,${INCLUDE_DIRS}} -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/${JNI_INCLUDE_FOLDER}" -DFIELD_ELEMENTS_PER_BLOB=${FIELD_ELEMENTS_PER_BLOB} -o ${LIBRARY_FOLDER}/${OS_ARCH}/${LIBRARY_RESOURCE} c_kzg_4844_jni.c c_kzg_4844.o ../../lib/libblst.a
|
||||
mkdir -p ${LIBRARY_FOLDER}
|
||||
${CLANG_EXECUTABLE} ${CC_FLAGS} ${CLANG_FLAGS} ${OPTIMIZATION_LEVEL} -Wall -Wno-missing-braces ${addprefix -I,${INCLUDE_DIRS}} -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/${JNI_INCLUDE_FOLDER}" -DFIELD_ELEMENTS_PER_BLOB=${FIELD_ELEMENTS_PER_BLOB} -o ${LIBRARY_FOLDER}/${LIBRARY_RESOURCE} ${TARGETS}
|
||||
|
||||
test:
|
||||
${GRADLE_COMMAND} clean test
|
||||
|
||||
benchmark:
|
||||
${GRADLE_COMMAND} clean jmh
|
||||
|
||||
|
|
|
@ -2,17 +2,33 @@
|
|||
|
||||
## Prerequisites
|
||||
|
||||
* Follow the instructions in the [README.md](../../README.md) to build blst and the C-KZG library.
|
||||
* `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 build blst.
|
||||
* `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/ethereum/ckzg4844/lib` folder with a name according to your OS
|
||||
This will install the 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
|
||||
the [Makefile](./Makefile)
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
make test
|
||||
```
|
||||
|
||||
## Benchmark
|
||||
|
||||
JMH is used for benchmarking.
|
||||
See [CKZG4844JNIBenchmark.java](src/jmh/java/ethereum/ckzg4844/CKZG4844JNIBenchmark.java) for more information.
|
||||
|
||||
```bash
|
||||
make benchmark
|
||||
```
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
plugins {
|
||||
id "application"
|
||||
id "java-test-fixtures"
|
||||
id "me.champeau.jmh" version "0.6.8"
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
@ -13,6 +15,8 @@ dependencies {
|
|||
testImplementation("org.junit.jupiter:junit-jupiter:${junitVersion}")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-params:${junitVersion}")
|
||||
|
||||
testFixturesImplementation("org.apache.tuweni:tuweni-units:2.3.1")
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
|
|
|
@ -22,7 +22,12 @@ void throw_exception(JNIEnv *env, const char *message)
|
|||
(*env)->ThrowNew(env, Exception, message);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_loadTrustedSetup(JNIEnv *env, jclass thisCls, jstring file)
|
||||
JNIEXPORT jint JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_getFieldElementsPerBlob(JNIEnv *env, jclass thisCls)
|
||||
{
|
||||
return (jint)FIELD_ELEMENTS_PER_BLOB;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_loadTrustedSetup(JNIEnv *env, jclass thisCls, jstring file)
|
||||
{
|
||||
if (settings != NULL)
|
||||
{
|
||||
|
@ -61,7 +66,7 @@ JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_loadTrustedSetup(JNIEn
|
|||
(*env)->ReleaseStringUTFChars(env, file, file_native);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_freeTrustedSetup(JNIEnv *env, jclass thisCls)
|
||||
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_freeTrustedSetup(JNIEnv *env, jclass thisCls)
|
||||
{
|
||||
if (settings == NULL)
|
||||
{
|
||||
|
@ -72,7 +77,7 @@ JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_freeTrustedSetup(JNIEn
|
|||
reset_trusted_setup();
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_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 +109,7 @@ JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_computeAggregate
|
|||
return proof;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_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)
|
||||
{
|
||||
|
@ -112,6 +117,13 @@ JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_verifyAggregateKzg
|
|||
return 0;
|
||||
}
|
||||
|
||||
size_t blobs_size = (size_t)(*env)->GetArrayLength(env, blobs);
|
||||
if (blobs_size == 0)
|
||||
{
|
||||
throw_exception(env, "Passing byte array with 0 elements for blobs is not supported.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
jbyte *blobs_native = (*env)->GetByteArrayElements(env, blobs, NULL);
|
||||
uint8_t *commitments_native = (uint8_t *)(*env)->GetByteArrayElements(env, commitments, NULL);
|
||||
uint8_t *proof_native = (uint8_t *)(*env)->GetByteArrayElements(env, proof, NULL);
|
||||
|
@ -163,7 +175,7 @@ JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_verifyAggregateKzg
|
|||
return (jboolean)out;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_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)
|
||||
{
|
||||
|
@ -171,10 +183,17 @@ JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_blobToKzgCommitm
|
|||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *blob_native = (uint8_t *)(*env)->GetByteArrayElements(env, blob, NULL);
|
||||
size_t blob_size = (size_t)(*env)->GetArrayLength(env, blob);
|
||||
if (blob_size == 0)
|
||||
{
|
||||
throw_exception(env, "Passing byte array with 0 elements for a blob is not supported.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jbyte *blob_native = (*env)->GetByteArrayElements(env, blob, NULL);
|
||||
|
||||
KZGCommitment c;
|
||||
blob_to_kzg_commitment(&c, blob_native, settings);
|
||||
blob_to_kzg_commitment(&c, (uint8_t *)blob_native, settings);
|
||||
|
||||
jbyteArray commitment = (*env)->NewByteArray(env, BYTES_PER_COMMITMENT);
|
||||
uint8_t *out = (uint8_t *)(*env)->GetByteArrayElements(env, commitment, 0);
|
||||
|
@ -186,7 +205,7 @@ JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_blobToKzgCommitm
|
|||
return commitment;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_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)
|
||||
{
|
||||
|
|
|
@ -1,54 +1,67 @@
|
|||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class ethereum_ckzg4844_CKzg4844JNI */
|
||||
/* Header for class ethereum_ckzg4844_CKZG4844JNI */
|
||||
|
||||
#ifndef _Included_ethereum_ckzg4844_CKzg4844JNI
|
||||
#define _Included_ethereum_ckzg4844_CKzg4844JNI
|
||||
#ifndef _Included_ethereum_ckzg4844_CKZG4844JNI
|
||||
#define _Included_ethereum_ckzg4844_CKZG4844JNI
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#undef ethereum_ckzg4844_CKZG4844JNI_BYTES_PER_COMMITMENT
|
||||
#define ethereum_ckzg4844_CKZG4844JNI_BYTES_PER_COMMITMENT 48L
|
||||
#undef ethereum_ckzg4844_CKZG4844JNI_BYTES_PER_PROOF
|
||||
#define ethereum_ckzg4844_CKZG4844JNI_BYTES_PER_PROOF 48L
|
||||
#undef ethereum_ckzg4844_CKZG4844JNI_BYTES_PER_FIELD_ELEMENT
|
||||
#define ethereum_ckzg4844_CKZG4844JNI_BYTES_PER_FIELD_ELEMENT 32L
|
||||
/*
|
||||
* Class: ethereum_ckzg4844_CKzg4844JNI
|
||||
* Class: ethereum_ckzg4844_CKZG4844JNI
|
||||
* Method: getFieldElementsPerBlob
|
||||
* Signature: ()I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_getFieldElementsPerBlob(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: ethereum_ckzg4844_CKZG4844JNI
|
||||
* Method: loadTrustedSetup
|
||||
* Signature: (Ljava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_loadTrustedSetup(JNIEnv *, jclass, jstring);
|
||||
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_loadTrustedSetup(JNIEnv *, jclass, jstring);
|
||||
|
||||
/*
|
||||
* Class: ethereum_ckzg4844_CKzg4844JNI
|
||||
* Class: ethereum_ckzg4844_CKZG4844JNI
|
||||
* Method: freeTrustedSetup
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_freeTrustedSetup(JNIEnv *, jclass);
|
||||
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_freeTrustedSetup(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: ethereum_ckzg4844_CKzg4844JNI
|
||||
* Class: ethereum_ckzg4844_CKZG4844JNI
|
||||
* Method: computeAggregateKzgProof
|
||||
* Signature: ([BJ)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_computeAggregateKzgProof(JNIEnv *, jclass, jbyteArray, jlong);
|
||||
JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_computeAggregateKzgProof(JNIEnv *, jclass, jbyteArray, jlong);
|
||||
|
||||
/*
|
||||
* Class: ethereum_ckzg4844_CKzg4844JNI
|
||||
* Class: ethereum_ckzg4844_CKZG4844JNI
|
||||
* Method: verifyAggregateKzgProof
|
||||
* Signature: ([B[BJ[B)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_verifyAggregateKzgProof(JNIEnv *, jclass, jbyteArray, jbyteArray, jlong, jbyteArray);
|
||||
JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_verifyAggregateKzgProof(JNIEnv *, jclass, jbyteArray, jbyteArray, jlong, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: ethereum_ckzg4844_CKzg4844JNI
|
||||
* Class: ethereum_ckzg4844_CKZG4844JNI
|
||||
* Method: blobToKzgCommitment
|
||||
* Signature: ([B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_blobToKzgCommitment(JNIEnv *, jclass, jbyteArray);
|
||||
JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_blobToKzgCommitment(JNIEnv *, jclass, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: ethereum_ckzg4844_CKzg4844JNI
|
||||
* Class: ethereum_ckzg4844_CKZG4844JNI
|
||||
* Method: verifyKzgProof
|
||||
* Signature: ([B[B[B[B)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKzg4844JNI_verifyKzgProof(JNIEnv *, jclass, jbyteArray, jbyteArray, jbyteArray, jbyteArray);
|
||||
JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_verifyKzgProof(JNIEnv *, jclass, jbyteArray, jbyteArray, jbyteArray, jbyteArray);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
package ethereum.ckzg4844;
|
||||
|
||||
import ethereum.ckzg4844.CKZG4844JNI.Preset;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.IntStream;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Level;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Param;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.TearDown;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@Fork(value = 1)
|
||||
@Warmup(iterations = 1, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
|
||||
@Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
@State(Scope.Benchmark)
|
||||
public class CKZG4844JNIBenchmark {
|
||||
|
||||
static {
|
||||
CKZG4844JNI.loadNativeLibrary(Preset.MAINNET);
|
||||
}
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
public static class BlobToKzgCommitmentState {
|
||||
|
||||
private byte[] blob;
|
||||
|
||||
@Setup(Level.Iteration)
|
||||
public void setUp() {
|
||||
blob = TestUtils.createRandomBlob();
|
||||
}
|
||||
}
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
public static class ComputeAndVerifyState {
|
||||
|
||||
@Param({"1", "4", "8", "16"})
|
||||
private int count;
|
||||
|
||||
private byte[] blobs;
|
||||
private byte[] commitments;
|
||||
private byte[] proof;
|
||||
|
||||
@Setup(Level.Iteration)
|
||||
public void setUp() {
|
||||
final byte[][] blobs = new byte[count][];
|
||||
final byte[][] commitments = new byte[count][];
|
||||
IntStream.range(0, count).forEach(i -> {
|
||||
blobs[i] = TestUtils.createRandomBlob();
|
||||
commitments[i] = CKZG4844JNI.blobToKzgCommitment(blobs[i]);
|
||||
});
|
||||
this.blobs = TestUtils.flatten(blobs);
|
||||
this.commitments = TestUtils.flatten(commitments);
|
||||
proof = CKZG4844JNI.computeAggregateKzgProof(TestUtils.flatten(blobs), count);
|
||||
}
|
||||
}
|
||||
|
||||
@Setup
|
||||
public void setUp() {
|
||||
CKZG4844JNI.loadTrustedSetup("../../src/trusted_setup.txt");
|
||||
}
|
||||
|
||||
@TearDown
|
||||
public void tearDown() {
|
||||
CKZG4844JNI.freeTrustedSetup();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public byte[] blobToKzgCommitment(final BlobToKzgCommitmentState state) {
|
||||
return CKZG4844JNI.blobToKzgCommitment(state.blob);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public byte[] computeAggregateKzgProof(final ComputeAndVerifyState state) {
|
||||
return CKZG4844JNI.computeAggregateKzgProof(state.blobs, state.count);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean verifyAggregateKzgProof(final ComputeAndVerifyState state) {
|
||||
return CKZG4844JNI.verifyAggregateKzgProof(state.blobs, state.commitments, state.count,
|
||||
state.proof);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
package ethereum.ckzg4844;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
public class CKZG4844JNI {
|
||||
|
||||
private static final String LIBRARY_NAME = "ckzg4844jni";
|
||||
private static final String PLATFORM_NATIVE_LIBRARY_NAME = System.mapLibraryName(LIBRARY_NAME);
|
||||
|
||||
/**
|
||||
* Loads the appropriate native library based on your platform and the selected {@link Preset}
|
||||
*
|
||||
* @param preset the preset
|
||||
*/
|
||||
public static void loadNativeLibrary(Preset preset) {
|
||||
String libraryResourcePath =
|
||||
"lib/" + System.getProperty("os.arch") + "/" + preset.name().toLowerCase() + "/"
|
||||
+ PLATFORM_NATIVE_LIBRARY_NAME;
|
||||
InputStream libraryResource = CKZG4844JNI.class.getResourceAsStream(libraryResourcePath);
|
||||
if (libraryResource == null) {
|
||||
try {
|
||||
System.loadLibrary(LIBRARY_NAME);
|
||||
} catch (UnsatisfiedLinkError __) {
|
||||
String exceptionMessage = String.format(
|
||||
"Couldn't load native library (%s). It wasn't available at %s or the library path.",
|
||||
LIBRARY_NAME, libraryResourcePath);
|
||||
throw new RuntimeException(exceptionMessage);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Path tempDir = Files.createTempDirectory(LIBRARY_NAME + "@");
|
||||
tempDir.toFile().deleteOnExit();
|
||||
Path tempDll = tempDir.resolve(PLATFORM_NATIVE_LIBRARY_NAME);
|
||||
tempDll.toFile().deleteOnExit();
|
||||
Files.copy(libraryResource, tempDll, StandardCopyOption.REPLACE_EXISTING);
|
||||
libraryResource.close();
|
||||
System.load(tempDll.toString());
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Preset {
|
||||
MAINNET(4096), MINIMAL(4);
|
||||
|
||||
public final int fieldElementsPerBlob;
|
||||
|
||||
Preset(int fieldElementsPerBlob) {
|
||||
this.fieldElementsPerBlob = fieldElementsPerBlob;
|
||||
}
|
||||
}
|
||||
|
||||
public static final BigInteger BLS_MODULUS = new BigInteger(
|
||||
"52435875175126190479447740508185965837690552500527637822603658699938581184513");
|
||||
public static final int BYTES_PER_COMMITMENT = 48;
|
||||
public static final int BYTES_PER_PROOF = 48;
|
||||
public static final int BYTES_PER_FIELD_ELEMENT = 32;
|
||||
|
||||
private CKZG4844JNI() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the bytes per blob based on the output from {@link #getFieldElementsPerBlob()}
|
||||
*
|
||||
* @return the bytes per blob
|
||||
*/
|
||||
public static int getBytesPerBlob() {
|
||||
return getFieldElementsPerBlob() * BYTES_PER_FIELD_ELEMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the compile-time configured FIELD_ELEMENTS_PER_BLOB. The value will be based on the
|
||||
* selected {@link Preset} when loading the native library.
|
||||
*
|
||||
* @return the field elements per blob
|
||||
*/
|
||||
public static native int getFieldElementsPerBlob();
|
||||
|
||||
/**
|
||||
* Loads the trusted setup from a file. Once loaded, the same setup will be used for all the
|
||||
* crypto 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 crypto 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);
|
||||
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
package ethereum.ckzg4844;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
public class CKzg4844JNI {
|
||||
|
||||
private static final String LIBRARY_NAME = "ckzg4844jni";
|
||||
private static final String PLATFORM_NATIVE_LIBRARY_NAME = System.mapLibraryName(LIBRARY_NAME);
|
||||
|
||||
static {
|
||||
InputStream libraryResource = CKzg4844JNI.class.getResourceAsStream(
|
||||
"lib/" + System.getProperty("os.arch") + "/" + PLATFORM_NATIVE_LIBRARY_NAME);
|
||||
if (libraryResource == null) {
|
||||
try {
|
||||
System.loadLibrary(LIBRARY_NAME);
|
||||
} catch (UnsatisfiedLinkError ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Path tmpdir = Files.createTempDirectory(LIBRARY_NAME + "@");
|
||||
tmpdir.toFile().deleteOnExit();
|
||||
Path tmpdll = tmpdir.resolve(PLATFORM_NATIVE_LIBRARY_NAME);
|
||||
tmpdll.toFile().deleteOnExit();
|
||||
Files.copy(libraryResource, tmpdll, StandardCopyOption.REPLACE_EXISTING);
|
||||
libraryResource.close();
|
||||
System.load(tmpdll.toString());
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int BYTES_PER_COMMITMENT = 48;
|
||||
public static int BYTES_PER_PROOF = 48;
|
||||
public static int FIELD_ELEMENTS_PER_BLOB = 4096;
|
||||
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);
|
||||
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
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;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import ethereum.ckzg4844.CKZG4844JNI.Preset;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.IntStream;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class CKZG4844JNITest {
|
||||
|
||||
private static final Preset PRESET;
|
||||
|
||||
static {
|
||||
PRESET = Optional.ofNullable(System.getenv("PRESET")).map(String::toUpperCase)
|
||||
.map(Preset::valueOf).orElse(Preset.MAINNET);
|
||||
CKZG4844JNI.loadNativeLibrary(PRESET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsTheConfiguredFieldElementsPerBlob() {
|
||||
assertEquals(PRESET.fieldElementsPerBlob, CKZG4844JNI.getFieldElementsPerBlob());
|
||||
assertEquals(PRESET.fieldElementsPerBlob * CKZG4844JNI.BYTES_PER_FIELD_ELEMENT,
|
||||
CKZG4844JNI.getBytesPerBlob());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void computesAndVerifiesProofs() {
|
||||
|
||||
loadTrustedSetup();
|
||||
|
||||
final int count = 3;
|
||||
|
||||
final byte[][] blobsArray = new byte[count][];
|
||||
final byte[][] commitmentsArray = new byte[count][];
|
||||
IntStream.range(0, count).forEach(i -> {
|
||||
blobsArray[i] = TestUtils.createRandomBlob();
|
||||
commitmentsArray[i] = CKZG4844JNI.blobToKzgCommitment(blobsArray[i]);
|
||||
});
|
||||
final byte[] blobs = TestUtils.flatten(blobsArray);
|
||||
final byte[] commitments = TestUtils.flatten(commitmentsArray);
|
||||
|
||||
assertEquals(CKZG4844JNI.BYTES_PER_COMMITMENT * count, commitments.length);
|
||||
|
||||
final byte[] proof = CKZG4844JNI.computeAggregateKzgProof(blobs, count);
|
||||
|
||||
assertEquals(CKZG4844JNI.BYTES_PER_PROOF, proof.length);
|
||||
|
||||
assertTrue(CKZG4844JNI.verifyAggregateKzgProof(blobs, commitments, count, proof));
|
||||
|
||||
final byte[] fakeProof = TestUtils.createRandomProof(count);
|
||||
assertFalse(CKZG4844JNI.verifyAggregateKzgProof(blobs, commitments, count, fakeProof));
|
||||
|
||||
final byte[] fakeBlobs = TestUtils.createRandomBlobs(count);
|
||||
assertFalse(CKZG4844JNI.verifyAggregateKzgProof(fakeBlobs, commitments, count, proof));
|
||||
|
||||
final byte[] fakeCommitments = TestUtils.createRandomCommitments(count);
|
||||
assertFalse(CKZG4844JNI.verifyAggregateKzgProof(blobs, fakeCommitments, count, proof));
|
||||
|
||||
CKZG4844JNI.freeTrustedSetup();
|
||||
|
||||
}
|
||||
|
||||
@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();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void passingZeroElementArraysForBlobsDoesNotCauseSegmentationFaultErrors() {
|
||||
|
||||
loadTrustedSetup();
|
||||
|
||||
RuntimeException exception = assertThrows(RuntimeException.class,
|
||||
() -> CKZG4844JNI.blobToKzgCommitment(new byte[0]));
|
||||
|
||||
assertEquals("Passing byte array with 0 elements for a blob is not supported.",
|
||||
exception.getMessage());
|
||||
|
||||
exception = assertThrows(RuntimeException.class,
|
||||
() -> CKZG4844JNI.verifyAggregateKzgProof(new byte[0], TestUtils.createRandomCommitment(),
|
||||
1,
|
||||
TestUtils.createRandomProof(1)));
|
||||
|
||||
assertEquals("Passing byte array with 0 elements for blobs is not supported.",
|
||||
exception.getMessage());
|
||||
|
||||
CKZG4844JNI.freeTrustedSetup();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwsIfMethodIsUsedWithoutLoadingTrustedSetup() {
|
||||
|
||||
final RuntimeException exception = assertThrows(RuntimeException.class,
|
||||
() -> CKZG4844JNI.blobToKzgCommitment(TestUtils.createRandomBlob()));
|
||||
|
||||
assertExceptionIsTrustedSetupIsNotLoaded(exception);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwsIfSetupIsLoadedTwice() {
|
||||
|
||||
loadTrustedSetup();
|
||||
|
||||
final RuntimeException exception = assertThrows(RuntimeException.class, this::loadTrustedSetup);
|
||||
|
||||
assertEquals("Trusted Setup is already loaded. Free it before loading a new one.",
|
||||
exception.getMessage());
|
||||
|
||||
CKZG4844JNI.freeTrustedSetup();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwsIfTryToFreeTrustedSetupWithoutLoadingIt() {
|
||||
|
||||
final RuntimeException exception = assertThrows(RuntimeException.class,
|
||||
CKZG4844JNI::freeTrustedSetup);
|
||||
|
||||
assertExceptionIsTrustedSetupIsNotLoaded(exception);
|
||||
|
||||
}
|
||||
|
||||
private void assertExceptionIsTrustedSetupIsNotLoaded(final RuntimeException exception) {
|
||||
assertEquals("Trusted Setup is not loaded.", exception.getMessage());
|
||||
}
|
||||
|
||||
private void loadTrustedSetup() {
|
||||
if (PRESET.equals(Preset.MINIMAL)) {
|
||||
CKZG4844JNI.loadTrustedSetup("../../src/trusted_setup_4.txt");
|
||||
} else {
|
||||
CKZG4844JNI.loadTrustedSetup("../../src/trusted_setup.txt");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
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;
|
||||
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;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
public class CKzg4844JNITest {
|
||||
|
||||
private final Random random = new Random();
|
||||
|
||||
@Test
|
||||
public void computesAndVerifiesProofs() {
|
||||
|
||||
loadTrustedSetup();
|
||||
|
||||
final byte[] blob = createRandomBlob();
|
||||
final byte[] blob2 = createRandomBlob();
|
||||
|
||||
final byte[] commitment = CKzg4844JNI.blobToKzgCommitment(blob);
|
||||
final byte[] commitment2 = CKzg4844JNI.blobToKzgCommitment(blob2);
|
||||
|
||||
assertEquals(CKzg4844JNI.BYTES_PER_COMMITMENT, commitment.length);
|
||||
assertEquals(CKzg4844JNI.BYTES_PER_COMMITMENT, commitment2.length);
|
||||
|
||||
final byte[] blobs = flatten(blob, blob2);
|
||||
final byte[] commitments = flatten(commitment, commitment2);
|
||||
|
||||
final byte[] proof = CKzg4844JNI.computeAggregateKzgProof(blobs, 2);
|
||||
|
||||
assertEquals(CKzg4844JNI.BYTES_PER_PROOF, proof.length);
|
||||
|
||||
assertTrue(CKzg4844JNI.verifyAggregateKzgProof(blobs, commitments, 2, proof));
|
||||
|
||||
final byte[] fakeProof = createRandomProof(2);
|
||||
assertFalse(CKzg4844JNI.verifyAggregateKzgProof(blobs, commitments, 2, fakeProof));
|
||||
|
||||
CKzg4844JNI.freeTrustedSetup();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifiesPointEvaluationPrecompile() {
|
||||
|
||||
loadTrustedSetup();
|
||||
|
||||
final byte[] commitment = new byte[48];
|
||||
commitment[0] = (byte) 0xc0;
|
||||
final byte[] z = new byte[32];
|
||||
final byte[] y = new byte[32];
|
||||
final byte[] proof = new byte[48];
|
||||
proof[0] = (byte) 0xc0;
|
||||
|
||||
assertTrue(CKzg4844JNI.verifyKzgProof(commitment, z, y, proof));
|
||||
|
||||
CKzg4844JNI.freeTrustedSetup();
|
||||
|
||||
}
|
||||
|
||||
@Disabled("Use for manually testing performance.")
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {1, 10, 100, 1000})
|
||||
public void testPerformance(final int count) {
|
||||
|
||||
loadTrustedSetup();
|
||||
|
||||
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() {
|
||||
|
||||
final RuntimeException exception = assertThrows(RuntimeException.class,
|
||||
() -> CKzg4844JNI.blobToKzgCommitment(createRandomBlob()));
|
||||
|
||||
assertExceptionIsTrustedSetupIsNotLoaded(exception);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwsIfSetupIsLoadedTwice() {
|
||||
|
||||
loadTrustedSetup();
|
||||
|
||||
final RuntimeException exception = assertThrows(RuntimeException.class, this::loadTrustedSetup);
|
||||
|
||||
assertEquals("Trusted Setup is already loaded. Free it before loading a new one.",
|
||||
exception.getMessage());
|
||||
|
||||
CKzg4844JNI.freeTrustedSetup();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void throwsIfTryToFreeTrustedSetupWithoutLoadingIt() {
|
||||
|
||||
final RuntimeException exception = assertThrows(RuntimeException.class,
|
||||
CKzg4844JNI::freeTrustedSetup);
|
||||
|
||||
assertExceptionIsTrustedSetupIsNotLoaded(exception);
|
||||
|
||||
}
|
||||
|
||||
private void assertExceptionIsTrustedSetupIsNotLoaded(final RuntimeException exception) {
|
||||
assertEquals("Trusted Setup is not loaded.", exception.getMessage());
|
||||
}
|
||||
|
||||
private void loadTrustedSetup() {
|
||||
CKzg4844JNI.loadTrustedSetup("../../src/trusted_setup.txt");
|
||||
}
|
||||
|
||||
private byte[] createRandomBlob() {
|
||||
final byte[] blob = new byte[CKzg4844JNI.BYTES_PER_BLOB];
|
||||
random.nextBytes(blob);
|
||||
return blob;
|
||||
}
|
||||
|
||||
private byte[] createRandomBlobs(final int count) {
|
||||
final byte[][] blobs = IntStream.range(0, count).mapToObj(__ -> createRandomBlob())
|
||||
.toArray(byte[][]::new);
|
||||
return flatten(blobs);
|
||||
}
|
||||
|
||||
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);
|
||||
return buffer.array();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package ethereum.ckzg4844;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import java.util.stream.IntStream;
|
||||
import org.apache.tuweni.units.bigints.UInt256;
|
||||
|
||||
public class TestUtils {
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
public static 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);
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
public static byte[] createRandomBlob() {
|
||||
final byte[][] blob = IntStream.range(0, CKZG4844JNI.getFieldElementsPerBlob())
|
||||
.mapToObj(__ -> randomBigIntegerInModulus())
|
||||
.map(UInt256::valueOf)
|
||||
.map(UInt256::toArray)
|
||||
.toArray(byte[][]::new);
|
||||
return flatten(blob);
|
||||
}
|
||||
|
||||
public static byte[] createRandomBlobs(final int count) {
|
||||
final byte[][] blobs = IntStream.range(0, count).mapToObj(__ -> createRandomBlob())
|
||||
.toArray(byte[][]::new);
|
||||
return flatten(blobs);
|
||||
}
|
||||
|
||||
public static byte[] createRandomProof(final int count) {
|
||||
return CKZG4844JNI.computeAggregateKzgProof(createRandomBlobs(count), count);
|
||||
}
|
||||
|
||||
public static byte[] createRandomCommitment() {
|
||||
return CKZG4844JNI.blobToKzgCommitment(createRandomBlob());
|
||||
}
|
||||
|
||||
public static byte[] createRandomCommitments(final int count) {
|
||||
final byte[][] commitments = IntStream.range(0, count).mapToObj(__ -> createRandomCommitment())
|
||||
.toArray(byte[][]::new);
|
||||
return flatten(commitments);
|
||||
}
|
||||
|
||||
private static BigInteger randomBigIntegerInModulus() {
|
||||
final BigInteger attempt = new BigInteger(CKZG4844JNI.BLS_MODULUS.bitLength(), RANDOM);
|
||||
if (attempt.compareTo(CKZG4844JNI.BLS_MODULUS) < 0) {
|
||||
return attempt;
|
||||
}
|
||||
return randomBigIntegerInModulus();
|
||||
}
|
||||
|
||||
}
|
|
@ -25,7 +25,6 @@ blst:
|
|||
cp libblst.a ../lib && \
|
||||
cp bindings/*.h ../inc
|
||||
|
||||
# Make sure c_kzg_4844.o is built and copy it for the NodeJS and Java bindings
|
||||
# Make sure c_kzg_4844.o is built and copy it for the NodeJS bindings
|
||||
lib: c_kzg_4844.o Makefile
|
||||
cp *.o ../bindings/node.js
|
||||
cp *.o ../bindings/java
|
||||
|
|
Loading…
Reference in New Issue