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
72
73
74
75
76
77
78
79
80
81
82
83
84
use dep::std;
global state_depth = 9;
global utxo_depth = 4;
global batch_depth = 4;
fn main(
current_root: pub Field,
deposit: pub Field,
withdrawals: pub [Field; 16],
commitment_out: pub [Field; 16],
recipients: pub [Field; 16],
oracle: pub Field,
old_root_proof: [Field; 16],
nullifier_hashes: pub [Field; 16],
secrets: [Field; 16],
utxo_in: [Field; 48],
utxo_out: [Field; 48],
indexes: [Field; 48],
hash_path: [Field; 272],
) -> pub Field {
let trees: Field = 4;
let mut sum_in: Field = deposit;
let mut sum_out: Field = withdrawals.reduce(|a, b| a + b);
for i in 0..16 {
if (utxo_in[i*3 + 1] != 0) {
let owner = std::hash::pedersen([secrets[i]]);
assert(owner[0] == utxo_in[i*3 + 0]);
assert(nullifier_hashes[i] == std::hash::pedersen([secrets[i], secrets[i]])[0]);
let commitment_in = std::hash::pedersen([utxo_in[i*3 + 0], utxo_in[i*3 + 1], utxo_in[i*3 + 2]])[0];
let mut hash_path_utxo: [Field; utxo_depth] = [0; utxo_depth];
let mut hash_path_tx: [Field; batch_depth] = [0; batch_depth];
let mut hash_path_historic: [Field; state_depth] = [0; state_depth];
for j in 0..4 {
hash_path_utxo[j] = hash_path[(state_depth + utxo_depth + batch_depth) * i + j];
hash_path_tx[j] = hash_path[(state_depth + utxo_depth + batch_depth) * i + utxo_depth + j];
}
for l in 0..state_depth {
hash_path_historic[l] = hash_path[(state_depth + utxo_depth + batch_depth) * i + utxo_depth + batch_depth + l];
}
let index_utxo = indexes[trees * i + 0];
let index_tx = indexes[trees * i + 1];
let index_historic = indexes[trees * i + 2];
let utxo_root = std::merkle::compute_merkle_root(
commitment_in,
index_utxo,
hash_path_utxo
);
let tx_root = std::merkle::compute_merkle_root(
utxo_root,
index_tx,
hash_path_tx
);
let leaf_batch = std::hash::pedersen([tx_root, oracle])[0];
let leaf_historic = std::hash::pedersen([leaf_batch, old_root_proof[i]])[0];
let historic_root = std::merkle::compute_merkle_root(
leaf_historic,
index_historic,
hash_path_historic
);
assert(historic_root == current_root);
sum_in += utxo_in[i*3 + 1];
}
}
for k in 0..16 {
if (utxo_out[k*3 + 1] != 0) {
let commitment_out_calc = std::hash::pedersen([utxo_out[k*3 + 0], utxo_out[k*3 + 1], utxo_out[k*3 + 2]]);
assert(commitment_out_calc[0] == commitment_out[k]);
sum_out += utxo_out[k*3 + 1];
}
else {
let zero_hash = 0xf35fcb490b7ea67c3ac26ed530fa5d8dfe8be344e7177ebb63fe02723fb6f725 as Field;
assert(commitment_out[k] == zero_hash);
}
}
assert(sum_in == sum_out);
let utxo_root_calc: Field = pedersen_tree_four(commitment_out);
utxo_root_calc
}
fn pedersen_tree_four(leaves: [Field; 16]) -> Field {
let mut tx_tree: [Field; 16] = leaves;
for l in 0..8 { tx_tree[l] = std::hash::pedersen([tx_tree[2*l], tx_tree[2*l + 1]])[0]; }
for l in 0..4 { tx_tree[l] = std::hash::pedersen([tx_tree[2*l], tx_tree[2*l + 1]])[0]; }
for l in 0..2 { tx_tree[l] = std::hash::pedersen([tx_tree[2*l], tx_tree[2*l + 1]])[0]; }
std::hash::pedersen([tx_tree[0], tx_tree[1]])[0]
}