UNPKG

@xorddotcom/shield

Version:

p align="center" > <img src="https://xord.notion.site/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F283b98b7-fdae-4e5a-acaf-248242084e4a%2FICON.png?table=block&id=5306223c-a4f7-45d1-9f54-b9a5f4004cd6&spaceId=49976899-64a1-40f

211 lines 7.74 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Checker = void 0; // @ts-ignore const r1csfile_1 = require("r1csfile"); // @ts-ignore const ffjavascript_1 = require("ffjavascript"); const logger_1 = require("./logger"); const assert_1 = __importDefault(require("assert")); const nodefs = require("fs"); const fs = require("fs/promises"); const groupOrderPrimeStr = "21888242871839275222246405745257275088548364400416034343698204186575808495617"; const groupOrderPrime = BigInt(groupOrderPrimeStr); class Checker { r1csFilepath; symFilepath; r1cs; symbols; signals; constructor(r1csFilepath, symFilepath) { this.r1csFilepath = r1csFilepath; this.symFilepath = symFilepath; } async load() { this.r1cs = await (0, r1csfile_1.load)(this.r1csFilepath, true, false); const { symbols, signals } = await readSymbols(this.symFilepath); this.symbols = symbols; this.signals = signals; } async checkConstraintsAndOutput(witnessFilePath) { // 0. load r1cs and witness try { if (!this.r1cs) { await this.load(); } let witness; if (witnessFilePath.endsWith("json")) { witness = JSON.parse(nodefs.readFileSync(witnessFilePath).toString()); } // 1. check constraints const F = new ffjavascript_1.ZqField(this.r1cs?.prime); const constraints = this.r1cs?.constraints; if (this.r1cs.nConstraints !== 0) { await checkConstraints(F, constraints, witness, this.signals); } else { (0, logger_1.log)("No quadratic constraint signal found:\n", "info"); } return true; } catch (err) { console.log({ err }); } } } exports.Checker = Checker; async function readSymbols(path) { let symbols = {}; let signals = {}; const symsStr = await fs.readFile(path, "utf8"); const lines = symsStr.split("\n"); for (let i = 0; i < lines.length; i++) { const arr = lines[i].split(","); if (arr.length != 4) continue; const symbol = arr[3]; const labelIdx = Number(arr[0]); const varIdx = Number(arr[1]); const componentIdx = Number(arr[2]); symbols[symbol] = { labelIdx, varIdx, componentIdx, }; if (signals[varIdx] == null) { signals[varIdx] = [symbol]; } else { signals[varIdx].push(symbol); } } return { symbols, signals }; } async function checkConstraints(F, constraints, witness, signals) { if (!constraints) { throw new Error("empty constraints"); } for (let i = 0; i < constraints.length; i++) { checkConstraint(constraints[i], i); } function checkConstraint(constraint, initializer) { const a = evalLC(constraint[0]); const b = evalLC(constraint[1]); const c = evalLC(constraint[2]); const passed = F.isZero(F.sub(F.mul(a, b), c)); (0, logger_1.log)(`Constraint no ${initializer + 1}: ${passed ? "passed" : "fail"}`, passed ? "success" : "error"); const equation = `${displayLc(constraint[0])} * ${displayLc(constraint[1])} = ${displayLc(constraint[2])}`; (0, logger_1.log)(`=> ${equation}`, "normal"); if (!passed) { (0, logger_1.log)("\nInvalid constraint:", "error"); (0, logger_1.log)(`=> ${equation}`, "error"); let sigs = new Set(); for (const c of constraint) { for (const s in c) { sigs.add(Number(s)); } } let calculatedEquation = equation; for (const s of sigs) { if (s != 0) { calculatedEquation = calculatedEquation.replaceAll(`signal${s}`, witness[s]); } else { calculatedEquation = calculatedEquation.replace(`signal${0}`, "1"); } } (0, logger_1.log)(`=> ${calculatedEquation}`, "error"); (0, logger_1.log)("Related signals:", "normal"); for (const s of sigs) { // signal 0 is 'one' if (s != 0) { (0, logger_1.log)(`signal${s}: ${signals[s].join(" ")}, value: ${witness[s]}`, "normal"); } } (0, logger_1.log)(`please check your circuit and input at constraint ${initializer + 1} \n`, "error"); throw new Error("Constraint doesn't match"); } else { let sigs = new Set(); for (const c of constraint) { for (const s in c) { sigs.add(Number(s)); } } let calculatedEquation = equation; for (const s of sigs) { if (s != 0) { calculatedEquation = calculatedEquation.replace(`signal${s}`, witness[s]); } else { calculatedEquation = calculatedEquation.replaceAll(`signal${0}`, "1"); } } (0, logger_1.log)(`=> ${calculatedEquation}`, "normal"); (0, logger_1.log)("Related signals:", "normal"); for (const s of sigs) { if (s != 0) { (0, logger_1.log)(`signal${s}: ${signals[s].join(" ")}, value: ${witness[s]}`, "normal"); } else { (0, logger_1.log)(`signal0: constant, value: 1`, "normal"); } } } } function evalLC(lc) { let v = F.zero; for (let w in lc) { v = F.add(v, F.mul(BigInt(lc[w]), BigInt(witness[w]))); } return v; } function displayLc(lc) { const entries = Object.entries(lc); if (entries.length == 0) { return "0"; } function displayField(x) { const f = BigInt(x); // display some field element as negative int for better reading if (f >= groupOrderPrime - 200n) { return `(-${(groupOrderPrime - f).toString()})`; } return f.toString(); } function displayMonomial(coef, signalIdx) { return `${displayField(coef)}*signal${signalIdx}`; } return ("(" + entries.map((kv) => displayMonomial(kv[1], kv[0])).join(" + ") + ")"); } } async function assertOut(symbols, actualOut, expectedOut) { if (!symbols) { throw new Error("empty symbols"); } checkObject("main", expectedOut); function checkObject(prefix, eOut) { if (Array.isArray(eOut)) { for (let i = 0; i < eOut.length; i++) { checkObject(prefix + "[" + i + "]", eOut[i]); } } else if (typeof eOut == "object" && eOut.constructor.name == "Object") { for (let k in eOut) { checkObject(prefix + "." + k, eOut[k]); } } else { if (typeof symbols[prefix] == "undefined") { (0, assert_1.default)(false, "Output variable not defined: " + prefix); } const ba = actualOut[symbols[prefix].varIdx].toString(); const be = eOut.toString(); assert_1.default.strictEqual(ba, be, prefix); } } } //# sourceMappingURL=checker.js.map