Relayer Network
Specter's data privacy protocol relies on three off-chain services that bridge the gap between computationally constrained clients (mobile devices, browsers, light wallets) and the on-chain smart contracts that require Poseidon hashes, Merkle roots, and Groth16 proofs. These services are computation-only — they never see your secrets, private keys, or plaintext data.
All three relayers are Node.js processes managed by PM2, bound to localhost, and proxied to the public internet via nginx with TLS termination.
Architecture Overview
Root Updater (Port 3001)
The Root Updater is a background service that keeps the on-chain Merkle root synchronized with the current state of the commitment tree.
Why It Exists
The commitment Merkle tree stores leaves on-chain, but recomputing the full Merkle root from all leaves on every transaction would be prohibitively expensive in gas. Instead, the Root Updater runs off-chain:
- Reads the current leaf count from the on-chain
CommitmentTreecontract. - Fetches all commitment leaves from the tree.
- Computes the Merkle root off-chain using Poseidon hashing over the full tree.
- Publishes the new root on-chain by calling the root update function.
Without the Root Updater, reveals (Summon operations) cannot verify Merkle membership against the current state. A stale root means valid commitments appear absent from the tree, causing proof verification to fail.
Operational Characteristics
| Property | Value |
|---|---|
| Update interval | Configurable (default: every new commitment batch) |
| Root history | On-chain contract stores a rolling window of recent roots |
| Failure mode | Reveals fail against stale roots; commits continue unaffected |
| Recovery | Stateless — restarts from current on-chain leaf count |
Trust Implication
The Root Updater computes a deterministic Merkle root from public on-chain data. Any party can independently verify the published root by reading the same leaves and recomputing. A compromised Root Updater could publish a stale root (denial-of-service) but cannot publish a fraudulent root — the on-chain verifier would reject proofs against an incorrect root.
Commitment Relayer (Port 3002)
The Commitment Relayer computes Poseidon commitment hashes on behalf of clients that cannot efficiently run the Poseidon hash function locally.
Why It Exists
Poseidon hashing operates over the BN254 scalar field (a ~254-bit prime). Computing Poseidon4(secret, nullifierSecret, dataHash, blinding) or the 7-input token variant requires modular arithmetic over this large field — operations that are expensive on mobile processors and WebAssembly environments.
The Commitment Relayer accepts the hashed inputs (not the raw data) and returns the computed Poseidon commitment. Desktop clients with sufficient compute can bypass this relayer entirely and compute commitments locally.
Request Flow
Trust Implication
The Commitment Relayer receives derived field elements — outputs of key derivation functions, not raw secrets. Even if the relayer is fully compromised, the attacker receives Poseidon input field elements that are computationally infeasible to reverse back to the original seed or plaintext data. The commitment output is deterministic and verifiable — a client can check the result against a local computation or a second relayer.
Proof Relayer (Port 3003)
The Proof Relayer generates Groth16 zero-knowledge proofs on behalf of clients that lack the computational resources to run the proving algorithm locally.
Why It Exists
Groth16 proof generation for the Specter redemption circuit involves:
- Evaluating a constraint system with thousands of R1CS constraints
- Performing multi-scalar multiplications on the BN254 curve
- Computing an FFT over the evaluation domain
On a modern desktop, this takes 2-5 seconds. On a mobile device, it can take 30-60 seconds or fail entirely due to memory constraints. The Proof Relayer performs this computation server-side and returns the serialized proof to the client.
Request Flow
Trust Implication
The Proof Relayer receives a witness — the set of private inputs to the ZK circuit. These inputs are field elements (secret, nullifierSecret, blinding, Merkle path siblings, etc.) derived via HKDF from a seed the relayer never sees. The relayer computes a proof that these values satisfy the circuit constraints, but:
- It cannot reverse the field elements back to the original seed.
- It cannot determine which commitment in the Merkle tree the proof corresponds to (the commitment index is not directly exposed).
- It cannot alter the proof to redirect funds — the recipient address is bound into the public inputs verified on-chain.
A compromised Proof Relayer could refuse to generate proofs (denial-of-service) or log witnesses for future analysis, but it cannot steal data or redirect value.
Faucet (Port 3005)
The Faucet is a testnet-only service that distributes GHOST tokens to developers and testers. It is not part of the production protocol and will be decommissioned at mainnet launch.
| Property | Value |
|---|---|
| Purpose | Distribute testnet GHOST tokens |
| Rate limiting | Per-wallet, time-based |
| Environment | Testnet only |
Authentication
All relayer endpoints are authenticated using a two-factor scheme:
- HMAC Authentication: Each request includes an HMAC signature computed over the request body using a shared secret. This prevents unauthorized access and request tampering.
- EIP-191 Wallet Signature: Clients sign a challenge message with their Ethereum-compatible wallet private key. This binds the request to a specific wallet address and prevents replay attacks.
Both factors must be valid for the relayer to process the request.
Network Configuration
All services follow the same deployment pattern:
| Property | Detail |
|---|---|
| Binding | All services bind to localhost only — no external network exposure |
| TLS | nginx terminates TLS with valid certificates |
| Process management | PM2 with automatic restart on crash, log rotation, and cluster mode |
| Rate limiting | nginx-level rate limiting per IP and per endpoint |
| Monitoring | PM2 metrics + nginx access logs |
Trust Model Summary
The relayer network operates on a principle of computational delegation without trust:
| Threat | Impact | Mitigation |
|---|---|---|
| Relayer sees commitment inputs | Cannot reverse field elements to raw data | Inputs are HKDF-derived; one-way |
| Relayer sees proof witness | Cannot identify which commitment is being revealed | Witness contains field elements, not indices |
| Relayer logs all requests | Historical data is field elements only | No usable plaintext is ever transmitted |
| Relayer goes offline | Denial-of-service for light clients | Desktop clients compute locally; multiple relayers can be deployed |
| Relayer publishes wrong root | Proofs against incorrect root fail verification | Root is deterministic and independently verifiable |
| Relayer modifies proof | On-chain verifier rejects invalid proofs | Groth16 soundness guarantees |
The fundamental guarantee: even a fully compromised relayer cannot steal your data, redirect your tokens, or link your commits to your reveals. Relayers are a convenience layer for resource-constrained clients, not a trust dependency.