Skip to content

Commit 4e55253

Browse files
committed
refactor: hash merkle tree pubkey onchain, chore: update circuit readme
1 parent 0a531fc commit 4e55253

4 files changed

Lines changed: 31 additions & 63 deletions

File tree

zk-id/circuits/README.md

Lines changed: 24 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,41 @@
1-
# ZK Circom Circuit for Compressed Account Merkle Proof
1+
# Compressed Account Merkle Proof Circuit
22

3-
This directory contains a circom circuit that verifies a Merkle proof of a compressed account on Solana.
3+
Zero-knowledge circuit that proves ownership of a compressed account in a Merkle tree without revealing the account details.
44

5-
## Circuit Overview
5+
## What It Does
66

7-
The `compressed_account_merkle_proof.circom` circuit combines two key components:
7+
The circuit verifies:
8+
1. **Account Hash** - Computes Poseidon hash of account fields (owner, discriminator, data)
9+
2. **Merkle Inclusion** - Proves the account exists at a specific leaf in a 26-level tree
810

9-
1. **Compressed Account Hash**: Computes the hash of a compressed account using Poseidon hash
10-
- Based on: https://github.com/ananas-block/compressed-account-circuit
11-
- Inputs: owner_hashed, leaf_index, merkle_tree_hashed, discriminator, data_hash
12-
13-
2. **Merkle Proof Verification**: Verifies the account exists in a Merkle tree
14-
- Based on: /Users/ananas/dev/light-protocol2/circuit-lib/circuit-lib.circom
15-
- Inputs: pathElements (26 levels), expectedRoot
16-
17-
## Setup
18-
19-
Run the setup script - it will handle dependencies, compilation, and key generation:
11+
## Setup & Testing
2012

2113
```bash
14+
# Compile circuit and generate keys
2215
./scripts/setup.sh
23-
```
2416

25-
To clean up build artifacts:
17+
# Run tests
18+
cargo test-sbf
2619

27-
```bash
20+
# Clean build artifacts
2821
./scripts/clean.sh
2922
```
3023

31-
## Testing
32-
33-
### Rust Test with Mopro
24+
## Circuit I/O
3425

35-
The circuit can be tested from Rust using the mopro library:
26+
**Public inputs** (visible in proof):
27+
- `owner_hashed`, `merkle_tree_hashed`, `discriminator` - Account identifiers
28+
- `issuer_hashed` - Credential issuer
29+
- `expectedRoot` - Merkle tree root
30+
- `public_encrypted_data_hash`, `public_data_hash` - Data commitments
3631

37-
```bash
38-
cargo test test_compressed_account_merkle_proof_circuit
39-
```
32+
**Private inputs** (hidden):
33+
- `leaf_index` - Account position in tree
34+
- `pathElements[26]` - Merkle proof path
4035

41-
This test:
42-
1. Loads the compiled circuit and zkey
43-
2. Generates a proof with sample inputs
44-
3. Verifies the proof is valid
36+
## Architecture
4537

46-
## Circuit Structure
47-
48-
```
49-
CompressedAccountMerkleProof (main)
50-
├── CompressedAccountHash
51-
│ └── Poseidon(5) - Hashes account fields
52-
└── MerkleProof(26)
53-
├── Num2Bits - Converts leaf index to bits
54-
├── Switcher[26] - Routes left/right based on path
55-
└── Poseidon(2)[26] - Hashes up the tree
5638
```
57-
58-
## Public Inputs
59-
60-
The following inputs are public (visible in the proof):
61-
- owner_hashed
62-
- merkle_tree_hashed
63-
- discriminator
64-
- data_hash
65-
- expectedRoot
66-
67-
Private inputs:
68-
- leaf_index
69-
- pathElements
70-
71-
## References
72-
73-
- Compressed Account Circuit: https://github.com/ananas-block/compressed-account-circuit
74-
- Mopro ZK Library: https://github.com/zkmopro/mopro
75-
- SnarkJS: https://github.com/iden3/snarkjs
39+
CompressedAccountMerkleProof
40+
├── CompressedAccountHash (Poseidon hash of 5 fields)
41+
└── MerkleProof (26-level binary tree verification)

