v0.1 · devnet

Occlude Docs

Occlude is a privacy Protocol Layer anchored to Solana. It adds a shielded pool where SOL and SPL tokens move privately. Validators verify Groth16 ZK proofs in under 10 ms on commodity hardware. Settlement finality equals Solana finality — the Anchor program on-chain holds the canonical merkle root and nullifier set.

Devnet is live. Connect with @occlude/sdk and the devnet RPC. Mainnet opens after MPC ceremony, external audit, and output-note compute benchmarks.

What Occlude is not

Not a sidechain. Not a new L1. Occlude does not issue a gas token or run its own consensus chain. Proof verification and state transitions happen offchain; the on-chain Anchor program acts as the settlement layer.


Architecture

Occlude combines an offchain prover network with an on-chain Anchor program. The prover network batches shielded transactions and generates Groth16 proofs. The Anchor program verifies each proof and updates the merkle root and nullifier set on Solana.

Anchor program

The on-chain program holds two data structures:

  • Merkle tree — Poseidon-hashed commitment tree. Each deposit adds a leaf. Depth 20 supports ~1M simultaneous notes.
  • Nullifier set — Every spent note emits a nullifier. The program rejects duplicate nullifiers, making double-spend structurally impossible.

Proof system

Groth16 with BLS12-381 curve and Poseidon hash. A proof encodes validity of a state transition without revealing inputs. Proof size: ~192 bytes. Verification time: ~8–12 ms on a single CPU core. Any laptop qualifies as a verifier node.

Validator network

10 validators run BFT consensus with 7-of-10 threshold. Each validator independently verifies incoming proofs, signs state updates, and broadcasts to peers. The Anchor program accepts a state update once it carries ≥7 valid signatures.

Data flow

User submits tx  →  Validator pool receives note + proof
                 →  7-of-10 validators verify Groth16 proof
                 →  Threshold signature produced
                 →  Anchor program verifies signature + proof on Solana
                 →  Merkle root updated, nullifier recorded on-chain
                 →  Solana finality  ≈  settlement finality

Primitives

Occlude exposes three shielded operations. All three produce Groth16 proofs verified by the validator set before the Anchor program updates state.

Primitive Input Output On-chain effect
deposit SOL / SPL amount + shielded pubkey Encrypted note New leaf in merkle tree
transfer Input note(s) + recipient shielded address New encrypted note(s) Nullifier added, new leaf committed
withdraw Note + Solana destination address SOL / SPL to destination Nullifier added, funds released

Notes

A note commits to four fields: (value, token_mint, pubkey, blinding_factor). Notes are encrypted to the recipient's shielded key and stored off-chain. Only the note commitment (Poseidon hash) lives on-chain.

Nullifiers

Spending a note produces a nullifier: nullifier = Poseidon(note_preimage, spend_key). The nullifier is published on-chain. Attempting to reuse a note fails at the Anchor program — no validator cooperation required to prevent double-spend.


Privacy model

On-chain, only three things are public per transaction: a nullifier, a new commitment leaf, and the Groth16 proof. Sender, receiver, amount, and token type are all hidden inside the ZK circuit.

What the proof encodes

  • The spending party knows the note preimage (value, pubkey, blinding factor).
  • The commitment in the merkle tree matches the note.
  • The nullifier is correctly derived from the note and spend key.
  • The output commitment correctly encodes the transferred value.
  • No value is created or destroyed (conservation constraint in-circuit).

What validators see

Validators receive the proof, the public inputs (nullifier, new commitment, root), and the encrypted note for the recipient. They verify the proof is valid. They cannot infer sender, receiver, or amount from these inputs.

Trusted setup

Groth16 requires a one-time trusted setup (MPC ceremony) to generate proving and verification keys. This is Mainnet Gate 1. The ceremony requires ≥100 independent participants — a single honest participant is sufficient to destroy toxic waste and make the setup sound.


Validators

Validators are the BFT verification layer between users and the Anchor program. They verify proofs, cosign state updates, and submit batches on-chain.

Admission

New validators earn a rank on the public testnet before admission to the mainnet set. Rank is derived from uptime, correct verification history, and latency. This gates Sybil attacks without a permissioned whitelist.

Consensus

7-of-10 BFT threshold. Each validator signs a state update independently. The Anchor program verifies the threshold signature on-chain before accepting any state change. A minority coalition of up to 3 validators can delay but not corrupt state.

Slashing

Two slashable conditions:

  • Equivocation — signing conflicting state updates at the same height.
  • Persistent unavailability — missing more than a configurable fraction of rounds.

Slashing is executed by the Anchor program. Stake is locked at registration and reduced on proven violation.

Fee model

Protocol fees accumulate in the Anchor program's fee account. Validators call claim_rewards proportionally to their participation weight. No founder allocation. No protocol treasury cut.

Run a validator →


