Overview — Choosing the Right Codebase
Full Comparison Matrix
| Project | Type | ZK System | ZK Color | Circuit Lang | Chain | Compliance | Matching | Status | Dark Pool? |
|---|---|---|---|---|---|---|---|---|---|
| Renegade | Dark Pool | colzkSNARK (PLONK) | PLONK | Rust | Arbitrum One | None | MPC P2P | Mainnet 2024-09 | Yes |
| Penumbra | Shielded L1 | Groth16 | Groth16 | Rust (arkworks) | Cosmos / IBC | External | バッチオークション (FBA) | Mainnet | Yes (batch) |
| Privacy Pools | Compliance Pool | Groth16 | Groth16 | Circom | Ethereum | ASP (assoc. set) | N/A | Mainnet 2025-03 | No |
| Aztec 3 | Smart Contract L2 | UltraHONK | UltraHONK | Noir | Ethereum L2 | Programmable | Programmable | Mainnet Nov 2025 | Yes (programmable) |
| RAILGUN | Private DeFi Wrapper | Groth16 | Groth16 | Circom | Multi-EVM | PPOI (post-hoc) | N/A | Mainnet | No |
| ZKBob | Stablecoin Pool | Groth16 | Groth16 | Circom | Polygon / ETH / OP | CM key (pre-emptive) | N/A | アクティブ | No |
ZK System Color Legend
Groth16 (BN254)
Smallest proof size (~200 bytes). Requires per-circuit trusted setup. Native EVM precompile support (ecPairing). Used by: Penumbra, Privacy Pools, RAILGUN, ZKBob.
Collaborative PLONK (BN254)
Universal trusted setup (one per curve). Enables MPC-in-the-head style collaborative proving. Ozdemir-Boneh 2022. Used by: Renegade.
UltraHONK (barretenberg)
No trusted setup. Recursive. Developed by Aztec Labs. Powers Noir language. Very large gates (millions) feasible. Used by: Aztec 3.
Which Codebase to Fork?
Renegade — MPC Dark Pool with Collaborative ZK-SNARKs
ZK / MPC Stack
- Proof system: PLONK-based collaborative SNARK
- Curve: BN254 (EVM precompile compatible)
- MPC: 2-party SPDZ-style (relayer-to-relayer)
- Hash in circuit: Poseidon
- Commitment: Pedersen + Poseidon
- MPC framework: mpc-stark (renegade-fi fork)
Trust Model
- Relayer holds pk_match — semi-trusted (Type B)
- Intra-cluster: Raft fail-stop
- Inter-cluster: ビザンチン耐性 MPC ハンドシェイク
- Stylus: censorship resistant; integrity via ZK
Repository Architecture
renegade/
├── crates/
│ ├── circuits/ # ZK circuits + colzkSNARK (most important)
│ │ ├── src/
│ │ │ ├── zk_circuits/
│ │ │ │ ├── valid_commitments.rs
│ │ │ │ ├── valid_reblind.rs
│ │ │ │ ├── valid_commitments_match.rs
│ │ │ │ ├── valid_match_settle.rs
│ │ │ │ ├── valid_wallet_create.rs
│ │ │ │ ├── valid_wallet_update.rs
│ │ │ │ └── valid_offline_fee_settlement.rs
│ │ │ └── mpc_circuits/ # collaborative proving
│ ├── workers/ # actor model: MPC handshake / proof gen / matching engine
│ │ ├── handshake_manager/ # relayer-to-relayer MPC coordination
│ │ ├── proof_manager/ # async proof generation
│ │ └── matching_engine/ # order book + match execution
│ ├── state/ # Raft-like cluster state (fail-stop intra-cluster)
│ ├── darkpool-client/ # RPC client to Stylus on-chain contract
│ ├── system-primitives/ # Wallet, Order types (shared off/on-chain)
│ ├── core/ # core business logic + handshake protocols
│ └── api/ # REST + WebSocket API endpoints
└── contracts/ # Arbitrum Stylus (same Rust code → WASM)
7 ZK Circuits (NP Statements)
-
1VALID COMMITMENTSProves wallet state is well-formed. Inputs: wallet (private), commitment (public). Ensures balances non-negative, orders well-formed, fee valid.
-
2VALID REBLINDRe-randomization preserves wallet state. Allows relayer to update nullifiers/commitments without revealing wallet contents. Critical for forward secrecy.
-
3VALID COMMITMENTS MATCHProves two wallets' orders are compatible (price overlap, same token pair). Runs collaboratively via MPC — neither party sees the other's wallet.
-
4VALID MATCH SETTLESettlement arithmetic is correct: asset balances update consistently, fees deducted, no new money created.
-
5VALID WALLET CREATENew wallet has valid initial state. Zero balances or deposited balances match on-chain event.
-
6VALID WALLET UPDATEWallet update (deposit/withdraw/order placement) is authorized by user's private key and preserves conservation of assets.
-
7VALID OFFLINE FEE SETTLEMENTRelayer fee payment correct without live on-chain call. Allows async fee settlement in background.
MPC Handshake Flow (Counterparty Matching)
Penumbra — Fully Shielded L1 with Batch Auction DEX
ZK Stack
- Proof system: Groth16
- Curve: BLS12-377
- Internal group: decaf377 (cofactor-clear Edwards)
- Library: arkworks-rs
- Consensus: CometBFT (prev. Tendermint)
3-Binary Architecture
- pd — full node (never holds plaintext)
- pcli — user wallet CLI
- pclientd — view daemon (trial-decrypts all notes)
pclientd trial-decrypts every note in the chain to find wallet's — O(n) scan cost grows with chain size.
Repository Architecture
penumbra/
├── crates/
│ ├── core/
│ │ ├── component/
│ │ │ ├── shielded-pool/ # ABCI handler for spend/output/notes
│ │ │ ├── dex/ # Batch auction DEX logic
│ │ │ ├── stake/ # Delegation + governance
│ │ │ └── fee/ # Transaction fee handling
│ │ └── crypto/
│ │ ├── decaf377/ # cofactor-clear Edwards curve
│ │ ├── poseidon377/ # Poseidon hash over BLS12-377
│ │ └── pedersen/ # Pedersen commitments (multi-asset)
│ ├── bin/
│ │ ├── pd/ # Full node binary
│ │ ├── pcli/ # CLI wallet
│ │ └── pclientd/ # View server daemon
│ └── cnidarium-component/ # Custom state framework (replaces Cosmos SDK store)
└── proto/ # gRPC definitions
7 ZK Circuits
-
1SpendNote existence + Merkle inclusion proof + nullifier consistency. Core privacy primitive — equivalent to Zcash Sapling Spend.
-
2OutputNew commitment + balance preservation. Creates a new private note from a spend.
-
3SwapDEX order submission with hidden amounts. Commits to trading pair and reserves without revealing trade size or direction to validators.
-
4SwapClaimReceive output tokens after batch match. Proves you submitted a valid swap and claims the correct output at the batch clearing price.
-
5DelegatorVoteGovernance anti-double-vote. Delegates can vote without revealing stake size. Nullifier prevents double-voting.
-
6UndelegateClaimStaking exit. Claims unbonded tokens after unbonding period. Proves delegation was valid and unbonding period elapsed.
-
7Nullifier DerivationDeterministic nullifier from spend key + note commitment. Prevents double-spend without revealing which note was spent.
Batch Auction DEX Design (FBA-Style)
Penumbra's DEX does not use a continuous double auction (CDA / order book). Instead it uses a Frequent Batch Auction (FBA) — orders are aggregated per block and cleared at a single uniform price.
Multi-Asset Privacy
Penumbra uses separate Pedersen generators per asset. Each asset type has its own generator point on decaf377. This prevents cross-asset correlation attacks while allowing homomorphic balance checks.
// Commitment to amount v of asset a:
// C = v * G_a + r * H
// where G_a is asset-specific generator, H is blinding generator
// Different assets use different G_a — cannot aggregate across assets
Privacy Pools / RAILGUN / ZKBob — Compliance-Oriented Codebases
Privacy Pools / 0xbow
アーキテクチャ
privacy-pools-core/
├── packages/
│ ├── circuits/ # Circom 2.x + snarkjs setup artifacts
│ │ ├── withdraw.circom
│ │ └── ptau/ # Groth16 trusted setup files
│ ├── contracts/ # Solidity
│ │ ├── Entrypoint.sol # deposit/withdraw router
│ │ ├── PrivacyPool.sol # per-asset shielded pool
│ │ ├── State.sol # commitment Merkle tree
│ │ ├── ASPManager.sol # manages ASP roots
│ │ └── Verifier.sol # Groth16 on-chain verifier
│ ├── relayer/ # minimal gasless relayer
│ └── sdk/ # TypeScript (dapp integration)
Association Set Provider (ASP) — 核心イノベーション
state_tree = MerkleTree(
all deposit commitments // full set
)
asp_tree = MerkleTree(
approved-only commitments // curated subset
)
// Withdrawal proof requires inclusion in BOTH:
withdrawal_proof {
private: note, secret, path_in_state_tree, path_in_asp_tree
public: state_root, asp_root, nullifier
}
// Semantics:
// "I am SOMEONE in the clean subset"
// (NOT who exactly — subset membership, not identity)
RAILGUN
Key Design: 54 Specialized Circuits
// [1-10 inputs] × [1-10 outputs] = 100 combinations
// But only valid: inputs ≥ 1, outputs ≥ 1 → 54 circuits
// Each circuit is pre-compiled + trusted-setup'd
// Allows gas-optimal proof for exact tx shape
// Example:
circuit_1_1.zkey // 1 input, 1 output
circuit_2_3.zkey // 2 inputs, 3 outputs
// ...
circuit_10_1.zkey // 10 inputs, 1 output
PPOI — Proof of Innocence (Post-hoc Compliance)
// Public inputs:
txidMerkleRoot // full Tx Merkle Tree root
blocklistTxidMerkleRoot // blacklist Tx root
blindedCommitment // hidden commitment
// Circuit proves:
// 1. My Tx IS in the full tree (I am valid user)
// 2. My Tx is NOT in the blacklist tree (I am clean)
// Key: prover does NOT reveal which Tx is theirs
// Semantics: "I can prove I'm not on the blacklist"
// without revealing what I did
Private DeFi Cookbook (Railgun-Community/cookbook)
Pre-built recipes for using any DeFi protocol privately via RAILGUN. Gas paid by Broadcaster (relayer) via RAILGUN internal tokens.
// Example: private Uniswap V3 swap
const recipe = new UniswapV3SwapRecipe(
tokenIn, tokenOut, amount,
slippage, deadline
);
const shieldedTx = await railgun.generateShieldedTransaction(recipe);
// → Broadcaster pays gas, receives tip in RAILGUN tokens
// → No on-chain link between user's wallet and UniswapV3 call
ZKBob
Compliance Manager Key (Pre-emptive Compliance)
// Every Note includes DUAL encryption:
Note = {
amount: encrypted_to_recipient_key,
audit_log: encrypted_to_pk_cm, // ← audit trail
nullifier: ...,
commitment: ...
}
// Flow:
// Regulator subpoenas exchange
// Exchange → CM → decrypts audit_log for specific Notes
// → reveals specific tx details for that user
// Key: CM can decrypt ALL tx but is trusted not to do so
Universal Transaction Circuit
// ZKBob: 1 universal circuit handles all tx types
// vs RAILGUN: 54 specialized circuits
// Universal circuit inputs:
{
type: deposit | transfer | withdrawal,
inputs: Note[], // max configurable
outputs: Note[], // max configurable
fee: amount,
cm_audit_log: ..., // always included
}
// Simpler audit, higher circuit complexity
反構造化コントロール
ZKBob enforces withdrawal limits per period on-chain to prevent structuring (breaking large amounts into small transactions to evade detection). This is a circuit-level constraint, not just policy.
Compliance Mechanism Comparison
| Feature | Privacy Pools (ASP) | RAILGUN (PPOI) | ZKBob (CM Key) |
|---|---|---|---|
| Compliance model | Subset membership | Post-hoc exclusion proof | Pre-emptive audit log |
| Who curates? | ASP (0xbow — centralized) | ブロックリスト保守者(外部) | Compliance Manager key holder |
| Timing | 引き出し時(セットに含まれる) | Post-tx (prove not blacklisted) | トランザクション作成時(常にログ記録) |
| Regulator access | Set membership only | Nothing (user self-proves) | Full tx details via CM |
| Criminal can exit? | If ASP approves (fail: ASP compromised) | ブロックリストが引き出し証明を防止 | Yes, but tx is logged |
| Token scope | Any ERC-20 (per pool) | Any ERC-20 | USDC / BOB stablecoin |
| Circuit count | 2 (withdraw circuit) | 54 specialized | 1 universal |
Aztec 3 — プログラム可能なプライベートスマートコントラクト L2
Proof System: UltraHONK
- No trusted setup — transparent SRS
- Recursive proofs — stack arbitrary depth
- バックエンド: barretenberg (C++, Aztec Labs)
- Frontend: Noir DSL → ACIR → barretenberg
- Very large circuits (millions of gates) feasible
PXE — Private eXecution Environment
The PXE runs on the user's device (or trusted server). It:
- Holds user's private keys
- Executes private contract functions locally
- Generates proofs before submitting to sequencer
- Trial-decrypts incoming notes (like pclientd in Penumbra)
Sequencer never sees private inputs — only sees the proof and public outputs.
Private Kernel Circuit — 5 Phases
Every private transaction runs through this pipeline on the user's device (PXE). Each phase is a separate proof, recursively accumulated.
Gate Counts (Typical 2-Private-Call TX)
Approximate gate counts — actual varies by circuit version and app complexity. Max is private_kernel_inner (~101k gates) × number of inner calls.
Noir Language — Writing Private Contracts
// Noir: Rust-like DSL for ZK circuits
// Used for: application contracts, protocol circuits, standalone ZK programs
// Example: private order struct in Noir
struct PrivateOrder {
amount: u64, // private
price: u64, // private
direction: bool, // private (true=buy)
commitment: Field, // public output
nullifier: Field, // public output (when consumed)
}
// Private function (runs in PXE, no sequencer visibility)
#[aztec(private)]
fn submit_order(
order: PrivateOrder,
context: &mut PrivateContext
) -> Field {
// Hash order to commitment
let commitment = pedersen_hash([order.amount, order.price, order.direction]);
// Emit note to private state
context.emit_note(OrderNote { commitment, owner: context.msg_sender() });
commitment
}
// Public matching function (sequencer executes, visible on-chain)
#[aztec(public)]
fn match_orders(
buyer_nullifier: Field,
seller_nullifier: Field,
clearing_price: u64,
) {
// Verify nullifiers not already used
assert(!storage.nullifiers.contains(buyer_nullifier));
assert(!storage.nullifiers.contains(seller_nullifier));
// ... settlement logic
}
自前ダークプールの構築 — 実装ガイド
Key Decision Flowchart
Recommended Stack by Goal
Goal: Fastest to Mainnet
Fork Renegade
- 監査済みプロダクションコードベース
- Stylus = shared off/on-chain Rust
- 7 circuits already implemented
- MPC framework (mpc-stark) ready
- EVM settlement day 1
Risk: IoI problem, business-source license
Goal: Maximum Programmability
Aztec 3 で構築
- Noir DSL — accessible ZK contracts
- No trusted setup needed
- Ethereum L2 — existing liquidity
- Hybrid public/private execution
- Define your own matching logic
Risk: ecosystem new, higher dev complexity
Goal: Institutional Compliance
Fork Privacy Pools + CM Key
- ポストホック部分集合証明用 ASP
- CM key for pre-emptive audit trail
- Circom + snarkjs — simple tooling
- Ethereum mainnet ready
- Regulatory engagement possible
Risk: centralized ASP trust assumption
Step-by-Step Implementation Guide
Phase 1: Define Adversary Model (Week 1-2)
| Question | Answer defines |
|---|---|
| Who is your adversary: relayer, sequencer, or both? | MPC design, ZK circuit scope |
| Semi-honest or malicious adversary? | SPDZ overhead vs simpler protocols |
| What leaks on match? (price, size, direction) | IoI design, circuit inputs |
| Regulatory jurisdiction? | Compliance hook (ASP vs CM key vs none) |
| MEV protection needed? | バッチオークション対 CDA |
Phase 2: Choose Matching Mechanism (Week 2-3)
バッチオークション (FBA) — 推奨
- Eliminates front-running entirely
- Uniform clearing price = no order priority MEV
- Simpler circuit: no real-time matching state
- Penumbra reference implementation
- 最適用途: 機関投資家向けダークプール
MPC Continuous Matching
- Renegade approach: real-time 2PC matching
- Harder: counterparty discovery problem
- Requires P2P relayer network
- IoI leaks partial order info
- 最適用途: 高頻度/トレーダーUX
Phase 3: Circuit Development (Month 1-4)
# Minimum viable circuit set for a dark pool:
1. DEPOSIT CIRCUIT
Input: amount (private), asset (public), nonce (private)
Output: commitment (public), nullifier_key (private)
Proves: commitment = hash(amount, asset, nonce)
2. ORDER CIRCUIT (submit)
Input: price, size, direction (all private), wallet_commitment (public)
Output: order_commitment (public), order_nullifier_hint (private)
Proves: wallet has sufficient balance for order; order params valid
3. MATCH CIRCUIT (collaborative, run via MPC)
Input: buyer_order (private-shared), seller_order (private-shared)
Output: match_exists (public), clearing_price (public if FBA)
Proves: orders overlap (price_buy >= price_sell, same asset pair)
4. SETTLE CIRCUIT
Input: match_proof, buyer_wallet, seller_wallet (all private)
Output: new_buyer_commitment, new_seller_commitment (public)
buyer_nullifier, seller_nullifier (public)
Proves: balances updated correctly, conservation holds
5. WITHDRAW CIRCUIT
Input: note (private), nullifier_key (private)
Output: nullifier (public), amount (public)
Proves: note valid, not previously spent
# Timeline estimate:
# - Groth16 + Circom: 2-3 months (simpler tooling, less expressive)
# - PLONK + Rust: 3-5 months (more expressive, heavier)
# - Noir + UltraHONK: 2-4 months (easiest DX if using Aztec)
Phase 4: MPC Layer (Month 3-5, if needed)
# For MPC-based matching (Renegade pattern):
# Option A: Use mpc-stark (Renegade's fork)
git clone https://github.com/renegade-fi/mpc-stark
# Implements: SPDZ preprocessing, Beaver triples, authenticated shares
# Interface: MpcFabric::new() → share values → compute circuits jointly
# Option B: MP-SPDZ (academic reference)
git clone https://github.com/data61/MP-SPDZ
# Full SPDZ, MASCOT, LOWGEAR protocols
# More protocols but heavier — good for research
# Minimum MPC design for dark pool:
# - Preprocessing phase: generate Beaver triples offline
# - Online phase: share order values, compute match predicate jointly
# - Output: both parties learn match result (and proof) but not each other's order
Phase 5: Trusted Setup (Groth16 only)
# snarkjs ceremony workflow:
# Phase 1 (powers of tau — universal):
snarkjs powersoftau new bn128 20 pot20_0000.ptau
snarkjs powersoftau contribute pot20_0000.ptau pot20_0001.ptau --name="contributor1"
# ... repeat with many contributors
snarkjs powersoftau prepare phase2 pot20_final.ptau pot20_final_pp.ptau
# Phase 2 (circuit-specific):
snarkjs groth16 setup order_circuit.r1cs pot20_final_pp.ptau order_0000.zkey
snarkjs zkey contribute order_0000.zkey order_0001.zkey --name="contributor1"
snarkjs zkey beacon order_0001.zkey order_final.zkey [beacon_hash] 10
snarkjs zkey export verificationkey order_final.zkey verification_key.json
# Export Solidity verifier:
snarkjs zkey export solidityverifier order_final.zkey verifier.sol
Phase 6: Security Audit Checklist
| カテゴリ | Check | Tool / Method |
|---|---|---|
| Circuit soundness | Under-constrained signals → forged proofs | Manual review + circom-mutator / Picus |
| Nullifier uniqueness | Double-spend possible? | Formal verification (Lean/Coq) or manual |
| Arithmetic overflow | Field arithmetic edge cases | Ecne (Trail of Bits) for R1CS |
| Trusted setup | Toxic waste properly destroyed? | セレモニートランスクリプトレビュー |
| MPC protocol | 中止/不正行為パーティ回復 | Protocol analysis + UC simulation |
| Smart contract | Reentrancy, access control, verifier linkage | Slither / Aderyn / manual |
| Nullifier set | Merkle tree soundness, root manipulation | ZK circuit audit specialist |
Phase 7: Launch Strategy
Gas Cost Benchmarks (Reference)
| System | Settlement Cost | Proof Verify Cost | Notes |
|---|---|---|---|
| Renegade (Arbitrum Stylus) | ~$0.30 | PLONK on WASM | Stylus ~10× cheaper than Solidity |
| Privacy Pools (Ethereum) | ~$8-15 | Groth16 ecPairing (~250k gas) | EVM precompile |
| RAILGUN (Ethereum) | ~$12-25 | Groth16 × 1 circuit | More inputs/outputs = more gas |
| Aztec 3 (L2) | ~$0.10-0.50 | Rollup amortized | 多数のトランザクションにわたってバッチ処理 |
| Penumbra (Cosmos) | Low fixed fee | Groth16 in validator | No EVM overhead |