Protocol
Privacy Primitives
Four production-grade primitives, each addressing a different leak point in the agent pipeline: Semaphore for identity, XMTP for delivery, Phala TEE for inference, and Railgun for execution.
Threat Model
Adversaries
SHADE is designed to be secure against four adversaries under standard cryptographic assumptions (DDH on Curve25519, knowledge-of-exponent / AGM for Groth16, and SGX/SEV hardware integrity for TEE attestation).
- Network adversary A_N: passive observer of all network traffic. Cannot break TLS 1.3, AES-256, or Curve25519.
- On-chain adversary A_C: full read access to Base, all connected L2s, and the public mempool. Can correlate timestamps, addresses, and gas fingerprints.
- Operator adversary A_O: SHADE itself, assumed honest-but-curious. Controls servers and front-end but cannot break TEE attestation or zk soundness.
- Subscriber adversary A_S: a paying subscriber attempting to deanonymize others, harvest signals for resale, or correlate group membership with on-chain activity.
Identity
Semaphore: zero-knowledge group membership
Semaphore is a zk-SNARK protocol over BN254 for anonymous group membership proofs. SHADE maintains an on-chain Merkle tree T of identity commitments, where each commitment is computed via the Poseidon hash:
A user holding at least T $SHADE generates a Groth16 proof attesting to four facts: knowledge of a Merkle pre-image, knowledge of a wallet w with balance ≥ T at a recent block, a unique nullifier scoped to the current epoch, and a signal payload bound to the proof. The wallet address is never transmitted; only the proof.
Proof generation runs entirely client-side in WebAssembly with circuit complexity of approximately 2^20 constraints and proving time of 3–5 seconds on a modern laptop. Verification is constant-time, on the order of 2 ms.
import { Identity } from "@semaphore-protocol/identity";
import { generateProof } from "@semaphore-protocol/proof";
const identity = new Identity(walletSignature);
const group = await fetchSubscriberGroup();
const externalNullifier = currentEpochId();
const signal = sessionRequestPayload();
const proof = await generateProof(
identity,
group,
externalNullifier,
signal,
);
// Send only `proof` to SHADE. Wallet never leaves the device.Delivery
XMTP: end-to-end encrypted signals
Once authenticated, signals are pushed via XMTP. XMTP implements the Signal Protocol stack adapted for wallet-keyed identities:
- Identity keys are derived deterministically from a wallet signature over a canonical XMTP key-bundle message.
- Initial key agreement uses X3DH (Extended Triple Diffie–Hellman) over Curve25519.
- Ongoing message keys are derived via the Double Ratchet algorithm, providing forward secrecy and post-compromise security.
- Payloads are encrypted with AES-256-GCM under per-message keys.
Inference
Phala TEE: confidential AI inference
Ad-hoc research queries ("score this arbitrary token") run inside a trusted execution environment. SHADE uses Phala Network, which orchestrates Intel SGX and AMD SEV-SNP enclaves under a unified attestation API.
- The user fetches a remote attestation α from the enclave, proving the running code matches a published, audited binary hash h.
- The user encrypts the query under the enclave's ephemeral public key epk, which is bound to α.
- The enclave decrypts, executes the inference, and returns the result encrypted under the user's public key.
- Neither plaintext query nor result ever appears outside enclave memory; nothing is logged.
Execution
Railgun: shielded trade routing
Railgun provides shielded UTXOs on top of Base. A user deposits ETH or USDC into the Railgun shielded pool, and subsequent withdrawals are unlinkable to the original deposit beyond the pool's anonymity set.
- Deposit v ETH into Railgun from primary wallet w, producing a shielded note n_1.
- Wait a delay Δ drawn from a stochastic distribution to avoid timing correlation.
- Withdraw to a fresh wallet w'. From an on-chain observer's perspective, w' is unlinkable to w within the anonymity set |S|.
- w' executes the trade.
Analysis
Anonymity-set sizing
Trade-attribution privacy is parameterized by the effective Railgun anonymity set at withdrawal time — the count of deposits of comparable magnitude within a rolling time window:
Default parameters are eps = 0.10 (10% magnitude tolerance) and W = 24 hours. SHADE displays |S_eff| to the user before execution and recommends delaying when the set drops below a configurable threshold.