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