← All posts

April 10, 2026 · Permissionless Technologies

Universal Private Pool vs RAILGUN: On-Chain Compliance vs Wallet-Level Trust

Both protocols hide your transactions on Ethereum. But one enforces compliance inside the smart contract — the other trusts the wallet to do it. That distinction changes everything.

privacycomplianceRAILGUNASPzero-knowledgePPOI
Two digital vaults representing different privacy architectures

Two Protocols, One Question

RAILGUN and Universal Private Pool both solve the same problem: private transactions on Ethereum. Both use zero-knowledge proofs. Both support multiple tokens. Both let you shield, transfer, and withdraw without exposing sender, recipient, or amount.

But if a regulator sits down with your legal team and asks, "How do you ensure sanctioned funds can't move through this system?" — the two protocols give fundamentally different answers.

RAILGUN says: "Our wallet software checks a list of known bad actors before accepting deposits. If the wallet cooperates."

Universal Private Pool says: "The smart contract itself refuses to process a withdrawal unless the user proves, on-chain, that they belong to an approved compliance set."

One is a software policy. The other is a mathematical constraint. That difference isn't academic — it determines whether a protocol can survive serious regulatory scrutiny, whether institutions will touch it, and whether users' funds can be held hostage by a compliance failure.

This article compares both approaches in detail — starting with what a decision-maker needs to know, then going progressively deeper into the cryptography, circuits, and contract code.

What RAILGUN Does

RAILGUN is the most fully featured privacy protocol on Ethereum. It supports shielded transfers, multi-token pools, note merging and splitting, and works across Ethereum, Polygon, Arbitrum, and BSC. It has processed $4.5 billion in cumulative volume.

Users deposit tokens into a shielded UTXO system. Once inside, tokens can be transferred privately — the sender, recipient, and amount are all hidden behind Groth16 zk-SNARK proofs. When users want to exit, they "unshield" tokens back to a public Ethereum address.

RAILGUN's compliance mechanism is called Private Proof of Innocence (PPOI). Here's how it works:

  1. A user shields tokens into the RAILGUN pool.
  2. During a 1-hour standby period, List Providers (entities like Chainalysis, Elliptic, and ScamSniffer) check whether the source wallet is associated with sanctions violations, known exploits, or flagged activity.
  3. If the deposit passes screening, it's added to a PPOI accumulator — a cryptographic data structure attesting to its legitimacy.
  4. This proof follows the funds through subsequent private transfers.

The system is designed to create a clean separation between honest and illicit funds, based on the assumption that the wallet and the SDK will enforce these checks.

What Universal Private Pool Does

Universal Private Pool (UPP) takes a different approach. Instead of checking compliance at deposit time through the wallet, UPP checks compliance at withdrawal and transfer time inside the smart contract itself.

UPP uses Association Set Providers (ASPs), based on the model proposed by Vitalik Buterin et al. in the 2023 Privacy Pools paper. An ASP maintains a Merkle tree of approved origin addresses — addresses that have passed whatever compliance criteria the ASP defines (sanctions screening, KYC, behavioral analysis, etc.). The ASP publishes updated Merkle roots to an on-chain registry.

When a user withdraws or transfers from UPP, they must generate a zero-knowledge proof demonstrating two things simultaneously:

  1. They own the note they're spending (standard privacy pool proof).
  2. The note's origin address is a member of the ASP's approved set.

The smart contract verifies both proofs. If either fails, the transaction reverts. No wallet cooperation needed. No SDK enforcement. The contract simply will not process a non-compliant withdrawal.

The Executive Summary

Before diving deeper, here's the core comparison:

