본문으로 건너뛰기
privacyJanuary 3, 2026·10 min read

Privacy-Preserving Token Transfers: A Technical Deep Dive

How NixProtocol implements private transfers using UTXO notes, ECIES encryption, and zero-knowledge proofs in a privacy pool architecture.

E

Engineering Team

NixProtocol

공유:

Your wallet is a glass house

Every token balance you have on Ethereum? Public. Every transfer you make? Public. That address you used to receive your paycheck? Anyone can see exactly how much you make, when you get paid, and where you spend it.

For individuals, that's creepy. For businesses, it's a disaster. Your competitors can watch your treasury. They can see when you're accumulating tokens before a big announcement. They can front-run your trades.

Mixing services help a bit, but they're clunky and regulators hate them. We wanted something better: a privacy pool where you can deposit, transfer, and withdraw tokens without anyone tracing the flow.

How the privacy pool works

NixProtocol uses a UTXO model, not encrypted ERC-20 balances. The concept is straightforward: you deposit tokens into the NixPool contract and receive private UTXO notes in return. These notes live in a Merkle tree on-chain, and only you know which ones are yours.

Each note is a commitment:

note = Poseidon2(value, owner_pubkey, salt)

The on-chain contract stores these commitments in a Merkle tree (depth 20, supporting roughly 1 million notes). Nobody can tell what value a note holds or who owns it just by looking at the commitment.

But wait, how do we know nobody's cheating?

This is where zero-knowledge proofs come in. Every transaction in the NixPool is authorized by an UltraHonk proof (compiled from Noir circuits via Barretenberg). No signatures needed. The ZK proof itself is the authorization.

For a transfer, the proof says:

  1. "I know the secret values behind two input notes that exist in the Merkle tree" (without revealing which ones)
  2. "I'm creating two new output notes whose values add up correctly" (no tokens created from thin air)
  3. "I'm publishing nullifiers for the input notes so they can't be spent again"
  4. "The ECIES-encrypted data attached to this transaction is correct" (for auditor compliance)

The smart contract verifies this proof. If it checks out, the transfer goes through. If not, it reverts.

Walking through the lifecycle

Deposit: entering the privacy pool

Alice wants to make 100 USDC private.

  1. She calls the deposit circuit on the NixPool contract, sending 100 USDC
  2. The contract creates a note commitment: Poseidon2(100, alice_pubkey, random_salt)
  3. This commitment gets inserted into the Merkle tree
  4. Alice stores the note details locally (value, salt, leaf index)

Her 100 USDC is now a private note. On-chain, it's just a hash. Nobody knows the value or who owns it.

Transfer: moving value privately

Alice wants to send Bob 50 USDC inside the privacy pool.

On Alice's device:

  • She selects two of her notes as inputs (the protocol always uses 2-in/2-out)
  • She creates two output notes: one for Bob (50 USDC) and one back to herself as change (50 USDC)
  • She encrypts the output note details using ECIES so Bob can discover his note
  • She generates an UltraHonk proof that everything's correct

On-chain:

  • The contract receives the transaction with nullifiers, new commitments, the proof, and ECIES-encrypted data
  • It verifies the proof
  • It checks nullifiers haven't been used before (prevents double-spending)
  • It inserts the two new note commitments into the Merkle tree
  • Done. No one learned any amounts or identities.

Bob's side:

  • Bob's wallet scans for new transactions
  • He tries to decrypt the ECIES-encrypted data with his Grumpkin private key
  • When decryption succeeds, he discovers a note meant for him
  • He now knows he received 50 USDC and stores the note details locally

Withdraw: leaving the privacy pool

Bob wants to take his 50 USDC back to a regular ERC-20 balance. He consumes his note (publishes a nullifier, proves ownership via ZK proof) and the contract releases 50 USDC to his address.

Nullifiers: preventing double-spending

Every note can only be spent once. When you spend a note, you publish a nullifier derived from the note and your private key. The contract keeps a set of all used nullifiers. If a nullifier has been seen before, the transaction reverts.

The key insight: the nullifier is deterministic for a given note and owner, but you can't link a nullifier back to the note commitment it came from. This is what keeps the privacy pool private.

What about compliance?

"But won't regulators freak out about a privacy pool?"

We thought about this. Every transaction in the NixPool includes ECIES-encrypted data that a designated auditor can decrypt. The auditor holds a Grumpkin private key set at pool deployment. They can decrypt every transaction's details (sender, receiver, amounts) if needed for compliance.

This means:

  • Regulators can audit the pool if legally required
  • The auditor can trace funds for AML/KYC purposes
  • But random strangers on the internet still can't see anything

You get privacy by default with compliance when you need it.

Real-world numbers

WhatCost
Deposit into NixPool~3M gas
Private transfer (2-in/2-out)~3M gas, proof takes ~3 seconds to generate
Withdraw from NixPool~3M gas
Registration~2.8M gas

UltraHonk proof verification is expensive - ~3M gas is significantly more than a regular ERC-20 transfer. That's the cost of real privacy: ZK proof verification is computationally heavy on-chain. On low-fee chains like Avalanche, this translates to cents rather than dollars, which makes it practical. For the privacy you get - hidden amounts, unlinkable transfers, and full sender/recipient confidentiality - we think it's worth it.

The bottom line

You shouldn't have to broadcast your financial life to participate in crypto. With the right cryptography, you can have all the benefits of blockchain (trustless, permissionless, verifiable) without giving up your privacy.

That's what we're building.

계속 읽기

프라이버시 인프라와 영지식 증명에 대한 더 많은 연구 아티클을 탐색하세요.

모든 아티클 보기