| name | privacy-patterns |
| description | Implement privacy-preserving patterns using zero-knowledge proofs on Midnight Network. Use when designing private data handling, commitment schemes, nullifiers, or selective disclosure. Triggers on privacy, ZK proof, commitment, nullifier, or confidential computing questions. |
Privacy Patterns for Midnight
Design and implement privacy-preserving applications using zero-knowledge proofs.
Core Privacy Model
| Concept | Description | Visibility |
|---|---|---|
| Public | Ledger state | Everyone |
| Private | Circuit inputs | Only prover |
| Witness | Prover-provided data | Only prover |
| Disclosed | Explicitly revealed | Everyone |
Reference Files
| Topic | Resource |
|---|---|
| Zero-Knowledge Basics | references/zk-fundamentals.md |
| Commitment Schemes | references/commitments.md |
| Nullifier Patterns | references/nullifiers.md |
| Selective Disclosure | references/selective-disclosure.md |
Pattern Overview
1. Commitment Scheme
Hide a value while binding to it:
commitment = persistentCommit(value, randomness);
// Later: prove you know the opening
2. Nullifier Pattern
Prevent double-use without revealing identity:
nullifier = transientHash(secret, commitment);
// Can only be generated once per commitment
3. Selective Disclosure
Prove properties without revealing data:
// Prove over 18 without revealing actual age
disclose(age >= 18); // Only boolean is public
4. Merkle Membership
Prove membership in a set without revealing position:
// Verify path from leaf to root
assert verifyMerklePath(leaf, proof, root);
Quick Examples
Private Balance Check
// Only reveal if balance is sufficient, not actual amount
export circuit checkFunds(balance: Uint<64>, required: Uint<64>): Boolean {
return disclose(balance >= required);
}
Anonymous Voting
export circuit vote(voter: Bytes<32>, choice: Boolean): [] {
// Voter identity disclosed (prevents double voting)
hasVoted.insert(voter);
// Choice remains private, only totals change
if (choice) { yesCount = yesCount + 1; }
}
Commitment-Reveal
witness randomness: Field;
// Phase 1: Commit
export circuit commit(value: Uint<64>): Field {
return persistentCommit(value, randomness);
}
// Phase 2: Reveal
export circuit reveal(value: Uint<64>, commitment: Field): [] {
assert persistentCommit(value, randomness) == commitment;
disclose(value);
}
Privacy Best Practices
- ✅ Use
witnessfor data that should never appear on-chain - ✅ Use
persistentCommit(with randomness) to hide values - ✅ Use nullifiers to prevent double-actions
- ✅ Disclose only what's necessary (prefer booleans)
- ❌ Don't store unhashed sensitive data on ledger
- ❌ Don't use predictable randomness in commitments
- ❌ Don't reveal intermediate values unnecessarily
Privacy Levels
┌────────────────────────────────────────────────┐
│ Level 0: Fully Public │
│ - All data visible on-chain │
├────────────────────────────────────────────────┤
│ Level 1: Hidden Values │
│ - Commitments on-chain, values private │
├────────────────────────────────────────────────┤
│ Level 2: Unlinkable Actions │
│ - Nullifiers prevent linking actions │
├────────────────────────────────────────────────┤
│ Level 3: Anonymous Membership │
│ - Merkle proofs hide set position │
└────────────────────────────────────────────────┘
When to Use Each Pattern
| Pattern | Use Case |
|---|---|
| Commitment | Sealed bids, hidden votes before reveal |
| Nullifier | Preventing double-spend, one-time tokens |
| Merkle Proof | Membership in allowlist without revealing identity |
| Selective Disclosure | Age verification, credential proofs |