DimensionRAILGUN (PPOI)Universal Private Pool (ASP)
Compliance enforcementWallet/SDK level (soft)Smart contract level (hard)
When compliance is checkedAt deposit timeAt withdrawal/transfer time
Can compliance be bypassed?Yes — submit tx directly to contractNo — contract rejects non-compliant proofs
Compliance modelExclusion ("prove you're NOT bad")Inclusion ("prove you ARE good")
Can proofs be updated?No — immutable once generatedYes — re-prove against updated ASP set
If user is wrongly flaggedFunds stuck, no remediation pathRe-prove against updated set, or ragequit
Ragequit (emergency exit)Not availableYes — original depositor can always exit
Viewing keys for auditBlinded sender/receiver keysPer-transaction decryption keys (DVK)
Proof systemGroth16 on BN254 (~100-bit security)PLONK on BLS12-381 (128-bit) + Circle STARK (PQ-safe)
Fee structure0.25% shield + 0.25% unshield = 0.50% round-tripNo protocol fee

Every claim in this table is backed by code and documentation referenced below.

Comparison of wallet-level versus contract-level compliance enforcement

Soft Enforcement vs Hard Enforcement

This is the single most important architectural difference between the two protocols, and it deserves a careful explanation.

RAILGUN: Compliance Lives in the Wallet

RAILGUN's PPOI system operates at the SDK and wallet level. The RAILGUN wallet SDK generates PPOI proofs and attaches them to transactions before submission. POI Nodes — a network similar to IPFS — validate and distribute these proofs.

But the on-chain smart contracts have no knowledge of PPOI. The word "PPOI" does not appear anywhere in RAILGUN's deployed contract code. The contract's transact() function validates the zk-SNARK proof (ownership, nullifiers, Merkle membership) — but it does not check whether the user has a valid PPOI attestation.

This means: anyone who constructs a valid zk-SNARK proof can submit it directly to the RAILGUN contract, bypassing the wallet, the SDK, and the PPOI system entirely. The contract will accept it. The SNARK is valid. The compliance check never happened.

This isn't a bug. It's a design choice. RAILGUN's position is that PPOI serves as a social and legal signal — honest users generate PPOI proofs, and downstream recipients (exchanges, services) can require them. The contract remains permissionless.

The counterargument: a compliance mechanism that depends on voluntary cooperation provides no guarantee. If the wallet is the only enforcement point, and the wallet is open-source software that anyone can modify, the compliance is a convention, not a constraint.

UPP: Compliance Lives in the Contract

In UPP, the smart contract checks ASP membership as part of transaction validation. For a withdrawal, the relevant check is:

if (!isRagequit) {
    if (!aspHub.isValidASPRoot(aspId, aspRoot)) revert InvalidASPRoot();
}

The aspRoot must match a root published by a registered ASP. This root is also a public input to the zero-knowledge circuit — the circuit verifies that the note's origin address is a leaf in the ASP's Merkle tree. The contract verifies both the circuit proof and the ASP root validity.

For transfers (moving funds privately between shielded notes), there is no ragequit option — ASP membership is unconditionally required:

if (!aspHub.isValidASPRoot(aspId, aspRoot)) revert InvalidASPRoot();

This enforcement is not optional, not configurable, and not bypassable. There is no equivalent of "submit directly to the contract to skip compliance." The proof is the compliance. If the circuit can't generate a valid proof of ASP membership, the transaction doesn't exist.

Exclusion vs Inclusion: A Regulatory Design Choice

Beyond enforcement location, the two protocols use opposite compliance models.

RAILGUN (Exclusion): "Prove you are NOT in the set of known bad actors." List Providers maintain blacklists. Users prove non-membership. The default assumption: everyone is allowed unless specifically excluded.

UPP (Inclusion): "Prove you ARE in the set of approved participants." ASPs maintain allowlists. Users prove membership. The default assumption: compliance is demonstrated, not assumed.

The practical difference shows up in failure modes:

  • Exclusion failure (RAILGUN): If a blacklist update is delayed — say a new hack is discovered but the List Provider hasn't flagged the addresses yet — illicit funds pass through the system undetected. Researchers at AnChain identified a straightforward bypass: move stolen funds to a fresh wallet first, then shield from there. The clean wallet has no blacklist history.

  • Inclusion failure (UPP): If an ASP is slow to add a legitimate user to its allowlist, that user can't withdraw through normal channels — but they can ragequit to recover their funds publicly. The failure mode is temporary inconvenience, not permanent fund loss.

