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