Optimization of the int_mul code

This commit is contained in:
Jordi Baylina 2019-06-25 11:08:40 +02:00
parent 6c5cf8d4e5
commit 4e6f320667
No known key found for this signature in database
GPG Key ID: 7480C80C1BE43112
10 changed files with 260 additions and 55 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -35,7 +35,17 @@ function calcProof() {
}); });
} }
function test() { function test(funcName, a, b, r, n) {
const start = new Date().getTime();
window.groth16.instance.exports[funcName](a,b,r, n);
const end = new Date().getTime();
const time = end - start;
console.log("Time (ms): " + time);
}
function test2() {
const groth16 = window.groth16; const groth16 = window.groth16;
const nSignals = 1; const nSignals = 1;

File diff suppressed because one or more lines are too long

@ -284,9 +284,106 @@ module.exports = function buildInt(module, n64, _prefix) {
function buildMul() { function buildMul() {
const f = module.addFunction(prefix+"_mul");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
f.addLocal("c0", "i64");
f.addLocal("c1", "i64");
for (let i=0;i<n32; i++) {
f.addLocal("x"+i, "i64");
f.addLocal("y"+i, "i64");
}
const c = f.getCodeBuilder();
const loadX = [];
const loadY = [];
function mulij(i, j) {
let X,Y;
if (!loadX[i]) {
X = c.teeLocal("x"+i, c.i64_load32_u( c.getLocal("x"), i*4));
loadX[i] = true;
} else {
X = c.getLocal("x"+i);
}
if (!loadY[j]) {
Y = c.teeLocal("y"+j, c.i64_load32_u( c.getLocal("y"), j*4));
loadY[j] = true;
} else {
Y = c.getLocal("y"+j);
}
return c.i64_mul( X, Y );
}
let c0 = "c0";
let c1 = "c1";
for (let k=0; k<n32*2-1; k++) {
for (let i=Math.max(0, k-n32+1); (i<=k)&&(i<n32); i++) {
const j= k-i;
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
mulij(i,j)
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.getLocal(c1),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
)
);
}
f.addCode(
c.i64_store32(
c.getLocal("r"),
k*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*2-4,
c.getLocal(c0)
)
);
}
function buildMulOld() {
const mulBuff = module.alloc(n32*n32*8); const mulBuff = module.alloc(n32*n32*8);
const f = module.addFunction(prefix+"_mul"); const f = module.addFunction(prefix+"_mulOld");
f.addParam("x", "i32"); f.addParam("x", "i32");
f.addParam("y", "i32"); f.addParam("y", "i32");
f.addParam("r", "i32"); f.addParam("r", "i32");
@ -843,6 +940,7 @@ module.exports = function buildInt(module, n64, _prefix) {
buildAdd(); buildAdd();
buildSub(); buildSub();
buildMul(); buildMul();
buildMulOld();
buildDiv(); buildDiv();
buildInverseMod(); buildInverseMod();
module.exportFunction(prefix+"_copy"); module.exportFunction(prefix+"_copy");
@ -853,6 +951,7 @@ module.exports = function buildInt(module, n64, _prefix) {
module.exportFunction(prefix+"_gte"); module.exportFunction(prefix+"_gte");
module.exportFunction(prefix+"_add"); module.exportFunction(prefix+"_add");
module.exportFunction(prefix+"_sub"); module.exportFunction(prefix+"_sub");
module.exportFunction(prefix+"_mulOld");
module.exportFunction(prefix+"_mul"); module.exportFunction(prefix+"_mul");
module.exportFunction(prefix+"_div"); module.exportFunction(prefix+"_div");
module.exportFunction(prefix+"_inverseMod"); module.exportFunction(prefix+"_inverseMod");

23
src/build_test.js Normal file

@ -0,0 +1,23 @@
function buildTest(module, fn) {
const f = module.addFunction("test_"+fn);
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
f.addParam("n", "i32");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
f.addCode(c.setLocal("i", c.getLocal("n")));
f.addCode(c.block(c.loop(
c.call(fn, c.getLocal("x"), c.getLocal("y"), c.getLocal("r")),
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
c.br_if(1, c.i32_eqz ( c.getLocal("i") )),
c.br(0)
)));
module.exportFunction("test_"+fn);
}
module.exports = buildTest;

25
test/helpers/helpers.js Normal file

@ -0,0 +1,25 @@
const bigInt = require("big-integer");
function genValues(n, neg, bitsPerWord) {
bitsPerWord = bitsPerWord || 32;
const res = [];
res.push(bigInt.zero);
for (let i=0; i<n; i++) {
if (i>0) {
res.push( bigInt.one.shiftLeft(bitsPerWord*i).minus(1));
}
if (i<n-1) {
res.push( bigInt.one.shiftLeft(bitsPerWord*i));
res.push( bigInt.one.shiftLeft(bitsPerWord*i).add(1));
}
}
if (neg) {
const nt= res.length;
for (let i=0; i<nt; i++) res.push(bigInt.zero.minus(res[i]));
}
return res;
}
module.exports.genValues = genValues;

84
test/int.js Normal file

@ -0,0 +1,84 @@
const assert = require("assert");
const bigInt = require("big-integer");
const buildProtoboard = require("../src/protoboard.js");
const buildInt = require("../src/build_int.js");
const buildTest = require("../src/build_test.js");
const helpers = require("./helpers/helpers.js");
describe("Basic tests for Int", () => {
let pbInt;
before(async () => {
pbInt = await buildProtoboard((module) => {
buildInt(module, 4);
buildTest(module, "int_mul");
buildTest(module, "int_mulOld");
}, 32);
});
it("It should do a basic multiplication", async () => {
let c;
const pA = pbInt.alloc();
const pB = pbInt.alloc();
const pC = pbInt.alloc(64);
const values = helpers.genValues(8, false);
for (let i=0; i<values.length; i++) {
for (let j=0; j<values.length; j++) {
pbInt.set(pA, values[i]);
pbInt.set(pB, values[j]);
// console.log(values[i].toString(16));
// console.log(values[j].toString(16));
pbInt.int_mul(pA, pB, pC);
c = pbInt.get(pC, 1, 64);
// console.log("Result: " + c.toString(16));
// console.log("Refere: " + values[i].times(values[j]).toString(16));
assert(c.equals(values[i].times(values[j])));
}
}
});
it("It should profile int", async () => {
const pA = pbInt.alloc();
const pB = pbInt.alloc();
const pC = pbInt.alloc(64);
let start, end, time;
const A = bigInt.one.shiftLeft(256).minus(1);
const B = bigInt.one.shiftLeft(256).minus(1);
pbInt.set(pA, A);
pbInt.set(pB, B);
start = new Date().getTime();
pbInt.test_int_mul(pA, pB, pC, 50000000);
end = new Date().getTime();
time = end - start;
const c1 = pbInt.get(pC, 1, 64);
assert(c1.equals(A.times(B)));
console.log("Mul Time (ms): " + time);
start = new Date().getTime();
pbInt.test_int_mulOld(pA, pB, pC, 50000000);
end = new Date().getTime();
time = end - start;
const c2 = pbInt.get(pC, 1, 64);
assert(c2.equals(A.times(B)));
console.log("Mul Old Time (ms): " + time);
}).timeout(10000000);
});

@ -4,49 +4,11 @@ const bigInt = require("big-integer");
const buildProtoboard = require("../src/protoboard.js"); const buildProtoboard = require("../src/protoboard.js");
const buildTomCook = require("../src/build_tomcook.js"); const buildTomCook = require("../src/build_tomcook.js");
const buildInt = require("../src/build_int.js"); const buildInt = require("../src/build_int.js");
const buildTest = require("../src/build_test.js");
const helpers = require("./helpers/helpers.js");
function buildTest(module, fn) {
const f = module.addFunction("test_"+fn);
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
f.addParam("n", "i32");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
f.addCode(c.setLocal("i", c.getLocal("n")));
f.addCode(c.block(c.loop(
c.call(fn, c.getLocal("x"), c.getLocal("y"), c.getLocal("r")),
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
c.br_if(1, c.i32_eqz ( c.getLocal("i") )),
c.br(0)
)));
module.exportFunction("test_"+fn);
}
function genValues(n, neg) {
const res = [];
res.push(bigInt.zero);
for (let i=0; i<n; i++) {
if (i>0) {
res.push( bigInt.one.shiftLeft(29*i).minus(1));
}
if (i<8) {
res.push( bigInt.one.shiftLeft(29*i));
res.push( bigInt.one.shiftLeft(29*i).add(1));
}
}
if (neg) {
const nt= res.length;
for (let i=0; i<nt; i++) res.push(bigInt.zero.minus(res[i]));
}
return res;
}
describe("Basic tests for Tom Cook Multiplication Strategy", () => { describe("Basic tests for Tom Cook Multiplication Strategy", () => {
let pbTC; let pbTC;
@ -67,7 +29,7 @@ describe("Basic tests for Tom Cook Multiplication Strategy", () => {
let c; let c;
const pA = pbTC.alloc(6*4); const pA = pbTC.alloc(6*4);
const values = genValues(6, true); const values = helpers.genValues(6, true, 29);
for (let i=0; i<values.length; i++) { for (let i=0; i<values.length; i++) {
pbTC.set(pA, values[i], 24); pbTC.set(pA, values[i], 24);
@ -81,7 +43,7 @@ describe("Basic tests for Tom Cook Multiplication Strategy", () => {
let c; let c;
const pA = pbTC.alloc(6*4); const pA = pbTC.alloc(6*4);
const values = genValues(6, true); const values = helpers.genValues(6, true, 29);
for (let i=0; i<values.length; i++) { for (let i=0; i<values.length; i++) {
pbTC.set(pA, values[i], 24); pbTC.set(pA, values[i], 24);
@ -96,7 +58,7 @@ describe("Basic tests for Tom Cook Multiplication Strategy", () => {
let c; let c;
const pA = pbTC.alloc(6*4); const pA = pbTC.alloc(6*4);
const values = genValues(6, true); const values = helpers.genValues(6, true, 29);
for (let i=0; i<values.length; i++) { for (let i=0; i<values.length; i++) {
// console.log(values[i].toString(16)); // console.log(values[i].toString(16));
@ -114,7 +76,7 @@ describe("Basic tests for Tom Cook Multiplication Strategy", () => {
const pB = pbTC.alloc(); const pB = pbTC.alloc();
const pC = pbTC.alloc(24); const pC = pbTC.alloc(24);
const values = genValues(3, true); const values = helpers.genValues(3, true, 29);
for (let i=0; i<values.length; i++) { for (let i=0; i<values.length; i++) {
for (let j=0; j<values.length; j++) { for (let j=0; j<values.length; j++) {
@ -164,7 +126,7 @@ describe("Basic tests for Tom Cook Multiplication Strategy", () => {
const pB = pbTC.alloc(9*4); const pB = pbTC.alloc(9*4);
const pC = pbTC.alloc(9*4*2); const pC = pbTC.alloc(9*4*2);
const values = genValues(9, false); const values = helpers.genValues(9, false, 29);
for (let i=0; i<values.length; i++) { for (let i=0; i<values.length; i++) {
for (let j=0; j<values.length; j++) { for (let j=0; j<values.length; j++) {
@ -186,6 +148,7 @@ describe("Basic tests for Tom Cook Multiplication Strategy", () => {
} }
}); });
it("It should profile school", async () => { it("It should profile school", async () => {
const A = bigInt.one.shiftLeft(254).minus(1); const A = bigInt.one.shiftLeft(254).minus(1);
const B = bigInt.one.shiftLeft(254).minus(1); const B = bigInt.one.shiftLeft(254).minus(1);
@ -195,7 +158,7 @@ describe("Basic tests for Tom Cook Multiplication Strategy", () => {
const pC = pbInt.alloc(64); const pC = pbInt.alloc(64);
const start = new Date().getTime(); const start = new Date().getTime();
pbInt.test_int_mul(pA, pB, pC, 100000000); pbInt.test_int_mul(pA, pB, pC, 10000000);
const end = new Date().getTime(); const end = new Date().getTime();
const time = end - start; const time = end - start;
@ -225,7 +188,7 @@ describe("Basic tests for Tom Cook Multiplication Strategy", () => {
// console.log("Mul1 Tom Cook Time (ms): " + time); // console.log("Mul1 Tom Cook Time (ms): " + time);
start = new Date().getTime(); start = new Date().getTime();
pbTC.test_tomcook_mul9(pA, pB, pC, 100000000); pbTC.test_tomcook_mul9(pA, pB, pC, 10000000);
end = new Date().getTime(); end = new Date().getTime();
time = end - start; time = end - start;

@ -4,10 +4,10 @@ const buildF1m = require("../src/build_f1m.js");
const buildF2m = require("../src/build_f2m.js"); const buildF2m = require("../src/build_f2m.js");
const buildF1 = require("../src/build_f1.js"); const buildF1 = require("../src/build_f1.js");
const buildCurve = require("../src/build_curve.js"); const buildCurve = require("../src/build_curve.js");
const buildTest = require("../src/build_testg1");
const buildFFT = require("../src/build_fft"); const buildFFT = require("../src/build_fft");
const buildMultiexp = require("../src/build_multiexp"); const buildMultiexp = require("../src/build_multiexp");
const buildPol = require("../src/build_pol"); const buildPol = require("../src/build_pol");
const buildTest = require("../src/build_test");
const utils = require("../src/utils"); const utils = require("../src/utils");
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
@ -37,7 +37,8 @@ function buildWasm() {
buildCurve(moduleBuilder, "g2", "f2m"); buildCurve(moduleBuilder, "g2", "f2m");
buildMultiexp(moduleBuilder, "g2", "g2", "f2m", "fr"); buildMultiexp(moduleBuilder, "g2", "g2", "f2m", "fr");
buildTest(moduleBuilder); buildTest(moduleBuilder, "int_mul");
buildTest(moduleBuilder, "int_mulOld");
const code = moduleBuilder.build(); const code = moduleBuilder.build();