> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useabyss.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Commitments, Nullifiers, and Anonymity Sets

> Formalizes how Abyss represents ownership, prevents double-spends, and achieves unlinkability at scale.

### 5.1 Commitment Construction

In Abyss, deposits are not tracked as balances tied to addresses. Instead, each deposit is represented as a **cryptographic commitment** derived from a secret known only to the depositor. This commitment is what enters the anonymity pool.

Formally, a commitment is constructed as:

```
commitment C := H(secret_key || deposit_nonce || deposit_amount)
```

Where:

* `secret_key` is generated client-side and never revealed
* `deposit_nonce` ensures uniqueness across deposits
* `deposit_amount` binds value to the commitment

The hash function `H` is collision-resistant and circuit-compatible. Once computed, `C` is inserted as a leaf into the global Merkle tree representing the anonymity pool.

This design ensures that the protocol can verify the existence of a deposit without learning anything about who made it or how it will be spent.

***

### 5.2 Merkle-Based Anonymity Set

All commitments exist within a single Merkle tree:

```
AnonymitySet := { C₁, C₂, …, Cₙ }
```

The anonymity set size `|AnonymitySet| = n` directly bounds privacy. A withdrawal proof only asserts that *one* of these commitments is being spent, without revealing which one.

Key property:

```
Pr(link deposit → withdrawal) ≈ 1 / n
```

assuming uniform usage and no external leakage.

Abyss intentionally avoids multiple pools or denominations to prevent entropy fragmentation. Every new deposit strictly increases the anonymity set for all participants.

***

### 5.3 Nullifier Design

To prevent double-spending without revealing identity, Abyss uses **nullifiers**.

For a given secret:

```
nullifier N := H(secret_key || withdrawal_index)
```

Properties:

* Deterministic per withdrawal
* Unique per spend
* Unlinkable to commitment without secret knowledge

On withdrawal, `N` is revealed as a public input and checked against an on-chain nullifier registry:

```
require(!nullifierUsed[N], "DOUBLE_SPEND");
nullifierUsed[N] = true;
```

This ensures that no withdrawal can be repeated, while revealing nothing about which commitment generated it.

***

### 5.4 Infinite Withdrawal Model

Unlike single-use note systems, Abyss supports **multiple withdrawals from a single deposit**. Internally, this is enforced through balance accounting inside the ZK circuit.

The circuit asserts:

```
Σ withdrawn_amounts ≤ deposit_amount
```

Each withdrawal consumes balance but does not exhaust the commitment unless fully spent. This enables:

* Micropayments
* Streaming payouts
* Merchant payments
* Partial liquidity exits

All without reducing anonymity.

***

### 5.5 Anonymity Set Dynamics

Anonymity is not static. It evolves with protocol usage.

Positive factors:

* Frequent deposits
* Overlapping withdrawals
* Time separation between actions

Negative factors:

* Immediate withdraw-after-deposit
* Unique withdrawal patterns
* Low pool usage

Abyss does not enforce behavior. It provides the cryptographic substrate. Privacy emerges from correct usage patterns, not protocol coercion.

***

### 5.6 Security Implications

Commitments, nullifiers, and Merkle inclusion together ensure:

* Ownership without identity
* One-time spend guarantees
* No balance inflation
* No linkage across time

These primitives are the foundation upon which all higher-level privacy features in Abyss are built.

***
