circom/src/r1csfile.js
src/r1csfile.jsRaw
1
2const fastFile = require("fastfile");
3const assert = require("assert");
4const BigArray = require("./bigarray");
5
6module.exports.buildR1cs = buildR1cs;
7
8
9async function buildR1cs(ctx, fileName) {
10
11 const fd = await fastFile.createOverride(fileName);
12
13
14 const buffBigInt = new Uint8Array(ctx.F.n8);
15
16 const type = "r1cs";
17 const buff = new Uint8Array(4);
18 for (let i=0; i<4; i++) buff[i] = type.charCodeAt(i);
19 await fd.write(buff, 0); // Magic "r1cs"
20
21 await fd.writeULE32(1); // Version
22 await fd.writeULE32(3); // Number of Sections
23
24 // Write the header
25 ///////////
26 await fd.writeULE32(1); // Header type
27 const pHeaderSize = fd.pos;
28 await fd.writeULE64(0); // Temporally set to 0 length
29
30
31 const n8 = (Math.floor( (ctx.F.bitLength - 1) / 64) +1)*8;
32 // Field Def
33 await fd.writeULE32(n8); // Temporally set to 0 length
34 await writeBigInt(ctx.F.p);
35
36 const NWires =
37 ctx.totals[ctx.stONE] +
38 ctx.totals[ctx.stOUTPUT] +
39 ctx.totals[ctx.stPUBINPUT] +
40 ctx.totals[ctx.stPRVINPUT] +
41 ctx.totals[ctx.stINTERNAL];
42
43 await fd.writeULE32(NWires);
44 await fd.writeULE32(ctx.totals[ctx.stOUTPUT]);
45 await fd.writeULE32(ctx.totals[ctx.stPUBINPUT]);
46 await fd.writeULE32(ctx.totals[ctx.stPRVINPUT]);
47 await fd.writeULE64(ctx.signals.length);
48 await fd.writeULE32(ctx.constraints.length);
49
50 const headerSize = fd.pos - pHeaderSize - 8;
51
52 // Write constraints
53 ///////////
54 await fd.writeULE32(2); // Constraints type
55 const pConstraintsSize = fd.pos;
56 await fd.writeULE64(0); // Temporally set to 0 length
57
58 for (let i=0; i<ctx.constraints.length; i++) {
59 if ((ctx.verbose)&&(i%10000 == 0)) {
60 if (ctx.verbose) console.log("writing constraint: ", i);
61 }
62 await writeConstraint(ctx.constraints[i]);
63 }
64
65 const constraintsSize = fd.pos - pConstraintsSize - 8;
66
67 // Write map
68 ///////////
69 await fd.writeULE32(3); // wires2label type
70 const pMapSize = fd.pos;
71 await fd.writeULE64(0); // Temporally set to 0 length
72
73
74 const arr = new BigArray(NWires);
75 for (let i=0; i<ctx.signals.length; i++) {
76 const outIdx = ctx.signals[i].id;
77 if (ctx.signals[i].e>=0) continue; // If has an alias, continue..
78 assert(typeof outIdx != "undefined", `Signal ${i} does not have index`);
79 if (outIdx>=NWires) continue; // Is a constant or a discarded variable
80 if (typeof arr[ctx.signals[i].id] == "undefined") {
81 arr[outIdx] = i;
82 }
83 }
84 for (let i=0; i<arr.length; i++) {
85 await fd.writeULE64(arr[i]);
86 if ((ctx.verbose)&&(i%100000 == 0)) console.log(`writing wire2label map: ${i}/${arr.length}`);
87 }
88
89 const mapSize = fd.pos - pMapSize - 8;
90
91 // Write sizes
92 await fd.writeULE64(headerSize, pHeaderSize);
93 await fd.writeULE64(constraintsSize, pConstraintsSize);
94 await fd.writeULE64(mapSize, pMapSize);
95
96 await fd.close();
97
98 function writeConstraint(c) {
99 const n8 = ctx.F.n8;
100 const idxA = Object.keys(c.a.coefs);
101 const idxB = Object.keys(c.b.coefs);
102 const idxC = Object.keys(c.c.coefs);
103 const buff = new Uint8Array((idxA.length+idxB.length+idxC.length)*(n8+4) + 12);
104 const buffV = new DataView(buff.buffer);
105 let o=0;
106
107 buffV.setUint32(o, idxA.length, true); o+=4;
108 for (let i=0; i<idxA.length; i++) {
109 const coef = idxA[i];
110 let lSignal = ctx.signals[coef];
111 while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
112 buffV.setUint32(o, lSignal.id, true); o+=4;
113 ctx.F.toRprLE(buff, o, c.a.coefs[coef]); o+=n8;
114 }
115
116 buffV.setUint32(o, idxB.length, true); o+=4;
117 for (let i=0; i<idxB.length; i++) {
118 const coef = idxB[i];
119 let lSignal = ctx.signals[coef];
120 while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
121 buffV.setUint32(o, lSignal.id, true); o+=4;
122
123 ctx.F.toRprLE(buff, o, c.b.coefs[coef]); o+=n8;
124 }
125
126 buffV.setUint32(o, idxC.length, true); o+=4;
127 for (let i=0; i<idxC.length; i++) {
128 const coef = idxC[i];
129 let lSignal = ctx.signals[coef];
130 while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
131 buffV.setUint32(o, lSignal.id, true); o+=4;
132 ctx.F.toRprLE(buff, o, ctx.F.neg(c.c.coefs[coef])); o+=n8;
133 }
134
135 return fd.write(buff);
136 }
137
138 async function writeBigInt(n, pos) {
139
140 ctx.F.toRprLE(buffBigInt, 0, n);
141
142 await fd.write(buffBigInt, pos);
143
144 }
145}