/*
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