This maps to a known distinction in regulatory design. Financial regulation overwhelmingly uses positive identification: you prove who you are, you prove your funds are legitimate, you prove compliance. The burden is on the actor, not the system. Exclusion-based systems — "allow unless blacklisted" — create a structural window between when bad activity occurs and when the blacklist updates.

Vitalik Buterin's Privacy Pools paper calls this a "separating equilibrium": a system where honest and dishonest users reveal their type through their behavior. Inclusion-based models create stronger separating equilibria because opting out of compliance (refusing to prove ASP membership) is itself a signal.

The ragequit safety valve — a user choosing between normal compliant withdrawal and emergency public exit

The Ragequit Safety Valve

One of the deepest concerns with compliance-gated privacy pools is: what happens when the compliance system fails? What if an ASP incorrectly excludes you? What if every ASP refuses to include your origin address? Are your funds locked forever?

In RAILGUN, the answer is uncomfortable. If your deposit is flagged by List Providers during the standby period, it's excluded from the PPOI accumulator. The proof is immutable — once generated, it can't be updated. There is no mechanism to re-prove against corrected data. Your funds are inside the pool but may be effectively inaccessible through legitimate channels.

UPP takes a different approach: ragequit. Any original depositor can always recover their funds, even if no ASP will include their origin address.

Here's how it works in the circuit:

// If ragequit: recipient must equal origin
// (recipient - origin) * isRagequit === 0
signal originDiff <== recipient - inputOrigin;
originDiff * isRagequit === 0;

Two constraints enforce ragequit:

  1. The isRagequit flag must be binary (0 or 1) — enforced as isRagequit * (1 - isRagequit) === 0.
  2. If ragequit is active, the recipient address must equal the note's original depositor address — enforced as (recipient - origin) * isRagequit === 0.

When ragequit is active, the ASP membership check is bypassed:

// ASP check bypassed if ragequit
signal aspRootDiff <== aspRoot - aspMerkle.root;
signal aspMustMatch <== 1 - isRagequit;
aspRootDiff * aspMustMatch === 0;

The trade-off is explicit: ragequit lets you recover funds, but only to the original depositing address (publicly visible). You sacrifice privacy for fund safety. The withdrawal is visible on-chain — anyone can see that address X ragequit from the pool. But your money is never locked.

This is a censorship-resistance guarantee: no ASP, no governance process, and no legal action can permanently freeze funds inside UPP. The worst case is a public exit — not a permanent loss.

After the Tornado Cash sanctions in August 2022 and the subsequent delisting in March 2025, the ability of privacy protocol users to always access their funds is no longer a theoretical concern. It's a design requirement.

Re-Provability: What Happens When Compliance Status Changes?

PPOI proofs in RAILGUN are generated once, at shield time, and carry forward through all subsequent transactions. If your compliance status changes — you complete additional KYC, a false positive is corrected, a sanctions list is updated — the existing proof doesn't change. You cannot generate a new PPOI proof against updated List Provider data for tokens already inside the pool.

In UPP, compliance is verified at transaction time, not deposit time. Each withdrawal or transfer generates a fresh proof against the ASP's current Merkle root. If your status changes:

  • Added to an ASP: You can now withdraw normally. Generate a proof against the new root.
  • Removed from an ASP: Your next withdrawal attempt will fail. You can ragequit or wait for reinstatement.
  • Moved between ASPs: Different services trust different ASPs. UPP supports multiple simultaneous ASPs via the ASPRegistryHub, which maintains independent root histories for each registered ASP.

The ASP registry stores a circular buffer of 64 historical roots per ASP, so proofs remain valid even if the ASP updates its root between when you generate a proof and when it's included in a block.

This re-provability is architecturally significant. In a regulatory environment where sanctions lists change, compliance requirements evolve, and false positives happen, the ability to re-prove against updated data is not a convenience — it's a necessity.

Viewing Keys: Audit Granularity

Both protocols support selective disclosure for audits and tax compliance. The mechanisms differ substantially.

RAILGUN: Blinded Keys

RAILGUN provides viewing keys that allow auditors to see sender and receiver information for transactions. The keys are "blinded" — they reveal transaction participants without exposing the full spending authority.

