forked from Dshield-xyz/Dshield
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.nr
More file actions
71 lines (62 loc) · 2.36 KB
/
Copy pathmain.nr
File metadata and controls
71 lines (62 loc) · 2.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use dep::poseidon::poseidon2::Poseidon2;
global TREE_DEPTH: u32 = 20;
fn hash2(a: Field, b: Field) -> Field {
Poseidon2::hash([a, b], 2)
}
fn constrain_bit(bit: Field) {
assert(bit * (1 - bit) == 0);
}
fn compute_root(leaf: Field, path_siblings: [Field; TREE_DEPTH], path_bits: [Field; TREE_DEPTH]) -> Field {
let mut cur = leaf;
for i in 0..TREE_DEPTH {
let sib = path_siblings[i];
let bit = path_bits[i];
constrain_bit(bit);
if bit == 0 {
cur = hash2(cur, sib);
} else {
cur = hash2(sib, cur);
}
}
cur
}
pub fn main(
// Public inputs
merkle_root: pub Field,
kyc_hash: pub Field,
threshold: pub Field,
auditor_key: pub Field,
// Private inputs
kyc_preimage: Field,
nullifier: Field,
secret: Field,
amount: Field,
path_siblings: [Field; TREE_DEPTH],
path_bits: [Field; TREE_DEPTH],
) {
// 1. KYC proof: user knows the preimage behind the registered kyc_hash
let computed_kyc = hash2(kyc_preimage, 0);
assert(computed_kyc == kyc_hash);
// 2. Wallet authorization: user owns a note in the shielded pool
let leaf = hash2(nullifier, secret);
let computed_root = compute_root(leaf, path_siblings, path_bits);
assert(computed_root == merkle_root);
// 3. Threshold proof: balance >= threshold without revealing exact amount.
// Like compliance/main.nr, `amount` is NOT bound to the note above (the
// leaf is hash2(nullifier, secret)), so this assert alone doesn't prove
// the prover's real balance meets `threshold` -- it only proves the
// prover's own self-chosen `amount` does. The `_binding` hash below is
// likewise unconstrained (never asserted against anything) and proves
// nothing on its own.
//
// The real binding happens on-chain: DShield pools are
// fixed-denomination, so the compliance contract's `amount_for_root`
// resolves which configured pool `merkle_root` belongs to and rejects
// the proof unless `threshold` does not exceed that pool's actual
// `get_deposit_amount()`. See contracts/compliance/src/lib.rs
// `verify_disclosure`.
let amount_u64 = amount as u64;
let threshold_u64 = threshold as u64;
assert(amount_u64 >= threshold_u64);
let _binding = Poseidon2::hash([amount, auditor_key, nullifier], 3);
}