Developer guide

Occlude ships an SDK for Node.js and browser environments. The devnet endpoint is available now. No API key needed for devnet.

Install

npm install @occlude/sdk

Connect to devnet

import { OccludeClient } from '@occlude/sdk';

const client = new OccludeClient({
  network: 'devnet',
  // rpcUrl: 'https://api.devnet.solana.com',  // optional override
});

Generate a shielded keypair

import { generateShieldedKeypair } from '@occlude/sdk';

const { publicKey, secretKey } = generateShieldedKeypair();
// Store secretKey securely — it controls all notes created for publicKey

Deposit

import { Connection, Keypair } from '@solana/web3.js';

const solanaWallet = Keypair.generate(); // your Solana wallet

const { note, txSignature } = await client.deposit({
  wallet: solanaWallet,
  amount: 1_000_000,   // lamports
  token: 'SOL',
  to: publicKey,       // shielded recipient
});

console.log('Note commitment:', note.commitment);
console.log('Solana tx:', txSignature);

Transfer

const { newNote, txSignature } = await client.transfer({
  note,              // input note from deposit (or prior transfer)
  secretKey,         // spend authority
  to: recipientPublicKey,
  amount: 500_000,   // must be ≤ note.value
});

Withdraw

const { txSignature } = await client.withdraw({
  note,
  secretKey,
  to: solanaDestinationAddress,  // standard base58 pubkey
});

console.log('Withdrawn:', txSignature);

Note storage. Notes are not stored on-chain. You are responsible for persisting note data. Losing a note means losing the funds it represents. Use note.encrypt(publicKey) to store an encrypted blob.


SDK reference

OccludeClient

MethodParametersReturns
deposit(opts) wallet, amount, token, to { note, txSignature }
transfer(opts) note, secretKey, to, amount { newNote, txSignature }
withdraw(opts) note, secretKey, to { txSignature }
getMerkleRoot() Buffer (32 bytes)
getNullifierSet() Set<string>
isSpent(nullifier) nullifier: Buffer boolean

Note

Field / MethodTypeDescription
note.commitmentBufferPoseidon hash of note preimage
note.valuebigintAmount in base units
note.tokenstringToken mint address or 'SOL'
note.encrypt(pubkey)Uint8ArrayEncrypt note to storage
Note.decrypt(blob, sk)NoteRestore note from encrypted blob

Utilities

import { generateShieldedKeypair, poseidonHash, groth16Verify } from '@occlude/sdk';

// Verify a proof locally without submitting
const valid = groth16Verify(proof, publicInputs, verificationKey);

// Compute a commitment manually
const commitment = poseidonHash([value, pubkeyScalar, blindingFactor]);

Security

Threat model

Occlude assumes an honest majority of validators (7-of-10). A minority coalition can delay state updates but cannot:

  • Steal funds — the Anchor program enforces nullifier uniqueness on-chain.
  • Forge proofs — Groth16 soundness holds under the DLOG hardness assumption.
  • Reverse finality — once the Anchor program accepts a root update, Solana's consensus guarantees it.

Known limitations (devnet)

  • Trusted setup not yet complete. Devnet uses a local ceremony for testing only.
  • Note storage is client-side. No recovery service exists yet.
  • Front-running at the validator layer is possible in adversarial conditions (timing-based). Mitigated on mainnet by encrypted mempool.

Audit scope

Mainnet Gate 2 requires an external audit covering the Anchor program, the ZK circuit, and the validator consensus logic. Audit firm TBD — selection announced on @paraloomlabs.

Bug reports

Open an issue at github.com/paraloom-labs/paraloom-core. Critical vulnerabilities: email directly before public disclosure.


Roadmap

Mainnet requires three gates to pass in sequence. Each gate has an objective completion criterion — no date targets, no soft promises.

Gate 1
MPC Ceremony

Groth16 trusted setup with ≥100 independent participants. A single honest participant destroys toxic waste. Open participation — anyone can join.

Gate 2
External Audit

Independent security audit of Anchor program, ZK circuit, and validator consensus. Full report published before mainnet.

Gate 3
Output-Note Compute

Final performance benchmarks for output note generation at production scale. Throughput target: ≥50 private transfers/sec on the validator set.

Currently on devnet

  • Full Groth16 circuit (deposit, transfer, withdraw)
  • 10-validator BFT set (permissioned devnet)
  • Anchor program v0.1 deployed on Solana devnet
  • @occlude/sdk v0.1 (Node.js + browser)
  • Proof verification in ~10 ms (commodity hardware)

After mainnet

  • SPL token support (ERC-20 equivalents on Solana)
  • Encrypted mempool (validator-side front-run protection)
  • Cross-program invocation from Solana programs into the shielded pool
  • Mobile SDK

Follow progress at github.com/paraloom-labs/paraloom-core. All development is open source, MIT licensed.