# ZK Circuits

> The zero-knowledge circuits that power Senddy's privacy — Shield, Spend, and Association.

Source: https://www.senddy.com/docs/technical/circuits
Last modified: 2026-08-01T23:49:54.000Z

---

## Overview

Senddy's zero-knowledge proofs are built with **Noir**, a domain-specific language for writing ZK circuits. Proofs are generated using the **UltraHonk** proving system and compiled to WebAssembly for client-side execution.

### Universal setup

UltraHonk uses a **universal trusted setup**, meaning the same setup ceremony works for any circuit. This is a significant advantage:

- **No per-circuit ceremony** — Adding new circuits or upgrading existing ones doesn't require a new trusted setup
- **Battle-tested parameters** — The universal setup has been used across many production systems
- **Upgradeable** — The system can evolve without re-running ceremonies or asking users to trust new setups

## Shield Circuit

The shield circuit converts public deposits into private notes.

**Purpose:** Prove that a deposit was correctly converted into private notes without revealing the note details.

**What it proves:**

- Total output value equals the deposit amount (value conservation)
- Note commitments are correctly computed (Poseidon2 hash of value, owner, randomness)
- Output notes belong to the depositor

## Spend Circuit

The spend circuit transfers or withdraws private notes.

**Purpose:** Prove that the spender owns the input notes, they exist in the Merkle tree, and the input/output values balance.

**What it proves:**

- Each input note exists in the Merkle tree (membership proof via Merkle path)
- The spender knows the secret key for each input note
- Nullifiers are correctly derived from the commitment and secret key
- Total input value equals total output value plus fees and withdrawal (conservation)
- Supports optional withdrawal to a public Ethereum address
- Supports optional relayer fee for gasless transactions

## Association Circuit

The association circuit enables optional, privacy-preserving compliance. It complements Senddy's [deposit screening](/docs/technical/compliance#deposit-screening) (which blocks sanctioned addresses) by giving legitimate users a way to *prove* their funds are clean after they've been in the private pool.

**Purpose:** Prove that a user's funds trace back to approved deposit sources without revealing their full transaction history.

**What it proves:**

- The note's nullifier is correctly derived from the user's secrets
- The source deposit exists in an Association Set Provider's (ASP) approved set (Merkle membership proof)
- A valid chain of custody links the deposit to the user's current note

**Key properties:**

- **Voluntary** — Association proofs are never required for basic usage
- **Privacy-preserving** — The proof reveals nothing about which specific deposit funded the note, only that it was in the approved set
- **Multi-ASP support** — Different ASPs can maintain different compliance standards for different jurisdictions

See [Compliance](/docs/technical/compliance#association-proofs) for the full compliance model.

## Proof Performance

| Metric | Value |
|---|---|
| **Proving time (browser)** | 2-5 seconds |
| **Proving time (mobile)** | 3-7 seconds |
| **Proof size** | ~8 KB |
| **Verification (attestor)** | < 1 second |

Proofs are generated client-side using WebAssembly. The UltraHonk proving system is optimized for browser performance.
