-
Notifications
You must be signed in to change notification settings - Fork 15
/
merkleTree.circom
106 lines (84 loc) · 2.87 KB
/
merkleTree.circom
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
include "../node_modules/circomlib/circuits/mimcsponge.circom";
include "../node_modules/circomlib/circuits/bitify.circom";
template HashLeftRight() {
signal input left;
signal input right;
signal output hash;
component hasher = MiMCSponge(2, 220, 1);
hasher.ins[0] <== left;
hasher.ins[1] <== right;
hasher.k <== 0;
hash <== hasher.outs[0];
}
// if s == 0 returns [in[0], in[1]]
// if s == 1 returns [in[1], in[0]]
template Selector() {
signal input in[2];
signal input indice;
signal output outs[2];
indice * (1 - indice) === 0; // constrain s equal to 0 or 1
outs[0] <== (in[1] - in[0]) * indice + in[0];
outs[1] <== (in[0] - in[1]) * indice + in[1];
}
template MerkleTreeCheck(levels) {
signal input leaf;
signal input root;
signal input pathElements[levels];
signal input pathIndices[levels];
component hashers[levels];
component selectors[levels];
for (var i = 0; i < levels; i++) {
selectors[i] = Selector();
selectors[i].in[0] <== i == 0 ? leaf : hashers[i - 1].hash;
selectors[i].in[1] <== pathElements[i];
selectors[i].indice <== pathIndices[i];
hashers[i] = HashLeftRight();
hashers[i].left <== selectors[i].outs[0];
hashers[i].right <== selectors[i].outs[1];
}
root === hashers[levels - 1].hash;
}
template RawMerkleTree(levels) {
signal input leaf;
signal input pathElements[levels];
signal input pathIndices[levels];
signal output root;
component selectors[levels];
component hashers[levels];
for (var i = 0; i < levels; i++) {
selectors[i] = Selector();
selectors[i].in[0] <== i == 0 ? leaf : hashers[i - 1].hash;
selectors[i].in[1] <== pathElements[i];
selectors[i].indice <== pathIndices[i];
hashers[i] = HashLeftRight();
hashers[i].left <== selectors[i].outs[0];
hashers[i].right <== selectors[i].outs[1];
}
root <== hashers[levels - 1].hash;
}
template MerkleTreeUpdater(levels, zeroLeaf) {
signal input oldRoot;
signal input newRoot;
signal input leaf;
signal input pathIndices;
signal private input pathElements[levels];
// Compute indexBits once for both trees
// Since Num2Bits is non deterministic, 2 duplicate calls to it cannot be
// optimized by circom compiler
component indexBits = Num2Bits(levels);
indexBits.in <== pathIndices;
component treeBefore = RawMerkleTree(levels);
for(var i = 0; i < levels; i++) {
treeBefore.pathIndices[i] <== indexBits.out[i];
treeBefore.pathElements[i] <== pathElements[i];
}
treeBefore.leaf <== zeroLeaf;
treeBefore.root === oldRoot;
component treeAfter = RawMerkleTree(levels);
for(var i = 0; i < levels; i++) {
treeAfter.pathIndices[i] <== indexBits.out[i];
treeAfter.pathElements[i] <== pathElements[i];
}
treeAfter.leaf <== leaf;
treeAfter.root === newRoot;
}