arnaucube
arnaucube/circomPublic Self-hosted repository
circom/src/r1csfile.js
src/r1csfile.jsRaw
  1
  2const fs = require("fs");
  3const assert = require("assert");
  4const bigInt = require("big-integer");
  5
  6module.exports.buildR1cs = buildR1cs;
  7
  8async function buildR1cs(ctx, fileName) {
  9
 10    const fd = await fs.promises.open(fileName, "w");
 11
 12
 13    await fd.write("r1cs"); // Magic "r1cs"
 14
 15    let p = 4;
 16    await writeU32(1); // Version
 17    await writeU32(3); // Number of Sections
 18
 19    // Write the header
 20    ///////////
 21    await writeU32(1); // Header type
 22    const pHeaderSize = p;
 23    await writeU64(0); // Temporally set to 0 length
 24
 25
 26    const n8 = (Math.floor( (ctx.field.p.bitLength() - 1) / 64) +1)*8;
 27    // Field Def
 28    await writeU32(n8); // Temporally set to 0 length
 29    await writeBigInt(ctx.field.p);
 30
 31    const NWires =
 32        ctx.totals[ctx.stONE] +
 33        ctx.totals[ctx.stOUTPUT] +
 34        ctx.totals[ctx.stPUBINPUT] +
 35        ctx.totals[ctx.stPRVINPUT] +
 36        ctx.totals[ctx.stINTERNAL];
 37
 38    await writeU32(NWires);
 39    await writeU32(ctx.totals[ctx.stOUTPUT]);
 40    await writeU32(ctx.totals[ctx.stPUBINPUT]);
 41    await writeU32(ctx.totals[ctx.stPRVINPUT]);
 42    await writeU64(ctx.signals.length);
 43    await writeU32(ctx.constraints.length);
 44
 45    const headerSize = p - pHeaderSize - 8;
 46
 47    // Write constraints
 48    ///////////
 49    await writeU32(2); // Constraints type
 50    const pConstraintsSize = p;
 51    await writeU64(0); // Temporally set to 0 length
 52
 53    for (let i=0; i<ctx.constraints.length; i++) {
 54        if ((ctx.verbose)&&(i%10000 == 0)) {
 55            if (ctx.verbose) console.log("writing constraint: ", i);
 56            await fd.datasync();
 57        }
 58        await writeConstraint(ctx.constraints[i]);
 59    }
 60
 61    const constraintsSize = p - pConstraintsSize - 8;
 62
 63    // Write map
 64    ///////////
 65    await writeU32(3); // wires2label type
 66    const pMapSize = p;
 67    await writeU64(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 writeU64(arr[i]);
 82        if ((ctx.verbose)&&(i%100000)) console.log("writing wire2label map: ", i);
 83    }
 84
 85    const mapSize = p - pMapSize - 8;
 86
 87    // Write sizes
 88    await writeU32(headerSize, pHeaderSize);
 89    await writeU32(constraintsSize, pConstraintsSize);
 90    await writeU32(mapSize, pMapSize);
 91
 92    await fd.sync();
 93    await fd.close();
 94
 95    async function writeU32(v, pos) {
 96        const b = Buffer.allocUnsafe(4);
 97        b.writeInt32LE(v);
 98
 99        await fd.write(b, 0, 4, pos);
100
101        if (typeof(pos) == "undefined") p += 4;
102    }
103
104    async function writeU64(v, pos) {
105        const b = Buffer.allocUnsafe(8);
106
107        const LSB = v & 0xFFFFFFFF;
108        const MSB = Math.floor(v / 0x100000000);
109        b.writeInt32LE(LSB, 0);
110        b.writeInt32LE(MSB, 4);
111
112        await fd.write(b, 0, 8, pos);
113
114        if (typeof(pos) == "undefined") p += 8;
115    }
116
117    async function writeConstraint(c) {
118        await writeLC(c.a);
119        await writeLC(c.b);
120        await writeLC(ctx.lc.neg(c.c));
121    }
122
123    async function writeLC(lc) {
124        const idxs = Object.keys(lc.coefs);
125        await writeU32(idxs.length);
126        for (let s in lc.coefs) {
127            let lSignal = ctx.signals[s];
128
129            while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
130
131            await writeU32(lSignal.id);
132            await writeBigInt(lc.coefs[s]);
133        }
134    }
135
136    async function writeBigInt(n, pos) {
137        const b = Buffer.allocUnsafe(n8);
138
139        const dwords = bigInt(n).toArray(0x100000000).value;
140
141        for (let i=0; i<dwords.length; i++) {
142            b.writeUInt32LE(dwords[dwords.length-1-i], i*4, 4 );
143        }
144        b.fill(0, dwords.length*4);
145
146        await fd.write(b, 0, fs, pos);
147
148        if (typeof(pos) == "undefined") p += n8;
149    }
150}