A Java SDK for the Barretenberg UltraHonk proving system, built on the native Barretenberg static library via JNI.
bb-ultrahonk-java-native calls the official Barretenberg C++ engine through a thin JNI shim that statically links libbb-external.a. Proving and verification run at full native speed — the same speed as the bb CLI binary — directly inside your JVM, with no subprocess and no WebAssembly translation layer.
If you do not need native speed, see the sibling project bb-ultrahonk-java-wasm, which runs the same Barretenberg engine in pure Java via Chicory at the cost of significantly slower proving.
- Native performance — full C++ speed for both proving and verification, with the multi-threaded thread pool that ships inside Barretenberg
- JNI bridge — a small C++ shim (~20 MB shared library) statically links the entire Barretenberg engine; no Barretenberg dynamic library required at runtime
- Stable RPC — talks to Barretenberg through the MessagePack
bbapi()protocol used bybb.jsand the official Rust binding - Auto download — the build script downloads the matching Barretenberg static archive from the official Aztec release; the bundled JAR ships only the JNI shared library
- High-level and low-level APIs —
UltraHonkfor everyday prove/verify,BarretenbergNativefor direct access
| Java | 21 or later |
| Operating system | macOS arm64, macOS x86_64, Linux x86_64, Linux arm64, Windows x86_64 |
| Build prerequisites | a C++ toolchain (clang++ or g++), tar, curl (only when building from source) |
| Noir compiler | nargo 1.0.0-beta.19 (only required to compile and execute circuits — not needed at runtime) |
The BN254 Common Reference String is loaded automatically. The SDK first checks the local cache at ~/.bb-crs/ (populated by the standard bb CLI) and otherwise downloads from https://crs.aztec.network/.
Once published, add the dependency to your build:
dependencies {
implementation 'bb.ultrahonk:bb-ultrahonk-java-native:0.1.0'
}Until then, build from source:
git clone https://github.com/wstran/bb-ultrahonk-java-native
cd bb-ultrahonk-java-native
./gradlew buildThe first build downloads barretenberg-static-<platform>.tar.gz from the Aztec GitHub release and compiles a JNI shim against it. The resulting libbb_jni.<ext> is bundled inside the JAR.
import bb.ultrahonk.*;
import java.nio.file.Path;
import java.util.Map;
try (UltraHonk honk = UltraHonk.create()) {
honk.initSrs(1 << 18);
Map<String, Object> result = honk.prove(
Path.of("target/my_circuit.json"),
Path.of("target/my_circuit.gz")
);
byte[][] proof = (byte[][]) result.get("proof");
byte[][] publicInputs = (byte[][]) result.get("public_inputs");
@SuppressWarnings("unchecked")
Map<String, Object> vk = (Map<String, Object>) result.get("vk");
byte[] vkBytes = (byte[]) vk.get("bytes");
boolean valid = honk.verify(vkBytes, publicInputs, proof);
}UltraHonk.create(); // default CRS cache (~/.bb-crs/)
UltraHonk.create(Path crsCacheDir); // custom CRS cache directory
honk.initSrs(int numPoints);
honk.prove(Path circuitJson, Path witnessGz);
honk.proveKeccak(Path circuitJson, Path witnessGz);
honk.prove(byte[] acir, byte[] witness);
honk.verify(byte[] vk, byte[][] publicInputs, byte[][] proof);
honk.verifyKeccak(byte[] vk, byte[][] publicInputs, byte[][] proof);
honk.computeVk(Path circuitJson);BarretenbergNative bb = BarretenbergNative.create();
bb.initSrs(g1Points, numPoints, g2Point);
bb.initSrsFromFiles(g1Path, g2Path, numPoints);
bb.circuitProve(acirBytes, witnessBytes, "poseidon2");
bb.circuitVerify(vkBytes, publicInputs, proof, "poseidon2");
bb.circuitComputeVk(acirBytes, "poseidon2");Measured on macOS arm64 (Apple Silicon), executing the bundled minimal arithmetic circuit (x * x == y) with a 1,024-point SRS:
| Phase | Time |
|---|---|
| Native library load (one-time) | ≈ 86 ms |
| SRS initialization | < 1 ms |
| Prove | ≈ 33 ms |
| Verify | ≈ 4 ms |
| JVM heap usage | ≈ 14 MB |
These numbers reflect the cost of the proving system itself, not the JNI overhead — JNI marshalling adds well under a millisecond per call. Larger circuits scale primarily with the proving phase; verification cost stays roughly constant.
To run the benchmark yourself:
./gradlew test --tests "*.UltraHonkBenchmarkTest"./gradlew downloadNativeLibs # download the Barretenberg static archive
./gradlew buildJniShim # compile the C++ JNI shim
./gradlew build # full build, including the above
./gradlew test # run unit and benchmark tests
./gradlew javadoc # generate API documentationBuild artifacts are written to build/libs/. The JNI shared library is generated under src/main/resources/native/<platform>/ and bundled into the resulting JAR.
The build script auto-detects the host platform and downloads the matching libbb-external.a. To produce a cross-platform JAR you must build the JNI shim on each target OS+architecture and merge the resulting src/main/resources/native/* directories. A typical CI matrix:
| Job | Host runner | Output |
|---|---|---|
| macos-arm64 | macos-14 (Apple Silicon) |
libbb_jni.dylib |
| macos-x86_64 | macos-13 (Intel) |
libbb_jni.dylib |
| linux-x86_64 | ubuntu-22.04 |
libbb_jni.so |
| linux-arm64 | ubuntu-22.04-arm |
libbb_jni.so |
| windows-x86_64 | windows-2022 |
bb_jni.dll |
After all jobs complete, merge the src/main/resources/native/ trees and run ./gradlew jar once more to produce a single fat JAR.
| Component | Value |
|---|---|
| Protocol | UltraHonk |
| Polynomial commitment scheme | KZG |
| Curve | BN254 |
| Oracle hash | Poseidon2 (default), Keccak (EVM target) |
| Circuit format | ACIR |
| Native library | Barretenberg 4.2.0-aztecnr-rc.2 (libbb-external.a) |
bb-ultrahonk-java-native calls into native code via JNI. The trust boundary is the Barretenberg static archive published by Aztec Labs as part of the official aztec-packages GitHub release. Your build pulls this archive directly from github.com/AztecProtocol/aztec-packages over HTTPS using the version tag pinned in build.gradle.
The JNI shim is intentionally minimal: it forwards a single MessagePack-encoded byte buffer to Barretenberg's bbapi() entry point, copies the response back into a Java byte[], and frees the native buffer. There is no shared mutable state between Java and the native code outside of these explicit calls.
The Java surface validates null arguments and out-of-range numeric inputs before they reach the native layer.
bb-ultrahonk-java-native/
├── native/lib/<platform>/ Barretenberg static archives (downloaded, gitignored)
├── src/main/cpp/
│ └── bb_jni.cpp JNI shim source
├── src/main/java/bb/ultrahonk/
│ ├── BarretenbergNative.java Low-level native runtime
│ ├── UltraHonk.java High-level prove / verify API
│ ├── CircuitLoader.java Compiled circuit JSON parser
│ └── CrsLoader.java BN254 SRS loader
├── src/main/resources/
│ └── native/<platform>/ Generated JNI shared libraries (built, gitignored)
├── src/test/java/bb/ultrahonk/
│ ├── BarretenbergNativeTest.java
│ ├── CircuitLoaderTest.java
│ └── UltraHonkBenchmarkTest.java
└── src/test/resources/
├── test_circuit.json Minimal test circuit (x * x == y)
└── test_circuit.gz Witness for test_circuit
This SDK is a thin Java wrapper around the Barretenberg cryptography library developed by Aztec Labs. See the NOTICE file for full attribution.
Licensed under the MIT License. See LICENSE for the full text.
This software statically links Barretenberg, which is licensed under the Apache License 2.0. See NOTICE for required attribution.