The limitation: RAILGUN's viewing key system operates at the wallet level. You share a key that reveals a category of transactions, not specific individual ones. The granularity is coarser than per-transaction disclosure.

UPP: Per-Transaction Decryption Viewing Keys

UPP implements a per-transaction viewing key system using dual ECDH key agreement. Each shielded note is encrypted with a unique Decryption Viewing Key (DVK) derived from the recipient's master viewing secret and the transaction's ephemeral public key:

DVK = masterViewingSecret + Poseidon(masterViewingPubKey.x, masterViewingPubKey.y, R.x)

This enables surgical disclosure:

  • Export DVK₁ for a specific transaction to show your tax preparer.
  • Export DVK₂ and DVK₃ for two more transactions for a regulatory inquiry.
  • Keep everything else private.

The auditor receives decryption keys for specific notes only. They cannot: spend the tokens, derive other DVKs, infer the master viewing secret, or see any transaction not specifically disclosed. The math is one-way — individual DVKs reveal nothing about the master key.

This is the equivalent of showing a bank auditor three specific wire transfers without giving them access to your entire account history.

Proof Systems: Security Levels and Post-Quantum Readiness

The cryptographic foundations differ significantly.

RAILGUN: Groth16 on BN254

RAILGUN uses Groth16 zk-SNARKs over the BN254 elliptic curve (also called alt-bn128). This is the most battle-tested proof system in the Ethereum ecosystem — the same curve used by Tornado Cash, 0xBow's Privacy Pools, and the EIP-196/197 Ethereum precompiles.

