Security
Trust assumptions, what's enforced where, audit status, and how to report issues.
Security
Paraloom's security model is layered: the on-chain Anchor program is the trust anchor, Groth16 over BLS12-381 enforces shielded-pool soundness, and a BFT cohort with on-chain stake keeps liveness and finality fast. Each layer's compromise is bounded by the layers below it.
What enforces what
| Enforced by | If compromised, attacker can | |
|---|---|---|
| Nullifier uniqueness | On-chain PDA (init fails if exists) | nothing — even a 10/10 malicious cohort can't double-spend |
| Withdrawal proof validity | On-chain Groth16 verification | nothing — chain re-verifies every proof |
| Replay prevention | On-chain expiration_slot check | nothing — leaked proofs expire |
| Merkle root authenticity | Authority-signed update + on-chain storage | mint commitments out-of-set (requires authority key) |
| Withdrawal liveness | BFT cohort | delay or refuse withdrawals — not forge them |
| Validator stake / slashing | On-chain ValidatorAccount PDA | nothing — economic penalty enforced on-chain |
The pattern: safety lives on-chain, throughput lives off-chain. This is what makes paraloom a Layer 2 rather than a sidechain.
Trust assumptions
Cryptographic
| Assumption | Source |
|---|---|
| Poseidon hash is collision-resistant (≈128-bit) | Standard Sapling parameters (full 8 / partial 57, α=5) |
| Groth16 is sound under q-PKE / q-SDH on BLS12-381 | Established literature |
| BLS12-381 discrete log is hard (≈128-bit) | Curve choice |
| At least one MPC ceremony participant is honest | BGM17 phase-2 ceremony, public transcript |
Operational
| Assumption | |
|---|---|
| At most 3-of-10 validators simultaneously malicious | BFT threshold; reputation gating + slashing make this expensive |
| Solana liveness | Standard Solana L1 assumption |
| Anchor program integrity | Source published, deployed at fixed program ID, upgrade authority documented |
| Coordinator (HA primary) | Doesn't need to be trusted for safety; only for liveness — failover < 30 s |
Threat model
Mitigated
- Double-spend: nullifier PDAs (on-chain init-or-fail). Cohort attacks can't bypass.
- Value forgery: in-circuit u64 range proofs (#60) prevent field-arithmetic wrap attacks.
- Replay: withdrawal proofs carry
expiration_slot(#61); on-chain rejects expired txs. - Equivocation by validators: cryptographic evidence catalog → on-chain slashing.
- Persistent unavailability: missed-heartbeat evidence → on-chain slashing.
- Coordinator crash (liveness): active/passive HA failover.
- Supply-chain compromise of releases: keyless Sigstore signatures bound to GitHub Actions OIDC (#70).
Not in scope (and how to mitigate at the application layer)
| Concern | Mitigation |
|---|---|
| Network metadata (IP, timing) | Tor / VPN at submission time |
| Off-chain identity correlation (KYC at on-ramp before deposit) | Outside paraloom's threat model |
| Statistical fingerprinting (unique amounts, predictable cadence) | Use round denominations, vary timing |
| Endpoint compromise (your machine) | Hardware wallets for keys; encrypt note storage |
| Front-running of public Solana txs around the privacy boundary | Application-level intent layers; outside the privacy primitive |
Privacy boundary
What's hidden:
- Sender, recipient, amount of in-pool transfers
- Link between deposit and withdrawal
What's necessarily visible:
- Deposits enter the pool publicly (sender + amount on-chain)
- Withdrawals leave publicly (recipient + amount on-chain)
- Nullifier set (membership only — unlinkable to commitments)
- Merkle root updates
Privacy is between deposit and withdrawal, not at the edges.
Trusted setup
The Groth16 system requires a per-circuit trusted setup. Paraloom uses the BGM17 phase-2 ceremony with the following discipline:
| Phase 1 | Powers-of-tau ceremony (industry-standard, reused) |
| Phase 2 | Per-circuit, multi-contributor ceremony |
| Honesty bar | One honest participant suffices for soundness |
| Verifiability | Full transcript chain published; anyone can re-verify |
| Tooling | paraloom-ceremony-contribute / verify / finalize |
Devnet uses locally generated keys for development convenience. Mainnet is gated on a real ceremony with verified transcripts. Tracked in #64. See Ceremony for the contribution workflow.
Audit status
| Status | |
|---|---|
| Privacy circuits | internal review |
Anchor program (programs/paraloom/) | internal review |
| BFT cohort + slashing logic | internal review |
| Networking + DHT discovery | internal review |
| External audit | planned before mainnet — not yet commissioned |
| Formal verification | not in scope for v0.5.0 |
External audit is a hard prerequisite for mainnet, alongside the MPC ceremony. The order is: audit → ceremony → mainnet activation.
Known limitations
These are public on purpose:
- No external audit yet. Internal review only. Don't move real-value funds on devnet.
- Compute layer is alpha. The output-notes path back into the shielded pool isn't wired; treat as experimental.
- No formal verification of circuits or program logic. Test coverage (407 tests) catches a lot but isn't a substitute.
- Single implementation. There's no second client to cross-check consensus or bridge behaviour.
- Limited fuzz coverage at the codec / proof boundary; this is on the pre-mainnet TODO.
- Devnet-only proving keys by default. Sending mainnet keys to devnet code (or vice versa) is a footgun the SDK will eventually guard against.
Validator operational security
| Key files | chmod 600 for validator.key and validator-wallet.json |
| Backups | offline copy of wallet keypair; the staked SOL depends on it |
| Time sync | NTP — slot-based heartbeats break under large drift |
| Firewall | TCP/9001 inbound from anywhere; TCP/9300 (metrics) only from your monitoring net |
| Monitoring | watch paraloom_proof_verify_seconds, paraloom_consensus_round_total, times_slashed |
| Graceful exit | paraloom validator unregister before extended downtime — avoids unavailability slashing |
See Validator guide for the full setup.
User security
| Notes are bearer instruments | anyone with the secret can spend the commitment |
| Backups | shielded notes are unrecoverable if lost — back them up encrypted |
| Hardware wallet | recommended for the public wallet that owns the deposit/withdrawal addresses |
| Fresh addresses | don't reuse the same withdrawal address across many withdrawals |
| Round amounts | unusual amounts narrow the anonymity set — prefer common denominations |
The CLI writes notes with restricted permissions; if you build your own client, replicate that.
Reporting vulnerabilities
Please do not open public GitHub issues for security-sensitive findings.
Report privately to security@paraloom.network, or via GitHub's private vulnerability reporting on paraloom-labs/paraloom-core.
Include: clear description, reproduction steps, impact assessment, and (if you have one) a proposed fix. We'll acknowledge within a reasonable window and coordinate disclosure timing with you.
A formal bug bounty program will launch alongside the external audit. Until then, responsible disclosure is welcomed and credited.
Pre-mainnet security checklist
- BGM17 phase-2 MPC ceremony executed end-to-end (#64)
- External audit of circuits + Anchor program + BFT path
- Compute layer output-notes integrated with shielded pool
- Fuzz coverage on proof / codec boundary
- Bug bounty program live
- Decentralized validator set on devnet (multi-operator) before mainnet activation
This list is the gate. None of these are checked off yet.