From 1dbf2063a21d7d29ed3ec2d0b0c0fa933f1b1349 Mon Sep 17 00:00:00 2001 From: Satya Date: Sun, 17 May 2026 19:58:30 +0800 Subject: [PATCH 1/2] Align docs with latest code change --- README.md | 56 +++++---- docs/alternate-prover-backends.md | 30 ++--- docs/architecture-overview.md | 25 ++-- docs/circuit-dsl-user-guide.md | 52 +++------ docs/getting-started.md | 183 +++++++++++++----------------- docs/plonk-support.md | 90 ++++++++++----- docs/pure-java-prover-guide.md | 42 +++---- 7 files changed, 237 insertions(+), 241 deletions(-) diff --git a/README.md b/README.md index 04db30a..e99aee0 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,36 @@ # ZeroJ +> [!WARNING] +> **Status: Experimental — Research & Learning Project** +> +> This project is generated using AI, with human-assisted design, testing, and verification. +> It is an experimental project created mainly for research and exploration purposes. +> +> **Please do not use this in production.** Expect rough edges, incomplete features, and potential bugs. + Java-first zero-knowledge proof toolkit for Cardano. -ZeroJ lets Java developers **define ZK circuits**, **generate proofs**, **verify** them off-chain, and **execute on-chain verification** on Cardano — all without leaving the Java ecosystem. **Zero external tools required.** +ZeroJ lets Java developers **define ZK circuits**, **generate proofs**, **verify** them off-chain, and **execute on-chain verification** on Cardano. The Java DSL and pure-Java proving path require no native libraries or external CLIs. ## What You Can Do Today ### Define ZK Circuits - **CircuitSpec Java DSL** (recommended) — define circuits as reusable Java classes with `CircuitSpec` - **Inline lambda DSL** — quick prototyping with `CircuitBuilder.define(api -> ...)` -- **circom support** — use existing circom circuits (`.circom` → `.r1cs` + `.wasm`) -- **Standard library** — Poseidon, PoseidonN (variable arity), MiMC, MiMCSponge, Merkle proofs, comparators, binary ops, AliasCheck -- **Multi-backend** — single Java circuit compiles to Groth16 (R1CS), PlonK, or Halo2 +- **circom interop** — use externally compiled circom/snarkjs artifacts (`.r1cs`, `.zkey`, `.wtns`; `.wasm` witness calculation in incubator) +- **Standard library** — Poseidon, PoseidonN, MiMC, MiMCSponge, Merkle, Comparators, Binary, Mux, AliasCheck +- **Multi-backend compilation** — one Java circuit can compile to R1CS for Groth16 or to PlonK ### Generate Proofs - **Pure Java prover** (recommended) — Groth16 + PlonK for BLS12-381 and BN254. Zero native dependencies. GraalVM compatible. -- **gnark FFM** — in-process Groth16/PlonK proving via Go native library (10-50x faster for large circuits) +- **gnark FFM** — optional in-process Groth16/PlonK proving via Go native library - **snarkjs CLI** — external CLI for circom-based circuits -- **circom interop** — import snarkjs `.zkey` files, prove with the pure Java prover +- **snarkjs key import** — import `.zkey` files, prove with the pure Java prover ### Verify ZK Proofs (Pure Java, Zero Native Deps) - **Groth16 BN254** — pure Java verification -- **Groth16 BLS12-381** — pure Java verification (also available via blst for ~1ms perf) +- **Groth16 BLS12-381** — pure Java verification; optional blst-backed native verifier is also available - **PlonK BN254/BLS12-381** — pure Java verification -- **Halo2 IPA** — via Rust FFM bindings (incubator) - Parse snarkjs proof artifacts (`proof.json`, `verification_key.json`, `public.json`) - Pluggable backend SPI — add new proof systems without changing application code @@ -70,8 +77,11 @@ var witness = circuit.calculateWitness(Map.of( // 3. Setup + Prove (pure Java — zero native dependencies) var srs = PowersOfTauBLS381.generate(4); // dev/test only -var setup = Groth16SetupBLS381.setup(constraints, numWires, numPublic, srs.tauScalar()); -var proof = Groth16ProverBLS381.prove(setup.provingKey(), witness, constraints, numWires); +var constraints = r1cs.constraints(); +var setup = Groth16SetupBLS381.setup( + constraints, r1cs.numWires(), r1cs.numPublicInputs(), srs.tauScalar()); +var proof = Groth16ProverBLS381.prove( + setup.provingKey(), witness, constraints, r1cs.numWires()); // 4. Verify off-chain (pure Java) boolean valid = BLS12381Pairing.pairingCheck(...); // Groth16 pairing equation @@ -81,12 +91,12 @@ var script = JulcScriptLoader.load(Groth16BLS12381Verifier.class, vkParams...); // Lock ADA → unlock with ZK proof → Cardano verifies BLS12-381 pairing ``` -For production setup, use an MPC ceremony `.zkey` instead of `PowersOfTauBLS381.generate()`. See the [Pure Java Prover Guide](docs/pure-java-prover-guide.md). +For setup beyond local tests, use an MPC ceremony `.zkey` instead of `PowersOfTauBLS381.generate()`. See the [Pure Java Prover Guide](docs/pure-java-prover-guide.md). -### Alternative: gnark FFM (for maximum speed) +### Alternative: gnark FFM ```java -// Same circuit, but prove via gnark (10-50x faster, requires Go native lib) +// Same circuit, but prove via gnark (requires Go native lib) try (var prover = new GnarkProver()) { var result = prover.groth16FullProve(r1cs, witness, CurveId.BLS12_381); String proofJson = result.proveResponse().proofJson(); @@ -117,8 +127,7 @@ sdk use java 25.0.2-graal | Dependency | Version | Required By | Notes | |------------|---------|-------------|-------| -| **Go** | 1.21+ | `zeroj-prover-gnark` | For gnark native prover (faster) | -| **Rust** | stable | `zeroj-verifier-halo2` (incubator) | For Halo2 verification | +| **Go** | 1.21+ | `zeroj-prover-gnark` | For the optional gnark native prover | | **circom** | 2.x | Circuit compilation (if using circom) | `cargo install circom` | | **snarkjs** | 0.7+ | Proof generation (if using snarkjs) | `npm install -g snarkjs` | @@ -133,7 +142,7 @@ The **pure Java prover and verifier require no optional dependencies**. # Build the core privacy path only ./gradlew :zeroj-bom-core:build :zeroj-verifier-core:build :zeroj-verifier-groth16:build :zeroj-verifier-plonk:build :zeroj-crypto:build :zeroj-onchain-julc:build -# Run all tests (2680+ tests) +# Run all tests ./gradlew test # Run end-to-end on-chain tests (requires Yaci DevKit) @@ -155,7 +164,7 @@ The **pure Java prover and verifier require no optional dependencies**. │ │ Pure Java Prover gnark FFM Prover (Groth16ProverBLS381) (GnarkProver) - Zero native deps 10-50x faster + Zero native deps Optional native backend │ │ └──────────┬──────────────────┘ │ @@ -178,19 +187,19 @@ The **pure Java prover and verifier require no optional dependencies**. | [`zeroj-codec`](zeroj-codec/) | Proof serialization — snarkjs JSON, CBOR, canonical hashing | | [`zeroj-backend-spi`](zeroj-backend-spi/) | Service Provider Interface for verification backends | | [`zeroj-verifier-core`](zeroj-verifier-core/) | Verifier orchestration and backend routing | -| [`zeroj-verifier-groth16`](zeroj-verifier-groth16/) | Groth16 verification — BN254 (pure Java) + BLS12-381 (pure Java / blst) | +| [`zeroj-verifier-groth16`](zeroj-verifier-groth16/) | Groth16 verification — BN254 pure Java + BLS12-381 pure Java/native blst | | [`zeroj-verifier-plonk`](zeroj-verifier-plonk/) | PlonK verification — BN254 + BLS12-381 (pure Java) | | [`zeroj-bls12381`](zeroj-bls12381/) | Pure Java BLS12-381 field, curve, and pairing primitives | | [`zeroj-blst`](zeroj-blst/) | BLS12-381 pairing operations via blst native library | | [`zeroj-crypto`](zeroj-crypto/) | **Pure Java prover** — Montgomery field arithmetic, EC operations, Groth16 + PlonK for BN254 and BLS12-381 | -| [`zeroj-circuit-dsl`](zeroj-circuit-dsl/) | Java Circuit DSL — define circuits with CircuitSpec, compile to R1CS/PlonK/Halo2 | -| [`zeroj-circuit-lib`](zeroj-circuit-lib/) | Circuit standard library — Poseidon, PoseidonN, MiMC, MiMCSponge, Merkle, comparators, AliasCheck | +| [`zeroj-circuit-dsl`](zeroj-circuit-dsl/) | Java Circuit DSL — define circuits with CircuitSpec, compile to R1CS/PlonK | +| [`zeroj-circuit-lib`](zeroj-circuit-lib/) | Circuit standard library — Poseidon, PoseidonN, MiMC, MiMCSponge, Merkle, Comparators, Binary, Mux, AliasCheck | | [`zeroj-prover-spi`](zeroj-prover-spi/) | Minimal prover request/response SPI shared by prover implementations | | [`zeroj-prover-gnark`](zeroj-prover-gnark/) | gnark native prover (Groth16 + PlonK) via FFM | | [`zeroj-patterns`](zeroj-patterns/) | High-level ZK patterns — state transitions, nullifier claims, membership proofs | | [`zeroj-cardano`](zeroj-cardano/) | Cardano anchoring — proof anchor model, metadata encoding | | [`zeroj-ccl`](zeroj-ccl/) | Cardano Client Lib integration — fluent transaction helpers | -| [`zeroj-onchain-julc`](zeroj-onchain-julc/) | Reusable Plutus V3 on-chain verifiers via Julc; Groth16 is production, PlonK is an experimental prototype | +| [`zeroj-onchain-julc`](zeroj-onchain-julc/) | Reusable Plutus V3 on-chain verifiers via Julc; Groth16 is the primary supported path, PlonK is an experimental prototype | #### Mainline Opt-In Modules (`zeroj-bom-all` only) @@ -206,7 +215,7 @@ The **pure Java prover and verifier require no optional dependencies**. |--------|-------------| | [`zeroj-test-vectors`](zeroj-test-vectors/) | Shared test fixtures — pre-generated proofs and VKs | | [`zeroj-examples`](zeroj-examples/) | End-to-end demos: circuit definition to on-chain verification | -| [`zeroj-bom-core`](zeroj-bom-core/) | BOM for the stable v3 core path | +| [`zeroj-bom-core`](zeroj-bom-core/) | BOM for the v3 core path | | [`zeroj-bom-all`](zeroj-bom-all/) | BOM for core plus opt-in and incubator modules | #### Incubator Modules (`incubator/`) @@ -214,7 +223,6 @@ The **pure Java prover and verifier require no optional dependencies**. | Module | Description | |--------|-------------| | [`zeroj-prover-wasm`](incubator/zeroj-prover-wasm/) | Circom witness calculation via GraalVM WebAssembly | -| [`zeroj-verifier-halo2`](incubator/zeroj-verifier-halo2/) | Halo2 IPA verification via Rust FFM (no trusted setup) | ## Dependency (Gradle) @@ -237,7 +245,7 @@ dependencies { // On-chain verification (Cardano Plutus V3) implementation 'com.bloxbean.cardano:zeroj-onchain-julc' - // Optional: gnark FFM prover (faster, requires Go native lib) + // Optional: gnark FFM prover (requires Go native lib) // implementation 'com.bloxbean.cardano:zeroj-prover-gnark' } ``` diff --git a/docs/alternate-prover-backends.md b/docs/alternate-prover-backends.md index 6732d73..3f7b142 100644 --- a/docs/alternate-prover-backends.md +++ b/docs/alternate-prover-backends.md @@ -12,17 +12,17 @@ ZeroJ's **recommended** prover is the [pure Java prover](pure-java-prover-guide.md) (`zeroj-crypto`), which requires zero native dependencies. This document covers the **alternate native backends** for cases where you need: -- Maximum proving speed (~10-100x faster for large circuits) +- Integration with a native proving library - Compatibility with existing gnark/snarkjs workflows -- BN254 curve support (pure Java prover focuses on BLS12-381 for Cardano) +- External ceremony or proof-generation tooling ## Backend Comparison -| Backend | Proof Systems | Curves | Speed | Dependencies | Module | -|---------|-------------|--------|-------|-------------|--------| -| **Pure Java** | Groth16, PlonK | BN254, BLS12-381 | Baseline | None | `zeroj-crypto` | -| **gnark FFM** | Groth16, PlonK | BN254, BLS12-381 | ~10-50x faster | Go native lib | `zeroj-prover-gnark` | -| **snarkjs CLI** | Groth16, PlonK | BN254, BLS12-381 | Slowest | Node.js + snarkjs | (external process) | +| Backend | Proof Systems | Curves | Dependencies | Module | +|---------|-------------|--------|--------------|--------| +| **Pure Java** | Groth16, PlonK | BN254, BLS12-381 | None | `zeroj-crypto` | +| **gnark FFM** | Groth16, PlonK | BN254, BLS12-381 | Go native lib | `zeroj-prover-gnark` | +| **snarkjs CLI** | Groth16, PlonK | BN254, BLS12-381 | Node.js + snarkjs | external process | ## gnark FFM (Foreign Function & Memory) @@ -85,6 +85,7 @@ implemented. ### Gradle ```gradle +implementation platform('com.bloxbean.cardano:zeroj-bom-all:0.1.0') implementation 'com.bloxbean.cardano:zeroj-prover-gnark' ``` @@ -131,7 +132,7 @@ var proof = Groth16ProverBLS381.prove(zkeyData.provingKey(), witness, zkeyData.constraints(), zkeyData.numWires()); ``` -This is the **recommended production pattern**: ceremony via snarkjs, proving via pure Java. +This is the recommended ceremony/import pattern when evaluating a setup beyond local single-party test keys. ## circom Integration @@ -166,10 +167,9 @@ var proof = snarkjs.groth16Prove(zkeyPath, wtnsPath, workDir); | Scenario | Recommended Backend | |----------|-------------------| -| **Cardano on-chain verification** | Pure Java (BLS12-381) | -| **Development / testing** | Pure Java (zero setup, instant) | -| **Large circuits (>10K constraints)** | gnark FFM (10-50x faster) | -| **BN254 proofs (Ethereum)** | gnark FFM | -| **Existing snarkjs workflow** | snarkjs CLI → import .zkey → pure Java prove | -| **Mobile / serverless** | Pure Java (no native deps, GraalVM compatible) | -| **CI/CD pipelines** | Pure Java (no build toolchain needed) | +| **Cardano on-chain verification** | Pure Java BLS12-381 path | +| **Development / testing** | Pure Java local setup | +| **Native proving acceptable** | gnark FFM | +| **Existing snarkjs workflow** | snarkjs CLI for setup/artifacts, then import `.zkey` | +| **Mobile / serverless** | Pure Java path | +| **CI/CD pipelines** | Pure Java path when native build toolchains are undesirable | diff --git a/docs/architecture-overview.md b/docs/architecture-overview.md index 61384cb..9086942 100644 --- a/docs/architecture-overview.md +++ b/docs/architecture-overview.md @@ -25,7 +25,7 @@ structured proof adapter is added. ## Module Organization Modules are organized into core modules, mainline opt-in modules, and incubator -modules. `zeroj-bom-core` covers the stable v3 privacy path. `zeroj-bom-all` +modules. `zeroj-bom-core` covers the v3 core privacy path. `zeroj-bom-all` covers core plus opt-in BBS/WASM and incubator modules. ## Module Dependency Graph @@ -42,9 +42,6 @@ zeroj-api (foundation types) | +-- zeroj-verifier-groth16 (→ zeroj-backend-spi, zeroj-codec, zeroj-bls12381, zeroj-blst) | | | +-- zeroj-verifier-plonk (→ zeroj-backend-spi, zeroj-codec, zeroj-crypto, zeroj-verifier-groth16 for BN254 arithmetic) - | | - | +-- zeroj-verifier-halo2 (→ zeroj-backend-spi, zeroj-codec, Rust FFM) [incubator] - | +-- zeroj-bls12381 (pure Java BLS12-381 field/curve/pairing) | | | +-- zeroj-crypto (→ zeroj-api, zeroj-bls12381) @@ -81,8 +78,8 @@ zeroj-bom-core / zeroj-bom-all (platform modules, no code) ### Layer 1: Core Model (`zeroj-api`) Immutable data types shared across all modules: - `ZkProofEnvelope` -- the proof container -- `ProofSystemId` -- GROTH16, PLONK, FFLONK, HALO2 -- `CurveId` -- BN254, BLS12_381, PALLAS +- `ProofSystemId` -- public docs focus on GROTH16, PLONK, and BBS +- `CurveId` -- public docs focus on BN254 and BLS12_381 - `VerificationResult` -- crypto validity + policy validity - `VerificationMaterial` -- verification key + metadata @@ -90,7 +87,6 @@ Immutable data types shared across all modules: Proof format parsers and serializers: - snarkjs JSON format (proof.json, verification_key.json, public.json) - gnark PlonK/Groth16 format -- Halo2 proof format - CBOR binary format for network transmission - Canonical hashing for deterministic proof identification @@ -105,14 +101,13 @@ Backend abstraction: Concrete implementations: - `zeroj-verifier-groth16` -- Groth16 for BN254 (pure Java) + BLS12-381 (pure Java / blst) - `zeroj-verifier-plonk` -- structured PlonK proof verification for BN254 + BLS12-381 (pure Java) -- `zeroj-verifier-halo2` -- Halo2 IPA via Rust FFM (incubator) - `zeroj-blst` -- Low-level BLS12-381 curve operations ### Layer 5: Circuit Definition (`zeroj-circuit-dsl`, `zeroj-circuit-lib`) Java circuit definition and compilation: - `CircuitBuilder` / `CircuitAPI` -- define circuits in Java - `SignalBuilder` -- OO Signal-style API -- Compiles to R1CS (Groth16), PlonK gates, or Halo2 PLONKish +- Compiles to R1CS (Groth16) or PlonK gates - `zeroj-circuit-lib` -- Poseidon, MiMC, Merkle, comparators, binary ops ### Layer 6: Orchestration (`zeroj-verifier-core`) @@ -122,7 +117,7 @@ Routes verification requests to the correct backend based on proof system and cu Proof generation backends: - `zeroj-crypto` -- pure Java Groth16 and PlonK proving where supported - `zeroj-prover-spi` -- minimal prover-side request/response contract -- `zeroj-prover-gnark` -- production native Groth16/PlonK proving via Go FFM +- `zeroj-prover-gnark` -- optional native Groth16/PlonK proving via Go FFM - `zeroj-prover-wasm` -- Circom witness calculation via GraalVM WASM (incubator) ### Layer 8: High-Level Patterns (`zeroj-patterns`) @@ -147,15 +142,14 @@ Reusable Plutus V3 spending validators compiled via Julc: | Proof System | Curve | Backend | Implementation | Native Deps | |-------------|-------|---------|----------------|-------------| | Groth16 | BLS12-381 | Pure Java | `zeroj-verifier-groth16` | None | -| Groth16 | BLS12-381 | blst native (FFM) | `zeroj-verifier-groth16` | blst (~1ms) | +| Groth16 | BLS12-381 | blst native (FFM) | `zeroj-verifier-groth16` | blst | | Groth16 | BN254 | Pure Java | `zeroj-verifier-groth16` | None | | PlonK | BLS12-381 | Pure Java | `zeroj-verifier-plonk` | None | | PlonK | BN254 | Pure Java | `zeroj-verifier-plonk` | None | -| Halo2 IPA | Pallas | Rust FFM | `zeroj-verifier-halo2` (incubator) | Rust binary | - BLS12-381 pure Java verifier uses field arithmetic validated against gnark - BN254 uses pure Java field arithmetic, validated against Ethereum EIP-196/197 test vectors -- blst option available for BLS12-381 when maximum performance is needed (~1ms vs ~100ms) +- blst option available for BLS12-381 when a native verifier backend is acceptable ## On-Chain Verification @@ -183,13 +177,10 @@ Best-effort compatibility from the start; hardened in later milestones. | ADR | Decision | |-----|----------| | [0001](adr/0001-verifier-first-architecture.md) | Verifier-first, no prover in core | -| [0002](adr/0002-external-proof-submission-first-class.md) | External proof submission as primary flow | | [0003](adr/0003-pure-java-mvp.md) | Hybrid: blst for BLS12-381, pure Java for BN254 | -| [0004](adr/0004-off-chain-cardano-anchoring-first.md) | Off-chain Cardano anchoring first | -| [0005](adr/0005-plugin-provability-contract.md) | Explicit plugin provability contract | | [0006](adr/0006-separation-of-crypto-and-policy-verification.md) | Separate crypto and policy verification | | [0007](adr/0007-module-structure-and-boundaries.md) | Multi-module structure | | [0008](adr/0008-plonk-support-via-gnark.md) | PlonK support via gnark | -| [0009](adr/0009-halo2-support-strategy.md) | Halo2 support strategy | | [0010](adr/0010-java-circuit-dsl.md) | Java Circuit DSL | +| [0012](adr/0012-pure-java-provers-groth16-plonk.md) | Pure Java Groth16 and PlonK provers | | [0020](adr/0020-module-cleanup-and-core-restructure.md) | Module cleanup and core restructure | diff --git a/docs/circuit-dsl-user-guide.md b/docs/circuit-dsl-user-guide.md index 01e56b4..019e942 100644 --- a/docs/circuit-dsl-user-guide.md +++ b/docs/circuit-dsl-user-guide.md @@ -22,15 +22,14 @@ ## Overview -The ZeroJ Circuit DSL lets you define ZK arithmetic circuits in Java and compile them to **three proof systems** from a single definition: +The ZeroJ Circuit DSL lets you define ZK arithmetic circuits in Java and compile them to the main ZeroJ proof-system shapes from a single definition: | Backend | Proof System | Prover | Use Case | |---------|-------------|--------|----------| | R1CS | Groth16 | **Pure Java**, gnark FFM | Smallest proofs, cheapest on-chain verification | | PlonK | PlonK | **Pure Java**, gnark FFM | Universal setup, no per-circuit ceremony | -| Halo2 | Halo2 (IPA/KZG) | Halo2 Rust FFM | No trusted setup (IPA), recursive proofs | -No circom, no Go, no Rust needed. Just Java. +No circom, Go, or Rust is needed for the Java DSL plus pure-Java proving path. ## Two Ways to Define Circuits @@ -68,7 +67,7 @@ var circuit = CircuitBuilder.create("multiplier") }); ``` -Both produce identical R1CS constraints. **Use CircuitSpec for production code** — it's testable, reusable, and self-documenting. +Both produce identical R1CS constraints. **Use CircuitSpec for reusable application circuits** — it is testable, reusable, and self-documenting. ## Quick Start @@ -83,10 +82,9 @@ var witness = circuit.calculateWitness(Map.of( "y", List.of(BigInteger.valueOf(11)) ), CurveId.BLS12_381); -// 3. Compile to any proof system +// 3. Compile to the supported mainline proof-system shapes var r1cs = circuit.compileR1CS(CurveId.BLS12_381); // Groth16 var plonk = circuit.compilePlonK(CurveId.BLS12_381); // PlonK -var halo2 = circuit.compileHalo2(CurveId.PALLAS); // Halo2 // 4. Prove with pure Java prover (see pure-java-prover-guide.md) var proof = Groth16ProverBLS381.prove(pk, witness, constraints, numWires); @@ -127,7 +125,7 @@ api.assertInRange(v, 8); // 0 ≤ v < 256 (8-bit range) ## Writing CircuitSpec Circuits (Recommended) -A `CircuitSpec` is a Java class that defines a ZK circuit. This is the **preferred pattern** for production circuits because it's reusable, testable, and self-documenting. +A `CircuitSpec` is a Java class that defines a ZK circuit. This is the **preferred pattern** for reusable circuits because it is testable, reusable, and self-documenting. ### Anatomy of a CircuitSpec @@ -302,10 +300,8 @@ System.out.println("Public inputs: " + r1cs.numPublicInputs()); byte[] r1csBytes = R1CSSerializer.serialize(r1cs); Files.write(Path.of("circuit.r1cs"), r1csBytes); -// Calculate and export witness +// Calculate witness for Java proving BigInteger[] witness = circuit.calculateWitness(inputs, CurveId.BLS12_381); -byte[] wtnsBytes = WitnessExporter.toWtns(witness, r1cs.prime(), r1cs.fieldConfig().n32()); -Files.write(Path.of("witness.wtns"), wtnsBytes); ``` ## CircuitAPI Reference @@ -641,15 +637,13 @@ var r1cs = circuit.compileR1CS(CurveId.BN254); byte[] r1csBytes = R1CSSerializer.serialize(r1cs); Files.write(Path.of("circuit.r1cs"), r1csBytes); -// Serialize witness to .wtns -byte[] wtnsBytes = WitnessExporter.toWtns(witness, r1cs.prime(), r1cs.fieldConfig().n32()); +// Witness values are returned as BigInteger[] for Java proving. ``` Properties: - **Additions are free** — absorbed into linear combinations - Only multiplications create constraints -- Smallest proofs (~128 bytes for BN254) -- Fastest verification (~3ms) +- Compact proofs compared with universal-setup systems - Requires per-circuit trusted setup ### PlonK @@ -664,29 +658,12 @@ Properties: - Universal setup (one ceremony for all circuits) - Slightly larger proofs than Groth16 -### Halo2 (PLONKish) - -```java -var halo2 = circuit.compileHalo2(CurveId.PALLAS); - -// Serialize to JSON (intermediate format for Rust FFM prover) -String json = halo2.toJson(witness); -``` - -Properties: -- Same gate model as PlonK (compatible) -- 3 advice columns (a, b, c) + 5 fixed selector columns -- Permutation cycles for copy constraints -- Supports Pallas/Vesta (IPA, no setup) and BLS12-381 (KZG) -- Future: custom gates, lookup tables - ## Curves | Curve | Proof Systems | On-chain? | Note | |-------|--------------|-----------|------| | BN254 | Groth16, PlonK | No (no Plutus builtins) | circom/snarkjs ecosystem | | BLS12-381 | Groth16, PlonK | Groth16: **Yes**; PlonK: prototype | Cardano-native BLS builtins; PlonK KZG pairing check is still deferred on-chain | -| Pallas | Halo2 IPA | No | No trusted setup, recursive proofs | ## Witness Calculation @@ -742,8 +719,6 @@ Java CircuitSpec / CircuitBuilder DSL ├──▶ compilePlonK() ──▶ PlonKProverBLS381 (pure Java) ──▶ proof │ └──▶ gnark FFM ──▶ proof │ - ├──▶ compileHalo2() ──▶ Halo2 Rust FFM ──▶ proof - │ └──▶ calculateWitness() ──▶ BigInteger[] (pure Java) Verification (pure Java, zero native deps): @@ -773,14 +748,19 @@ See the [Pure Java Prover Guide](pure-java-prover-guide.md) for the complete pip ## Module Dependencies ```gradle +implementation platform('com.bloxbean.cardano:zeroj-bom-core:0.1.0') + // Circuit DSL (define and compile circuits) implementation 'com.bloxbean.cardano:zeroj-circuit-dsl' -// Standard library (Poseidon, Merkle, comparators) +// Standard library (Poseidon, MiMC, Merkle, Comparators, Binary, Mux, AliasCheck) implementation 'com.bloxbean.cardano:zeroj-circuit-lib' -// Provers (choose based on your proof system) -implementation 'com.bloxbean.cardano:zeroj-prover-gnark' // gnark (Groth16 + PlonK) +// Pure Java prover +implementation 'com.bloxbean.cardano:zeroj-crypto' + +// Optional native prover +// implementation 'com.bloxbean.cardano:zeroj-prover-gnark' // gnark (Groth16 + PlonK) // Verifiers (pure Java, zero native deps) implementation 'com.bloxbean.cardano:zeroj-verifier-groth16' // Groth16 (BN254 + BLS12-381) diff --git a/docs/getting-started.md b/docs/getting-started.md index 5ace823..d6e1d41 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -5,7 +5,7 @@ - [Prerequisites](#prerequisites) - [Step 1: Define the Circuit (Java DSL)](#step-1-define-the-circuit-java-dsl) - [Step 2: Compile and Calculate Witness (Pure Java)](#step-2-compile-and-calculate-witness-pure-java) -- [Step 3: Generate Proof (gnark FFM)](#step-3-generate-proof-gnark-ffm) +- [Step 3: Generate Proof (Pure Java)](#step-3-generate-proof-pure-java) - [Step 4: Verify Off-Chain (Pure Java)](#step-4-verify-off-chain-pure-java) - [Step 5: Deploy On-Chain Verifier (Julc / Plutus V3)](#step-5-deploy-on-chain-verifier-julc--plutus-v3) - [Step 6: Lock Funds with Public Inputs as Datum](#step-6-lock-funds-with-public-inputs-as-datum) @@ -20,7 +20,7 @@ This guide walks through the complete ZeroJ flow: define a ZK circuit in Java, generate a proof, verify it off-chain, and execute on-chain verification on Cardano via Yaci DevKit. -We'll build a **sealed-bid auction** where a bidder proves their bid exceeds a reserve price without revealing the actual bid amount. +We'll build a **private multiplier** circuit where the prover shows they know a secret factor `b` such that `a * b = c`, while `a` and `c` remain public. This small circuit matches the reusable Groth16 on-chain verifier, which currently accepts two public inputs. ## Prerequisites @@ -31,7 +31,7 @@ We'll build a **sealed-bid auction** where a bidder proves their bid exceeds a r ### Building the gnark native prover (optional) -The gnark native library is only needed if you want to generate proofs using the in-process gnark FFM prover (Steps 3+). Circuit definition, R1CS compilation, witness calculation, and off-chain verification are all **pure Java** with no native dependencies. +The gnark native library is only needed if you want to generate proofs using the optional in-process gnark FFM prover. The main flow in this guide uses the pure Java prover. If you want to use the gnark prover, you need **Go 1.21+** to build the native library once: @@ -46,134 +46,115 @@ yaci-cli:default> create-node -o --start ## Step 1: Define the Circuit (Java DSL) -The circuit proves: "I know a bid amount and salt such that `MiMC(bidAmount, salt) == commitment` and `bidAmount >= reservePrice`." +The circuit proves: "I know a secret `b` such that `a * b == c`." ```java -// SealedBidCircuit.java -public class SealedBidCircuit implements CircuitSpec { - - public static CircuitBuilder build() { - return CircuitBuilder.create("sealed-bid", new SealedBidCircuit()); +// PrivateMultiplierCircuit.java +public class PrivateMultiplierCircuit implements CircuitSpec { + @Override + public void define(SignalBuilder c) { + Signal a = c.publicInput("a"); + Signal b = c.privateInput("b"); + Signal cOut = c.publicOutput("c"); + c.assertEqual(a.mul(b), cOut); } - @Override - public void define(CircuitBuilder builder) { - builder - .secretVar("bidAmount") - .secretVar("salt") - .publicVar("reservePrice") - .publicVar("bidCommitment") // output - .publicVar("isAboveReserve") // output - .define(api -> { - // 1. Prove knowledge of commitment - var hash = MiMC.hash(api, api.var("bidAmount"), api.var("salt")); - api.assertEqual(hash, api.var("bidCommitment")); - - // 2. Prove bid >= reserve - var result = Comparators.greaterOrEqual( - api, api.var("bidAmount"), api.var("reservePrice"), 64); - api.assertEqual(result, api.var("isAboveReserve")); - }); + public static CircuitBuilder build() { + return CircuitBuilder.create("private-multiplier") + .publicVar("a") + .publicVar("c") + .secretVar("b") + .defineSignals(new PrivateMultiplierCircuit()); } } ``` Key points: -- `secretVar` -- only the prover knows these (bid amount, salt) -- `publicVar` -- visible to the verifier (reserve price, commitment, result) -- `MiMC.hash` and `Comparators.greaterOrEqual` are from `zeroj-circuit-lib` +- `secretVar` -- only the prover knows this value (`b`) +- `publicVar` -- visible to the verifier (`a` and `c`) +- `CircuitSpec` keeps the circuit reusable and testable ## Step 2: Compile and Calculate Witness (Pure Java) ```java -var circuit = SealedBidCircuit.build(); +var circuit = PrivateMultiplierCircuit.build(); // Compile circuit to R1CS (Groth16 constraint system) var r1cs = circuit.compileR1CS(CurveId.BLS12_381); -byte[] r1csBytes = R1CSSerializer.serialize(r1cs); - // Calculate witness with concrete inputs -BigInteger bidAmount = BigInteger.valueOf(1000); -BigInteger salt = BigInteger.valueOf(42); -BigInteger reservePrice = BigInteger.valueOf(500); -BigInteger commitment = MiMCHash.hash(bidAmount, salt, BLS12_381_PRIME); +BigInteger a = BigInteger.valueOf(3); +BigInteger b = BigInteger.valueOf(11); +BigInteger c = BigInteger.valueOf(33); var witness = circuit.calculateWitness(Map.of( - "bidAmount", List.of(bidAmount), - "salt", List.of(salt), - "reservePrice", List.of(reservePrice), - "bidCommitment", List.of(commitment), - "isAboveReserve", List.of(BigInteger.ONE) // bid 1000 >= reserve 500 + "a", List.of(a), + "b", List.of(b), + "c", List.of(c) ), CurveId.BLS12_381); - -byte[] wtnsBytes = WitnessExporter.toWtns(witness, r1cs.prime(), r1cs.fieldConfig().n32()); ``` This is all pure Java -- no external tools needed. -## Step 3: Generate Proof (gnark FFM) +## Step 3: Generate Proof (Pure Java) ```java -try (var prover = new GnarkProver()) { - var result = prover.groth16FullProve(r1cs, witness, CurveId.BLS12_381); - - String proofJson = result.proveResponse().proofJson(); - String vkJson = result.vkJson(); - List publicSignals = result.proveResponse().publicSignals(); - String publicJson = publicSignals.stream() - .map(v -> "\"" + v + "\"") - .collect(java.util.stream.Collectors.joining(",", "[", "]")); -} +var constraints = r1cs.constraints(); + +// Local test setup only: toxic waste is known. +var srs = PowersOfTauBLS381.generate(4); +var setupResult = Groth16SetupBLS381.setup( + constraints, r1cs.numWires(), r1cs.numPublicInputs(), srs.tauScalar()); + +var proof = Groth16ProverBLS381.prove( + setupResult.provingKey(), witness, constraints, r1cs.numWires()); ``` -This runs gnark **inside the JVM** via Foreign Function & Memory API -- no external CLI, no Node.js. +For setup beyond local tests, import MPC-generated `.zkey` artifacts instead of using `PowersOfTauBLS381.generate(...)`. ## Step 4: Verify Off-Chain (Pure Java) ```java -// Parse proof artifacts -var envelope = SnarkjsJsonCodec.toEnvelopeFromJson( - proofJson, vkJson, publicJson, new CircuitId("sealed-bid")); - -// Verify -- pure Java, zero native dependencies -var verifier = new Groth16BLS12381PureJavaVerifier(); -var material = VerificationMaterial.of(vkBytes, - ProofSystemId.GROTH16, CurveId.BLS12_381, new CircuitId("sealed-bid")); -var result = verifier.verify(envelope, material); +BigInteger[] publicInputs = new BigInteger[r1cs.numPublicInputs()]; +for (int i = 0; i < publicInputs.length; i++) { + publicInputs[i] = witness[i + 1]; +} -assert result.proofValid(); // cryptographic proof is valid +boolean ok = verifyGroth16Pairing(proof, setupResult, publicInputs); +assert ok; ``` +The complete helper is shown in `PureJavaProverYaciE2ETest`; it computes the Groth16 `vk_x` linear combination and runs the BLS12-381 pairing equation. + ## Step 5: Deploy On-Chain Verifier (Julc / Plutus V3) ZeroJ includes reusable Plutus V3 validators compiled from Java via Julc. The VK is baked into the script at deploy time: ```java -// Parse VK for on-chain parameters -var vkCompressed = SnarkjsToCardano.parseVk(vkJson); +// Compress proof + VK for on-chain BLS format +var compressedVk = ProverToCardano.compressVk(setupResult); +var compressedProof = ProverToCardano.compressProof(proof); // Compile Julc validator with VK parameters var script = JulcScriptLoader.load(Groth16BLS12381Verifier.class, - new BytesPlutusData(reservePriceBytes), - new BytesPlutusData(vkCompressed.alpha()), // VK alpha (G1, 48 bytes) - new BytesPlutusData(vkCompressed.beta()), // VK beta (G2, 96 bytes) - new BytesPlutusData(vkCompressed.gamma()), // VK gamma (G2, 96 bytes) - new BytesPlutusData(vkCompressed.delta()), // VK delta (G2, 96 bytes) - new BytesPlutusData(vkCompressed.ic(0)), // IC[0] (G1, 48 bytes) - new BytesPlutusData(vkCompressed.ic(1)), // IC[1] (G1, 48 bytes) - new BytesPlutusData(vkCompressed.ic(2)) // IC[2] (G1, 48 bytes) + new BytesPlutusData(compressedVk.alpha()), + new BytesPlutusData(compressedVk.beta()), + new BytesPlutusData(compressedVk.gamma()), + new BytesPlutusData(compressedVk.delta()), + new BytesPlutusData(compressedVk.ic().get(0)), + new BytesPlutusData(compressedVk.ic().get(1)), + new BytesPlutusData(compressedVk.ic().get(2)) ); -var scriptAddr = AddressProvider.getEntAddress(script, Networks.testnet()); +var scriptAddr = AddressProvider.getEntAddress(script, Networks.testnet()).toBech32(); ``` ## Step 6: Lock Funds with Public Inputs as Datum ```java -// Datum = public inputs that the on-chain verifier checks +// Datum = public inputs that the on-chain verifier checks: [a, c] var datum = ListPlutusData.of( - BigIntPlutusData.of(bidCommitment), - BigIntPlutusData.of(reservePrice) + BigIntPlutusData.of(a), + BigIntPlutusData.of(c) ); // Lock 5 ADA at the script address @@ -194,9 +175,9 @@ var lockResult = new QuickTxBuilder(backend) var redeemer = ConstrPlutusData.builder() .alternative(0) .data(ListPlutusData.of( - new BytesPlutusData(proof.piA()), // G1 compressed (48 bytes) - new BytesPlutusData(proof.piB()), // G2 compressed (96 bytes) - new BytesPlutusData(proof.piC()) // G1 compressed (48 bytes) + new BytesPlutusData(compressedProof.piA()), + new BytesPlutusData(compressedProof.piB()), + new BytesPlutusData(compressedProof.piC()) )) .build(); @@ -220,25 +201,24 @@ var unlockResult = new QuickTxBuilder(backend) The `Groth16BLS12381Verifier` Plutus V3 script executes: -1. **Extract** public inputs from datum: `[bidCommitment, reservePrice]` -2. **Check** reserve price matches the parameter baked at deploy -3. **Decompress** proof points (piA, piB, piC) from BLS12-381 compressed bytes -4. **Compute** `vk_x = ic[0] + pub[0] * ic[1] + pub[1] * ic[2]` (linear combination) -5. **Verify** pairing equation: `e(piA, piB) == e(alpha, beta) * e(vk_x, gamma) * e(piC, delta)` -6. Return `True` if pairing check passes -- UTXO unlocked +1. **Extract** public inputs from datum: `[a, c]` +2. **Decompress** proof points (piA, piB, piC) from BLS12-381 compressed bytes +3. **Compute** `vk_x = ic[0] + pub[0] * ic[1] + pub[1] * ic[2]` (linear combination) +4. **Verify** pairing equation: `e(piA, piB) == e(alpha, beta) * e(vk_x, gamma) * e(piC, delta)` +5. Return `True` if pairing check passes -- UTXO unlocked ## End-to-End Flow Summary ``` -SealedBidCircuit.java (define in Java DSL) +PrivateMultiplierCircuit.java (define in Java DSL) | compileR1CS() (pure Java → R1CS binary) | calculateWitness() (pure Java → BigInteger[]) | - gnark FFM prove (in-process → proofJson, vkJson) + pure Java prove (Groth16ProverBLS381) | - Java verify (pure Java → VerificationResult) + Java verify (pure Java pairing check) | Julc compile (VK baked → Plutus V3 script) | @@ -256,7 +236,7 @@ SealedBidCircuit.java (define in Java DSL) The `zeroj-examples` module contains complete working examples: ```bash -# Off-chain: DSL circuit → snarkjs/gnark prove → Java verify +# Off-chain: DSL circuit → prove → Java verify ./gradlew :zeroj-examples:test # On-chain: full flow on Yaci DevKit (requires running Yaci) @@ -296,22 +276,21 @@ See the [examples README](../zeroj-examples/README.md) for detailed descriptions ## Prover Options -| Prover | Proof System | Curve | External Deps | Speed | +| Prover | Proof System | Curve | External Deps | Notes | |--------|-------------|-------|---------------|-------| -| **Pure Java** | Groth16 + PlonK | BLS12-381, BN254 | **None** | Seconds | -| **gnark FFM** | Groth16 + PlonK | BLS12-381, BN254 | gnark native lib | ~50-300ms | -| **snarkjs CLI** | Groth16 + PlonK | BLS12-381, BN254 | Node.js + snarkjs | Minutes | +| **Pure Java** | Groth16 + PlonK | BLS12-381, BN254 | **None** | Recommended default path | +| **gnark FFM** | Groth16 + PlonK | BLS12-381, BN254 | Go native lib | Optional native backend | +| **snarkjs CLI** | Groth16 + PlonK | BLS12-381, BN254 | Node.js + snarkjs | External CLI workflow | -**Pure Java** is the recommended prover for Cardano -- zero dependencies, GraalVM-compatible, proven end-to-end on-chain. See the [Pure Java Prover Guide](pure-java-prover-guide.md) for the complete pipeline. +**Pure Java** is the recommended prover for the core Cardano path -- zero native dependencies and covered by end-to-end on-chain tests. See the [Pure Java Prover Guide](pure-java-prover-guide.md) for the complete pipeline. -For maximum speed with large circuits, see [Alternate Prover Backends](alternate-prover-backends.md) (gnark FFM). +For native or CLI alternatives, see [Alternate Prover Backends](alternate-prover-backends.md). ## Curves and On-Chain Feasibility | Curve | Off-Chain | On-Chain (Plutus V3) | Notes | |-------|-----------|---------------------|-------| -| BLS12-381 | Full support | Full support | Plutus V3 has native BLS builtins | -| BN254 | Full support | Not feasible | No Plutus BN254 builtins | -| Pallas | Halo2 only (incubator) | Not feasible | No Plutus Pallas builtins | +| BLS12-381 | Groth16 + PlonK | Groth16 supported; PlonK prototype | Plutus V3 has native BLS builtins | +| BN254 | Groth16 + PlonK | Not feasible | No Plutus BN254 builtins | For on-chain verification, always use **BLS12-381**. diff --git a/docs/plonk-support.md b/docs/plonk-support.md index 8bdf886..8a206c7 100644 --- a/docs/plonk-support.md +++ b/docs/plonk-support.md @@ -2,7 +2,7 @@ ## Table of Contents -- [Status](#status-production-off-chain-pure-java-on-chain-via-julc) +- [Status](#status-off-chain-implemented-experimental-on-chain) - [What Works Today](#what-works-today) - [Quick Start (Off-Chain)](#quick-start-off-chain) - [Use Cases](#use-cases) @@ -13,10 +13,11 @@ --- -## Status: Production Off-Chain, Experimental On-Chain +## Status: Off-Chain Implemented, Experimental On-Chain -ZeroJ supports PlonK proof generation via gnark FFM and **pure Java verification** -for structured snarkjs/ZeroJ PlonK proof JSON on BLS12-381 and BN254 curves. +ZeroJ supports PlonK proof generation via the pure Java prover and gnark FFM, +plus **pure Java verification** for structured snarkjs/ZeroJ PlonK proof JSON +on BLS12-381 and BN254 curves. gnark's opaque binary PlonK proof JSON should be verified with gnark native verification until a dedicated adapter is added. The Julc on-chain PlonK path is an experimental prototype today: transcript and inverse checks are implemented, @@ -24,7 +25,7 @@ but the KZG batch opening pairing check is still deferred. ## What Works Today -### Off-Chain PlonK (Production-Ready) +### Off-Chain PlonK - **Setup**: Universal SRS generation (one setup works for any circuit up to the SRS size) - **Prove**: Generate PlonK proofs with the pure Java prover or with gnark FFM - **Verify**: **Pure Java verification** for structured snarkjs/ZeroJ proof JSON; gnark binary PlonK proof JSON uses gnark native verification until an adapter lands @@ -48,24 +49,58 @@ but the KZG batch opening pairing check is still deferred. ## Quick Start (Off-Chain) ```java -try (var prover = new GnarkProver()) { - // 1. Setup (one-time per SRS) - var setup = prover.plonkSetup("bls12381", Path.of("circuit.scs")); - - // 2. Prove (per-transaction) - var response = prover.plonkProveRaw("bls12381", - Path.of("circuit.scs"), - Path.of(setup.pkPath()), - Path.of("witness.bin")); - - // 3. Verify (any party with VK) - boolean valid = prover.plonkVerify("bls12381", - Path.of("verification_key.bin"), - proofBase64, - Path.of("public_witness.bin")); +var circuit = CircuitBuilder.create("multiplier") + .publicVar("c") + .secretVar("a") + .secretVar("b") + .define(api -> api.assertEqual( + api.mul(api.var("a"), api.var("b")), + api.var("c"))); + +var plonk = circuit.compilePlonK(CurveId.BLS12_381); +var witness = circuit.calculateWitness(Map.of( + "c", List.of(BigInteger.valueOf(33)), + "a", List.of(BigInteger.valueOf(3)), + "b", List.of(BigInteger.valueOf(11))), CurveId.BLS12_381); + +var srs = PowersOfTauBLS381.generate(8); // local test setup only +int numGates = plonk.numGates(); +BigInteger[][] gateSelectors = new BigInteger[numGates][5]; +for (int i = 0; i < numGates; i++) { + var row = plonk.gateRows().get(i); + gateSelectors[i] = new BigInteger[]{row.qL(), row.qR(), row.qO(), row.qM(), row.qC()}; } + +var pk = PlonKSetupBLS381.setup(numGates, plonk.numPublicInputs(), + gateSelectors, plonk.sigmaA(), plonk.sigmaB(), plonk.sigmaC(), + plonk.numWires(), srs); + +var extendedWitness = plonk.extendWitness(witness); +int n = pk.domainSize(); +MontFr381[] wireA = new MontFr381[n]; +MontFr381[] wireB = new MontFr381[n]; +MontFr381[] wireC = new MontFr381[n]; +for (int i = 0; i < n; i++) { + if (i < numGates) { + var row = plonk.gateRows().get(i); + wireA[i] = MontFr381.fromBigInteger(extendedWitness[row.wireA()]); + wireB[i] = MontFr381.fromBigInteger(extendedWitness[row.wireB()]); + wireC[i] = MontFr381.fromBigInteger(extendedWitness[row.wireC()]); + } else { + wireA[i] = wireB[i] = wireC[i] = MontFr381.ZERO; + } +} + +BigInteger[] publicInputs = new BigInteger[plonk.numPublicInputs()]; +for (int i = 0; i < publicInputs.length; i++) { + publicInputs[i] = witness[i + 1]; +} + +var proof = PlonKProverBLS381.prove(pk, wireA, wireB, wireC, publicInputs); ``` +See `PlonKBLS381EndToEndTest.java` for the full wire-evaluation and verification code. + ## Use Cases ### Today (Off-Chain) @@ -77,12 +112,12 @@ try (var prover = new GnarkProver()) { ### Future (On-Chain) - PlonK verification on Cardano Plutus V3 is feasible using BLS12-381 builtins - **Limitation**: Plutus V3 lacks SHA-256 (needed for Fiat-Shamir transcript). Workaround: pass pre-computed challenges as redeemer data -- **CIP-0133 (Multi-Scalar Multiplication)**: Would significantly improve on-chain PlonK verification performance (~7-37x speedup) +- **CIP-0133 (Multi-Scalar Multiplication)**: Would improve the shape of on-chain PlonK verification if available - See [ADR-0008](adr/0008-plonk-support-via-gnark.md) for detailed analysis ## Limitations -1. **Test SRS**: The setup uses gnark's `unsafekzg.NewSRS()` which is NOT suitable for production. Production deployments must use an MPC-generated SRS. +1. **Test SRS**: Local test setups are not suitable beyond development. Use MPC-generated SRS artifacts when evaluating non-local deployments. 2. **gnark format**: Proofs and VKs are in gnark's binary format, not snarkjs format. A codec adapter is planned. ## Architecture @@ -90,13 +125,15 @@ try (var prover = new GnarkProver()) { ``` Java Application | -GnarkProver (Java FFM) +CircuitBuilder.compilePlonK(...) + | +PlonKConstraintSystem | -libzeroj_gnark.dylib (Go shared library) +PlonKSetupBLS381 / PlonKProverBLS381 | -gnark v0.14.0 (PlonK + KZG) +PlonkBLS12381Verifier / PlonkBN254Verifier | -BLS12-381 / BN254 curve +Optional: GnarkProver for native proving and native verification of gnark binary artifacts ``` ## Test Vectors @@ -112,4 +149,3 @@ Circuit: `X * Y = Z` (multiplier), Witness: X=3, Y=11, Z=33 ## Related ADRs - [ADR-0008: PlonK Support via gnark](adr/0008-plonk-support-via-gnark.md) -- [ADR-0009: Halo2 Support Strategy](adr/0009-halo2-support-strategy.md) diff --git a/docs/pure-java-prover-guide.md b/docs/pure-java-prover-guide.md index 68130fa..5d2e8a4 100644 --- a/docs/pure-java-prover-guide.md +++ b/docs/pure-java-prover-guide.md @@ -1,15 +1,15 @@ # Pure Java Prover — Circuit to On-Chain Verification -Zero external tools. 100% Java 25. Prove ZK circuits and verify on Cardano. +Pure Java path for defining circuits, generating proofs, and evaluating Cardano on-chain verification flows. ZeroJ is experimental; use local generated setup only for tests. ## Table of Contents - [Overview](#overview) -- [Quick Start — 5 Minutes to Your First Proof](#quick-start--5-minutes-to-your-first-proof) +- [Quick Start](#quick-start) - [Complete End-to-End: Circuit → Prove → On-Chain Verify](#complete-end-to-end-circuit--prove--on-chain-verify) - [PlonK Prover (Pure Java)](#plonk-prover-pure-java) - [Circom Compatibility](#circom-compatibility) -- [Production vs Development Setup](#production-vs-development-setup) +- [MPC vs Local Test Setup](#mpc-vs-local-test-setup) - [End-to-End Flow Diagram](#end-to-end-flow-diagram) - [Module Dependencies](#module-dependencies) - [Running the Examples](#running-the-examples) @@ -18,7 +18,7 @@ Zero external tools. 100% Java 25. Prove ZK circuits and verify on Cardano. ## Overview -The zeroj pure Java prover generates Groth16 and PlonK proofs for BLS12-381 without any native dependencies — no gnark, no snarkjs, no circom, no Go, no Node.js, no Rust. +The ZeroJ pure Java prover generates Groth16 and PlonK proofs for Java-defined circuits without native dependencies. gnark, snarkjs, circom, Go, Node.js, and Rust are not required for the Java DSL plus local pure-Java proving path. ``` Java Circuit → compileR1CS(BLS12_381) → Groth16ProverBLS381.prove() → on-chain verify ✓ @@ -26,18 +26,19 @@ Java Circuit → compileR1CS(BLS12_381) → Groth16ProverBLS381.prove() → on-c | Proof System | Curve | Module | Status | |-------------|-------|--------|--------| -| Groth16 | BLS12-381 | `zeroj-crypto` | Production-ready | -| PlonK | BLS12-381 | `zeroj-crypto` | Production-ready | -| Groth16 | BN254 | `zeroj-crypto` | Production-ready (off-chain only) | -| PlonK | BN254 | `zeroj-crypto` | Production-ready (off-chain only) | +| Groth16 | BLS12-381 | `zeroj-crypto` | Implemented; primary on-chain path | +| PlonK | BLS12-381 | `zeroj-crypto` | Implemented off-chain; on-chain prototype | +| Groth16 | BN254 | `zeroj-crypto` | Implemented off-chain | +| PlonK | BN254 | `zeroj-crypto` | Implemented off-chain | For on-chain Cardano verification, use **BLS12-381** (Plutus V3 has native BLS builtins). -## Quick Start — 5 Minutes to Your First Proof +## Quick Start ### 1. Add Dependencies ```gradle +implementation platform('com.bloxbean.cardano:zeroj-bom-core:0.1.0') implementation 'com.bloxbean.cardano:zeroj-circuit-dsl' implementation 'com.bloxbean.cardano:zeroj-circuit-lib' implementation 'com.bloxbean.cardano:zeroj-crypto' @@ -81,9 +82,7 @@ import com.bloxbean.cardano.zeroj.bls12381.field.*; // Compile circuit var circuit = SecretMultiplierCircuit.build(); var r1cs = circuit.compileR1CS(CurveId.BLS12_381); -var constraints = r1cs.constraints().stream() - .map(c -> new Groth16Prover.R1CSConstraint(c.a(), c.b(), c.c())) - .toArray(Groth16Prover.R1CSConstraint[]::new); +var constraints = r1cs.constraints(); // Compute witness: a=3, b=11 (secret), product=33 BigInteger[] witness = circuit.calculateWitness(Map.of( @@ -92,7 +91,7 @@ BigInteger[] witness = circuit.calculateWitness(Map.of( "product", List.of(BigInteger.valueOf(33)) ), CurveId.BLS12_381); -// Trusted setup (DEVELOPMENT ONLY — see "Production Setup" below) +// Local test setup only: toxic waste is known. var srs = PowersOfTauBLS381.generate(4); var setup = Groth16SetupBLS381.setup(constraints, r1cs.numWires(), r1cs.numPublicInputs(), srs.tauScalar()); @@ -141,6 +140,7 @@ public class BalanceProofCircuit implements CircuitSpec { ```java var circuit = BalanceProofCircuit.build(); var r1cs = circuit.compileR1CS(CurveId.BLS12_381); +var constraints = r1cs.constraints(); System.out.println("Constraints: " + r1cs.numConstraints()); System.out.println("Public inputs: " + r1cs.numPublicInputs()); @@ -158,14 +158,14 @@ BigInteger[] witness = circuit.calculateWitness(Map.of( **For development/testing — single-party setup (pure Java):** ```java -// WARNING: Single-party setup. Toxic waste is known. DO NOT use for production. +// WARNING: Single-party setup. Toxic waste is known. Use for local tests only. var srs = PowersOfTauBLS381.generate(8); // 2^8 = 256 constraints max var setup = Groth16SetupBLS381.setup(constraints, r1cs.numWires(), r1cs.numPublicInputs(), srs.tauScalar()); var pk = setup.provingKey(); ``` -**For production — import snarkjs .zkey from MPC ceremony:** +**For non-local evaluation — import snarkjs .zkey from an MPC ceremony:** ```java // Import .zkey generated by snarkjs multi-party ceremony @@ -308,17 +308,17 @@ var proof = Groth16ProverBLS381.prove(zkeyData.provingKey(), witness, // 6. Verify on-chain (same as above) ``` -## Production vs Development Setup +## MPC vs Local Test Setup -| | Development | Production | +| | Local tests | MPC artifacts | |---|---|---| | **Powers of Tau** | `PowersOfTauBLS381.generate(n)` | Import .ptau from MPC ceremony (Hermez, PPOT) | | **Phase 2 Setup** | `Groth16SetupBLS381.setup(...)` | `snarkjs groth16 setup` with multi-party ceremony | | **Importing** | Use `srs.tauScalar()` directly | Use `ZkeyImporterBLS381.importZkeyFull(...)` | | **Trust** | Single party (toxic waste known) | Multi-party (trust distributed) | -| **Use for** | Testing, development, CI | Mainnet deployment | +| **Use for** | Testing, development, CI | Evaluation beyond local tests | -**Never deploy single-party setup to production.** The generator knows the toxic waste and could forge proofs. +**Never deploy single-party setup.** The generator knows the toxic waste and could forge proofs. ## End-to-End Flow Diagram @@ -363,6 +363,8 @@ var proof = Groth16ProverBLS381.prove(zkeyData.provingKey(), witness, ## Module Dependencies ```gradle +implementation platform('com.bloxbean.cardano:zeroj-bom-core:0.1.0') + // Circuit definition + standard library implementation 'com.bloxbean.cardano:zeroj-circuit-dsl' implementation 'com.bloxbean.cardano:zeroj-circuit-lib' @@ -390,7 +392,7 @@ testImplementation 'com.bloxbean.cardano:cardano-client-lib' # On-chain tests (requires Yaci DevKit running) ./gradlew :zeroj-examples:e2eTest -# Full crypto test suite (2680+ tests) +# Full crypto test suite ./gradlew :zeroj-crypto:test ``` From e0536557daaacaf7454c7d3751344dc048a84191 Mon Sep 17 00:00:00 2001 From: Satya Date: Sun, 17 May 2026 19:59:43 +0800 Subject: [PATCH 2/2] Snapshot version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 77deb0b..cbdccd1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ group = com.bloxbean.cardano -version = 0.1.0-SNAPSHOT +version = 0.1.0-pre1