Key characteristics:

  • Proof size: ~200 bytes (constant regardless of circuit complexity)
  • Verification gas: ~200,000 gas
  • Security level: ~100 bits (below NIST's 128-bit minimum for new systems; reduced from the original ~128-bit estimate after the Kim-Barbulescu attack on discrete logarithms in finite fields)
  • Trusted setup: Required (circuit-specific). RAILGUN conducted its own ceremony.
  • Post-quantum security: None. Shor's algorithm on a sufficiently powerful quantum computer would break BN254 completely.

UPP: PLONK on BLS12-381 + Circle STARK

UPP runs two proof systems side by side — not as a migration path, but as complementary tools for different threat models.

PLONK on BLS12-381 is the everyday system:

  • Security level: 128 bits (NIST-compliant)
  • On-chain verification: Uses EIP-2537 BLS12-381 precompiles (available since the Pectra upgrade, May 2025)
  • Trusted setup: Universal (Powers of Tau ceremony, reusable across circuits)
  • Post-quantum security: None — still pairing-based

Circle STARK is the post-quantum vault:

  • Security level: ~128 bits (hash-based, conjectured)
  • Proof size: ~5 KB (larger than SNARKs)
  • Verification gas: ~20 million (significantly more expensive)
  • Trusted setup: None (transparent)
  • Post-quantum security: Yes — relies only on hash function collision resistance

The rationale: most private transactions are routine — paying for coffee, transferring between wallets, settling invoices. For these, the gas efficiency of PLONK makes sense. But for high-value long-term storage where harvest-now-decrypt-later attacks are a real concern, Circle STARK provides a proof system that doesn't depend on any assumption a quantum computer could break.

Three papers published between May 2025 and March 2026 — by Craig Gidney at Google, Iceberg Quantum, and Google Quantum AI — reduced estimated qubit requirements for breaking 256-bit elliptic curves from ~9 million to under 500,000. Expert consensus places "Q-Day" in the 2030-2040 range, with optimistic estimates as early as 2027-2033. For a privacy pool holding long-term value, that's within planning horizon.

Users choose between SNARK and STARK mode based on their own risk assessment. Both coexist in the same pool. Both use the same ASP compliance layer.

Circuit Architecture and Flexibility

RAILGUN: Dynamic N-in-M-out

RAILGUN supports a flexible set of circuit configurations through a dynamic verification key system. The contract stores verification keys indexed by (nullifiers, commitments) — governance can register new circuit variants without code changes.

Known configurations include 1-in-2-out, 2-in-3-out, 8-in-4-out, and 12-in-2-out. This flexibility enables complex operations: consolidating many small notes into fewer large ones, splitting a single note into many recipients, or batch transfers.

The Merkle tree depth is 16 levels (65,536 commitments per tree), with automatic new tree creation when a tree fills.

UPP: Purpose-Built Circuits

UPP uses a smaller set of purpose-built circuits, each with a specific function:

CircuitInputs → OutputsPurpose
shield0 → 1Deposit with token binding
transfer1 → 2Private send, origin preserved, ASP check mandatory
merge_and_claim2 → 1Merge notes, merger becomes new origin
withdraw1 → 0Exit pool, ASP check + ragequit
joinsplit4 → 2Batch with same origin
merge_transfer_2x22 → 2Merge + transfer combined
merge_transfer_4x24 → 2Batch merge + transfer

Each circuit embeds the compliance logic directly — ASP membership proof, origin tracking, ragequit constraints. The trade-off: less flexible than RAILGUN's arbitrary N-in-M-out, but each circuit is optimized for its specific purpose and carries no dead constraint weight.

UPP's Merkle tree uses LeanIMT with dynamic depth up to 32 levels — a theoretical capacity of over 4 billion commitments. Root history uses a 64-element circular buffer.

The Merge-and-Claim Model

One of UPP's distinctive features is the merge_and_claim circuit, which implements a pattern we call the "bona fide purchaser" model.

When two notes are merged, the merger's address becomes the new origin. The original origins are recorded on-chain (in merge records visible via viewing keys), but the resulting note carries the merger's identity as its compliance-relevant origin.

This mirrors a legal doctrine dating to the 1500s: when a business accepts payment in good faith, they take responsibility for the funds. A car dealer doesn't need to trace where your cash came from. Downstream responsibility resets at each point of commerce.

RAILGUN's note consolidation preserves the original origin — notes can be merged, but the compliance chain is never broken. This provides stronger traceability at the cost of requiring every participant in the chain to maintain their compliance status indefinitely.

Fees

RAILGUN charges a percentage fee on shield and unshield operations. The fee is configurable by governance and capped at 50% per operation. Current values are documented at 0.25% per operation (0.50% round-trip). On a $100,000 stablecoin transfer, that's $500. Fees go to a governance-controlled treasury.

UPP has no protocol fee. Gas costs are borne by the user (proof verification gas), but the protocol itself extracts nothing.

For stablecoin use cases — where users frequently move in and out of shielded positions — the fee difference compounds quickly.

What This Means

Both RAILGUN and UPP are serious privacy protocols built by teams that care about getting the cryptography right. They solve the same fundamental problem — hiding transaction details on a transparent blockchain — and they both work.

The difference is in the compliance architecture, and that difference matters for different audiences:

If you're building a consumer wallet and want to offer privacy as a feature, RAILGUN's production readiness, multi-chain support, and large existing pool may be the right starting point. PPOI provides a compliance story even if it doesn't provide a compliance guarantee.

If you're building institutional infrastructure — a compliant stablecoin, a regulated exchange, a privacy SDK for financial services — the distinction between soft and hard compliance enforcement is load-bearing. Regulators will ask how compliance is enforced, not just whether it exists. The answer "the wallet checks" and the answer "the smart contract mathematically rejects non-compliant transactions" land very differently.

If you care about post-quantum security, UPP is the only privacy pool offering STARK-based proofs alongside SNARKs. As quantum computing timelines compress, this stops being a nice-to-have.

If you want to guarantee fund access, ragequit is a binary feature — you either have it or you don't. UPP has it. RAILGUN doesn't.

We didn't build UPP because RAILGUN is bad. We built it because the compliance model needs to be stronger, the fund safety guarantees need to be absolute, and the cryptography needs to be ready for what's coming.


Universal Private Pool is pre-audit and deployed on Sepolia testnet. The SDK packages are available at @permissionless-technologies. For technical documentation, visit our docs. For ASP operator guides, see publishing roots.

If you're working on privacy infrastructure, compliant financial protocols, or post-quantum cryptography — get in touch.