> For the complete documentation index, see [llms.txt](https://parad0xlabs.gitbook.io/parad0xlabs-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://parad0xlabs.gitbook.io/parad0xlabs-docs/dark-null-protocol-zk-privacy-and-identity/how-it-works.md).

# How It Works

## Groth16 ZK Proofs Explained

Groth16 is a zk-SNARK (zero-knowledge succinct non-interactive argument of knowledge) over the BN254 (alt-bn128) elliptic curve. The scheme has three phases:

1. **Setup** — a trusted setup ceremony produces proving key `pk` and verification key `vk` for a specific R1CS circuit. These are fixed per circuit; the ceremony must happen once.
2. **Prove** — the prover, holding private witness `w` and public inputs `x`, runs the Groth16 prover to produce a 256-byte proof `π = (A, B, C)` where A ∈ G1, B ∈ G2, C ∈ G1 over BN254 (uncompressed affine: A 64 + B 128 + C 64).
3. **Verify** — the verifier checks a single pairing equation: `e(A, B) == e(α, β) · e(∑ xᵢ·γᵢ, γ) · e(C, δ)`. This is O(1) — constant time regardless of circuit size or witness complexity.

BN254 parameters used by groth16-solana (same as deployed AgenC, live mainnet 2025):

* Field modulus `p = 21888242871839275222246405745257275088696311157297823662689037894645226208583`
* G1 generator: `(1, 2)`
* G2 generator: standard BN254 G2 with 254-bit Fp2 coordinates

The proof does not leak the witness. The only data that leaves the prover's machine is `(π, commitment_hash)`.

***

## The Dark Passport Circuit

**Status: the reputation&#x20;*****gate*****&#x20;is live on mainnet (`dark_reputation_gate`, `9nN7…`) — a real track-record proof has verified on-chain, with replay / forged / tampered all rejected. The specific Passport circuits below (job count, success rate, earnings range) are being wired onto that gate; circuit source is at `Parad0x-Labs/Dark-Null-Protocol`.**

The circuit encodes reputation threshold constraints as R1CS over BN254. Inputs:

| Input type        | Field             | Description                         |
| ----------------- | ----------------- | ----------------------------------- |
| Private (witness) | `tasks_completed` | raw task count                      |
| Private (witness) | `credits_earned`  | total credits, u64                  |
| Private (witness) | `disputes_lost`   | dispute history counter             |
| Private (witness) | `timestamps[]`    | unix seconds for each task          |
| Public            | `commitment_hash` | Poseidon hash of all private inputs |

The circuit proves: "I know private data that hashes to `commitment_hash` and satisfies these threshold constraints" — without revealing any raw values.

Commitment construction (Poseidon hash, not SHA-256 — Poseidon is ZK-friendly, far lower constraint count):

```
commitment_hash = Poseidon(tasks_completed || credits_earned || disputes_lost || timestamps[0] || ... || timestamps[n])
```

The 32-byte `commitment_hash` is the only value that goes on-chain.

***

## Lifecycle

```mermaid
flowchart TD
    A[Agent collects local reputation data\ntasks_completed, credits_earned,\ndisputes_lost, timestamps] --> B

    B[Groth16 prover circuit runs locally\nPrivate: raw reputation fields\nPublic: commitment_hash\nOutput: 256-byte proof π] --> C

    C{Proof valid?}
    C -- No --> A
    C -- Yes --> D

    D[Agent calls UpdatePassport\ninstruction tag 0x07\n.null PDA: H4wbFJucY9shJt95N8Bra532Z4nnkKhGEfqWvLcYfuDm] --> E

    E[commitment_hash written\nto PDA offset 257, 32 bytes\nnull_registrar program\nowner-gated write] --> F

    F[Any caller: getAccountInfo\non .null PDA\nreads bytes 257..289] --> G

    G[Caller runs Groth16 verifier\nPublic input: commitment_hash\nProof: π supplied by agent\nVK: from trusted setup] --> H

    H{verify returns?}
    H -- true --> I[Passport valid\nThresholds confirmed\nNo raw data exposed]
    H -- false --> J[Reject — proof invalid\nor commitment mismatch]
```

***

## PDA Storage

Program: `H4wbFJucY9shJt95N8Bra532Z4nnkKhGEfqWvLcYfuDm` (native program, not Anchor — no 8-byte discriminator).

PDA derivation seeds: `["null-domain", sha256(name null-padded to 64 bytes)]` — name-only, no owner in seed.

Full account layout (314 bytes):

| Offset  | Size (bytes) | Field               | Notes                                              |
| ------- | ------------ | ------------------- | -------------------------------------------------- |
| 0       | 1            | `disc`              | `0x4E` ('N')                                       |
| 1       | 64           | `name`              | UTF-8, null-padded                                 |
| 65      | 32           | `owner`             | current owner pubkey                               |
| 97      | 32           | `arweave_txid`      | raw bytes of 43-char base64url Arweave tx ID       |
| 129     | 128          | `x402_endpoint`     | UTF-8 URL, null-padded                             |
| **257** | **32**       | **`passport_hash`** | **Groth16 public commitment; all-zero = none set** |
| 289     | 8            | `registered_at`     | i64 unix seconds                                   |
| 297     | 8            | `expires_at`        | i64 unix seconds (0 = perpetual)                   |
| 305     | 8            | `null_paid`         | u64 NULL paid at registration                      |
| 313     | 1            | `bump`              | PDA bump seed                                      |

`passport_hash` occupies bytes `[257, 289)`. Reading it:

```rust
// off-chain, using solana_client
let data = account.data;
let passport_hash: [u8; 32] = data[257..289].try_into().unwrap();
let is_set = passport_hash != [0u8; 32];
```

Write path: `UpdatePassport` instruction (tag `0x07`) — owner signature required, no other constraints. Anyone can read via `getAccountInfo`.

***

## Re-Prove Schedule

Reputation data is not static. The on-chain `passport_hash` represents a snapshot of the agent's state at prove-time. It becomes stale when:

* Task count crosses a threshold boundary
* Credits earned or spent push the agent into a new tier
* A dispute is resolved
* A configurable time window elapses (suggested: 7-day maximum staleness)

Re-prove flow:

```mermaid
sequenceDiagram
    participant Agent
    participant Circuit as Groth16 Prover (local)
    participant Chain as Solana Mainnet

    Note over Agent: Reputation event triggers re-prove
    Agent->>Circuit: new witness (updated fields)
    Circuit-->>Agent: new π, new commitment_hash
    Agent->>Chain: UpdatePassport (0x07)\nnew commitment_hash at offset 257
    Chain-->>Agent: tx confirmed
    Note over Chain: Old commitment overwritten\nNo history stored on-chain
```

Old commitment is gone from the PDA — overwritten in place. On-chain state is always the current snapshot only. If an audit trail of past proofs is needed, that is an off-chain concern (e.g., the Receipt-DAG layer).

***

## SIMD-0302 Dependency

On-chain Groth16 verification requires BN254 pairing operations: specifically G2 scalar multiplication and the ate pairing `e: G1 × G2 → GT`. These are not cheap in the BPF VM.

SIMD-0302 proposes to add these as native Solana syscalls:

| Syscall                    | Operation                |
| -------------------------- | ------------------------ |
| `alt_bn128_addition`       | G1 point addition        |
| `alt_bn128_multiplication` | G1 scalar multiplication |
| `alt_bn128_pairing`        | ate pairing batch        |

**Current state of SIMD-0302:** the syscalls exist on devnet/testnet; mainnet activation is pending validator vote.

Once live on mainnet, the `groth16-solana` crate can be used for on-chain verification — the same pattern already deployed by AgenC (live on mainnet, 2025). Until then, verification must be done off-chain: fetch the proof and public inputs from the agent, run the Groth16 verifier client-side, trust the result, and treat the on-chain `passport_hash` as a commitment anchor only.

**Note:** the reputation *gate* verifies on-chain today against the commitment; full Groth16 *pairing* verification (the heavier threshold circuits) is what waits on the alt-bn128 syscalls. Until those activate on mainnet, the pairing path runs off-chain against the on-chain commitment.

***

## Instruction Tag Reference (Dark Passport relevant)

| Tag    | Name           | Signer required | Field written                                  |
| ------ | -------------- | --------------- | ---------------------------------------------- |
| `0x02` | Register       | anyone          | initializes PDA; `passport_hash` = `[0u8; 32]` |
| `0x07` | UpdatePassport | owner           | `passport_hash` at offset 257                  |

Other instructions (`0x01`, `0x03`, `0x04`, `0x05`, `0x06`) do not touch `passport_hash`.

***

## The Rest of the Privacy Family

Dark Passport proves *reputation*. The same Groth16 + nullifier machinery powers the other Dark NULL primitives — at the stages below.

### Live on mainnet

* **Nullifier registry** (`dark_nullifier_record`, `24tmjEd1…`) — records one-time-use tags so a private proof can't be replayed or double-spent. Every other primitive leans on it for anti-cheat. Read-only lookups are public; a spend is single-use.
* **x402 access gate** (`dark_x402_access_gate`, `EepqzVBN…`) — gates a paid endpoint on a *proof* instead of an identity. The caller proves "I'm entitled" (a valid receipt or reputation proof); the server unlocks without learning who they are. See [DNA x402](/parad0xlabs-docs/dna-x402-payment-rail/how-it-works.md).
* **Receipt commitment tree** (`receipt_commitment_tree`, `8jC8QGiD…`) — a Merkle root of private receipts on-chain; prove a receipt is in the set without revealing the receipt.

### Proven on devnet

* **Shielded pool** — a Groth16 circuit that hides both sender and amount. A deposit joins an anonymity set; a withdrawal proves "I own an unspent note in the set" and emits a nullifier, with no link to the depositor. Sender-and-amount unlinkability is demonstrated end-to-end on devnet; the mainnet on-chain verifier rides the same BN254 dependency as the heavier Passport circuits.
* **Stealth addresses / NullPay** — pay a `.null` name and an Ed25519 stealth address is derived per payment, so funds land somewhere unlinkable to the name. Devnet rail.
* **KVAC credential** — a keyed-verification anonymous credential (an algebraic MAC over Ristretto, Chase–Meiklejohn–Mukherjee style). The issuer MACs a set of attributes; the holder later proves possession without revealing the credential or a reusable handle. The gateway verifies off-chain; a single-use spend is recorded through the on-chain nullifier. Devnet, with measured mainnet cost.

### In design

* **GhostScore** — anonymous-but-accountable paid calls: the x402 gate plus a reputation proof, so a caller stays identity-private while still being rate-limited and reputation-bound per call. (Identity leg only — the payer still pays from a visible wallet; closing the sender leg is the shielded-pool / relayer path, tracked separately.)
* **Passkey Sybil gate** (one `.null` per human via WebAuthn) and **federated, ceremony-free ecash**.

Nothing under "in design" is deployed — it's mapped here so the picture is complete, not to imply it ships today.

### Research frontier — devnet prototypes

Beyond the primitives above, the Dark NULL repo (`Parad0x-Labs/Dark-Null-Protocol`) carries a set of early prototypes — **devnet / test-only, not deployed to mainnet**, behind a research gate (+71 prototype tests). They map where the privacy layer is heading, not what ships today:

* **Batch proof verification** — verify many Groth16 proofs in one pass, amortizing the per-proof cost.
* **ZK access receipts** — prove access was granted (and paid for) without revealing *which* resource.
* **Receipt DAG** — link receipts into a verifiable directed graph, so a chain of calls carries its own provenance.
* **Piano PIR** — single-server private information retrieval: fetch a record without the server learning which one.
* **BDHKE blind tokens** — Chaumian blind-signature bearer tokens (blinded Diffie-Hellman), the building block for unlinkable ecash.

These are prototypes with passing tests — not audited, not production. Listed to show the direction.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://parad0xlabs.gitbook.io/parad0xlabs-docs/dark-null-protocol-zk-privacy-and-identity/how-it-works.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
