Improvement in multiexp

This commit is contained in:
Jordi Baylina 2019-04-27 07:09:17 +02:00
parent cd5cb59ecd
commit 0c19558260
No known key found for this signature in database
GPG Key ID: 7480C80C1BE43112
10 changed files with 368 additions and 20 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -5,7 +5,7 @@
<script> <script>
var witness; var witness;
var proving_key; var provingKey;
function onLoad() { function onLoad() {
@ -35,6 +35,42 @@ function calcProof() {
}); });
} }
function test() {
const groth16 = window.groth16;
const nSignals = 1;
const pkey32 = new Uint32Array(provingKey);
const pPointsA = pkey32[5];
const points = provingKey.slice(pPointsA, pPointsA + nSignals*64);
const signals = witness.slice(0, nSignals*32);
const pr1 = groth16.alloc(96);
const pPoints = groth16.alloc(points.byteLength);
groth16.putBin(pPoints, points);
const pSignals = groth16.alloc(signals.byteLength);
groth16.putBin(pSignals, signals);
groth16.instance.exports.g1_zero(pr1);
groth16.instance.exports.g1_multiexp(pSignals, pPoints, nSignals, 1, pr1);
groth16.instance.exports.g1_affine(pr1, pr1);
groth16.instance.exports.g1_fromMontgomery(pr1, pr1);
const r1 = groth16.bin2g1(groth16.getBin(pr1, 96));
groth16.instance.exports.g1_zero(pr1);
groth16.instance.exports.g1_multiexp2(pSignals, pPoints, nSignals, 1, pr1);
groth16.instance.exports.g1_affine(pr1, pr1);
groth16.instance.exports.g1_fromMontgomery(pr1, pr1);
const r2 = groth16.bin2g1(groth16.getBin(pr1, 96));
console.log(r1);
console.log(r2);
}
</script> </script>
<body onLoad="onLoad()"> <body onLoad="onLoad()">
<h1>iden3</h1> <h1>iden3</h1>

@ -1,17 +1,17 @@
{ {
"pi_a": [ "pi_a": [
"21266998874284424955919569029881989465699205822263354313670808828909395154496", "19680154454022615560994181976731030733614160737391726320224655882461434003166",
"13808207576200570409195938017448994370347750586807229689124956313666939364223", "14506888714805765338667645951908780974880796110792314129555830081443197782938",
"1" "1"
], ],
"pi_b": [ "pi_b": [
[ [
"20826174028125964218380958569361176477127093215239661788856774751838141561143", "16059656683940257022054872908684774362474111955649045792819322627462560715137",
"18124837593398705925374973761391356712682789028723957898056733210681657516129" "13049852697262082406165451331450805322803524667445339527980660565015589621048"
], ],
[ [
"11061422325891624289091287264538564377906983481144726751439738589444312205684", "20605106377063342149927518751710651784145311256228815403731163542864993273015",
"7233025874448062341952037774861209177679802086176943726704101043680595476782" "21378404564638469836584392472267247126799346914748790175589924808523044347833"
], ],
[ [
"1", "1",
@ -19,8 +19,8 @@
] ]
], ],
"pi_c": [ "pi_c": [
"16878419494624994424179370797390123339814891459464251523862017440818718425099", "16518590357890849860540962532185420206527846553862686657897809347816474967134",
"2746788445790348352996135341367179450489222192737650564198988415207995710311", "442279217743037306980955273644081896885475014739846912647180713387538594883",
"1" "1"
] ]
} }

@ -1,4 +1,4 @@
{ {
"protocol": "groth", "protocol": "groth",
"nVars": 66232, "nVars": 66232,
"nPublic": 58, "nPublic": 58,
@ -2884580,4 +2884580,4 @@
"1" "1"
] ]
] ]
} }

File diff suppressed because one or more lines are too long

