UNPKG

loopring-lightcone

Version:

A library to interact with the Loopring relayer system

115 lines (100 loc) 3.49 kB
const { bigInt, bn128 } = require("snarkjs"); const blake2b = require("blake2b"); const assert = require("assert"); const F = bn128.Fr; const SEED = "poseidon"; const NROUNDSF = 8; const NROUNDSP = 57; const T = 6; const getPseudoRandom = (seed, n) => { const res = []; let input = Buffer.from(seed); let h = blake2b(32).update(input).digest(); while (res.length < n) { const n = F.affine(bigInt.leBuff2int(h)); res.push(n); h = blake2b(32).update(h).digest(); } return res; }; const allDifferent = (v) => { for (let i = 0; i < v.length; i++) { if (v[i].isZero()) return false; for (let j = i + 1; j < v.length; j++) { if (v[i].equals(v[j])) return false; } } return true; }; const getMatrix = (t, seed, nRounds) => { if (typeof seed === "undefined") seed = SEED; if (typeof nRounds === "undefined") nRounds = NROUNDSF + NROUNDSP; if (typeof t === "undefined") t = T; let nonce = "0000"; let cmatrix = getPseudoRandom(seed + "_matrix_" + nonce, t * 2); while (!allDifferent(cmatrix)) { nonce = Number(nonce) + 1 + ""; while (nonce.length < 4) nonce = "0" + nonce; cmatrix = getPseudoRandom(seed + "_matrix_" + nonce, t * 2); } const M = new Array(t); for (let i = 0; i < t; i++) { M[i] = new Array(t); for (let j = 0; j < t; j++) { M[i][j] = F.affine(F.inverse(F.sub(cmatrix[i], cmatrix[t + j]))); } } return M; }; exports.getMatrix = getMatrix; const getConstants = (t, seed, nRounds) => { if (typeof seed === "undefined") seed = SEED; if (typeof nRounds === "undefined") nRounds = NROUNDSF + NROUNDSP; if (typeof t === "undefined") t = T; return getPseudoRandom(seed + "_constants", nRounds); }; exports.getConstants = getConstants; const ark = (state, c) => { for (let j = 0; j < state.length; j++) { state[j] = F.add(state[j], c); } }; const sigma = (a) => { return F.mul(a, F.square(F.square(a, a))); }; const mix = (state, M) => { const newState = new Array(state.length); for (let i = 0; i < state.length; i++) { newState[i] = F.zero; for (let j = 0; j < state.length; j++) { newState[i] = F.add(newState[i], F.mul(M[i][j], state[j])); } } for (let i = 0; i < state.length; i++) state[i] = newState[i]; }; exports.createHash = (t, nRoundsF, nRoundsP, seed) => { if (typeof seed === "undefined") seed = SEED; if (typeof nRoundsF === "undefined") nRoundsF = NROUNDSF; if (typeof nRoundsP === "undefined") nRoundsP = NROUNDSP; if (typeof t === "undefined") t = T; assert(nRoundsF % 2 === 0); const C = getConstants(t, seed, nRoundsF + nRoundsP); const M = getMatrix(t, seed, nRoundsF + nRoundsP); return function (inputs) { let state = []; assert(inputs.length < t); assert(inputs.length > 0); for (let i = 0; i < inputs.length; i++) state[i] = bigInt(inputs[i]); for (let i = inputs.length; i < t; i++) state[i] = F.zero; for (let i = 0; i < nRoundsF + nRoundsP; i++) { ark(state, C[i]); if (i < nRoundsF / 2 || i >= nRoundsF / 2 + nRoundsP) { for (let j = 0; j < t; j++) state[j] = sigma(state[j]); } else { state[0] = sigma(state[0]); } mix(state, M); } return F.affine(state[0]); }; };