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    function writeConstraint(c) {
 98        const n8 = ctx.F.n8;
 99        const idxA = Object.keys(c.a.coefs);
100        const idxB = Object.keys(c.b.coefs);
101        const idxC = Object.keys(c.c.coefs);
102        const buff = new Uint8Array((idxA.length+idxB.length+idxC.length)*(n8+4) + 12);
103        const buffV = new DataView(buff.buffer);
104        let o=0;
105
106        buffV.setUint32(o, idxA.length, true); o+=4;
107        for (let i=0; i<idxA.length; i++) {
108            const coef = idxA[i];
109            let lSignal = ctx.signals[coef];
110            while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
111            buffV.setUint32(o, lSignal.id, true); o+=4;
112            ctx.F.toRprLE(buff, o, c.a.coefs[coef]); o+=n8;
113        }
114
115        buffV.setUint32(o, idxB.length, true); o+=4;
116        for (let i=0; i<idxB.length; i++) {
117            const coef = idxB[i];
118            let lSignal = ctx.signals[coef];
119            while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
120            buffV.setUint32(o, lSignal.id, true); o+=4;
121
122            ctx.F.toRprLE(buff, o, c.b.coefs[coef]); o+=n8;
123        }
124
125        buffV.setUint32(o, idxC.length, true); o+=4;
126        for (let i=0; i<idxC.length; i++) {
127            const coef = idxC[i];
128            let lSignal = ctx.signals[coef];
129            while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
130            buffV.setUint32(o, lSignal.id, true); o+=4;
131            ctx.F.toRprLE(buff, o, ctx.F.neg(c.c.coefs[coef])); o+=n8;
132        }
133
134        return fd.write(buff);
135    }
136
137    async function writeBigInt(n, pos) {
138
139        ctx.F.toRprLE(buffBigInt, 0, n);
140
141        await fd.write(buffBigInt, pos);
142
143    }
144}