arnaucube
arnaucube/circomlibPublic Self-hosted repository
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*(t-1-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