/*
|
|
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 buildF1 = require("./build_f1.js");
|
|
const buildTestF1 = require("./build_testf1.js");
|
|
|
|
async function build(q) {
|
|
const f1 = new F1(q);
|
|
|
|
f1.q = bigInt(q);
|
|
f1.n64 = Math.floor((f1.q.minus(1).bitLength() - 1)/64) +1;
|
|
f1.n32 = f1.n64*2;
|
|
f1.n8 = f1.n64*8;
|
|
|
|
f1.memory = new WebAssembly.Memory({initial:1});
|
|
f1.i32 = new Uint32Array(f1.memory.buffer);
|
|
|
|
const moduleBuilder = new ModuleBuilder();
|
|
buildF1(moduleBuilder, f1.q);
|
|
buildTestF1(moduleBuilder);
|
|
|
|
const code = moduleBuilder.build();
|
|
|
|
const wasmModule = await WebAssembly.compile(code);
|
|
|
|
f1.instance = await WebAssembly.instantiate(wasmModule, {
|
|
env: {
|
|
"memory": f1.memory
|
|
}
|
|
});
|
|
|
|
Object.assign(f1, f1.instance.exports);
|
|
|
|
return f1;
|
|
}
|
|
|
|
class F1 {
|
|
|
|
constructor() {
|
|
|
|
}
|
|
|
|
alloc(length) {
|
|
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();
|
|
}
|
|
}
|
|
|
|
allocInt(_a) {
|
|
const p = this.alloc(this.n8);
|
|
if (_a) this.putInt(p, _a);
|
|
return p;
|
|
}
|
|
|
|
putInt2(pos, _a) {
|
|
const a = bigInt(_a);
|
|
if (pos & 0x7) throw new Error("Pointer must be aligned");
|
|
if (a.bitLength > this.n64*64*2) {
|
|
return this.putInt(a.mod(this.q));
|
|
}
|
|
for (let i=0; i<this.n32*2; 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;
|
|
}
|
|
|
|
getInt2(pos) {
|
|
if (pos & 0x7) throw new Error("Pointer must be aligned");
|
|
const last = this.n32*2-1;
|
|
let acc = bigInt(this.i32[(pos>>2)+last]);
|
|
for (let i=last; i>=0; i--) {
|
|
acc = acc.shiftLeft(32);
|
|
acc = acc.add(this.i32[(pos>>2)+i]);
|
|
}
|
|
return acc;
|
|
}
|
|
|
|
allocInt2(_a) {
|
|
const p = this.alloc(this.n8*2);
|
|
if (_a) this.putInt2(p, _a);
|
|
return p;
|
|
}
|
|
|
|
test_F1(n) {
|
|
const start = new Date().getTime();
|
|
|
|
this.instance.exports.testF1(n);
|
|
|
|
const end = new Date().getTime();
|
|
const time = end - start;
|
|
|
|
return time;
|
|
}
|
|
/*
|
|
function test(n) {
|
|
|
|
const q = 21888242871839275222246405745257275088696311157297823662689037894645226208583n;
|
|
let a = (1n << 512n)%q ;
|
|
let b = a >> 128n;
|
|
|
|
let c;
|
|
|
|
const start = new Date().getTime();
|
|
for (let i=0; i<n; i++) c = a+b;
|
|
|
|
const end = new Date().getTime();
|
|
const time = end - start;
|
|
|
|
console.log(time);
|
|
}
|
|
*/
|
|
}
|
|
|
|
module.exports = build;
|