Shielded is unaudited research software for Mutinynet test coins. Do not use it with real funds.
- Trusted setup. Phase 1 is the Hermez Perpetual Powers of Tau transcript, shared with many projects. The genesis 4 epoch-pool keys (release
rollup-genesis-4-keys, manifestrollup-keys/genesis-4.json) come from a small testnet phase-2 ceremony: one recorded contribution per circuit, sealed by the beacon of Bitcoin block 972846. Anyone who kept a contribution's randomness could forge proofs for that circuit; the beacon only stops the last contributor from choosing the final key. The genesis 3 keys (releaserollup-genesis-3-keys) were a development-only phase-2 setup with a single automated contribution and no beacon; that release stays published as the record of that setup. The README shows how to verify the published artifacts. - Who enforces the rules. The pool covenant verifies every client proof and the batch proof through the Arkade emulator's opcodes, and the Arkade operator co-signs. Bitcoin itself does not check the proofs. Both services must stay honest and online.
- If the Arkade service (emulator or arkd) goes offline, the pool is frozen on Bitcoin. Every pool-head spend path is keyed on the emulator, so with the emulator gone no leaf is spendable and the shared pool coin cannot be split — for everyone, not just you, and separate from the head-expiry point below. There is no emulator-free exit. This is a known limitation of running on Arkade; a privacy-preserving unilateral exit was explored and set aside because it costs the pool's amount privacy.
- The pool operator (the shielded sequencer, distinct from the Arkade service above) orders spends into batches and stores the encrypted note records. It can delay or refuse a spend, but it cannot spend a note without a proof that only the note owner's keys can make, and it holds no key in the pool covenant.
- If the sequencer stops or refuses you — and the Arkade service is still up — the batch leaf still accepts any valid batch. With the published batch key,
tools/rollup-fallback.tsproves one from your own spend and submits it to Arkade directly (so this path does not help if Arkade itself is offline; see above). That needs a mirror of the pool's records and keys, made while the sequencer was up (the batch proving keys are hundreds of megabytes, so this is a desktop step, not something a browser wallet can do). Other wallets, and the sequencer itself, follow such a batch only once its record is handed over (publish). Until then, the notes it creates cannot be found. Renewing the head needs the sequencer, so without it the head expires at most a week after its last renewal, and every payout made from it expires at the same time. Withdraw, and move the payout on Arkade, before then. - Recovery needs the published records and the wallet's recovery secret. Nobody can reset a lost secret. The pool forgets in epochs of 128 batches: a note spends directly in the epoch it was made in and the one after, and a wallet refreshes its notes inside that window. Recovering an older note needs the sealed spent-note sets of the epoch it came from and the one after, which the operator serves and a GitHub release mirrors; if every copy of an epoch's sets were lost, neither that epoch's notes nor the previous epoch's could be recovered.
- Viewing keys. A view key reveals every note a wallet received; a full viewing key also reveals which notes it spent and, through change, how much each payment out sent. Both are forever: a key handed out cannot be revoked. Neither can spend, and a full viewing key cannot freeze notes either, because a zero-value input's nullifier is hashed apart from real ones.
- Privacy. Deposits and withdrawals are public, including amounts and the Arkade addresses involved. Payments inside the pool hide sender, recipient and amount, and the anonymity set is the previous epoch's notes plus the current epoch so far: at least one whole epoch once the pool has rotated. A refresh is an ordinary payment to yourself. A recovery is a public event: it names the epoch the note came from, shows that its owner was away for over an epoch, and hides only among that one sealed epoch. Nullifiers are public: every spend reveals the spent note's nullifier, so an observer sees that a note was spent — not whose or how much, for an internal transfer. A payment that spends two or three notes at once — when no single note covers the amount, or when an asset moves alongside its Bitcoin leg — publicly marks those nullifiers as one group, so the batch feed shows those notes share an owner. This clusters a user's co-spent notes; it does not reveal identity or amount, and hiding it would need a different group construction left to a later genesis. Treat boundary amounts as public and do not reuse a withdrawal address.
Report issues privately to the maintainers. Do not post private details in public dependency issues or PRs.