Your identity,never exposed
Subscribe to APIs via a ShieldedPool contract on Stellar. The 402 response shows only the pool contract — subscriber never learns the merchant's address. The server receives only a commitment hash — merchant never learns who subscribed. Neither side learns the other. Prove access with a Groth16 ZK proof. No identity. No trace.
Three things
stay hidden.
ZeroGate enforces four privacy properties: hidden merchant, blind server, unlinkable sessions, and ZK proof of access. Payment routes through a ShieldedPool contract — the merchant never appears on-chain. The server never learns your wallet.
Merchant hidden on-chain
Your USDC never goes to the merchant's wallet. It goes to a ShieldedPool Soroban contract. The contract stores only a Poseidon commitment hash — no merchant address, no plan, no price ever touches the ledger. Anyone watching the chain sees: wallet → pool contract. That's it.
Server blind to your wallet
The /subscribe endpoint never receives your wallet address or transaction hash. It only receives a commitment hash — Poseidon(secret, expiry) — computed entirely in your browser. The server issues a session token tied to the commitment, not to you. It is provably unable to know who subscribed.
Unlinkable API access
Every API call carries a session token derived from your commitment hash via HMAC. The server verifies it without storing any wallet data. In production this becomes a full Groth16 ZK proof — the server learns only that a valid subscription exists, never which wallet holds it.
ZK proof of access
Your browser generates a Groth16 proof over the Poseidon Merkle tree — proving you hold a valid, unexpired subscription leaf without revealing which leaf, which wallet, or what amount was paid. 11,741 constraints, BN254 curve, verified by Stellar's native host functions.
Deposit.Prove.Access.
Four things
we never leak.
Every privacy property in ZeroGate is cryptographically enforced — not a policy promise. The Groth16 circuit proves all four simultaneously with a single pairing check on Stellar.
Amount-hiding
The USDC amount you pay is committed via Poseidon hash and never appears in any Stellar transaction field readable by the verifier or merchant.
Merchant-hiding
The API provider's Stellar address is replaced by a Poseidon commitment on-chain. No on-chain observer can determine who you paid, only that you paid someone.
Session unlinkability
Each API call produces a unique nullifier. The nullifier registry prevents replay without enabling any form of call correlation across sessions.
Non-custodial
No server or third party ever holds your wallet keys or session token. The ZK proof is generated entirely in-browser — your secret never leaves your machine.
Built on proven
ZK primitives.
Every layer of ZeroGate is open source. The circuit, the contracts, the middleware, and the frontend — all auditable and self-hostable.
Circom 2.0 circuit
11,741 constraints. Poseidon Merkle membership proof, nullifier derivation, merchant commitment, timestamp validity. Compiled with snarkjs Groth16.
Soroban verifier
Three contracts: Groth16Verifier (BN254 pairing check), NullifierRegistry (double-spend prevention), SubscriptionRegistry (Merkle tree + proof orchestration).
x402 payment layer
HTTP 402 flow over Stellar USDC SAC. The server issues a 402 challenge; the client pays and receives a leaf commitment. Amount never stored.
Freighter integration
In-browser wallet via @stellar/freighter-api. The wallet signs the x402 payment; the ZK proof is generated locally by snarkjs — no key material leaves the browser.
// subscription_proof.circom — core privacy circuit
pragma circom 2.0.0;
include "poseidon.circom";
include "merkleProof.circom";
template SubscriptionProof(levels) {
// Private inputs — never leave the browser
signal input secret;
signal input merkle_path[levels];
signal input path_indices[levels];
signal input nullifier_secret;
signal input merchant_addr;
signal input merchant_salt;
signal input amount; // ← amount stays private
// Public outputs — the only things the server sees
signal output root;
signal output nullifier;
signal output merchant_commitment;
signal output timestamp;
// Prove Merkle membership without revealing leaf
component merkle = MerkleProof(levels);
// ... 11,741 constraints total
}Private APIs,
merchant invisible.
Connect Freighter, deposit USDC into the ShieldedPool, and access any API with a ZK credential — the server never learns your wallet, the chain never reveals the merchant. Entirely in the browser, on Stellar Testnet.
Stellar Testnet · ShieldedPool deployed · Circom + Groth16 + Soroban



