grapevine-sonobe/circom/node_modules/circomlib/circuits/poseidon.circom
circom/node_modules/circomlib/circuits/poseidon.circomRaw
1pragma circom 2.0.0;
2
3include "./poseidon_constants.circom";
4
5template Sigma() {
6 signal input in;
7 signal output out;
8
9 signal in2;
10 signal in4;
11
12 in2 <== in*in;
13 in4 <== in2*in2;
14
15 out <== in4*in;
16}
17
18template Ark(t, C, r) {
19 signal input in[t];
20 signal output out[t];
21
22 for (var i=0; i<t; i++) {
23 out[i] <== in[i] + C[i + r];
24 }
25}
26
27template Mix(t, M) {
28 signal input in[t];
29 signal output out[t];
30
31 var lc;
32 for (var i=0; i<t; i++) {
33 lc = 0;
34 for (var j=0; j<t; j++) {
35 lc += M[j][i]*in[j];
36 }
37 out[i] <== lc;
38 }
39}
40
41template MixLast(t, M, s) {
42 signal input in[t];
43 signal output out;
44
45 var lc = 0;
46 for (var j=0; j<t; j++) {
47 lc += M[j][s]*in[j];
48 }
49 out <== lc;
50}
51
52template MixS(t, S, r) {
53 signal input in[t];
54 signal output out[t];
55
56
57 var lc = 0;
58 for (var i=0; i<t; i++) {
59 lc += S[(t*2-1)*r+i]*in[i];
60 }
61 out[0] <== lc;
62 for (var i=1; i<t; i++) {
63 out[i] <== in[i] + in[0] * S[(t*2-1)*r + t + i -1];
64 }
65}
66
67template PoseidonEx(nInputs, nOuts) {
68 signal input inputs[nInputs];
69 signal input initialState;
70 signal output out[nOuts];
71
72 // Using recommended parameters from whitepaper https://eprint.iacr.org/2019/458.pdf (table 2, table 8)
73 // Generated by https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/calc_round_numbers.py
74 // And rounded up to nearest integer that divides by t
75 var N_ROUNDS_P[16] = [56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68];
76 var t = nInputs + 1;
77 var nRoundsF = 8;
78 var nRoundsP = N_ROUNDS_P[t - 2];
79 var C[t*nRoundsF + nRoundsP] = POSEIDON_C(t);
80 var S[ N_ROUNDS_P[t-2] * (t*2-1) ] = POSEIDON_S(t);
81 var M[t][t] = POSEIDON_M(t);
82 var P[t][t] = POSEIDON_P(t);
83
84 component ark[nRoundsF];
85 component sigmaF[nRoundsF][t];
86 component sigmaP[nRoundsP];
87 component mix[nRoundsF-1];
88 component mixS[nRoundsP];
89 component mixLast[nOuts];
90
91
92 ark[0] = Ark(t, C, 0);
93 for (var j=0; j<t; j++) {
94 if (j>0) {
95 ark[0].in[j] <== inputs[j-1];
96 } else {
97 ark[0].in[j] <== initialState;
98 }
99 }
100
101 for (var r = 0; r < nRoundsF\2-1; r++) {
102 for (var j=0; j<t; j++) {
103 sigmaF[r][j] = Sigma();
104 if(r==0) {
105 sigmaF[r][j].in <== ark[0].out[j];
106 } else {
107 sigmaF[r][j].in <== mix[r-1].out[j];
108 }
109 }
110
111 ark[r+1] = Ark(t, C, (r+1)*t);
112 for (var j=0; j<t; j++) {
113 ark[r+1].in[j] <== sigmaF[r][j].out;
114 }
115
116 mix[r] = Mix(t,M);
117 for (var j=0; j<t; j++) {
118 mix[r].in[j] <== ark[r+1].out[j];
119 }
120
121 }
122
123 for (var j=0; j<t; j++) {
124 sigmaF[nRoundsF\2-1][j] = Sigma();
125 sigmaF[nRoundsF\2-1][j].in <== mix[nRoundsF\2-2].out[j];
126 }
127
128 ark[nRoundsF\2] = Ark(t, C, (nRoundsF\2)*t );
129 for (var j=0; j<t; j++) {
130 ark[nRoundsF\2].in[j] <== sigmaF[nRoundsF\2-1][j].out;
131 }
132
133 mix[nRoundsF\2-1] = Mix(t,P);
134 for (var j=0; j<t; j++) {
135 mix[nRoundsF\2-1].in[j] <== ark[nRoundsF\2].out[j];
136 }
137
138
139 for (var r = 0; r < nRoundsP; r++) {
140 sigmaP[r] = Sigma();
141 if (r==0) {
142 sigmaP[r].in <== mix[nRoundsF\2-1].out[0];
143 } else {
144 sigmaP[r].in <== mixS[r-1].out[0];
145 }
146
147 mixS[r] = MixS(t, S, r);
148 for (var j=0; j<t; j++) {
149 if (j==0) {
150 mixS[r].in[j] <== sigmaP[r].out + C[(nRoundsF\2+1)*t + r];
151 } else {
152 if (r==0) {
153 mixS[r].in[j] <== mix[nRoundsF\2-1].out[j];
154 } else {
155 mixS[r].in[j] <== mixS[r-1].out[j];
156 }
157 }
158 }
159 }
160
161 for (var r = 0; r < nRoundsF\2-1; r++) {
162 for (var j=0; j<t; j++) {
163 sigmaF[nRoundsF\2 + r][j] = Sigma();
164 if (r==0) {
165 sigmaF[nRoundsF\2 + r][j].in <== mixS[nRoundsP-1].out[j];
166 } else {
167 sigmaF[nRoundsF\2 + r][j].in <== mix[nRoundsF\2+r-1].out[j];
168 }
169 }
170
171 ark[ nRoundsF\2 + r + 1] = Ark(t, C, (nRoundsF\2+1)*t + nRoundsP + r*t );
172 for (var j=0; j<t; j++) {
173 ark[nRoundsF\2 + r + 1].in[j] <== sigmaF[nRoundsF\2 + r][j].out;
174 }
175
176 mix[nRoundsF\2 + r] = Mix(t,M);
177 for (var j=0; j<t; j++) {
178 mix[nRoundsF\2 + r].in[j] <== ark[nRoundsF\2 + r + 1].out[j];
179 }
180
181 }
182
183 for (var j=0; j<t; j++) {
184 sigmaF[nRoundsF-1][j] = Sigma();
185 sigmaF[nRoundsF-1][j].in <== mix[nRoundsF-2].out[j];
186 }
187
188 for (var i=0; i<nOuts; i++) {
189 mixLast[i] = MixLast(t,M,i);
190 for (var j=0; j<t; j++) {
191 mixLast[i].in[j] <== sigmaF[nRoundsF-1][j].out;
192 }
193 out[i] <== mixLast[i].out;
194 }
195
196}
197
198template Poseidon(nInputs) {
199 signal input inputs[nInputs];
200 signal output out;
201
202 component pEx = PoseidonEx(nInputs, 1);
203 pEx.initialState <== 0;
204 for (var i=0; i<nInputs; i++) {
205 pEx.inputs[i] <== inputs[i];
206 }
207 out <== pEx.out[0];
208}