Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/rust-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ jobs:
- counter/native
- counter/pinocchio
- account-comparison
- zk-id
- zk/zk-id
- zk/zk-vote
- zk/payments
- airdrop-implementations/simple-claim/program
include:
- example: basic-operations/native
Expand All @@ -51,10 +53,10 @@ jobs:
example: ${{ matrix.example }}
solana-cli-version: ${{ env.SOLANA_CLI_VERSION }}
rust-toolchain: ${{ env.RUST_TOOLCHAIN }}
install-circom: ${{ matrix.example == 'zk-id' }}
install-circom: ${{ startsWith(matrix.example, 'zk/') }}

- name: Setup ZK circuits
if: matrix.example == 'zk-id'
if: startsWith(matrix.example, 'zk/')
working-directory: ${{ matrix.example }}
run: ./scripts/setup.sh

Expand Down
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,10 @@ test-ledger
.claude
build
pot
zk/zk-infra.md

# ZK circuit artifacts (sensitive - do not commit)
*.zkey
*.ptau
*.r1cs
*_js/
File renamed without changes.
95 changes: 95 additions & 0 deletions zk/confidential-transfer/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# ZK Private Payments

Private token transfers using ZK proofs to hide payment amounts.

## Summary

- Deposit: Public tokens → private balance commitment = `Poseidon(amount, blinding)`
- Transfer: Send tokens privately (hidden amounts) with ZK proof
- Withdraw: Private balance → public tokens
- Nullifier prevents double-spend

## Quick Start

```bash
./scripts/setup.sh
cargo build-sbf
cargo test-sbf
```

## Source Structure

```
src/
├── lib.rs # Program entry, instructions, accounts
└── verifying_key.rs # Groth16 verifying key (7 public inputs)

circuits/
├── private_transfer.circom # Main transfer circuit
├── compressed_account.circom # Account hash computation
├── merkle_proof.circom # Merkle tree verification (26 levels)
└── range_check.circom # Balance sufficiency checks

tests/
└── test.rs # E2E test with proof generation
```

## Instructions

| Instruction | Description |
|-------------|-------------|
| `initialize` | Create vault for token mint |
| `deposit` | Deposit tokens, create balance commitment |
| `create_balance_commitment` | Create commitment without token transfer (testing) |
| `transfer` | Private transfer with ZK proof |
| `withdraw` | Withdraw tokens by proving commitment ownership |

## Compressed Accounts

| Account | Seeds | Fields |
|---------|-------|--------|
| `BalanceCommitment` | `[b"balance", commitment]` | `mint_hashed`, `commitment` |
| `NullifierAccount` | `[b"nullifier", nullifier]` | `nullifier` |

## ZK Circuit (PrivateTransfer)

**Public inputs** (7 signals):
1. `owner_hashed` - Program ID hashed to BN254 field
2. `merkle_tree_hashed` - State tree pubkey hashed
3. `discriminator` - BalanceCommitment discriminator
4. `mint_hashed` - Token mint hashed
5. `expectedRoot` - Merkle tree root
6. `nullifier` - Prevents double-spend
7. `receiver_commitment` - Receiver's balance commitment

**Private inputs**:
- `sender_amount`, `sender_blinding` - Sender's balance preimage
- `transfer_amount` - Amount to transfer
- `new_sender_blinding`, `receiver_blinding` - New blinding factors
- `leaf_index`, `account_leaf_index`, `address` - Account position
- `pathElements[26]` - Merkle proof

**Circuit constraints**:
1. Verify sender knows preimage: `sender_commitment = Poseidon(sender_amount, sender_blinding)`
2. Verify nullifier: `nullifier = Poseidon(sender_commitment, sender_blinding)`
3. Range check: `sender_amount >= transfer_amount` (64-bit decomposition)
4. Verify new sender commitment: `new_sender_commitment = Poseidon(sender_amount - transfer_amount, new_sender_blinding)`
5. Verify receiver commitment: `receiver_commitment = Poseidon(transfer_amount, receiver_blinding)`
6. Compute data_hash and account hash
7. Verify Merkle proof against `expectedRoot`

## Errors

| Code | Name | Message |
|------|------|---------|
| 6000 | `ZeroAmount` | Zero amount |
| 6001 | `Overflow` | Arithmetic overflow |
| 6002 | `InsufficientFunds` | Insufficient funds in vault |
| 6003 | `AccountNotEnoughKeys` | Not enough keys in remaining accounts |
| 6004 | `InvalidProof` | Invalid proof |

## Dependencies

- Light Protocol SDK (compression, Merkle trees)
- groth16-solana (on-chain proof verification)
- circomlib (Poseidon, comparators)
Loading
Loading