Configuration
ZeroJ has very little configuration, on purpose. At runtime the library reads three zeroj.*
system properties and two ZEROJ_* environment variables. Everything else is ordinary Java: the dependencies you
declare and the objects you construct. This page lists all of it, plus the native-library and
build details you may run into.
Runtime switches
Section titled “Runtime switches”| System property | Environment variable | Default | Dev-only? | Effect |
|---|---|---|---|---|
zeroj.allowInsecureTrustedSetup | ZEROJ_ALLOW_INSECURE_TRUSTED_SETUP | off | Yes | Allows single-party trusted setup |
zeroj.allowLegacyBn254 | ZEROJ_ALLOW_LEGACY_BN254 | off | Yes | Allows the legacy BN254 proving and verification classes |
zeroj.jubjub.debugSecretSubgroupChecks | — | off | Yes (diagnostic) | Adds a subgroup assertion inside the off-circuit Jubjub secret-scalar helpers |
A switch is on when the system property is true (via Boolean.getBoolean), or when the
environment variable equals true (case-insensitive). Either one is enough.
zeroj.allowInsecureTrustedSetup
Section titled “zeroj.allowInsecureTrustedSetup”Groth16 needs a trusted setup whose secret (“toxic waste”) must be destroyed. ZeroJ’s in-process setup generates that secret itself, so whoever runs it could forge proofs. The following refuse to run unless the switch is on:
PowersOfTauBLS381.generate(...)Groth16SetupBLS381.setup(...)andGroth16SetupBLS381.setupToStore(...)Groth16Keys.setupInMemory(...)andGroth16Keys.setupToStore(...), which call the above- the SRS cache, and the legacy BN254 setup classes
PowersOfTauandGroth16Setup(which also need the BN254 switch below)
Without it you get:
java.lang.IllegalStateException: Single-party trusted setup is disabled by default because the generator knows toxic waste and can forge proofs. Production deployments must use imported MPC ceremony artifacts and pinned artifact hashes. For local development or tests only, start the JVM with -Dzeroj.allowInsecureTrustedSetup=true.Turn it on for tests and local experiments only:
java -Dzeroj.allowInsecureTrustedSetup=true -jar my-dev-app.jar# orZEROJ_ALLOW_INSECURE_TRUSTED_SETUP=true ./gradlew runtasks.withType(Test).configureEach { systemProperty 'zeroj.allowInsecureTrustedSetup', 'true' // tests only}Production keys come from a multi-party ceremony and are imported (ZkeyPkStoreImporter,
ZkeyImporterBLS381); importing and proving with them needs no switch. The constants are
TrustedSetupPolicy.ALLOW_INSECURE_TRUSTED_SETUP_PROPERTY and
TrustedSetupPolicy.ALLOW_INSECURE_TRUSTED_SETUP_ENV, and
TrustedSetupPolicy.insecureTrustedSetupEnabled() tells you whether it is on.
zeroj.allowLegacyBn254
Section titled “zeroj.allowLegacyBn254”BN254 is not a Cardano curve. Plutus has no BN254 builtins. ZeroJ keeps a few BN254 classes for
old off-chain experiments, disabled by default and not registered with ServiceLoader. Without the
switch they fail with:
java.lang.IllegalStateException: BN254 is disabled by default because ZeroJ targets Cardano production flows and Cardano only supports BLS12-381 on-chain. For legacy off-chain experiments, start the JVM with -Dzeroj.allowLegacyBn254=true.The constants are LegacyCurvePolicy.ALLOW_LEGACY_BN254_PROPERTY / ALLOW_LEGACY_BN254_ENV, and
LegacyCurvePolicy.legacyBn254Enabled() reports the state. Use BLS12-381 instead.
zeroj.jubjub.debugSecretSubgroupChecks
Section titled “zeroj.jubjub.debugSecretSubgroupChecks”A diagnostic for the off-circuit Jubjub helpers in zeroj-circuit-lib (EdDSAJubjub,
PedersenCommitment). When set, their blinded secret-scalar multiplication first asserts that the
point is in the prime-order subgroup and throws IllegalStateException otherwise. Leave it unset
unless you are debugging those helpers.
Native blst library
Section titled “Native blst library”The default path is pure Java. Native code enters only if you add zeroj-blst or a module that
uses it:
| Where blst is used | Binding | Pulled in by |
|---|---|---|
Groth16 prover MSM (BlstProverBackend) | Java 25 FFM, with a libblst built from source (pinned v0.3.15) and bundled in the zeroj-blst jar | zeroj-crypto-blst |
Pairing for Groth16BLS12381Verifier (off-chain) and BlstBls12381Provider (BBS) | JNI via foundation.icon:blst-java | zeroj-verifier-groth16, zeroj-blst |
How the FFM library is found:
- There is no path setting.
BlstFfmpicks/native/<os>/<arch>/libblst.<ext>from the jar (osislinux,macorwindows;archisamd64oraarch64, withx86_64on macOS), copies it to a temp file namedlibblst-zeroj-*, and loads it. The JVM needs a writable temp directory. - Release builds rebuild the bundled binaries from source for each supported platform. macOS is arm64-only: Intel Macs can’t use the blst prover backend but work normally on the pure-Java default.
- If your platform has no bundled binary, the first blst MSM call fails with an error containing
Bundled libblst not found for this platform. Stay on the pure-Java path. - FFM downcalls need native access enabled:
java --enable-native-access=ALL-UNNAMED -cp … my.AppGraalVM native-image metadata for zeroj-blst ships under
META-INF/native-image/org.zeroj/zeroj-blst/.
External tools: circom and snarkjs
Section titled “External tools: circom and snarkjs”The published ZeroJ libraries never launch external processes. Nothing at runtime looks for
circom or snarkjs. You run those tools yourself, from your PATH, and hand ZeroJ their output
files (.r1cs, .zkey, .wtns, *.json):
# circom 2.x: build it from source as described at https://docs.circom.io/getting-started/installation/npm install -g snarkjs # ZeroJ's interop tests pin snarkjs 0.7.6
circom circuit.circom --r1cs --wasm --sym -p bls12381 # BLS12-381, not the default BN254ZeroJ’s own test suite finds snarkjs through the SNARKJS_BIN environment variable, then a few
common npm install locations, then PATH. See Bring circom & snarkjs circuits.
Gradle flags for contributors
Section titled “Gradle flags for contributors”These only matter when you build the ZeroJ repository itself. Use the Gradle wrapper.
| Command or flag | What it does |
|---|---|
./gradlew build | Default pure-Java build: no Go, Rust, Node.js, WASM toolchain or RocksDB needed |
-PincludeAssurance | Adds the WASM differential oracles (zeroj-bls12381-wasm, zeroj-bbs-wasm; need Rust + the wasm32-unknown-unknown target). Also makes :zeroj-bbs:test run the official BBS vectors through the WASM provider. |
-PincludeBenchmarks | Adds the MPF/JMT RocksDB load and benchmark tools |
-PrequireSnarkjs | Makes the snarkjs interop suites in zeroj-integration-tests fail instead of skip when snarkjs 0.7.6 is missing (sets zeroj.assurance.requireSnarkjs=true) |
./gradlew :zeroj-integration-tests:e2eTest | Runs @Tag("e2e") tests: Yaci DevKit on-chain flows and snarkjs proving. They skip gracefully when Yaci DevKit (localhost:8080) or snarkjs is absent. |
./gradlew verifyDefaultModuleSurface | Checks the stable module graph has no edge into assurance, benchmark or removed modules |
./gradlew -PincludeAssurance :zeroj-bls12381-wasm:test :zeroj-bbs-wasm:test :zeroj-bbs:test./gradlew -PincludeBenchmarks :zeroj-mpf-poseidon-load:build :zeroj-jmt-poseidon-load:build./gradlew -PrequireSnarkjs :zeroj-integration-tests:testInside the repository, every test JVM already runs with --enable-native-access=ALL-UNNAMED and
zeroj.allowInsecureTrustedSetup=true (and zeroj-crypto’s tests also set zeroj.allowLegacyBn254).
That is test scaffolding. Don’t copy it into application run configurations.
Opt-in benchmark tasks such as :zeroj-crypto:benchmark, :zeroj-crypto-blst:blstBench and
:zeroj-circuit-lib:heavyGadgetTest set their own internal zeroj.bench / zeroj.heavy
properties. They are heavy and never part of test.