Engine & Prover
Build matrix, feature flags, and verifier export for the Halo2-KZG proving system.
Build Matrix
The Rust engine (engine/) supports multiple build configurations via Cargo feature flags:
| Feature | Backend | Use Case | Binary |
|---|---|---|---|
zk | Halo2 IPA (Pallas) | Accounting proofs (period close, solvency, etc.) | axiomatic-prover |
zk-privacy | Halo2 KZG (BN254) | JoinSplit circuit for shielded transfers | export-verifier |
Default Build (WASM)
cargo build --target wasm32-unknown-unknownProduces the WASM module for the DSL engine. No ZK proving capabilities — proofs are mocked.
Native Prover Build
cargo build --release --features zkBuilds the axiomatic-prover binary with all accounting circuits. The TypeScript platform shells out to this binary for proof generation.
Privacy Prover Build
cargo build --release --features zk-privacyEnables the JoinSplit circuit (Halo2-KZG on BN254) and the export-verifier binary. This is required for real shielded transfer proofs.
Prover Commands
The axiomatic-prover binary accepts commands via CLI arguments and reads witness data from stdin:
| Command | Description |
|---|---|
prove-joinsplit | Generate a JoinSplit proof from a witness |
prove-innocence | Prove deposit origins are not in a sanctioned set |
prove-period | Generate a period close proof |
prove-solvency | Generate a solvency proof |
poseidon-hash | Compute Poseidon hash of two BN254 field elements |
verify | Verify a proof |
export-vk | Export verification key for a circuit |
JoinSplit Witness Format
The witness JSON sent to prove-joinsplit must match the Rust JoinSplitWitness struct:
{
"spending_key": "hex-string",
"input_notes": [
{ "owner_pubkey": "hex", "token_hash": "hex", "value": "hex", "salt": "hex" },
{ "owner_pubkey": "hex", "token_hash": "hex", "value": "hex", "salt": "hex" }
],
"input_merkle_paths": [
{ "siblings": ["hex", "...32 total"], "indices": [false, "...32 total"] },
{ "siblings": ["hex", "...32 total"], "indices": [false, "...32 total"] }
],
"output_notes": [
{ "owner_pubkey": "hex", "token_hash": "hex", "value": "hex", "salt": "hex" },
{ "owner_pubkey": "hex", "token_hash": "hex", "value": "hex", "salt": "hex" }
],
"merkle_root": "hex",
"nullifier_hashes": ["hex", "hex"],
"new_commitments": ["hex", "hex"],
"value_delta": "hex",
"token_hash": "hex",
"recipient_pubkey_hash": "hex"
}The circuit enforces:
- Input notes exist in the Merkle tree (membership proof)
- Nullifiers are correctly derived from spending key + commitment
- Output commitments are correctly computed
- Values are conserved:
sum(inputs) == sum(outputs) + value_delta - Owner derivation:
owner_pubkey == Poseidon(spending_key)
Verifier Export
flowchart LR
BUILD["cargo build<br/>--features zk-privacy"] --> VK["Generate VK from<br/>JoinSplit circuit"]
VK --> EXPORT["export-verifier binary"]
EXPORT --> SOL["Halo2KZGVerifier.sol"]
SOL --> DEPLOY["Deploy to chain"]To regenerate the Solidity verifier after circuit changes:
cargo run --features zk-privacy --bin export-verifier > protocol/packages/privacy/src/Halo2KZGVerifier.solThis generates the full Solidity verifier contract (via halo2-solidity-verifier) containing Halo2VerifyingKey, Halo2Verifier, and a wrapper Halo2KZGVerifier that implements IHalo2KZGVerifier. Pass --json to output VK metadata instead of Solidity.
Circuit Parameters
| Parameter | Value |
|---|---|
| Curve | BN254 |
| Backend | KZG (GWC prover) |
| k | 14 (16,384 rows) |
| Merkle depth | 32 |
| Inputs | 2 |
| Outputs | 2 |
| Public inputs | 8 |
| Estimated proving time | 2-5s (native), 30-60s (WASM) |
| On-chain verification gas | ~250,000-350,000 |