> For the complete documentation index, see [llms.txt](https://docs.silopay.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.silopay.io/privacy/zk-layer.md).

# ZK Layer

Silo uses zero-knowledge proofs to create mathematical unlinkability between deposits and withdrawals in the shared vault. This page explains the cryptographic mechanism that powers that unlinkability: how commitments are generated, how proofs are verified, and why the system ensures that only the primary wallet can withdraw funds without revealing which deposit is being claimed.

#### **How It Works**

Every Silo payment involves two cryptographic operations: a commitment at deposit time and a proof at withdrawal time. Both use the Poseidon hash function, a cryptographic algorithm optimized for zero-knowledge proof circuits (specifically ZK-SNARKs).

#### **Commitment (Deposit)**

At deposit time, Silo's backend generates the commitment using the following equation:

*<mark style="color:$success;">**commitment = Poseidon(amount, pubKey, blinding, recipientHash)**</mark>*

The inputs are:

**amount** — the exact token volume being deposited.

**pubKey** — a hash derived from a securely generated random private key, computed as Poseidon(privateKey).

**blinding** — a dynamically generated 32-byte entropy number. This ensures that even if multiple users deposit identical amounts bound to the same withdrawal address, their commitments remain entirely unique and untraceable.

**recipientHash** — the hashed representation of the primary withdrawal wallet address.

The commitment is computed entirely off-chain. Only after the computation succeeds is the commitment data bundled into the on-chain transaction that executes the vault deposit. The commitment is then added to an on-chain Merkle tree. The secret values (private key, blinding) are managed internally by Silo's backend. The user never sees or handles them.

#### **Nullifier (Withdrawal)**

At withdrawal time, a nullifier is generated to prevent double-spending. The nullifier is computed as:

*<mark style="color:$success;">**nullifier = Poseidon(commitment, leafIndex, signature)**</mark>*

The nullifier is submitted alongside a zero-knowledge proof that verifies the receiver's right to withdraw without revealing which deposit the withdrawal corresponds to. The proof demonstrates that the withdrawer knows the secret values bound to a valid commitment in the Merkle tree, without exposing those values or identifying which commitment is being claimed.

The smart contract verifies the proof and checks that the nullifier has not been used before. If valid, the contract consumes the nullifier and releases the funds. Because each commitment produces a unique nullifier, no deposit can be claimed twice. And because the nullifier reveals nothing about which commitment it corresponds to, the on-chain link between deposit and withdrawal remains broken.

#### **What This Achieves**

The commitment-proof system creates two guarantees simultaneously.

First, only the primary wallet can withdraw (the first wallet in his receiver preferences). The commitment cryptographically binds the secret to a specific withdrawal address at deposit time. No other wallet can produce a valid proof, so no other wallet can trigger the withdrawal. This is what makes the system non-custodial. Silo facilitates the process but cannot move funds on a user's behalf.

Second, no observer can link a deposit to a withdrawal. The ZK proof verifies that the withdrawer has a valid claim against some commitment in the Merkle tree, but it does not reveal which one. An on-chain observer sees that a valid withdrawal occurred but cannot determine which deposit it corresponds to. This is what creates unlinkability. The mathematical guarantee that the deposit-withdrawal link is hidden, beyond just the practical obscurity of the pooled vault.

Third, no deposit can be claimed twice. The nullifier system ensures that each commitment can only be withdrawn once. The smart contract tracks consumed nullifiers and rejects any attempt to reuse one. This is the double-spend protection layer.

#### **What the User Experiences**

None of this is visible to the user. There is no secret to save, no note to manage, no shielding or unshielding step. The sender types a username and amount. The receiver signs from their wallet to withdraw. All ZK operations happen in the background, managed entirely by Silo's backend. The user experience is identical to a simple payment. The cryptography is invisible to the users experience.

#### **Relationship to Shared Vaults**

The ZK layer and the shared vault work together but serve different functions. The shared vault provides practical privacy by pooling funds from multiple users, an observer cannot easily determine which deposit corresponds to which withdrawal because there are many possible pairings. The ZK layer provides mathematical privacy by ensuring that even with unlimited computational resources, the link between a specific deposit and a specific withdrawal cannot be proven. The vault makes linkage difficult. The ZK proof makes it impossible.

<br>


---

# 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, and the optional `goal` query parameter:

```
GET https://docs.silopay.io/privacy/zk-layer.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
