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