zk-id/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ pub mod zk_id {
156156
encrypted_data: Vec<u8>,
157157
credential_proof: CompressedProof,
158158
issuer: [u8; 32],
159-
merkle_tree_hashed: [u8; 32],
160159
data_hash: [u8; 32],
161160
verification_id: [u8; 32],
162161
) -> Result<()> {
@@ -190,6 +189,12 @@ pub mod zk_id {
190189
input_root_index,
191190
)
192191
.map_err(|e| ProgramError::from(e))?;
192+
193+
let merkle_tree_pubkey = ctx.accounts.input_merkle_tree.key();
194+
let merkle_tree_hashed =
195+
hashv_to_bn254_field_size_be_const_array::<2>(&[&merkle_tree_pubkey.to_bytes()])
196+
.unwrap();
197+
193198
let mut discriminator = [0u8; 32];
194199
discriminator[24..].copy_from_slice(CredentialAccount::LIGHT_DISCRIMINATOR_SLICE);
195200
let issuer_hashed = hashv_to_bn254_field_size_be_const_array::<2>(&[&issuer]).unwrap();

zk-id/src/verifying_key.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub const VERIFYINGKEY: Groth16Verifyingkey = Groth16Verifyingkey {
99

1010
vk_gamma_g2: [25u8, 142u8, 147u8, 147u8, 146u8, 13u8, 72u8, 58u8, 114u8, 96u8, 191u8, 183u8, 49u8, 251u8, 93u8, 37u8, 241u8, 170u8, 73u8, 51u8, 53u8, 169u8, 231u8, 18u8, 151u8, 228u8, 133u8, 183u8, 174u8, 243u8, 18u8, 194u8, 24u8, 0u8, 222u8, 239u8, 18u8, 31u8, 30u8, 118u8, 66u8, 106u8, 0u8, 102u8, 94u8, 92u8, 68u8, 121u8, 103u8, 67u8, 34u8, 212u8, 247u8, 94u8, 218u8, 221u8, 70u8, 222u8, 189u8, 92u8, 217u8, 146u8, 246u8, 237u8, 9u8, 6u8, 137u8, 208u8, 88u8, 95u8, 240u8, 117u8, 236u8, 158u8, 153u8, 173u8, 105u8, 12u8, 51u8, 149u8, 188u8, 75u8, 49u8, 51u8, 112u8, 179u8, 142u8, 243u8, 85u8, 172u8, 218u8, 220u8, 209u8, 34u8, 151u8, 91u8, 18u8, 200u8, 94u8, 165u8, 219u8, 140u8, 109u8, 235u8, 74u8, 171u8, 113u8, 128u8, 141u8, 203u8, 64u8, 143u8, 227u8, 209u8, 231u8, 105u8, 12u8, 67u8, 211u8, 123u8, 76u8, 230u8, 204u8, 1u8, 102u8, 250u8, 125u8, 170u8],
1111

12-
vk_delta_g2: [21u8, 72u8, 208u8, 181u8, 233u8, 215u8, 234u8, 232u8, 113u8, 68u8, 77u8, 114u8, 103u8, 162u8, 47u8, 11u8, 120u8, 77u8, 110u8, 19u8, 67u8, 254u8, 169u8, 8u8, 191u8, 75u8, 11u8, 227u8, 210u8, 6u8, 173u8, 116u8, 45u8, 185u8, 182u8, 83u8, 53u8, 212u8, 78u8, 213u8, 69u8, 211u8, 202u8, 5u8, 201u8, 183u8, 233u8, 109u8, 204u8, 118u8, 17u8, 183u8, 24u8, 152u8, 252u8, 216u8, 43u8, 181u8, 124u8, 88u8, 151u8, 223u8, 136u8, 89u8, 6u8, 22u8, 50u8, 253u8, 219u8, 31u8, 186u8, 76u8, 70u8, 153u8, 107u8, 169u8, 85u8, 202u8, 171u8, 74u8, 160u8, 61u8, 172u8, 104u8, 190u8, 41u8, 165u8, 192u8, 39u8, 17u8, 21u8, 78u8, 131u8, 223u8, 52u8, 147u8, 19u8, 186u8, 39u8, 3u8, 160u8, 232u8, 28u8, 85u8, 253u8, 159u8, 62u8, 190u8, 149u8, 21u8, 38u8, 33u8, 245u8, 201u8, 183u8, 80u8, 156u8, 157u8, 166u8, 239u8, 220u8, 76u8, 134u8, 209u8, 85u8, 64u8, 120u8, 130u8],
12+
vk_delta_g2: [21u8, 95u8, 178u8, 184u8, 133u8, 102u8, 147u8, 146u8, 185u8, 207u8, 155u8, 169u8, 158u8, 231u8, 105u8, 245u8, 57u8, 139u8, 26u8, 255u8, 16u8, 86u8, 101u8, 167u8, 236u8, 145u8, 51u8, 165u8, 20u8, 243u8, 112u8, 130u8, 38u8, 60u8, 197u8, 144u8, 223u8, 87u8, 184u8, 6u8, 235u8, 119u8, 43u8, 252u8, 230u8, 206u8, 211u8, 215u8, 100u8, 176u8, 179u8, 120u8, 38u8, 106u8, 147u8, 215u8, 224u8, 190u8, 214u8, 137u8, 240u8, 14u8, 47u8, 193u8, 16u8, 27u8, 107u8, 220u8, 204u8, 166u8, 239u8, 13u8, 108u8, 46u8, 38u8, 131u8, 183u8, 51u8, 95u8, 158u8, 158u8, 190u8, 201u8, 191u8, 130u8, 253u8, 232u8, 240u8, 162u8, 198u8, 123u8, 165u8, 73u8, 239u8, 104u8, 173u8, 20u8, 105u8, 38u8, 204u8, 145u8, 51u8, 145u8, 114u8, 144u8, 104u8, 74u8, 34u8, 237u8, 28u8, 141u8, 184u8, 26u8, 194u8, 19u8, 233u8, 9u8, 172u8, 238u8, 107u8, 40u8, 113u8, 252u8, 18u8, 171u8, 199u8, 146u8, 213u8],
1313

1414
vk_ic: &[
1515
[22u8, 24u8, 254u8, 206u8, 152u8, 246u8, 56u8, 167u8, 103u8, 120u8, 252u8, 140u8, 102u8, 72u8, 191u8, 241u8, 29u8, 106u8, 51u8, 197u8, 27u8, 159u8, 141u8, 78u8, 189u8, 160u8, 73u8, 24u8, 183u8, 155u8, 8u8, 91u8, 41u8, 139u8, 41u8, 97u8, 22u8, 78u8, 73u8, 136u8, 207u8, 61u8, 34u8, 70u8, 147u8, 59u8, 149u8, 33u8, 109u8, 142u8, 61u8, 247u8, 162u8, 228u8, 118u8, 62u8, 86u8, 245u8, 185u8, 137u8, 77u8, 166u8, 60u8, 84u8],

zk-id/tests/test.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,6 @@ where
332332
.get_random_state_tree_info()?
333333
.pack_output_tree_index(&mut remaining_accounts)?;
334334

335-
let merkle_tree_hashed = hash_to_bn254_field_size_be(state_tree.as_ref());
336-
337335
let instruction_data = zk_id::instruction::ZkVerifyCredential {
338336
proof: rpc_result.proof,
339337
address_tree_info: packed_address_tree_accounts[0],
@@ -342,7 +340,6 @@ where
342340
encrypted_data,
343341
credential_proof,
344342
issuer: credential_account_parsed.issuer.to_bytes(),
345-
merkle_tree_hashed,
346343
data_hash,
347344
verification_id,
348345
};

0 commit comments

Comments
 (0)