arnaucube
arnaucube/circomlibPublic Self-hosted repository
circomlib/src/poseidon.js
src/poseidon.jsRaw
  1const Scalar = require("ffjavascript").Scalar;
  2const blake2b = require("blake2b");
  3const assert = require("assert");
  4const ZqField = require("ffjavascript").ZqField;
  5const utils = require("ffjavascript").utils;
  6
  7const F = new ZqField(Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
  8exports.F = F;
  9
 10const SEED = "poseidon";
 11const NROUNDSF = 8;
 12const NROUNDSP = 57;
 13const T = 6;
 14
 15function getPseudoRandom(seed, n) {
 16    const res = [];
 17    let input = Buffer.from(seed);
 18    let h = blake2b(32).update(input).digest();
 19    while (res.length<n) {
 20        const n = F.normalize(utils.leBuff2int(Buffer.from(h)));
 21        res.push(n);
 22        h = blake2b(32).update(h).digest();
 23    }
 24
 25    return res;
 26}
 27
 28function allDifferent(v) {
 29    for (let i=0; i<v.length; i++) {
 30        if (F.isZero(v[i])) return false;
 31        for (let j=i+1; j<v.length; j++) {
 32            if (F.eq(v[i],v[j])) return false;
 33        }
 34    }
 35    return true;
 36}
 37
 38exports.getMatrix = (t, seed, nRounds) => {
 39    if (typeof seed === "undefined") seed = SEED;
 40    if (typeof nRounds === "undefined") nRounds = NROUNDSF + NROUNDSP;
 41    if (typeof t === "undefined") t = T;
 42    assert(t<=6);  // Force the same matrix for all.
 43    t=6;
 44    let nonce = "0000";
 45    let cmatrix = getPseudoRandom(seed+"_matrix_"+nonce, t*2);
 46    while (!allDifferent(cmatrix)) {
 47        nonce = (Number(nonce)+1)+"";
 48        while(nonce.length<4) nonce = "0"+nonce;
 49        cmatrix = getPseudoRandom(seed+"_matrix_"+nonce, t*2);
 50    }
 51
 52    const M = new Array(t);
 53    for (let i=0; i<t; i++) {
 54        M[i] = new Array(t);
 55        for (let j=0; j<t; j++) {
 56            M[i][j] = F.normalize(F.inv(F.sub(cmatrix[i], cmatrix[t+j])));
 57        }
 58    }
 59    return M;
 60};
 61
 62exports.getConstants = (t, seed, nRounds) => {
 63    if (typeof seed === "undefined") seed = SEED;
 64    if (typeof nRounds === "undefined") nRounds = NROUNDSF + NROUNDSP;
 65    if (typeof t === "undefined") t = T;
 66    const cts = getPseudoRandom(seed+"_constants", nRounds);
 67    return cts;
 68};
 69
 70function ark(state, c) {
 71    for (let j=0; j<state.length; j++ ) {
 72        state[j] = F.add(state[j], c);
 73    }
 74}
 75
 76function sigma(a) {
 77    return F.mul(a, F.square(F.square(a,a)));
 78}
 79
 80function mix(state, M) {
 81    const newState = new Array(state.length);
 82    for (let i=0; i<state.length; i++) {
 83        newState[i] = F.zero;
 84        for (let j=0; j<state.length; j++) {
 85            newState[i] = F.add(newState[i], F.mul(M[i][j], state[j]) );
 86        }
 87    }
 88    for (let i=0; i<state.length; i++) state[i] = newState[i];
 89}
 90
 91exports.createHash = (t, nRoundsF, nRoundsP, seed) => {
 92
 93    if (typeof seed === "undefined") seed = SEED;
 94    if (typeof nRoundsF === "undefined") nRoundsF = NROUNDSF;
 95    if (typeof nRoundsP === "undefined") nRoundsP = NROUNDSP;
 96    if (typeof t === "undefined") t = T;
 97
 98    assert(nRoundsF % 2 == 0);
 99    const C = exports.getConstants(t, seed, nRoundsF + nRoundsP);
100    const M = exports.getMatrix(t, seed, nRoundsF + nRoundsP);
101    return function(inputs) {
102        let state = [];
103        assert(inputs.length <= t);
104        assert(inputs.length > 0);
105        for (let i=0; i<inputs.length; i++) state[i] = F.e(inputs[i]);
106        for (let i=inputs.length; i<t; i++) state[i] = F.zero;
107
108        for (let i=0; i< nRoundsF + nRoundsP; i++) {
109            ark(state, C[i]);
110            if ((i<nRoundsF/2) || (i >= nRoundsF/2 + nRoundsP)) {
111                for (let j=0; j<t; j++) state[j] = sigma(state[j]);
112            } else {
113                state[0] = sigma(state[0]);
114            }
115            mix(state, M);
116        }
117        return F.normalize(state[0]);
118    };
119};
120
121