PARANOID

Security and trust

What you trust, and what you do not

You trustForYou do not trust
The Groth16 trusted setup of request.circomSoundness of proofsThe gateway with your identity
Poseidon and BN254Hiding the secret, binding the commitmentThe model provider with your identity
Your own deviceKeeping the secretThe chain with your request history (it has none)

How the proving key was made

The key every proof is checked against came from a two-phase Groth16 setup, finished on 18 October 2026 (UTC).

  • Phase 1 is the public Hermez perpetual powers of tau, 54 contributions plus a random beacon: powersOfTau28_hez_final_15.ptau, blake2b 982372c8...69ae6e, as listed in the snarkjs README.
  • Phase 2 has two contributions made from fresh operating-system randomness that was never stored, then a public random beacon: drand mainnet round 6564273, chosen and written down before that round existed.
  • snarkjs zkey verify checks the final key against the circuit and phase 1 and prints ZKey Ok!.

The setup decides only whether a proof can be forged, which would mean requests nobody paid for. It never decides who sent a request: that stays hidden either way. The key lives with the gateway, not in the program, so more people can add contributions later without touching anything on chain.

Unlinkability, stated plainly

A request hides among every member whose leaf is under the root it uses and who is paid up for its epoch. It does not hide you from:

  • Your network path. The gateway sees the IP a request comes from. PARANOID gives each conversation a fresh credential and lets the client add cover traffic, and Tor or a mixnet stays an option. Buterin calls Tor slow and far from optimal; PARANOID does not require it.
  • Your own words. A prompt that names you names you.
  • Timing with a tiny crowd. In an epoch with few active members, anonymity is small. Mainnet epochs last at least an hour (MIN_EPOCH_SECONDS = 3600) so each epoch gathers a crowd.

Double use is always slashable

Every slot of an epoch has exactly one line. Two different requests on the same slot always give two different points of it, so the secret is always recoverable, and slash accepts any secret that opens the member's commitment.

The vault stays solvent

The program keeps deposited - paid_treasury - paid_burn - refunded as the USDC the vault owes. Every instruction that moves USDC updates these totals with checked arithmetic.

No admin keys after launch

initialize and set_burn_target may be called once each, only by the program's upgrade authority. They fix every launch constant; no instruction changes them later.

Burn crank limits

The crank spends at most 0.1% of the pool's USDC side per call (BURN_MAX_RESERVE_BPS = 10) and must receive at least 98% of the pool's 30-minute time-weighted price (BURN_MIN_OUT_BPS = 9800, BURN_TWAP_SECS = 1800), so there is little for a caller to sandwich.

Next: Economics