/* 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=n32) { f.addCode( c.i64_store32( c.getLocal("r"), (k-n32)*4, c.getLocal(c0) ) ); } [c0, c1] = [c1, c0]; f.addCode( c.setLocal(c1, c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ); } f.addCode( c.i64_store32( c.getLocal("r"), n32*4-4, c.getLocal(c0) ) ); f.addCode( c.if( c.i32_wrap_i64(c.getLocal(c1)), 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 buildMulOld() { const pAux2 = module.alloc(n8*2); const f = module.addFunction(prefix+"_mulOld"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(intPrefix + "_mulOld", c.getLocal("x"), c.getLocal("y"), c.i32_const(pAux2) )); f.addCode(c.call(prefix + "_mReduct", c.i32_const(pAux2), c.getLocal("r"))); } function buildToMontgomery() { const f = module.addFunction(prefix+"_toMontgomery"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(prefix+"_mul", c.getLocal("x"), c.i32_const(pR2), c.getLocal("r"))); } function buildFromMontgomery() { const pAux2 = module.alloc(n8*2); const f = module.addFunction(prefix+"_fromMontgomery"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(intPrefix + "_copy", c.getLocal("x"), c.i32_const(pAux2) )); f.addCode(c.call(intPrefix + "_zero", c.i32_const(pAux2 + n8) )); f.addCode(c.call(prefix+"_mReduct", c.i32_const(pAux2), c.getLocal("r"))); } function buildInverse() { const f = module.addFunction(prefix+ "_inverse"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(prefix + "_fromMontgomery", c.getLocal("x"), c.getLocal("r"))); f.addCode(c.call(intPrefix + "_inverseMod", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))); f.addCode(c.call(prefix + "_toMontgomery", c.getLocal("r"), c.getLocal("r"))); } buildAdd(); buildSub(); buildNeg(); buildMReduct(); buildMul(); buildMulOld(); buildToMontgomery(); buildFromMontgomery(); buildInverse(); module.exportFunction(prefix + "_add"); module.exportFunction(prefix + "_sub"); module.exportFunction(prefix + "_neg"); module.exportFunction(prefix + "_mReduct"); module.exportFunction(prefix + "_mul"); module.exportFunction(prefix + "_mulOld"); module.exportFunction(prefix + "_fromMontgomery"); module.exportFunction(prefix + "_toMontgomery"); module.exportFunction(prefix + "_inverse"); module.exportFunction(intPrefix + "_copy", prefix+"_copy"); module.exportFunction(intPrefix + "_zero", prefix+"_zero"); module.exportFunction(intPrefix + "_isZero", prefix+"_isZero"); module.exportFunction(intPrefix + "_eq", prefix+"_eq"); buildOne(); module.exportFunction(prefix + "_one"); return prefix; };