/* Copyright 2019 0KIMS association. This file is part of websnark (Web Assembly zkSnark Prover). websnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. websnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with websnark. If not, see . */ const bigInt = require("big-integer"); const buildInt = require("./build_int.js"); const utils = require("./utils.js"); module.exports = function buildF1m(module, _q, _prefix, _intPrefix) { const q = bigInt(_q); const n64 = Math.floor((q.minus(1).bitLength() - 1)/64) +1; const n32 = n64*2; const n8 = n64*8; const prefix = _prefix || "f1m"; if (module.modules[prefix]) return prefix; // already builded const intPrefix = buildInt(module, n64, _intPrefix); const pq = module.alloc(n8, utils.bigInt2BytesLE(q, n8)); const pR2 = module.alloc(utils.bigInt2BytesLE(bigInt.one.shiftLeft(n64*64).square().mod(q), n8)); const pOne = module.alloc(utils.bigInt2BytesLE(bigInt.one.shiftLeft(n64*64).mod(q), n8)); const pZero = module.alloc(utils.bigInt2BytesLE(bigInt.zero, n8)); module.modules[prefix] = { pq: pq, pR2: pR2, n64: n64, q: q, pOne: pOne, pZero: pZero }; function buildOne() { const f = module.addFunction(prefix+"_one"); f.addParam("pr", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(prefix + "_copy", c.i32_const(pOne), c.getLocal("pr"))); } function buildAdd() { const f = module.addFunction(prefix+"_add"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode( c.if( c.call(intPrefix+"_add", c.getLocal("x"), c.getLocal("y"), c.getLocal("r")), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), c.if( c.call(intPrefix+"_gte", c.getLocal("r"), c.i32_const(pq) ), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), ) ) ); } function buildSub() { const f = module.addFunction(prefix+"_sub"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode( c.if( c.call(intPrefix+"_sub", c.getLocal("x"), c.getLocal("y"), c.getLocal("r")), c.drop(c.call(intPrefix+"_add", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))) ) ); } function buildNeg() { const f = module.addFunction(prefix+"_neg"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode( c.if( c.i32_eqz( c.call(intPrefix + "_isZero", c.getLocal("x"))), c.drop(c.call(intPrefix+"_sub", c.i32_const(pq), c.getLocal("x"), c.getLocal("r"))), ) ); } function buildMReduct() { const carries = module.alloc(n32*n32*8); const f = module.addFunction(prefix+"_mReduct"); f.addParam("t", "i32"); f.addParam("r", "i32"); f.addLocal("np32", "i64"); f.addLocal("c", "i64"); f.addLocal("m", "i64"); const c = f.getCodeBuilder(); const np32 = bigInt("100000000",16).minus( q.modInv(bigInt("100000000",16))).toJSNumber(); f.addCode(c.setLocal("np32", c.i64_const(np32))); for (let i=0; i