/*
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 utils = require("./utils.js");
module.exports = function buildInt(module, n64, _prefix) {
const prefix = _prefix || "int";
if (module.modules[prefix]) return prefix; // already builded
module.modules[prefix] = {};
const n32 = n64*2;
const n8 = n64*8;
const one = module.alloc(n8, utils.bigInt2BytesLE(1, n8));
function buildCopy() {
const f = module.addFunction(prefix+"_copy");
f.addParam("px", "i32");
f.addParam("pr", "i32");
const c = f.getCodeBuilder();
for (let i=0; i3)&&(Y[eY]==0) ey--;
f.addCode(c.block(c.loop(
c.br_if(
1,
c.i32_or(
c.i32_load8_u(
c.i32_add(Y , c.getLocal("eY")),
0,
0
),
c.i32_eq(
c.getLocal("eY"),
c.i32_const(3)
)
)
),
c.setLocal("eY", c.i32_sub(c.getLocal("eY"), c.i32_const(1))),
c.br(0)
)));
f.addCode(
c.setLocal(
"sy",
c.i64_add(
c.i64_load32_u(
c.i32_sub(
c.i32_add( Y, c.getLocal("eY")),
c.i32_const(3)
),
0,
0
),
c.i64_const(1)
)
)
);
// Force a divide by 0 if quotien is 0
f.addCode(
c.if(
c.i64_eq(
c.getLocal("sy"),
c.i64_const(1)
),
c.drop(c.i64_div_u(c.i64_const(0), c.i64_const(0)))
)
);
f.addCode(c.block(c.loop(
// while (eX>7)&&(Y[eX]==0) ex--;
c.block(c.loop(
c.br_if(
1,
c.i32_or(
c.i32_load8_u(
c.i32_add(R , c.getLocal("eX")),
0,
0
),
c.i32_eq(
c.getLocal("eX"),
c.i32_const(7)
)
)
),
c.setLocal("eX", c.i32_sub(c.getLocal("eX"), c.i32_const(1))),
c.br(0)
)),
c.setLocal(
"sx",
c.i64_load(
c.i32_sub(
c.i32_add( R, c.getLocal("eX")),
c.i32_const(7)
),
0,
0
)
),
c.setLocal(
"sx",
c.i64_div_u(
c.getLocal("sx"),
c.getLocal("sy")
)
),
c.setLocal(
"ec",
c.i32_sub(
c.i32_sub(
c.getLocal("eX"),
c.getLocal("eY")
),
c.i32_const(4)
)
),
// While greater than 32 bits or ec is neg, shr and inc exp
c.block(c.loop(
c.br_if(
1,
c.i32_and(
c.i64_eqz(
c.i64_and(
c.getLocal("sx"),
c.i64_const("0xFFFFFFFF00000000")
)
),
c.i32_ge_s(
c.getLocal("ec"),
c.i32_const(0)
)
)
),
c.setLocal(
"sx",
c.i64_shr_u(
c.getLocal("sx"),
c.i64_const(8)
)
),
c.setLocal(
"ec",
c.i32_add(
c.getLocal("ec"),
c.i32_const(1)
)
),
c.br(0)
)),
c.if(
c.i64_eqz(c.getLocal("sx")),
[
...c.br_if(
2,
c.i32_eqz(c.call(prefix + "_gte", R, Y))
),
...c.setLocal("sx", c.i64_const(1)),
...c.setLocal("ec", c.i32_const(0))
]
),
c.call(prefix + "__mul1", Y, c.getLocal("sx"), R2),
c.drop(c.call(
prefix + "_sub",
R,
c.i32_sub(R2, c.getLocal("ec")),
R
)),
c.call(
prefix + "__add1",
c.i32_add(C, c.getLocal("ec")),
c.getLocal("sx")
),
c.br(0)
)));
}
function buildInverseMod() {
const f = module.addFunction(prefix+"_inverseMod");
f.addParam("px", "i32");
f.addParam("pm", "i32");
f.addParam("pr", "i32");
f.addLocal("t", "i32");
f.addLocal("newt", "i32");
f.addLocal("r", "i32");
f.addLocal("qq", "i32");
f.addLocal("qr", "i32");
f.addLocal("newr", "i32");
f.addLocal("swp", "i32");
f.addLocal("x", "i32");
f.addLocal("signt", "i32");
f.addLocal("signnewt", "i32");
f.addLocal("signx", "i32");
const c = f.getCodeBuilder();
const aux1 = c.i32_const(module.alloc(n8));
const aux2 = c.i32_const(module.alloc(n8));
const aux3 = c.i32_const(module.alloc(n8));
const aux4 = c.i32_const(module.alloc(n8));
const aux5 = c.i32_const(module.alloc(n8));
const aux6 = c.i32_const(module.alloc(n8));
const mulBuff = c.i32_const(module.alloc(n8*2));
const aux7 = c.i32_const(module.alloc(n8));
f.addCode(
c.setLocal("t", aux1),
c.call(prefix + "_zero", aux1),
c.setLocal("signt", c.i32_const(0)),
);
f.addCode(
c.setLocal("r", aux2),
c.call(prefix + "_copy", c.getLocal("pm"), aux2)
);
f.addCode(
c.setLocal("newt", aux3),
c.call(prefix + "_one", aux3),
c.setLocal("signnewt", c.i32_const(0)),
);
f.addCode(
c.setLocal("newr", aux4),
c.call(prefix + "_copy", c.getLocal("px"), aux4)
);
f.addCode(c.setLocal("qq", aux5));
f.addCode(c.setLocal("qr", aux6));
f.addCode(c.setLocal("x", aux7));
f.addCode(c.block(c.loop(
c.br_if(
1,
c.call(prefix + "_isZero", c.getLocal("newr") )
),
c.call(prefix + "_div", c.getLocal("r"), c.getLocal("newr"), c.getLocal("qq"), c.getLocal("qr")),
c.call(prefix + "_mul", c.getLocal("qq"), c.getLocal("newt"), mulBuff),
c.if(
c.getLocal("signt"),
c.if(
c.getLocal("signnewt"),
c.if (
c.call(prefix + "_gte", mulBuff, c.getLocal("t")),
[
...c.drop(c.call(prefix + "_sub", mulBuff, c.getLocal("t"), c.getLocal("x"))),
...c.setLocal("signx", c.i32_const(0))
],
[
...c.drop(c.call(prefix + "_sub", c.getLocal("t"), mulBuff, c.getLocal("x"))),
...c.setLocal("signx", c.i32_const(1))
],
),
[
...c.drop(c.call(prefix + "_add", mulBuff, c.getLocal("t"), c.getLocal("x"))),
...c.setLocal("signx", c.i32_const(1))
]
),
c.if(
c.getLocal("signnewt"),
[
...c.drop(c.call(prefix + "_add", mulBuff, c.getLocal("t"), c.getLocal("x"))),
...c.setLocal("signx", c.i32_const(0))
],
c.if (
c.call(prefix + "_gte", c.getLocal("t"), mulBuff),
[
...c.drop(c.call(prefix + "_sub", c.getLocal("t"), mulBuff, c.getLocal("x"))),
...c.setLocal("signx", c.i32_const(0))
],
[
...c.drop(c.call(prefix + "_sub", mulBuff, c.getLocal("t"), c.getLocal("x"))),
...c.setLocal("signx", c.i32_const(1))
]
)
)
),
c.setLocal("swp", c.getLocal("t")),
c.setLocal("t", c.getLocal("newt")),
c.setLocal("newt", c.getLocal("x")),
c.setLocal("x", c.getLocal("swp")),
c.setLocal("signt", c.getLocal("signnewt")),
c.setLocal("signnewt", c.getLocal("signx")),
c.setLocal("swp", c.getLocal("r")),
c.setLocal("r", c.getLocal("newr")),
c.setLocal("newr", c.getLocal("qr")),
c.setLocal("qr", c.getLocal("swp")),
c.br(0)
)));
f.addCode(c.if(
c.getLocal("signt"),
c.drop(c.call(prefix + "_sub", c.getLocal("pm"), c.getLocal("t"), c.getLocal("pr"))),
c.call(prefix + "_copy", c.getLocal("t"), c.getLocal("pr"))
));
}
buildCopy();
buildZero();
buildIsZero();
buildOne();
buildEq();
buildGte();
buildAdd();
buildSub();
buildMul();
buildMulOld();
buildDiv();
buildInverseMod();
module.exportFunction(prefix+"_copy");
module.exportFunction(prefix+"_zero");
module.exportFunction(prefix+"_one");
module.exportFunction(prefix+"_isZero");
module.exportFunction(prefix+"_eq");
module.exportFunction(prefix+"_gte");
module.exportFunction(prefix+"_add");
module.exportFunction(prefix+"_sub");
module.exportFunction(prefix+"_mulOld");
module.exportFunction(prefix+"_mul");
module.exportFunction(prefix+"_div");
module.exportFunction(prefix+"_inverseMod");
return prefix;
};