Nullifiers & Ownership
Nullifiers & Ownership
Stealth Address Linkage and Preventing Double-Spends with Zero Disclosure
SnarkSide replaces the conventional model of wallet-based ownership with a system built around nullifiers — cryptographic identifiers derived from private key material and entropy salts, which serve as one-time-use markers of action or ownership. Within this framework, users control margin vaults, trade intents, and position states without ever exposing their address or identity on-chain.
This section explains the role of nullifiers in SnarkSide’s shielded trading system, their relation to stealth address linkage, and how they enforce single-use constraints (such as vault spending or trade execution) without disclosing wallet addresses, account balances, or ownership status.
Why Ownership Must Be Hidden
In traditional perp DEX models, ownership is explicitly address-linked:
Wallets map directly to margin balances.
Liquidations, funding payments, and executions all mutate on-chain
msg.senderstate.Traders’ activity becomes traceable through time, often feeding adversarial machine learning models or MEV targeting logic.
SnarkSide removes msg.sender from the equation entirely. The chain never sees who issued a trade, opened a position, or owns a vault. Instead, all ownership is abstracted behind non-replayable nullifiers that are:
One-time use
Derived from a secret trapdoor
Unique to the committed object (e.g. intent or vault)
Non-invertible
This enables users to prove they own something, without revealing what they own or who they are.
Nullifier Construction
Nullifiers are derived using a one-way Poseidon hash function, typically:
nullifier = Poseidon(owner_secret, salt)Where:
owner_secretis a private scalar (derived from a stealth address keypair or trapdoor).saltis a random or domain-separated value (e.g. intent ID, vault ID, epoch).
This guarantees:
Collision resistance: no two nullifiers will overlap unless the exact preimage is reused.
Non-linkability: no observer can tie a nullifier to a wallet, address, or other commitment.
One-time verifiability: the nullifier is publicly posted when an object is consumed, preventing reuse.
Nullifiers function as ZK-bound serial numbers. Once a nullifier is used, it becomes a cryptographic tombstone — visible to the chain, but meaningless to attackers.
Role in CipherVault and Trade Intents
Vault Commitments
Every vault (i.e. encrypted margin state) includes an ownership nullifier embedded at commitment time:
vault_commitment = Poseidon(
margin_amount,
expiry,
salt,
nullifier_owner
)To spend this vault (e.g. to close a position), the user must:
Provide a SNARK that proves knowledge of the commitment preimage.
Reveal
nullifier_ownerpublicly as part of the settlement proof.Demonstrate the nullifier is not reused (checked on-chain).
At no point is the user’s wallet or address revealed. The chain only sees that a valid vault was spent once — and never again.
Trade Intents
Trade intents are also bound to nullifiers:
intent_commitment = Poseidon(
notional,
direction,
expiry,
nullifier_intent,
salt
)This prevents a trader from reusing the same trade multiple times — even if encrypted and matched off-chain repeatedly.
Only one match can settle a specific intent. If a relayer or user attempts to match it again, the nullifier will already be marked used.
Stealth Address Linkage
While the protocol does not expose addresses, users often want continuous control across multiple trades and vaults. SnarkSide supports this via stealth address derivation:
User generates a root keypair
sk,pk.For each trade or vault, the user derives a new one-time subkey or salt via PRF:
salt_n = H(sk || domain_separator || nonce)This salt is used to generate a fresh nullifier:
nullifier_n = Poseidon(sk, salt_n)The vault or intent is committed with
nullifier_n.
Only the user with sk can regenerate the salt/nullifier pair and thus prove ownership in a settlement SNARK.
This gives the user a continuous, unlinkable ownership trail, without ever registering an address.
Preventing Double-Spends
SnarkSide enforces one-time use of nullifiers via an on-chain registry:
mapping(bytes32 => bool) public nullifierUsed;
function markNullifier(bytes32 nullifier) internal {
require(!nullifierUsed[nullifier], "Nullifier already used");
nullifierUsed[nullifier] = true;
}Any attempt to settle a trade or vault transition with a previously used nullifier will revert.
This check is:
Stateless (no knowledge of accounts or balances)
Efficient (single SSTORE)
Cryptographically unforgeable (due to preimage secrecy)
Summary
Nullifiers in SnarkSide provide a stateless, cryptographic alternative to addresses. They enable:
Encrypted object ownership without disclosure
Replay prevention for vaults and trades
Shielded account behavior through one-time identifiers
Stealth linkage of off-chain user history
Together, they form the core of SnarkSide’s privacy-preserving state machine — one where ownership is proven, not declared.
Last updated

