Architecture
System architecture
How shh stacks on Base, the component map across circuits / contracts / SDK / chain / explorer / app, and the trust and upgrade model that ties them together.
shh is an OP Stack rollup that settles batches to Base. On top of that base layer, each profile exposes a different privacy model — but both reuse the same circuits, Merkle tree, and verifiers.
The stack
Ethereum L1
│ (settlement of Base)
┌───┴────┐
│ Base │ L2 (OP Stack)
└───┬────┘
standard bridge │ shielded bridge
┌───┴────────────────────┐
│ shh (L3) │ OP Stack rollup, single sequencer
│ settles batches to Base │
├──────────────────────────┤
Profile A (full priv) │ ShieldedPool (UTXO) │ Profile B (open + pool)
│ every transfer = note │ transparent EVM +
│ │ PrivacyPool (fixed denom + ASP)
└──────────────────────────┘Component map
| Layer | Component | Tech | Package |
|---|---|---|---|
| Proofs | UTXO join-split, Privacy-Pool withdraw | Circom + Groth16 | packages/circuits |
| Contracts | Pools, Merkle tree, bridges, verifiers | Solidity (Hardhat) | packages/contracts |
| Client | Notes, Merkle, witness/proof gen | TypeScript | packages/sdk |
| Chain | op-geth / op-node / op-batcher / op-proposer | Docker Compose | infra/op-stack |
| Indexer | Block explorer | Blockscout | infra/explorer |
| App | Deposit / transfer / withdraw UI + backend | Next.js | apps/web |
Two profiles, one core
Profile A makes the ShieldedPool the canonical value layer — balances are UTXO note commitments in a Poseidon Merkle tree and transfers are join-split proofs. Profile B is a transparent EVM L3 where privacy is opt-in via the fixed-denomination PrivacyPool, whose withdrawals require an Association Set membership proof. The difference is which contract is the default value path and what the predeploys/genesis set — the cryptography underneath is identical.
Trust & upgrade model
- Trusted setup — Groth16 requires a per-circuit trusted setup. Mainnet uses a multi-party Powers-of-Tau ceremony; dev uses a single-contributor setup that is never for production funds.
- Upgradeability — contracts deploy behind a timelock-governed proxy with an emergency pause.
- Immutability — verifiers and Merkle parameters are immutable per deployment.