websnark/src/f1.js
src/f1.jsRaw
1/*
2 Copyright 2019 0KIMS association.
3
4 This file is part of websnark (Web Assembly zkSnark Prover).
5
6 websnark is a free software: you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 websnark is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with websnark. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20/* globals WebAssembly */
21const bigInt = require("big-integer");
22const ModuleBuilder = require("wasmbuilder");
23const buildF1 = require("./build_f1.js");
24const buildTestF1 = require("./build_testf1.js");
25
26async function build(q) {
27 const f1 = new F1(q);
28
29 f1.q = bigInt(q);
30 f1.n64 = Math.floor((f1.q.minus(1).bitLength() - 1)/64) +1;
31 f1.n32 = f1.n64*2;
32 f1.n8 = f1.n64*8;
33
34 f1.memory = new WebAssembly.Memory({initial:1});
35 f1.i32 = new Uint32Array(f1.memory.buffer);
36
37 const moduleBuilder = new ModuleBuilder();
38 buildF1(moduleBuilder, f1.q);
39 buildTestF1(moduleBuilder);
40
41 const code = moduleBuilder.build();
42
43 const wasmModule = await WebAssembly.compile(code);
44
45 f1.instance = await WebAssembly.instantiate(wasmModule, {
46 env: {
47 "memory": f1.memory
48 }
49 });
50
51 Object.assign(f1, f1.instance.exports);
52
53 return f1;
54}
55
56class F1 {
57
58 constructor() {
59
60 }
61
62 alloc(length) {
63 const res = this.i32[0];
64 this.i32[0] += length;
65 return res;
66 }
67
68 putInt(pos, _a) {
69 const a = bigInt(_a);
70 if (pos & 0x7) throw new Error("Pointer must be aligned");
71 if (a.bitLength > this.n64*64) {
72 return this.putInt(a.mod(this.q));
73 }
74 for (let i=0; i<this.n32; i++) {
75 this.i32[(pos>>2)+i] = a.shiftRight(i*32).and(0xFFFFFFFF).toJSNumber();
76 }
77 }
78
79 allocInt(_a) {
80 const p = this.alloc(this.n8);
81 if (_a) this.putInt(p, _a);
82 return p;
83 }
84
85 putInt2(pos, _a) {
86 const a = bigInt(_a);
87 if (pos & 0x7) throw new Error("Pointer must be aligned");
88 if (a.bitLength > this.n64*64*2) {
89 return this.putInt(a.mod(this.q));
90 }
91 for (let i=0; i<this.n32*2; i++) {
92 this.i32[(pos>>2)+i] = a.shiftRight(i*32).and(0xFFFFFFFF).toJSNumber();
93 }
94 }
95
96 getInt(pos) {
97 if (pos & 0x7) throw new Error("Pointer must be aligned");
98 let acc = bigInt(this.i32[(pos>>2)+this.n32-1]);
99 for (let i=this.n32-2; i>=0; i--) {
100 acc = acc.shiftLeft(32);
101 acc = acc.add(this.i32[(pos>>2)+i]);
102 }
103 return acc;
104 }
105
106 getInt2(pos) {
107 if (pos & 0x7) throw new Error("Pointer must be aligned");
108 const last = this.n32*2-1;
109 let acc = bigInt(this.i32[(pos>>2)+last]);
110 for (let i=last; i>=0; i--) {
111 acc = acc.shiftLeft(32);
112 acc = acc.add(this.i32[(pos>>2)+i]);
113 }
114 return acc;
115 }
116
117 allocInt2(_a) {
118 const p = this.alloc(this.n8*2);
119 if (_a) this.putInt2(p, _a);
120 return p;
121 }
122
123 test_F1(n) {
124 const start = new Date().getTime();
125
126 this.instance.exports.testF1(n);
127
128 const end = new Date().getTime();
129 const time = end - start;
130
131 return time;
132 }
133/*
134 function test(n) {
135
136 const q = 21888242871839275222246405745257275088696311157297823662689037894645226208583n;
137 let a = (1n << 512n)%q ;
138 let b = a >> 128n;
139
140 let c;
141
142 const start = new Date().getTime();
143 for (let i=0; i<n; i++) c = a+b;
144
145 const end = new Date().getTime();
146 const time = end - start;
147
148 console.log(time);
149 }
150*/
151}
152
153module.exports = build;