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