NULL
SPECIFICATION

PROTOCOL

What NULL verifies, what it does not, and how it can fail. Version 0.1.0. Live on Solana MAINNET.
CRYPTOGRAPHY

Identities are Semaphore v4 identities: a 32-byte secret, an EdDSA (Baby Jubjub) public key and a Poseidon commitment. Groups are LeanIMT Merkle trees over commitments (Poseidon). Membership proofs are Groth16 proofs over BN254 for the audited Semaphore v4 circuit at depth 16 (up to 65,536 members).

PUBLIC SIGNALS: [merkleTreeRoot, nullifier, keccak256(message)>>8, keccak256(scope)>>8]
NULLIFIER: Poseidon(hash(scope), secret)
SCOPE VALUE: keccak256("null-protocol/scope/v1" || group_pda || scope_id) with the top byte cleared, derived by the program

Proving artifacts (wasm 06df31461d17db86..., zkey 948763c7315a337b...) are the Semaphore 4.13.0 release from PSE's snark-artifacts, self-hosted here. The on-chain verifying key is generated from @semaphore-protocol/proof@4.14.4 and embedded in the program. Trusted setup: the Semaphore v4 ceremony (phase 2 on the Perpetual Powers of Tau). Nothing cryptographic was written in-house; the program only re-encodes points for Solana's alt_bn128 syscalls and negates A as groth16-solana expects.

ON-CHAIN VERIFIER

PROGRAM EeESX96fLQvMgRLWU5Fm1HFMofiSNPeoyymCWLAsSJrS (Anchor, Solana MAINNET)

verify_proof rebuilds the public inputs from chain state (the scope value comes from the Scope account, never from the caller), rejects roots the administrator never published or that expired from the history window, rejects non-canonical field elements, runs the pairing check through Light Protocol's groth16-solana, enforces one nullifier per one-time scope, and writes a Receipt PDA holding root, nullifier, message, slot and timestamp. Every failure is a hard error: nothing is written on an invalid proof.

Root handling: the group keeps a ring buffer of 8 roots. The current root always verifies; a superseded root verifies for root_validity_slots after replacement (about one hour for NULL GENESIS) so proofs built moments before a membership change still land. A removed member therefore keeps proving power for that window; set the window to 0 for immediate revocation at the cost of races.

WHAT A PROOF MEANS

"The prover holds the secret of some commitment the NULL GENESIS issuer placed in the published root, and has not acted before in this one-time scope." It does not prove unique humanity, legal identity, age, residency or anything the issuer did not check. The NULL GENESIS issuer checks exactly one thing: possession of a valid single-use invitation.

THREAT MODEL

Compromised issuer. The admin key controls membership and roots. It can admit fake members (diluting trust, not anonymity) or revoke by publishing a root without you. It cannot prove as you or deanonymize proofs: it never sees secrets. Mitigation path: multisig admin, transparency log of published roots (the Explorer shows on-chain root history), multiple independent issuers.

Malicious relayer. The relayer sees proof, root, nullifier, message and your IP address. It can censor or delay. It cannot alter the message or scope (the proof binds them) and cannot learn your commitment. Anyone can run their own relayer or pay the transaction from any wallet; the program does not care who pays.

Replay. Nullifier records are PDAs keyed by (scope, nullifier); a replayed or re-proven action in a one-time scope fails with NullifierAlreadyUsed. Multi-use scopes intentionally allow repeats and are linkable within the scope by nullifier.

Small anonymity sets. A proof is hidden among the members of the published root. With two members it is a coin flip. The UI shows the live set size and never pads groups with fictitious members.

Client storage compromise. The identity is encrypted at rest (PBKDF2-SHA256, 600k iterations, AES-256-GCM) in localStorage. Malware on the device, a weak passphrase, or a malicious browser extension can still extract it. Back up the encrypted file and keep the passphrase offline.

Enrollment-to-verification correlation. The issuer knows which commitment redeemed which invitation, and when. The relayer and RPC providers see when a proof is submitted and from which network address. Timing, IP metadata and tiny groups can correlate an enrollment with a verification even though the cryptography does not. Use Tor or a VPN, wait before proving, and prefer groups with many members. NULL does not claim perfect anonymity.

PRIVACY RULES THE SOFTWARE ENFORCES
  • Secrets are generated with the browser CSPRNG and never transmitted; the enrollment API accepts commitments only.
  • The database stores commitments, invitation hashes and public receipts. No wallets, no secrets, no raw IPs.
  • Credentials are never derived from a Solana wallet address.
  • Proofs are verified cryptographically off chain (relayer) and on chain (program). Fail closed everywhere.
  • Only the group administrator can change accepted roots; the program enforces it with has_one checks.
  • STATUS reads OPERATIONAL only when database, RPC, deployed program, relayer funds and issuer key all pass live checks.
ROADMAP

Private age-eligibility attestations, anonymous governance, unlinkable application access, expiring or revocable credentials and third-party issuers all fit this architecture (new groups, new scopes, new issuers; some need additional circuits). They arrive as new groups and issuers are added.

SOURCE AND DEVELOPER DOCS: REPOSITORY