Optimization of the int_mul code
This commit is contained in:
parent
6c5cf8d4e5
commit
4e6f320667
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
101
src/build_int.js
101
src/build_int.js
@ -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
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
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
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();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user