You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

240 lines
6.4 KiB

/*
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 <https://www.gnu.org/licenses/>.
*/
/* globals WebAssembly */
const bigInt = require("big-integer");
const ModuleBuilder = require("wasmbuilder");
const buildF1m = require("./build_f1m.js");
const buildF2m = require("./build_f2m.js");
const buildF1 = require("./build_f1.js");
const buildCurve = require("./build_curve.js");
const buildTest = require("./build_testg1");
const buildFFT = require("./build_fft");
const buildMultiexp = require("./build_multiexp");
const buildPol = require("./build_pol");
const utils = require("./utils");
async function build() {
const bn128 = new Bn128();
bn128.q = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583");
bn128.r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
bn128.n64 = Math.floor((bn128.q.minus(1).bitLength() - 1)/64) +1;
bn128.n32 = bn128.n64*2;
bn128.n8 = bn128.n64*8;
bn128.memory = new WebAssembly.Memory({initial:10000});
bn128.i32 = new Uint32Array(bn128.memory.buffer);
const moduleBuilder = new ModuleBuilder();
moduleBuilder.setMemory(10000);
buildF1m(moduleBuilder, bn128.q, "f1m");
buildF1(moduleBuilder, bn128.r, "fr", "frm");
buildCurve(moduleBuilder, "g1", "f1m");
buildMultiexp(moduleBuilder, "g1", "g1", "f1m", "fr");
buildFFT(moduleBuilder, "fft", "frm");
buildPol(moduleBuilder, "pol", "frm");
const pNonResidueF2 = moduleBuilder.alloc(
utils.bigInt2BytesLE(
bigInt("15537367993719455909907449462855742678907882278146377936676643359958227611562"), // -1 in montgomery
bn128.n8
)
);
buildF2m(moduleBuilder, pNonResidueF2, "f2m", "f1m");
buildCurve(moduleBuilder, "g2", "f2m");
buildMultiexp(moduleBuilder, "g2", "g2", "f2m", "fr");
buildTest(moduleBuilder);
const code = moduleBuilder.build();
const wasmModule = await WebAssembly.compile(code);
bn128.instance = await WebAssembly.instantiate(wasmModule, {
env: {
"memory": bn128.memory
}
});
bn128.pq = moduleBuilder.modules.f1m.pq;
bn128.pr = moduleBuilder.modules.frm.pq;
bn128.pg1 = bn128.g1_allocPoint([bigInt(1), bigInt(2), bigInt(1)]);
Object.assign(bn128, bn128.instance.exports);
return bn128;
}
class Bn128 {
constructor() {
}
alloc(length) {
while (this.i32[0] & 3) this.i32[0]++; // Return always aligned pointers
const res = this.i32[0];
this.i32[0] += length;
return res;
}
putInt(pos, _a) {
const a = bigInt(_a);
if (pos & 0x7) throw new Error("Pointer must be aligned");
if (a.bitLength > this.n64*64) {
return this.putInt(a.mod(this.q));
}
for (let i=0; i<this.n32; i++) {
this.i32[(pos>>2)+i] = a.shiftRight(i*32).and(0xFFFFFFFF).toJSNumber();
}
}
getInt(pos) {
if (pos & 0x7) throw new Error("Pointer must be aligned");
let acc = bigInt(this.i32[(pos>>2)+this.n32-1]);
for (let i=this.n32-2; i>=0; i--) {
acc = acc.shiftLeft(32);
acc = acc.add(this.i32[(pos>>2)+i]);
}
return acc;
}
allocInt(_a) {
const p = this.alloc(this.n8);
if (_a) this.putInt(p, _a);
return p;
}
putIntF2(pos, a) {
this.putInt(pos, a[0]);
this.putInt(pos+this.n8, a[1]);
}
getIntF2(pos) {
const p = Array(2);
p[0] = this.getInt(pos);
p[1] = this.getInt(pos+this.n8);
return p;
}
allocIntF2(a) {
const pP = this.alloc(this.n8*2);
if (a) {
this.putIntF2(pP, a);
}
return pP;
}
g1_putPoint(pos, p) {
this.putInt(pos, p[0]);
this.putInt(pos+this.n8, p[1]);
if (p.length == 3) {
this.putInt(pos+this.n8*2, p[2]);
} else {
this.putInt(pos+this.n8*2, 1);
}
}
g1_getPoint(pos) {
const p = Array(3);
p[0] = this.getInt(pos);
p[1] = this.getInt(pos+this.n8);
p[2] = this.getInt(pos+this.n8*2);
return p;
}
g1_allocPoint(p) {
const pP = this.alloc(this.n8*3);
if (p) {
this.g1_putPoint(pP, p);
}
return pP;
}
g2_putPoint(pos, p) {
this.putIntF2(pos, p[0]);
this.putIntF2(pos+this.n8*2, p[1]);
if (p.length == 3) {
this.putIntF2(pos+this.n8*4, p[2]);
} else {
this.putIntF2(pos+this.n8*4, 1);
}
}
g2_getPoint(pos) {
const p = Array(3);
p[0] = this.getIntF2(pos);
p[1] = this.getIntF2(pos+this.n8*2);
p[2] = this.getIntF2(pos+this.n8*4);
return p;
}
g2_allocPoint(p) {
const pP = this.alloc(this.n8*6);
if (p) {
this.g2_putPoint(pP, p);
}
return pP;
}
putBin(b) {
const p = this.alloc(b.byteLength);
const s32 = new Uint32Array(b);
this.i32.set(s32, p/4);
return p;
}
test_AddG1(n) {
const start = new Date().getTime();
const pg = this.g1_allocPoint([bigInt(1), bigInt(2), bigInt(1)]);
this.g1_toMontgomery(pg,pg);
const p2 = this.g1_allocPoint();
this.instance.exports.testAddG1(n, pg, p2);
this.g1_fromMontgomery(p2,p2);
const end = new Date().getTime();
const time = end - start;
return time;
}
test_fft(n) {
const N=n;
const p = this.i32[0];
for (let i=0; i<N; i++) {
this.putInt(p+i*32, i);
}
const start = new Date().getTime();
this.fft_ifft(p, N);
const end = new Date().getTime();
const time = end - start;
return time;
}
}
module.exports = build;