circomlib/src/poseidon_gencontract.js
src/poseidon_gencontract.jsRaw
1// Copyright (c) 2018 Jordi Baylina
2// License: LGPL-3.0+
3//
4
5const Poseidon = require("./poseidon.js");
6
7const Contract = require("./evmasm");
8
9const SEED = "poseidon";
10const NROUNDSF = 8;
11const NROUNDSP = 57;
12const T = 6;
13
14function toHex256(a) {
15 let S = a.toString(16);
16 while (S.length < 64) S="0"+S;
17 return "0x" + S;
18}
19
20function createCode(t, nRoundsF, nRoundsP, seed) {
21 if (typeof seed === "undefined") seed = SEED;
22 if (typeof nRoundsF === "undefined") nRoundsF = NROUNDSF;
23 if (typeof nRoundsP === "undefined") nRoundsP = NROUNDSP;
24 if (typeof t === "undefined") t = T;
25
26 const K = Poseidon.getConstants(t, seed, nRoundsP + nRoundsF);
27 const M = Poseidon.getMatrix(t, seed, nRoundsP + nRoundsF);
28
29 const C = new Contract();
30
31 function saveM() {
32 for (let i=0; i<t; i++) {
33 for (let j=0; j<t; j++) {
34 C.push(toHex256(M[i][j]));
35 C.push((1+i*t+j)*32);
36 C.mstore();
37 }
38 }
39 }
40
41 function ark(r) {
42 C.push(toHex256(K[r])); // K, st, q
43 for (let i=0; i<t; i++) {
44 C.dup(1+t); // q, K, st, q
45 C.dup(1); // K, q, K, st, q
46 C.dup(3+i); // st[i], K, q, K, st, q
47 C.addmod(); // newSt[i], K, st, q
48 C.swap(2 + i); // xx, K, st, q
49 C.pop();
50 }
51 C.pop();
52 }
53
54 function sigma(p) {
55 // sq, q
56 C.dup(t); // q, st, q
57 C.dup(1+p); // st[p] , q , st, q
58 C.dup(1); // q, st[p] , q , st, q
59 C.dup(0); // q, q, st[p] , q , st, q
60 C.dup(2); // st[p] , q, q, st[p] , q , st, q
61 C.dup(0); // st[p] , st[p] , q, q, st[p] , q , st, q
62 C.mulmod(); // st2[p], q, st[p] , q , st, q
63 C.dup(0); // st2[p], st2[p], q, st[p] , q , st, q
64 C.mulmod(); // st4[p], st[p] , q , st, q
65 C.mulmod(); // st5[p], st, q
66 C.swap(1+p);
67 C.pop(); // newst, q
68 }
69
70 function mix() {
71 C.label("mix");
72 for (let i=0; i<t; i++) {
73 for (let j=0; j<t; j++) {
74 if (j==0) {
75 C.dup(i+t); // q, newSt, oldSt, q
76 C.push((1+i*t+j)*32);
77 C.mload(); // M, q, newSt, oldSt, q
78 C.dup(2+i+j); // oldSt[j], M, q, newSt, oldSt, q
79 C.mulmod(); // acc, newSt, oldSt, q
80 } else {
81 C.dup(1+i+t); // q, acc, newSt, oldSt, q
82 C.push((1+i*t+j)*32);
83 C.mload(); // M, q, acc, newSt, oldSt, q
84 C.dup(3+i+j); // oldSt[j], M, q, acc, newSt, oldSt, q
85 C.mulmod(); // aux, acc, newSt, oldSt, q
86 C.dup(2+i+t); // q, aux, acc, newSt, oldSt, q
87 C.swap(2); // acc, aux, q, newSt, oldSt, q
88 C.addmod(); // acc, newSt, oldSt, q
89 }
90 }
91 }
92 for (let i=0; i<t; i++) {
93 C.swap((t -i) + (t -i-1));
94 C.pop();
95 }
96 C.push(0);
97 C.mload();
98 C.jmp();
99 }
100
101
102 // Check selector
103 C.push("0x0100000000000000000000000000000000000000000000000000000000");
104 C.push(0);
105 C.calldataload();
106 C.div();
107 C.push("0xc4420fb4"); // poseidon(uint256[])
108 C.eq();
109 C.jmpi("start");
110 C.invalid();
111
112 C.label("start");
113
114 saveM();
115
116 C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
117
118 // Load 6 values from the call data.
119 // The function has a single array param param
120 // [Selector (4)] [Pointer (32)][Length (32)] [data1 (32)] ....
121 // We ignore the pointer and the length and just load 6 values to the state
122 // (Stack positions 0-5) If the array is shorter, we just set zeros.
123 for (let i=0; i<t; i++) {
124 C.push(0x44+(0x20*(5-i)));
125 C.calldataload();
126 }
127
128 for (let i=0; i<nRoundsF+nRoundsP; i++) {
129 ark(i);
130 if ((i<nRoundsF/2) || (i>=nRoundsP+nRoundsF/2)) {
131 for (let j=0; j<t; j++) {
132 sigma(j);
133 }
134 } else {
135 sigma(0);
136 }
137 const strLabel = "aferMix"+i;
138 C._pushLabel(strLabel);
139 C.push(0);
140 C.mstore();
141 C.jmp("mix");
142 C.label(strLabel);
143 }
144
145 C.push("0x00");
146 C.mstore(); // Save it to pos 0;
147 C.push("0x20");
148 C.push("0x00");
149 C.return();
150
151 mix();
152
153 return C.createTxData();
154}
155
156module.exports.abi = [
157 {
158 "constant": true,
159 "inputs": [
160 {
161 "name": "input",
162 "type": "uint256[]"
163 }
164 ],
165 "name": "poseidon",
166 "outputs": [
167 {
168 "name": "",
169 "type": "uint256"
170 }
171 ],
172 "payable": false,
173 "stateMutability": "pure",
174 "type": "function"
175 }
176];
177
178module.exports.createCode = createCode;
179
180