@ -22,6 +22,7 @@
const buildGroth16 = require("./src/groth16.js"); const buildGroth16 = require("./src/groth16.js");
buildGroth16().then( (groth16) => { buildGroth16().then( (groth16) => {
window.groth16 = groth16;
window.genZKSnarkProof = function(witness, provingKey, cb) { window.genZKSnarkProof = function(witness, provingKey, cb) {
const p = groth16.proof(witness, provingKey); const p = groth16.proof(witness, provingKey);

@ -428,6 +428,7 @@ module.exports = function buildMultiexp(module, prefix, curvePrefix, pointFieldP
f.addCode(c.getLocal("pr")); f.addCode(c.getLocal("pr"));
} }
function buildMulw() { function buildMulw() {
const f = module.addFunction(prefix+"__mulw"); const f = module.addFunction(prefix+"__mulw");
f.addParam("pscalars", "i32"); f.addParam("pscalars", "i32");
@ -578,6 +579,264 @@ module.exports = function buildMultiexp(module, prefix, curvePrefix, pointFieldP
)); ));
} }
function buildMulw2() {
const f = module.addFunction(prefix+"__mulw2");
f.addParam("pscalars", "i32");
f.addParam("ppoints", "i32");
f.addParam("w", "i32"); // Window size Max 8
f.addParam("pr", "i32");
f.addLocal("i", "i32");
f.addLocal("pd", "i32");
const c = f.getCodeBuilder();
const psels = module.alloc(scalarN8 * 8);
f.addCode(c.call(
prefix + "__packbits",
c.getLocal("pscalars"),
c.getLocal("w"),
c.i32_const(psels)
));
f.addCode(c.call(
prefix + "__ptable_reset",
c.getLocal("ppoints"),
c.getLocal("w")
));
f.addCode(c.setLocal("i", c.i32_const(0)));
f.addCode(c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("i"),
c.i32_const(scalarN8 * 8)
)
),
c.setLocal(
"pd",
c.i32_add(
c.getLocal("pr"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(pointN8)
)
)
),
c.call(curvePrefix + "_add",
c.getLocal("pd"),
c.call(
prefix + "__ptable_get",
c.i32_load8_u(
c.i32_sub(
c.i32_const(psels + scalarN8 * 8 -1),
c.getLocal("i")
)
)
),
c.getLocal("pd")
),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
)));
}
function buildMultiexp2() {
const f = module.addFunction(prefix+"_multiexp2");
f.addParam("pscalars", "i32");
f.addParam("ppoints", "i32");
f.addParam("n", "i32"); // Number of points
f.addParam("w", "i32"); // Window size Max 8
f.addParam("pr", "i32");
f.addLocal("ps", "i32");
f.addLocal("pp", "i32");
f.addLocal("wf", "i32");
f.addLocal("lastps", "i32");
const c = f.getCodeBuilder();
const accumulators = c.i32_const(module.alloc(pointN8*scalarN8*8));
const aux = c.i32_const(module.alloc(pointN8));
f.addCode(c.call(prefix + "__resetAccumulators", accumulators, c.i32_const(scalarN8*8)));
f.addCode(c.setLocal("ps", c.getLocal("pscalars")));
f.addCode(c.setLocal("pp", c.getLocal("ppoints")));
f.addCode(c.setLocal(
"lastps",
c.i32_add(
c.getLocal("ps"),
c.i32_mul(
c.i32_mul(
c.i32_div_u(
c.getLocal("n"),
c.getLocal("w")
),
c.getLocal("w")
),
c.i32_const(scalarN8)
)
)
));
f.addCode(c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("ps"),
c.getLocal("lastps")
)
),
c.call(prefix + "__mulw2", c.getLocal("ps"), c.getLocal("pp"), c.getLocal("w"), accumulators),
c.setLocal(
"ps",
c.i32_add(
c.getLocal("ps"),
c.i32_mul(
c.i32_const(scalarN8),
c.getLocal("w")
)
)
),
c.setLocal(
"pp",
c.i32_add(
c.getLocal("pp"),
c.i32_mul(
c.i32_const(pointFieldN8*2),
c.getLocal("w")
)
)
),
c.br(0)
)));
f.addCode(c.setLocal("wf", c.i32_rem_u(c.getLocal("n"), c.getLocal("w"))));
f.addCode(c.if(
c.getLocal("wf"),
[
...c.call(prefix + "__mulw2", c.getLocal("ps"), c.getLocal("pp"), c.getLocal("wf"), accumulators),
]
));
f.addCode(c.call(
prefix + "__addAccumulators",
accumulators,
c.i32_const(scalarN8*8),
aux
));
f.addCode(c.call(curvePrefix + "_add", aux, c.getLocal("pr"), c.getLocal("pr")));
}
function buildResetAccumulators() {
const f = module.addFunction(prefix+"__resetAccumulators");
f.addParam("paccumulators", "i32");
f.addParam("n", "i32"); // Number of points
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
f.addCode(c.setLocal("i", c.i32_const(0)));
f.addCode(c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("i"),
c.getLocal("n")
)
),
c.call(
curvePrefix + "_zero",
c.i32_add(
c.getLocal("paccumulators"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(pointN8)
)
)
),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
)));
}
function buildAddAccumulators() {
const f = module.addFunction(prefix+"__addAccumulators");
f.addParam("paccumulators", "i32");
f.addParam("n", "i32"); // Number of points
f.addParam("pr", "i32");
f.addLocal("i", "i32");
f.addLocal("p", "i32");
const c = f.getCodeBuilder();
/*
f.addCode(c.setLocal(
"p",
c.i32_add(
c.getLocal("paccumulators"),
c.i32_sub(
c.i32_mul(
c.getLocal("n"),
c.i32_const(pointN8)
),
c.i32_const(pointN8)
)
)
));
*/
f.addCode(c.setLocal("p",c.getLocal("paccumulators")));
f.addCode(c.call(curvePrefix + "_copy", c.getLocal("p"), c.getLocal("pr")));
f.addCode(c.setLocal("p", c.i32_add(c.getLocal("p"), c.i32_const(pointN8))));
f.addCode(c.setLocal("i", c.i32_const(1)));
f.addCode(c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("i"),
c.getLocal("n")
)
),
c.call(
curvePrefix + "_double",
c.getLocal("pr"),
c.getLocal("pr")
),
c.call(
curvePrefix + "_add",
c.getLocal("p"),
c.getLocal("pr"),
c.getLocal("pr")
),
c.setLocal("p", c.i32_add(c.getLocal("p"), c.i32_const(pointN8))),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
)));
}
buildSetSet(); buildSetSet();
buildSetIsSet(); buildSetIsSet();
buildPTableReset(); buildPTableReset();
@ -585,7 +844,14 @@ module.exports = function buildMultiexp(module, prefix, curvePrefix, pointFieldP
buildPackBits(); buildPackBits();
buildMulw(); buildMulw();
buildMultiexp(); buildMultiexp();
buildMulw2();
buildResetAccumulators();
buildAddAccumulators();
buildMultiexp2();
module.exportFunction(prefix+"_multiexp"); module.exportFunction(prefix+"_multiexp");
module.exportFunction(prefix+"_multiexp2");
}; };

