Installation
ZeroJ is a set of Maven artifacts under the group org.zeroj. A single BOM,
org.zeroj:zeroj-bom-core, keeps the core module versions in sync. This page gets a Gradle or
Maven project ready for the Quickstart.
Prerequisites
Section titled “Prerequisites”| Requirement | Version | Notes |
|---|---|---|
| Java | 25 or newer | GraalVM is recommended if you want native images |
| Build tool | Gradle or Maven | ZeroJ itself builds with Gradle 9.2; use a Gradle version that runs on Java 25 |
The simplest way to install Java 25 is SDKMAN!:
sdk install java 25.0.2-graalsdk use java 25.0.2-graalThe default path of circuit, witness, prove, and verify needs nothing installed beyond a JDK: no native toolchain and no external CLIs. Everything below the “Optional tools” heading is only for specific scenarios.
Add ZeroJ to your build
Section titled “Add ZeroJ to your build”The dependencies below are everything the Quickstart needs: annotation-based circuits, the gadget library, the pure-Java Groth16 prover, and the pure-Java verifier.
plugins { id 'java'}
java { toolchain { languageVersion = JavaLanguageVersion.of(25) }}
repositories { mavenCentral()}
dependencies { // One BOM for all core ZeroJ modules implementation platform('org.zeroj:zeroj-bom-core:0.1.0-pre12') // The BOM must also apply to the annotation processor path annotationProcessor platform('org.zeroj:zeroj-bom-core:0.1.0-pre12')
// Circuits: @ZKCircuit annotations + the generated *Circuit companions implementation 'org.zeroj:zeroj-circuit-annotation-api' annotationProcessor 'org.zeroj:zeroj-circuit-annotation-processor'
// Gadgets (Poseidon, Merkle, comparators, ...) implementation 'org.zeroj:zeroj-circuit-lib'
// Pure-Java Groth16 prover + setup implementation 'org.zeroj:zeroj-crypto'
// Pure-Java verification: verifier, envelopes, snarkjs JSON codec implementation 'org.zeroj:zeroj-verifier-groth16' implementation 'org.zeroj:zeroj-codec'}plugins { java}
java { toolchain { languageVersion = JavaLanguageVersion.of(25) }}
repositories { mavenCentral()}
dependencies { // One BOM for all core ZeroJ modules implementation(platform("org.zeroj:zeroj-bom-core:0.1.0-pre12")) // The BOM must also apply to the annotation processor path annotationProcessor(platform("org.zeroj:zeroj-bom-core:0.1.0-pre12"))
// Circuits: @ZKCircuit annotations + the generated *Circuit companions implementation("org.zeroj:zeroj-circuit-annotation-api") annotationProcessor("org.zeroj:zeroj-circuit-annotation-processor")
// Gadgets (Poseidon, Merkle, comparators, ...) implementation("org.zeroj:zeroj-circuit-lib")
// Pure-Java Groth16 prover + setup implementation("org.zeroj:zeroj-crypto")
// Pure-Java verification: verifier, envelopes, snarkjs JSON codec implementation("org.zeroj:zeroj-verifier-groth16") implementation("org.zeroj:zeroj-codec")}<properties> <maven.compiler.release>25</maven.compiler.release> <zeroj.version>0.1.0-pre12</zeroj.version></properties>
<dependencyManagement> <dependencies> <!-- One BOM for all core ZeroJ modules --> <dependency> <groupId>org.zeroj</groupId> <artifactId>zeroj-bom-core</artifactId> <version>${zeroj.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>
<dependencies> <!-- Circuits: @ZKCircuit annotations --> <dependency> <groupId>org.zeroj</groupId> <artifactId>zeroj-circuit-annotation-api</artifactId> </dependency> <!-- Gadgets (Poseidon, Merkle, comparators, ...) --> <dependency> <groupId>org.zeroj</groupId> <artifactId>zeroj-circuit-lib</artifactId> </dependency> <!-- Pure-Java Groth16 prover + setup --> <dependency> <groupId>org.zeroj</groupId> <artifactId>zeroj-crypto</artifactId> </dependency> <!-- Pure-Java verification: verifier, envelopes, snarkjs JSON codec --> <dependency> <groupId>org.zeroj</groupId> <artifactId>zeroj-verifier-groth16</artifactId> </dependency> <dependency> <groupId>org.zeroj</groupId> <artifactId>zeroj-codec</artifactId> </dependency></dependencies>
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.14.0</version> <configuration> <!-- Generates the *Circuit companion classes --> <annotationProcessorPaths> <path> <groupId>org.zeroj</groupId> <artifactId>zeroj-circuit-annotation-processor</artifactId> <version>${zeroj.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins></build>zeroj-codec is listed explicitly because the verifier doesn’t expose it transitively on your
compile classpath, and the Quickstart uses its SnarkjsJsonCodec class directly.
Which modules do I need?
Section titled “Which modules do I need?”All modules in this table are managed by zeroj-bom-core, so you declare them without a version.
| I want to… | Add… |
|---|---|
Write circuits with @ZKCircuit annotations | zeroj-circuit-annotation-api + zeroj-circuit-annotation-processor (processor path) |
Write circuits with the CircuitSpec or inline DSL | zeroj-circuit-dsl |
| Use Poseidon, Merkle proofs, comparators, Blake2b, SHA-512, Ed25519, CIP-1852 gadgets | zeroj-circuit-lib |
| Run trusted setup and prove with Groth16 (pure Java) | zeroj-crypto |
Speed up Groth16 proving with native blst | zeroj-crypto-blst (opt-in; see below) |
| Verify Groth16 proofs off-chain | zeroj-verifier-groth16 + zeroj-codec |
| Work with proof envelopes and verification results | zeroj-api (comes in transitively with most modules) |
| Route proofs through pluggable verifier backends | zeroj-backend-spi |
| Verify proofs on-chain in a Plutus V3 validator | zeroj-onchain-julc plus JuLC and Cardano Client Lib (see below) |
Contribute to a Groth16 ceremony from your own code (ZkeyContributor) | zeroj-tools (also home of the zeroj-ceremony CLI) |
| Use BLS12-381 field, curve, and pairing primitives directly | zeroj-bls12381 |
For a description of every module, see Modules.
Opt-in modules outside the BOM
Section titled “Opt-in modules outside the BOM”Four published modules are deliberately outside zeroj-bom-core, so they never slip into a
dependency graph by accident. Give each one an explicit version:
dependencies { implementation 'org.zeroj:zeroj-bbs:0.1.0-pre12' // BBS selective-disclosure credentials implementation 'org.zeroj:zeroj-mpf-poseidon:0.1.0-pre12' // Poseidon MPF authenticated state (experimental) implementation 'org.zeroj:zeroj-jmt-poseidon:0.1.0-pre12' // Poseidon JMT authenticated state (experimental) implementation 'org.zeroj:zeroj-verifier-plonk:0.1.0-pre12' // PlonK verification (experimental)}dependencies { implementation("org.zeroj:zeroj-bbs:0.1.0-pre12") // BBS selective-disclosure credentials implementation("org.zeroj:zeroj-mpf-poseidon:0.1.0-pre12") // Poseidon MPF authenticated state (experimental) implementation("org.zeroj:zeroj-jmt-poseidon:0.1.0-pre12") // Poseidon JMT authenticated state (experimental) implementation("org.zeroj:zeroj-verifier-plonk:0.1.0-pre12") // PlonK verification (experimental)}<dependency> <groupId>org.zeroj</groupId> <artifactId>zeroj-bbs</artifactId> <version>${zeroj.version}</version></dependency><!-- same pattern for zeroj-mpf-poseidon, zeroj-jmt-poseidon, zeroj-verifier-plonk -->On-chain verification dependencies
Section titled “On-chain verification dependencies”To compile Plutus V3 validators in Java you also need JuLC,
and to build and submit transactions you need Cardano Client Lib. Both keep their own
com.bloxbean.cardano group and have their own versions. This block mirrors the builds in
zeroj-usecases:
dependencies { implementation 'org.zeroj:zeroj-onchain-julc' // Put ZeroJ's on-chain libraries on the processor path so JuLC can compile validators that use them annotationProcessor 'org.zeroj:zeroj-onchain-julc'
// JuLC: write Plutus V3 validators in Java implementation "com.bloxbean.cardano:julc-stdlib:0.1.0-pre16" annotationProcessor "com.bloxbean.cardano:julc-annotation-processor:0.1.0-pre16" implementation "com.bloxbean.cardano:julc-cardano-client-lib:0.1.0-pre16" runtimeOnly "com.bloxbean.cardano:julc-vm-java:0.1.0-pre16"
// Cardano Client Lib: build and submit transactions implementation "com.bloxbean.cardano:cardano-client-lib:0.8.0-pre5" implementation "com.bloxbean.cardano:cardano-client-backend-blockfrost:0.8.0-pre5"}The zeroj-usecases builds also fork javac with --enable-native-access=ALL-UNNAMED for the JuLC
annotation processor on Java 25:
compileJava { options.fork = true options.forkOptions.jvmArgs = ['--enable-native-access=ALL-UNNAMED']}Verify your proof on Cardano walks through a complete on-chain setup.
Enable the development trusted setup
Section titled “Enable the development trusted setup”Groth16 needs a trusted setup before you can prove anything. For local experiments ZeroJ can run
a quick single-party setup in-process (PowersOfTauBLS381.generate, Groth16Keys.setupInMemory,
Groth16SetupBLS381.setup). That setup is insecure by design: the process knows the secret
randomness (the “toxic waste”) and could forge proofs. So ZeroJ refuses to run it unless you opt
in, and the call fails with an IllegalStateException that explains why.
To opt in for local runs and tests, set the system property zeroj.allowInsecureTrustedSetup
to true or the environment variable ZEROJ_ALLOW_INSECURE_TRUSTED_SETUP=true. In code, the
property name is available as TrustedSetupPolicy.ALLOW_INSECURE_TRUSTED_SETUP_PROPERTY.
plugins { id 'application' // only if you use the run task}
application { mainClass = 'com.example.Main'}
// Dev/test only: allows the insecure single-party setuptasks.named('test') { systemProperty 'zeroj.allowInsecureTrustedSetup', 'true'}tasks.named('run') { systemProperty 'zeroj.allowInsecureTrustedSetup', 'true'}plugins { application // only if you use the run task}
application { mainClass = "com.example.Main"}
// Dev/test only: allows the insecure single-party setuptasks.test { systemProperty("zeroj.allowInsecureTrustedSetup", "true")}tasks.named<JavaExec>("run") { systemProperty("zeroj.allowInsecureTrustedSetup", "true")}<!-- Dev/test only: allows the insecure single-party setup --><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <systemPropertyVariables> <zeroj.allowInsecureTrustedSetup>true</zeroj.allowInsecureTrustedSetup> </systemPropertyVariables> </configuration></plugin>
<!-- For `mvn compile exec:java` --><plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.5.0</version> <configuration> <mainClass>com.example.Main</mainClass> <systemProperties> <systemProperty> <key>zeroj.allowInsecureTrustedSetup</key> <value>true</value> </systemProperty> </systemProperties> </configuration></plugin>java -Dzeroj.allowInsecureTrustedSetup=true -cp app.jar com.example.Main
# or, for any launcher:export ZEROJ_ALLOW_INSECURE_TRUSTED_SETUP=trueSnapshots
Section titled “Snapshots”Snapshot builds are published on demand to the Maven Central snapshot repository. Their
versions embed the short Git commit they were built from, in the form
<next-version>-<short-commit>-SNAPSHOT. Snapshots aren’t published for every commit, so check
the repository for the exact version you want. Snapshots are development builds, so prefer a
release for anything you share with others.
repositories { mavenCentral() maven { url = uri('https://central.sonatype.com/repository/maven-snapshots') mavenContent { snapshotsOnly() } }}repositories { mavenCentral() maven { url = uri("https://central.sonatype.com/repository/maven-snapshots") mavenContent { snapshotsOnly() } }}<repositories> <repository> <id>central-snapshots</id> <url>https://central.sonatype.com/repository/maven-snapshots</url> <releases><enabled>false</enabled></releases> <snapshots><enabled>true</enabled></snapshots> </repository></repositories>Optional tools
Section titled “Optional tools”None of these are needed for the pure-Java path.
| Tool | Version | When you need it |
|---|---|---|
| Yaci DevKit | latest | Running on-chain verification against a local Cardano devnet |
| circom | 2.x | Compiling existing circom circuits you want to prove with ZeroJ |
| snarkjs (Node.js) | 0.7.x (ZeroJ’s interop CI pins 0.7.6) | Interop only: MPC ceremony tooling, or cross-checking ZeroJ proofs with snarkjs |
Install them so they’re on your PATH. ZeroJ’s own interop tests find snarkjs through the
SNARKJS_BIN environment variable, common npm locations, or PATH. See
Bring circom & snarkjs circuits.
Native blst acceleration
Section titled “Native blst acceleration”zeroj-crypto-blst plugs the native blst library into
the Groth16 prover through Java’s Foreign Function & Memory API. It produces bit-identical proofs
and is purely a performance option; since the large-circuit memory work, the pure-Java prover
matches it at large sizes, so measure before you adopt it. The JVM needs native access at
runtime:
java --enable-native-access=ALL-UNNAMED ...See Performance for when it helps.
GraalVM native image
Section titled “GraalVM native image”ZeroJ’s pure-Java path doesn’t call into JNI, so it suits GraalVM. (The blst-java jar that
zeroj-verifier-groth16 brings along is only used by its native verifier; test your image with
the verifier you actually use.) Several
modules ship native-image metadata under META-INF/native-image/org.zeroj/<artifact>/, which
native-image picks up from the classpath automatically: zeroj-api, zeroj-codec,
zeroj-backend-spi, zeroj-verifier-groth16, zeroj-verifier-plonk, zeroj-bls12381,
zeroj-blst, zeroj-bbs, and zeroj-onchain-julc. The zeroj-ceremony CLI is itself
distributed as a native binary.
Build and test your own native image as part of your pipeline. If native-image reports missing
reflection or resource configuration for your application classes, the GraalVM tracing agent is
the usual way to generate it.
Next steps
Section titled “Next steps”- Quickstart: your first proof
- Zero-knowledge in plain English, if the concepts are new
- Configuration reference for all system properties and flags