arnaucube
arnaucube/circomPublic Self-hosted repository
circom/src/c_tester.js
src/c_tester.jsRaw
  1const chai = require("chai");
  2const assert = chai.assert;
  3
  4const fs = require("fs");
  5var tmp = require("tmp-promise");
  6const path = require("path");
  7const compiler = require("./compiler");
  8const util = require("util");
  9const exec = util.promisify(require("child_process").exec);
 10
 11const stringifyBigInts = require("./utils").stringifyBigInts;
 12const unstringifyBigInts = require("./utils").unstringifyBigInts;
 13const bigInt = require("snarkjs").bigInt;
 14
 15module.exports = c_tester;
 16
 17
 18async function  c_tester(circomFile, mainComponent, _options) {
 19    tmp.setGracefulCleanup();
 20    mainComponent = mainComponent || "main";
 21
 22    const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true });
 23
 24    const baseName = path.basename(circomFile, ".circom");
 25    const options = Object.assign({}, _options);
 26
 27    options.cSourceWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".cpp"));
 28    options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym"));
 29    options.mainComponent = mainComponent;
 30    await compiler(circomFile, options);
 31
 32    const cdir = path.join(__dirname, "..", "c");
 33    await exec("g++" +
 34               ` ${path.join(dir.path, baseName + ".cpp")} ` +
 35               ` ${path.join(cdir,  "main.cpp")}` +
 36               ` ${path.join(cdir,  "calcwit.cpp")}` +
 37               ` ${path.join(cdir,  "utils.cpp")}` +
 38               ` ${path.join(cdir,  "zqfield.cpp")}` +
 39               ` -o ${path.join(dir.path, baseName)}` +
 40               ` -I ${cdir}` +
 41               " -lgmp -std=c++11 -DSANITY_CHECK"
 42    );
 43
 44    // console.log(dir.path);
 45    return new CTester(dir, baseName, mainComponent);
 46}
 47
 48class CTester {
 49
 50    constructor(dir, baseName, mainComponent) {
 51        this.dir=dir;
 52        this.baseName = baseName;
 53        this.mainComponent = mainComponent;
 54    }
 55
 56    async release() {
 57        await this.dir.cleanup();
 58    }
 59
 60    async calculateWitness(input) {
 61        await fs.promises.writeFile(
 62            path.join(this.dir.path, "in.json"),
 63            JSON.stringify(stringifyBigInts(input), null, 1)
 64        );
 65        await exec(`${path.join(this.dir.path, this.baseName)}` +
 66                   ` ${path.join(this.dir.path, "in.json")}` +
 67                   ` ${path.join(this.dir.path, "out.json")}`
 68        );
 69        const resStr = await fs.promises.readFile(
 70            path.join(this.dir.path, "out.json")
 71        );
 72
 73        const res = unstringifyBigInts(JSON.parse(resStr));
 74        return res;
 75    }
 76
 77    async _loadSymbols() {
 78        this.symbols = {};
 79        const symsStr = await fs.promises.readFile(
 80            path.join(this.dir.path, this.baseName + ".sym"),
 81            "utf8"
 82        );
 83        const lines = symsStr.split("\n");
 84        for (let i=0; i<lines.length; i++) {
 85            const arr = lines[i].split(",");
 86            if (arr.length!=3) continue;
 87            this.symbols[arr[2]] = {
 88                idx: Number(arr[0]),
 89                idxWit: Number(arr[1])
 90            };
 91        }
 92    }
 93
 94    async assertOut(actualOut, expectedOut) {
 95        const self = this;
 96        if (!self.symbols) await self._loadSymbols();
 97
 98        checkObject("main", expectedOut);
 99
100        function checkObject(prefix, eOut) {
101
102            if (Array.isArray(eOut)) {
103                for (let i=0; i<eOut.length; i++) {
104                    checkObject(prefix + "["+i+"]", eOut[i]);
105                }
106            } else if ((typeof eOut == "object")&&(eOut.constructor.name == "Object")) {
107                for (let k in eOut) {
108                    checkObject(prefix + "."+k, eOut[k]);
109                }
110            } else {
111                const ba = bigInt(actualOut[self.symbols[prefix].idxWit]).toString();
112                const be = bigInt(eOut).toString();
113                assert.strictEqual(ba, be, prefix);
114            }
115        }
116    }
117
118}
119
120