websnark/tools/buildpkey.js
tools/buildpkey.jsRaw
1const {unstringifyBigInts} = require("./stringifybigint.js");
2const fs = require("fs");
3const bigInt = require("big-integer");
4const assert = require("assert");
5
6const version = require("../package").version;
7
8const argv = require("yargs")
9 .version(version)
10 .usage(`node buildpkey.js -i "proving_key.json" -o "proving_key.bin"
11 Default: circuit.json
12 `)
13 .alias("i", "input")
14 .alias("o", "output")
15 .help("h")
16 .alias("h", "help")
17 .epilogue(`Copyright (C) 2018 0kims association
18 This program comes with ABSOLUTELY NO WARRANTY;
19 This is free software, and you are welcome to redistribute it
20 under certain conditions; see the COPYING file in the official
21 repo directory at https://github.com/iden3/circom `)
22 .argv;
23
24const inputName = (argv.input) ? argv.input : "proving_key.json";
25const outputName = (argv.output) ? argv.output : "proving_key.bin";
26
27
28const provingKey = unstringifyBigInts(JSON.parse(fs.readFileSync(inputName, "utf8")));
29
30
31
32
33
34function writeUint32(h, val) {
35 h.dataView.setUint32(h.offset, val, true);
36 h.offset += 4;
37}
38
39function writeUint32ToPointer(h, p, val) {
40 h.dataView.setUint32(p, val, true);
41}
42
43
44function alloc(h, n) {
45 const o = h.offset;
46 h.offset += n;
47 return o;
48}
49
50function writeBigInt(h, bi) {
51 for (let i=0; i<8; i++) {
52 const v = bi.shiftRight(i*32).and(0xFFFFFFFF).toJSNumber();
53 writeUint32(h, v);
54 }
55}
56
57function toMontgomeryQ(p) {
58 const q = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583");
59 return p.times(bigInt.one.shiftLeft(256)).mod(q);
60}
61
62function toMontgomeryR(p) {
63 const r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
64 return p.times(bigInt.one.shiftLeft(256)).mod(r);
65}
66
67function writePoint(h, p) {
68 writeBigInt(h, toMontgomeryQ(p[0]));
69 writeBigInt(h, toMontgomeryQ(p[1]));
70}
71
72function writePoint2(h, p) {
73 writeBigInt(h, toMontgomeryQ(p[0][0]));
74 writeBigInt(h, toMontgomeryQ(p[0][1]));
75 writeBigInt(h, toMontgomeryQ(p[1][0]));
76 writeBigInt(h, toMontgomeryQ(p[1][1]));
77}
78
79function writeTransformedPolynomial(h, p) {
80
81 const keys = Object.keys(p);
82
83 writeUint32(h, keys.length);
84
85 for (let i=0; i<keys.length; i++) {
86 writeUint32(h, keys[i]);
87 writeBigInt(h, toMontgomeryR(p[keys[i]]));
88 }
89}
90
91function calculateBuffLen(provingKey) {
92 function polSize(pol) {
93 const l= Object.keys(pol).length;
94 return 36*l + 4;
95 }
96
97 let size = 40;
98
99 // alfa1, beta1, delta1
100 size += 3 * (32*2);
101
102 // beta2, delta2
103 size += 2 * (32*4);
104
105 for (let i=0; i<provingKey.nVars; i++) {
106 size += polSize(provingKey.polsA[i]);
107 size += polSize(provingKey.polsB[i]);
108 }
109
110 size += provingKey.nVars* (32*2);
111 size += provingKey.nVars* (32*2);
112 size += provingKey.nVars* (32*4);
113 size += (provingKey.nVars - provingKey.nPublic - 1)* (32*2);
114 size += provingKey.domainSize * (32*2);
115
116 return size;
117}
118
119
120const buffLen = calculateBuffLen(provingKey);
121
122const buff = new ArrayBuffer(buffLen);
123
124const h = {
125 dataView: new DataView(buff),
126 offset: 0
127};
128
129
130writeUint32(h, provingKey.nVars);
131writeUint32(h, provingKey.nPublic);
132writeUint32(h, provingKey.domainSize);
133const pPolsA = alloc(h, 4);
134const pPolsB = alloc(h, 4);
135const pPointsA = alloc(h, 4);
136const pPointsB1 = alloc(h, 4);
137const pPointsB2 = alloc(h, 4);
138const pPointsC = alloc(h, 4);
139const pPointsHExps = alloc(h, 4);
140
141writePoint(h, provingKey.vk_alfa_1);
142writePoint(h, provingKey.vk_beta_1);
143writePoint(h, provingKey.vk_delta_1);
144writePoint2(h, provingKey.vk_beta_2);
145writePoint2(h, provingKey.vk_delta_2);
146
147writeUint32ToPointer(h, pPolsA, h.offset);
148for (let i=0; i<provingKey.nVars; i++) {
149 writeTransformedPolynomial(h, provingKey.polsA[i]);
150}
151
152writeUint32ToPointer(h, pPolsB, h.offset);
153for (let i=0; i<provingKey.nVars; i++) {
154 writeTransformedPolynomial(h, provingKey.polsB[i]);
155}
156
157writeUint32ToPointer(h, pPointsA, h.offset);
158for (let i=0; i<provingKey.nVars; i++) {
159 writePoint(h, provingKey.A[i]);
160}
161
162writeUint32ToPointer(h, pPointsB1, h.offset);
163for (let i=0; i<provingKey.nVars; i++) {
164 writePoint(h, provingKey.B1[i]);
165}
166
167writeUint32ToPointer(h, pPointsB2, h.offset);
168for (let i=0; i<provingKey.nVars; i++) {
169 writePoint2(h, provingKey.B2[i]);
170}
171
172writeUint32ToPointer(h, pPointsC, h.offset);
173for (let i=provingKey.nPublic+1; i<provingKey.nVars; i++) {
174 writePoint(h, provingKey.C[i]);
175}
176
177writeUint32ToPointer(h, pPointsHExps, h.offset);
178for (let i=0; i<provingKey.domainSize; i++) {
179 writePoint(h, provingKey.hExps[i]);
180}
181
182assert.equal(h.offset, buffLen);
183
184var wstream = fs.createWriteStream(outputName);
185wstream.write(Buffer.from(buff));
186wstream.end();
187
188/*
189NSignals
190NPublic
191DomainSize (2 multiple)
192pPolsA
193pPolsB
194pPointsA
195pPointsB1
196pPointsB2
197pPointsC
198pPointsHExps
199Alfa1
200Beta1
201Delta1
202Beta2
203Delta2
204 PolinomialA_0
205 PolinomialA_1
206 PolinomialA_2
207 ...
208 PolinomialA_NVars-1
209
210 PolinomialB_0
211 PolinomialB_1
212 PolinomialB_2
213 ...
214 PolinomialB_NVars-1
215
216 PointA_0
217 PointA_1
218 ...
219 PointA_NVars-1
220
221 PointB1_0
222 PointB1_1
223 ...
224 PointB1_NVars-1
225
226 PointB2_0
227 PointB2_1
228 ...
229 PointB2_NVars-1
230
231 PointC_nPublics+1
232 PointC_nPublics+2
233 ...
234 PointC_nPublics+NVars
235
236 PointHExp_0
237 PointHExp_1
238 ...
239 PointHExp_DomainSize-1
240*/