@ -101,7 +101,7 @@ function thread(self) {
const pPoints = putBin(data.points); const pPoints = putBin(data.points);
const pRes = alloc(96); const pRes = alloc(96);
instance.exports.g1_zero(pRes); instance.exports.g1_zero(pRes);
instance.exports.g1_multiexp(pScalars, pPoints, data.n, 5, pRes); instance.exports.g1_multiexp2(pScalars, pPoints, data.n, 7, pRes);
data.result = getBin(pRes, 96); data.result = getBin(pRes, 96);
i32[0] = oldAlloc; i32[0] = oldAlloc;
@ -113,7 +113,7 @@ function thread(self) {
const pPoints = putBin(data.points); const pPoints = putBin(data.points);
const pRes = alloc(192); const pRes = alloc(192);
instance.exports.g2_zero(pRes); instance.exports.g2_zero(pRes);
instance.exports.g2_multiexp(pScalars, pPoints, data.n, 5, pRes); instance.exports.g2_multiexp(pScalars, pPoints, data.n, 7, pRes);
data.result = getBin(pRes, 192); data.result = getBin(pRes, 192);
i32[0] = oldAlloc; i32[0] = oldAlloc;

@ -7,6 +7,48 @@ const snarkjs = require("snarkjs");
const buildGroth16 = require("../index.js").buildGroth16; const buildGroth16 = require("../index.js").buildGroth16;
describe("Basic tests for groth16 proof generator", () => { describe("Basic tests for groth16 proof generator", () => {
it("should do basic multiexponentiation", async () => {
const groth16 = await buildGroth16();
const signalsAll = fs.readFileSync(path.join(__dirname, "data", "witness.bin"));
const provingKey = fs.readFileSync(path.join(__dirname, "data", "proving_key.bin"));
const nSignals = 1;
const pkey32 = new Uint32Array(provingKey);
const pPointsA = pkey32[5];
const points = provingKey.slice(pPointsA, pPointsA + nSignals*64);
const signals = signalsAll.slice(0, nSignals*32);
const pr1 = groth16.alloc(96);
const pPoints = groth16.alloc(points.byteLength);
groth16.putBin(pPoints, points);
const pSignals = groth16.alloc(signals.byteLength);
groth16.putBin(pSignals, signals);
groth16.instance.exports.g1_zero(pr1);
groth16.instance.exports.g1_multiexp(pSignals, pPoints, nSignals, 1, pr1);
groth16.instance.exports.g1_affine(pr1, pr1);
groth16.instance.exports.g1_fromMontgomery(pr1, pr1);
const r1 = groth16.bin2g1(groth16.getBin(pr1, 96));
groth16.instance.exports.g1_zero(pr1);
groth16.instance.exports.g1_multiexp2(pSignals, pPoints, nSignals, 1, pr1);
groth16.instance.exports.g1_affine(pr1, pr1);
groth16.instance.exports.g1_fromMontgomery(pr1, pr1);
const r2 = groth16.bin2g1(groth16.getBin(pr1, 96));
assert.equal(r1[0],r2[0]);
assert.equal(r1[1],r2[1]);
groth16.terminate();
});
it("It should do a basic point doubling G1", async () => { it("It should do a basic point doubling G1", async () => {
const groth16 = await buildGroth16(); const groth16 = await buildGroth16();
@ -22,4 +64,5 @@ describe("Basic tests for groth16 proof generator", () => {
groth16.terminate(); groth16.terminate();
}).timeout(10000000); }).timeout(10000000);
}); });