UPP — Universal Private PoolConcepts
Account Model
UTXO-style notes and commitments — how UPP stores private balances on-chain without revealing amounts or ownership.
Design Status
The note structure and commitment scheme are under active development. The model described here may evolve as we finalize compliance requirements.
Notes, Not Balances
UPP uses notes (like Bitcoin UTXOs) instead of account balances:
Ethereum: Address → Balance (1000 tokens)
UPP: Note A (500) + Note B (300) + Note C (200) = 1000 tokensTransactions consume notes and create new ones.
Note Structure
interface Note {
amount: bigint // Token amount
blinding: bigint // Random value (hides commitment)
origin: Address // Original depositor (for compliance)
sender: Address // Who sent this note
token: Address // ERC-20 contract
}Origin vs Sender:
origin= who first deposited. Used for ASP compliance. Only changes via merge.sender= who sent this specific note. Changes each transfer.
Commitments
Notes are stored on-chain as Poseidon hashes over BLS12-381:
ownerHash = Poseidon(spendingSecret)
commitment = Poseidon(amount, ownerHash, blinding, origin, token)Properties:
- Hiding: Can't see note contents from the commitment
- Binding: Can't create duplicate commitments (blinding ensures uniqueness)
- Token-locked: No transmutation attacks across token types
- Hash-based ownership: No elliptic curve operations —
ownerHashis a Poseidon hash of the spending secret, not a public key on BabyJubJub. This simplifies the circuit and makes the ownership model field-agnostic.
Nullifiers
Prevent double-spending:
nullifier = Poseidon(spendingSecret, leafIndex, commitment)When spent:
- Nullifier computed inside ZK proof (never revealed: spendingKey stays private)
- Nullifier published on-chain
- Contract records it as spent
- Same note can never be spent again
Merkle Tree
All commitments stored in a LeanIMT:
- Depth: 32 levels
- Hash: Poseidon over BLS12-381 scalar field
- Capacity: ~4 billion notes
- On-chain: Custom
InternalLeanIMTBLS12381fork of zk-kit with BLS12-381 field constant
Transfer Example
Alice sends 600 of 1000 UPD to Bob:
Note A is nullified. Notes B and C are new leaves in the tree.