UNPKG

export-ton-verifier

Version:

Tool for generating Groth16 and PLONK verifier code for the TON blockchain from SnarkJS .zkey or verification key JSON files.

1,486 lines (1,462 loc) 56.5 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { MAX_PLONK_PUBLIC_INPUTS: () => MAX_PLONK_PUBLIC_INPUTS2, calldataToTupleItems: () => calldataToTupleItems2, dictFromInputList: () => dictFromInputList2, exportPlonkFuncCalldata: () => exportPlonkFuncCalldata2, exportPlonkTolkCalldata: () => exportPlonkTolkCalldata2, formatDoctorReport: () => formatDoctorReport2, g1Compressed: () => g1Compressed2, g2Compressed: () => g2Compressed2, generateVerifier: () => generateVerifier2, getCurveFromName: () => getCurveFromName3, groth16CompressProof: () => groth16CompressProof2, inspectVerifierInput: () => inspectVerifierInput2, normalizeTonBlsCurveName: () => normalizeTonBlsCurveName2, proofToMessageBoc: () => proofToMessageBoc2, proofToMessageCell: () => proofToMessageCell2, zkeyExportPlonkVerificationKey: () => zkeyExportPlonkVerificationKey2 }); module.exports = __toCommonJS(index_exports); // src/dictFromInputList.ts var import_core = require("@ton/core"); function dictFromInputList(list) { const dict = import_core.Dictionary.empty( import_core.Dictionary.Keys.Int(32), import_core.Dictionary.Values.BigInt(256) ); for (let i = 0; i < list.length; i++) { dict.set(i, list[i]); } return dict; } // src/groth16CompressProof.js var import_ffjavascript2 = require("ffjavascript"); // src/utils.js var import_ffjavascript = require("ffjavascript"); async function getCurveFromName(name, options) { let curve; let singleThread = options && options.singleThread; const normName = normalizeName(name); if (["BN128", "BN254", "ALTBN128"].indexOf(normName) >= 0) { curve = await (0, import_ffjavascript.buildBn128)(singleThread); } else if (["BLS12381"].indexOf(normName) >= 0) { curve = await (0, import_ffjavascript.buildBls12381)(singleThread); } else { throw new Error(`Curve not supported: ${name}`); } return curve; function normalizeName(n) { return n.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); } } function toHexString(byteArray) { return Array.from( byteArray, (byte) => ("0" + (byte & 255).toString(16)).slice(-2) ).join(""); } function assertBls12381Curve(curve) { const normalizedName = String((curve == null ? void 0 : curve.name) ?? "").toLowerCase().replace(/[^a-z0-9]/g, ""); if (normalizedName !== "bls12381") { throw new Error("Compression helpers support only BLS12-381 curves."); } } function g1Compressed(curve, p1Raw) { assertBls12381Curve(curve); const p1 = curve.G1.fromObject(p1Raw); const buff = new Uint8Array(48); curve.G1.toRprCompressed(buff, 0, p1); if (buff[0] & 128) buff[0] |= 32; buff[0] |= 128; return toHexString(buff); } function g2Compressed(curve, p2Raw) { assertBls12381Curve(curve); const p2 = curve.G2.fromObject(p2Raw); const buff = new Uint8Array(96); curve.G2.toRprCompressed(buff, 0, p2); if (buff[0] & 128) buff[0] |= 32; buff[0] |= 128; return toHexString(buff); } // src/limits.js function normalizeTonBlsCurveName(raw, field = "curve") { if (typeof raw !== "string" || raw.trim() === "") { throw new Error(`${field}: BLS12-381 curve metadata is required.`); } const normalized = raw.toLowerCase().replace(/[^a-z0-9]/g, ""); if (normalized !== "bls12381") { throw new Error( `${field}: TON verifier templates use TVM BLS12-381 opcodes; got '${raw}'.` ); } return "bls12381"; } function assertTonBlsCurve(raw, field = "curve") { normalizeTonBlsCurveName(raw, field); } var MAX_PLONK_PUBLIC_INPUTS = 244; function assertPlonkPublicInputCount(count, field = "public inputs") { if (!Number.isInteger(count) || count < 0) { throw new Error(`${field}: public input count must be a non-negative integer.`); } if (count > MAX_PLONK_PUBLIC_INPUTS) { throw new Error( `${field}: PLONK verifier supports at most ${MAX_PLONK_PUBLIC_INPUTS} public inputs because the TVM Keccak transcript is limited to 255 tuple items.` ); } } // src/groth16CompressProof.js async function groth16CompressProof(proof, publicSignals) { assertTonBlsCurve(proof == null ? void 0 : proof.curve, "proof.curve"); const curve = await (0, import_ffjavascript2.buildBls12381)(); try { const proofProc = import_ffjavascript2.utils.unstringifyBigInts(proof); const pi_aS = g1Compressed(curve, proofProc.pi_a); const pi_bS = g2Compressed(curve, proofProc.pi_b); const pi_cS = g1Compressed(curve, proofProc.pi_c); const pi_a = Buffer.from(pi_aS, "hex"); const pi_b = Buffer.from(pi_bS, "hex"); const pi_c = Buffer.from(pi_cS, "hex"); const pubInputs = publicSignals.map((s) => BigInt(s)); return { pi_a, pi_b, pi_c, pubInputs }; } finally { if (curve && typeof curve.terminate === "function") { await curve.terminate(); } } } // src/generateVerifiers.js var import_promises4 = __toESM(require("fs/promises"), 1); var import_ejs = __toESM(require("ejs"), 1); var import_ffjavascript6 = require("ffjavascript"); // src/helpers.js var import_promises = __toESM(require("fs/promises"), 1); var import_path = __toESM(require("path"), 1); var binFileUtils = __toESM(require("@iden3/binfileutils"), 1); // src/curves.js var import_ffjavascript3 = require("ffjavascript"); var bls12381q = import_ffjavascript3.Scalar.e( "1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16 ); async function getCurveFromQ(q) { let curve; if (import_ffjavascript3.Scalar.eq(q, bls12381q)) { curve = await (0, import_ffjavascript3.buildBls12381)(); } else { throw new Error(`Curve not supported: ${import_ffjavascript3.Scalar.toString(q)}`); } return curve; } async function getCurveFromName2(name, options) { let curve; let singleThread = options && options.singleThread; const normName = normalizeName(name); if (["BLS12381"].indexOf(normName) >= 0) { curve = await (0, import_ffjavascript3.buildBls12381)(singleThread); } else { throw new Error(`Curve not supported: ${name}`); } return curve; function normalizeName(n) { return n.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); } } // src/helpers.js async function fileExists(p) { try { await import_promises.default.access(p); return true; } catch { return false; } } async function resolveTemplatePath(templatesDir, lang, protocol) { const withProtocol = `${lang}_verifier_${protocol}.ejs`; const fallback = `${lang}_verifier.ejs`; const pathWithProtocol = import_path.default.join(templatesDir, withProtocol); const pathFallback = import_path.default.join(templatesDir, fallback); if (await fileExists(pathWithProtocol)) { return pathWithProtocol; } if (protocol === "groth16" && await fileExists(pathFallback)) { return pathFallback; } throw new Error( `Template not found: '${withProtocol}' (or '${fallback}' for groth16) in ${templatesDir}` ); } function normalizeContractName(name = "MyVerifier") { const raw = String(name ?? "").trim(); if (!raw) return "MyVerifier"; const parts = raw.match(/[A-Za-z0-9]+/g) ?? []; if (parts.length === 0) return "MyVerifier"; let normalized = parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(""); if (!/^[A-Za-z_]/.test(normalized)) { normalized = `_${normalized}`; } return normalized; } function log2(V) { return ((V & 4294901760) !== 0 ? (V &= 4294901760, 16) : 0) | ((V & 4278255360) !== 0 ? (V &= 4278255360, 8) : 0) | ((V & 4042322160) !== 0 ? (V &= 4042322160, 4) : 0) | ((V & 3435973836) !== 0 ? (V &= 3435973836, 2) : 0) | (V & 2863311530) !== 0; } async function readG1(fd, curve, toObject) { const buff = await fd.read(curve.G1.F.n8 * 2); const res = curve.G1.fromRprLEM(buff, 0); return toObject ? curve.G1.toObject(res) : res; } async function readG2(fd, curve, toObject) { const buff = await fd.read(curve.G2.F.n8 * 2); const res = curve.G2.fromRprLEM(buff, 0); return toObject ? curve.G2.toObject(res) : res; } async function readHeaderPlonk(fd, sections, toObject) { const zkey = {}; zkey.protocol = "plonk"; await binFileUtils.startReadUniqueSection(fd, sections, 2); const n8q = await fd.readULE32(); zkey.n8q = n8q; zkey.q = await binFileUtils.readBigInt(fd, n8q); const n8r = await fd.readULE32(); zkey.n8r = n8r; zkey.r = await binFileUtils.readBigInt(fd, n8r); zkey.curve = await getCurveFromQ(zkey.q); zkey.nVars = await fd.readULE32(); zkey.nPublic = await fd.readULE32(); zkey.domainSize = await fd.readULE32(); zkey.power = log2(zkey.domainSize); zkey.nAdditions = await fd.readULE32(); zkey.nConstraints = await fd.readULE32(); zkey.k1 = await fd.read(n8r); zkey.k2 = await fd.read(n8r); zkey.Qm = await readG1(fd, zkey.curve, toObject); zkey.Ql = await readG1(fd, zkey.curve, toObject); zkey.Qr = await readG1(fd, zkey.curve, toObject); zkey.Qo = await readG1(fd, zkey.curve, toObject); zkey.Qc = await readG1(fd, zkey.curve, toObject); zkey.S1 = await readG1(fd, zkey.curve, toObject); zkey.S2 = await readG1(fd, zkey.curve, toObject); zkey.S3 = await readG1(fd, zkey.curve, toObject); zkey.X_2 = await readG2(fd, zkey.curve, toObject); await binFileUtils.endReadSection(fd); return zkey; } // src/templateResolver.js var import_path2 = __toESM(require("path"), 1); var import_module = require("module"); var PACKAGE_NAME = "export-ton-verifier"; function requireBases() { const bases = []; if (typeof __filename === "string") { bases.push(__filename); } if (process.argv[1]) { bases.push(import_path2.default.resolve(process.argv[1])); } bases.push(import_path2.default.join(process.cwd(), "__export_ton_verifier_resolver__.js")); return [...new Set(bases)]; } function packageRootFromResolvedEntry(entryPath) { const dir = import_path2.default.dirname(entryPath); return import_path2.default.basename(dir) === "dist" ? import_path2.default.dirname(dir) : dir; } function resolvePackageRootFromSelfReference() { for (const base of requireBases()) { try { return packageRootFromResolvedEntry( (0, import_module.createRequire)(base).resolve(PACKAGE_NAME) ); } catch { } } return null; } function resolvePackageRootFromModuleDir() { if (typeof __dirname !== "string") return null; if (import_path2.default.basename(__dirname) === "dist" || import_path2.default.basename(__dirname) === "src") { return import_path2.default.dirname(__dirname); } return __dirname; } function defaultTemplatesDir() { const packageRoot = resolvePackageRootFromSelfReference() ?? resolvePackageRootFromModuleDir() ?? process.cwd(); return import_path2.default.join(packageRoot, "templates"); } // src/logger.js function createLogger({ logger = null, quiet = false } = {}) { if (quiet || logger === false || logger == null) { return { log() { } }; } if (typeof logger === "function") { return { log: logger }; } if (typeof logger.log === "function") { return { log: logger.log.bind(logger) }; } throw new Error( "logger must be a function, an object with log(message), false, null, or undefined." ); } // src/formats/snarkjs.js var import_snarkjs = require("snarkjs"); // src/export_plonk_vk.js var binFileUtils2 = __toESM(require("@iden3/binfileutils"), 1); var import_ffjavascript4 = require("ffjavascript"); var { stringifyBigInts, unstringifyBigInts } = import_ffjavascript4.utils; var G1_KEYS = ["Qm", "Ql", "Qr", "Qo", "Qc", "S1", "S2", "S3"]; var G1_UC_KEYS = ["Qm_uc", "Ql_uc", "Qr_uc", "Qo_uc", "Qc_uc", "S1_uc", "S2_uc", "S3_uc"]; async function zkeyExportPlonkVerificationKey(zkeyName) { const { fd, sections } = await binFileUtils2.readBinFile(zkeyName, "zkey", 2); try { const zkey = await readHeaderPlonk(fd, sections); return await plonkVk(zkey); } finally { await fd.close(); } } async function normalizePlonkVerificationKey(vkRaw) { if (vkRaw.protocol !== "plonk") { throw new Error(`Expected PLONK verification key (got '${vkRaw.protocol}').`); } const nPublic = numberField(vkRaw, "nPublic"); assertPlonkPublicInputCount(nPublic, "verification_key.nPublic"); if (isTemplateReadyPlonkVerificationKey(vkRaw)) { return stringifyBigInts({ ...vkRaw, nPublic }); } const vk = unstringifyBigInts(vkRaw); const curve = await getCurveFromName(vkRaw.curve); try { const res = { protocol: "plonk", curve: curve.name, nPublic, power: numberField(vkRaw, "power"), k1: scalarToString(curve, vk.k1, "k1"), k2: scalarToString(curve, vk.k2, "k2"), w: vk.w === void 0 ? scalarToString(curve, curve.Fr.w[numberField(vkRaw, "power")], "w") : scalarToString(curve, vk.w, "w"), X_2: pointObjectToBlstCHex(curve.G2, vk.X_2, "X_2") }; for (const key of G1_KEYS) { res[key] = pointObjectToBlstCHex(curve.G1, vk[key], key); res[`${key}_uc`] = pointObjectToUncompressedHex(curve.G1, vk[key], key); } return stringifyBigInts(res); } finally { if (typeof curve.terminate === "function") { await curve.terminate(); } } } function isTemplateReadyPlonkVerificationKey(vkRaw) { return G1_KEYS.every((key) => typeof vkRaw[key] === "string") && G1_UC_KEYS.every((key) => typeof vkRaw[key] === "string") && typeof vkRaw.X_2 === "string"; } function numberField(vkRaw, key) { const value = Number(vkRaw[key]); if (!Number.isInteger(value) || value < 0) { throw new Error(`verification_key: invalid '${key}'.`); } return value; } function scalarToString(curve, value, key) { if (value === void 0 || value === null) { throw new Error(`verification_key: missing '${key}'.`); } return curve.Fr.toObject(curve.Fr.fromObject(value)).toString(); } function ffC2blstC(a, offset = 0) { if (a[offset] & 128) { a[offset] |= 32; } a[offset] |= 128; } function pointObjectToBlstCHex(curve, p, key) { if (p === void 0 || p === null) { throw new Error(`verification_key: missing '${key}'.`); } return pointToBlstCHex(curve, curve.fromObject(p)); } function pointToBlstCHex(curve, p) { const tmp = new Uint8Array(curve.F.n8); curve.toRprCompressed(tmp, 0, p); ffC2blstC(tmp, 0); return Buffer.from(tmp).toString("hex"); } function pointObjectToUncompressedHex(curve, p, key) { if (p === void 0 || p === null) { throw new Error(`verification_key: missing '${key}'.`); } return pointToUncompressedHex(curve, curve.fromObject(p)); } function pointToUncompressedHex(curve, p) { const tmp = new Uint8Array(curve.F.n8 * 2); curve.toRprUncompressed(tmp, 0, p); return Buffer.from(tmp).toString("hex"); } async function plonkVk(zkey) { const curve = zkey.curve; try { assertPlonkPublicInputCount(zkey.nPublic, "verification_key.nPublic"); let vKey = { protocol: zkey.protocol, curve: curve.name, nPublic: zkey.nPublic, power: zkey.power, k1: curve.Fr.toObject(zkey.k1), k2: curve.Fr.toObject(zkey.k2), Qm: pointToBlstCHex(curve.G1, zkey.Qm), Ql: pointToBlstCHex(curve.G1, zkey.Ql), Qr: pointToBlstCHex(curve.G1, zkey.Qr), Qo: pointToBlstCHex(curve.G1, zkey.Qo), Qc: pointToBlstCHex(curve.G1, zkey.Qc), S1: pointToBlstCHex(curve.G1, zkey.S1), S2: pointToBlstCHex(curve.G1, zkey.S2), S3: pointToBlstCHex(curve.G1, zkey.S3), Qm_uc: pointToUncompressedHex(curve.G1, zkey.Qm), Ql_uc: pointToUncompressedHex(curve.G1, zkey.Ql), Qr_uc: pointToUncompressedHex(curve.G1, zkey.Qr), Qo_uc: pointToUncompressedHex(curve.G1, zkey.Qo), Qc_uc: pointToUncompressedHex(curve.G1, zkey.Qc), S1_uc: pointToUncompressedHex(curve.G1, zkey.S1), S2_uc: pointToUncompressedHex(curve.G1, zkey.S2), S3_uc: pointToUncompressedHex(curve.G1, zkey.S3), X_2: pointToBlstCHex(curve.G2, zkey.X_2), w: curve.Fr.toObject(curve.Fr.w[zkey.power]) }; vKey = stringifyBigInts(vKey); return vKey; } finally { if (typeof curve.terminate === "function") { await curve.terminate(); } } } // src/formats/snarkjs.js var SNARKJS_JSON_SOURCE = "snarkjs-json"; var SNARKJS_ZKEY_SOURCE = "snarkjs-zkey"; var GROTH16_REQUIRED_FIELDS = [ "vk_alpha_1", "vk_beta_2", "vk_gamma_2", "vk_delta_2" ]; var PLONK_REQUIRED_FIELDS = [ "nPublic", "power", "k1", "k2", "Qm", "Ql", "Qr", "Qo", "Qc", "S1", "S2", "S3", "X_2" ]; function normalizeSnarkjsVerificationKey(vkRaw) { if (!(vkRaw == null ? void 0 : vkRaw.protocol)) { throw new Error("verification_key: missing 'protocol'."); } if (!vkRaw.curve) { throw new Error("verification_key: missing 'curve'."); } ensureSupportedProtocol(vkRaw.protocol, "JSON"); validateSnarkjsVerificationKeyShape(vkRaw); return vkRaw; } async function loadSnarkjsZkeyVerificationKey(inputPath, { logger = null } = {}) { var _a; (_a = logger == null ? void 0 : logger.log) == null ? void 0 : _a.call(logger, "Loading verification key from .zkey..."); const vkRaw = await import_snarkjs.zKey.exportVerificationKey(inputPath); ensureSupportedProtocol(vkRaw.protocol, ".zkey"); return vkRaw; } async function loadSnarkjsPlonkTemplateVerificationKey(verifierInput) { if (verifierInput.sourceFormat === SNARKJS_ZKEY_SOURCE) { return zkeyExportPlonkVerificationKey(verifierInput.inputPath); } return normalizePlonkVerificationKey(verifierInput.verificationKey); } function ensureSupportedProtocol(protocol, source) { if (protocol !== "groth16" && protocol !== "plonk") { throw new Error( `Only Groth16 and PLONK are supported from ${source} (got '${protocol}').` ); } } function validateSnarkjsVerificationKeyShape(vkRaw) { if (vkRaw.protocol === "groth16") { requireFields(vkRaw, GROTH16_REQUIRED_FIELDS); if (!Array.isArray(vkRaw.IC) || vkRaw.IC.length === 0) { throw new Error("verification_key: 'IC' must be a non-empty array."); } return; } requireFields(vkRaw, PLONK_REQUIRED_FIELDS); } function requireFields(value, fields) { for (const field of fields) { if (value[field] === void 0 || value[field] === null) { throw new Error(`verification_key: missing '${field}'.`); } } } // src/formats/gnark.js var import_promises3 = __toESM(require("fs/promises"), 1); // src/formats/common.js var import_promises2 = __toESM(require("fs/promises"), 1); var import_ffjavascript5 = require("ffjavascript"); var BLS12381_CURVE_NAME = "bls12381"; function normalizeBls12381CurveName(raw, field = "curve") { if (typeof raw !== "string" || raw.trim() === "") { throw new Error(`${field}: BLS12-381 curve metadata is required.`); } const normalized = raw.toLowerCase().replace(/[^a-z0-9]/g, ""); if (normalized !== "bls12381") { throw new Error( `${field}: only BLS12-381 artifacts are supported for gnark/arkworks inputs (got '${raw}').` ); } return BLS12381_CURVE_NAME; } function decimalString(value, field) { if (typeof value === "bigint") return value.toString(); if (typeof value === "number" && Number.isInteger(value)) return String(value); if (typeof value === "string") { const trimmed = value.trim(); if (/^[0-9]+$/.test(trimmed)) return trimmed; } throw new Error(`${field} must be a decimal string or integer.`); } function requireField(value, field) { if (value === void 0 || value === null) { throw new Error(`verification key: missing '${field}'.`); } return value; } function g1Point(x, y, field) { return [ decimalString(x, `${field}.X`), decimalString(y, `${field}.Y`), "1" ]; } function g2Point(x0, x1, y0, y1, field) { return [ [ decimalString(x0, `${field}.X.A0`), decimalString(x1, `${field}.X.A1`) ], [ decimalString(y0, `${field}.Y.A0`), decimalString(y1, `${field}.Y.A1`) ], ["1", "0"] ]; } function makeGroth16VerificationKey({ curve = BLS12381_CURVE_NAME, vk_alpha_1, vk_beta_2, vk_gamma_2, vk_delta_2, IC }) { if (!Array.isArray(IC) || IC.length === 0) { throw new Error("verification key: IC/G1.K must contain at least one point."); } return { protocol: "groth16", curve, vk_alpha_1, vk_beta_2, vk_gamma_2, vk_delta_2, IC, nPublic: IC.length - 1 }; } async function readJson(path4, label) { const content = await import_promises2.default.readFile(path4, "utf8"); try { return JSON.parse(content); } catch (err) { throw new Error(`invalid ${label} JSON in ${path4}: ${err.message}`); } } function decodeHex(raw, field) { if (typeof raw !== "string") { throw new Error(`${field} must be a hex string.`); } const hex = raw.trim().replace(/^0x/i, ""); if (hex.length === 0) throw new Error(`${field} must not be empty.`); if (hex.length % 2 !== 0) { throw new Error(`${field} has odd hex length.`); } if (!/^[0-9a-fA-F]+$/.test(hex)) { throw new Error(`${field} must be a hex string.`); } return Uint8Array.from(Buffer.from(hex, "hex")); } async function withBls12381(run) { const curve = await (0, import_ffjavascript5.buildBls12381)(); try { return await run(curve); } finally { if (curve && typeof curve.terminate === "function") { await curve.terminate(); } } } function decodeBls12381G1(curve, bytes, field) { const point = decodeBls12381Point(curve.G1, bytes, 48, field); return curvePointToObjectArray(curve.G1, point); } function decodeBls12381G2(curve, bytes, field) { const point = decodeBls12381Point(curve.G2, bytes, 96, field); return curvePointToObjectArray(curve.G2, point); } function curvePointToObjectArray(curveGroup, point) { return stringifyBigIntsDeep(curveGroup.toObject(point)); } function stringifyBigIntsDeep(value) { if (typeof value === "bigint") return value.toString(); if (Array.isArray(value)) return value.map(stringifyBigIntsDeep); return value; } function decodeBls12381Point(group, bytes, compressedSize, field) { const first = bytes[0]; if (first === void 0) { throw new Error(`${field}: empty point encoding.`); } const flag = first & 224; const compressed = flag === 128 || flag === 160 || flag === 192; const uncompressed = flag === 0 || flag === 64; if (!compressed && !uncompressed) { throw new Error( `${field}: unsupported gnark/arkworks point flag 0x${flag.toString(16)}.` ); } if (compressed) { if (bytes.length !== compressedSize) { throw new Error( `${field}: expected ${compressedSize} compressed bytes, got ${bytes.length}.` ); } if (flag === 192) return group.zero; return group.fromRprCompressed(toFfjavascriptCompressed(bytes), 0); } if (bytes.length !== compressedSize * 2) { throw new Error( `${field}: expected ${compressedSize * 2} uncompressed bytes, got ${bytes.length}.` ); } if (flag === 64) return group.zero; return group.fromRprUncompressed(bytes, 0); } function toFfjavascriptCompressed(bytes) { const converted = Uint8Array.from(bytes); const sign = converted[0] & 32; converted[0] &= 31; if (sign) converted[0] |= 128; return converted; } var BinaryReader = class { constructor(bytes, sourceName) { this.bytes = bytes instanceof Uint8Array ? bytes : Uint8Array.from(bytes); this.sourceName = sourceName; this.offset = 0; } readBytes(len, field) { const end = this.offset + len; if (end > this.bytes.length) { throw new Error( `${this.sourceName} ended while reading ${field}: need ${len} bytes at offset ${this.offset}, remaining ${this.bytes.length - this.offset}.` ); } const slice = this.bytes.slice(this.offset, end); this.offset = end; return slice; } peekByte(field) { const value = this.bytes[this.offset]; if (value === void 0) { throw new Error(`${this.sourceName} ended before reading ${field}.`); } return value; } readU32BE(field) { const bytes = this.readBytes(4, field); return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32( 0, false ); } readU64BE(field) { const bytes = this.readBytes(8, field); return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getBigUint64( 0, false ); } readU64LE(field) { const bytes = this.readBytes(8, field); return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getBigUint64( 0, true ); } finish(label = "artifact") { if (this.offset !== this.bytes.length) { throw new Error( `${this.sourceName} has ${this.bytes.length - this.offset} trailing bytes after ${label}.` ); } } }; // src/formats/gnark.js var BLS_FIELD_BYTES = 48; var GNARK_FLAG_MASK = 224; var GNARK_COMPRESSED_FLAGS = /* @__PURE__ */ new Set([128, 160, 192]); var GNARK_UNCOMPRESSED_FLAGS = /* @__PURE__ */ new Set([0, 64]); async function normalizeGnarkJsonVerificationKey(value) { const g1 = requireField(value == null ? void 0 : value.G1, "G1"); const g2 = requireField(value == null ? void 0 : value.G2, "G2"); ensureNoVerificationKeyCommitments(value); const k = requireField(g1.K, "G1.K"); if (!Array.isArray(k)) { throw new Error("verification key: G1.K must be an array."); } const verificationKey = makeGroth16VerificationKey({ curve: BLS12381_CURVE_NAME, vk_alpha_1: g1FromJson(requireField(g1.Alpha, "G1.Alpha"), "G1.Alpha"), vk_beta_2: g2FromJson(requireField(g2.Beta, "G2.Beta"), "G2.Beta"), vk_gamma_2: g2FromJson(requireField(g2.Gamma, "G2.Gamma"), "G2.Gamma"), vk_delta_2: g2FromJson(requireField(g2.Delta, "G2.Delta"), "G2.Delta"), IC: k.map((point, idx) => g1FromJson(point, `G1.K[${idx}]`)) }); await assertBls12381VerificationKeyPoints(verificationKey); return verificationKey; } async function loadGnarkBinaryVerificationKey(path4) { const bytes = await import_promises3.default.readFile(path4); return normalizeGnarkBinaryVerificationKey(Uint8Array.from(bytes), path4); } async function normalizeGnarkBinaryVerificationKey(bytes, sourceName = "gnark binary VK") { return withBls12381((curve) => { const reader = new BinaryReader(bytes, sourceName); const alpha = readG12(reader, curve, "G1.Alpha"); readG12(reader, curve, "G1.Beta"); const beta = readG22(reader, curve, "G2.Beta"); const gamma = readG22(reader, curve, "G2.Gamma"); readG12(reader, curve, "G1.Delta"); const delta = readG22(reader, curve, "G2.Delta"); const icLen = reader.readU32BE("G1.K length"); const IC = []; for (let idx = 0; idx < icLen; idx += 1) { IC.push(readG12(reader, curve, `G1.K[${idx}]`)); } const publicAndCommitmentCommitted = readU64SliceSlice( reader, "PublicAndCommitmentCommitted" ); const commitmentKeysLen = reader.readU32BE("CommitmentKeys length"); if (publicAndCommitmentCommitted.length !== 0 || commitmentKeysLen !== 0) { throw new Error( "gnark commitment keys are not supported by TON verifier generation." ); } reader.finish("gnark verification key"); return makeGroth16VerificationKey({ curve: BLS12381_CURVE_NAME, vk_alpha_1: alpha, vk_beta_2: beta, vk_gamma_2: gamma, vk_delta_2: delta, IC }); }); } function ensureNoVerificationKeyCommitments(value) { const commitmentKeys = value == null ? void 0 : value.CommitmentKeys; const publicAndCommitmentCommitted = value == null ? void 0 : value.PublicAndCommitmentCommitted; if (!isEmptyCommitmentValue(commitmentKeys) || !isEmptyCommitmentValue(publicAndCommitmentCommitted)) { throw new Error( "gnark commitment keys are not supported by TON verifier generation." ); } } function isEmptyCommitmentValue(value) { return value === void 0 || value === null || Array.isArray(value) && value.length === 0; } function g1FromJson(point, field) { return g1Point( requireField(point == null ? void 0 : point.X, `${field}.X`), requireField(point == null ? void 0 : point.Y, `${field}.Y`), field ); } function g2FromJson(point, field) { var _a, _b, _c, _d; return g2Point( requireField((_a = point == null ? void 0 : point.X) == null ? void 0 : _a.A0, `${field}.X.A0`), requireField((_b = point == null ? void 0 : point.X) == null ? void 0 : _b.A1, `${field}.X.A1`), requireField((_c = point == null ? void 0 : point.Y) == null ? void 0 : _c.A0, `${field}.Y.A0`), requireField((_d = point == null ? void 0 : point.Y) == null ? void 0 : _d.A1, `${field}.Y.A1`), field ); } async function assertBls12381VerificationKeyPoints(vk) { await withBls12381((curve) => { assertBls12381Point(curve.G1, vk.vk_alpha_1, "G1.Alpha"); assertBls12381Point(curve.G2, vk.vk_beta_2, "G2.Beta"); assertBls12381Point(curve.G2, vk.vk_gamma_2, "G2.Gamma"); assertBls12381Point(curve.G2, vk.vk_delta_2, "G2.Delta"); vk.IC.forEach((point, idx) => { assertBls12381Point(curve.G1, point, `G1.K[${idx}]`); }); }); } function assertBls12381Point(group, point, field) { let parsed; try { parsed = group.fromObject(bigintPoint(point)); } catch (err) { throw new Error( `${field}: expected a valid BLS12-381 point (${(err == null ? void 0 : err.message) || err}).` ); } if (!group.isValid(parsed)) { throw new Error(`${field}: point is not on BLS12-381.`); } } function bigintPoint(value) { if (Array.isArray(value)) return value.map(bigintPoint); if (typeof value === "bigint") return value; return BigInt(value); } function readG12(reader, curve, field) { const bytes = reader.readBytes(pointLength(reader, BLS_FIELD_BYTES, field), field); return decodeBls12381G1(curve, bytes, field); } function readG22(reader, curve, field) { const bytes = reader.readBytes( pointLength(reader, BLS_FIELD_BYTES * 2, field), field ); return decodeBls12381G2(curve, bytes, field); } function pointLength(reader, compressedSize, field) { const flag = reader.peekByte(field) & GNARK_FLAG_MASK; if (GNARK_COMPRESSED_FLAGS.has(flag)) return compressedSize; if (GNARK_UNCOMPRESSED_FLAGS.has(flag)) return compressedSize * 2; throw new Error( `${field}: unsupported gnark point flag 0x${flag.toString(16).padStart(2, "0")}.` ); } function readU64SliceSlice(reader, field) { const outerLen = reader.readU32BE(`${field} length`); const outer = []; for (let outerIdx = 0; outerIdx < outerLen; outerIdx += 1) { const innerLen = reader.readU32BE(`${field}[${outerIdx}] length`); const inner = []; for (let innerIdx = 0; innerIdx < innerLen; innerIdx += 1) { inner.push(reader.readU64BE(`${field}[${outerIdx}][${innerIdx}]`)); } outer.push(inner); } return outer; } // src/formats/arkworks.js var G1_COMPRESSED_BYTES = 48; var G2_COMPRESSED_BYTES = 96; async function normalizeArkworksVerificationKey(value) { const curve = parseCurve(value); const vkHex = firstString(value, ["vk", "verification_key", "verifying_key"], "vk"); return decodeArkworksVerificationKey(vkHex, curve); } async function decodeArkworksVerificationKey(raw, curveName = BLS12381_CURVE_NAME) { normalizeBls12381CurveName(curveName, "curve"); const bytes = decodeHex(raw, "vk"); return withBls12381((curve) => { const reader = new BinaryReader(bytes, "arkworks verification key"); const vk_alpha_1 = decodeBls12381G1( curve, reader.readBytes(G1_COMPRESSED_BYTES, "vk.alpha_g1"), "vk.alpha_g1" ); const vk_beta_2 = decodeBls12381G2( curve, reader.readBytes(G2_COMPRESSED_BYTES, "vk.beta_g2"), "vk.beta_g2" ); const vk_gamma_2 = decodeBls12381G2( curve, reader.readBytes(G2_COMPRESSED_BYTES, "vk.gamma_g2"), "vk.gamma_g2" ); const vk_delta_2 = decodeBls12381G2( curve, reader.readBytes(G2_COMPRESSED_BYTES, "vk.delta_g2"), "vk.delta_g2" ); const icLen = Number(reader.readU64LE("vk.gamma_abc_g1 length")); if (!Number.isSafeInteger(icLen)) { throw new Error("vk.gamma_abc_g1 length is too large."); } const IC = []; for (let idx = 0; idx < icLen; idx += 1) { IC.push( decodeBls12381G1( curve, reader.readBytes(G1_COMPRESSED_BYTES, `vk.gamma_abc_g1[${idx}]`), `vk.gamma_abc_g1[${idx}]` ) ); } reader.finish("arkworks verification key"); return makeGroth16VerificationKey({ curve: BLS12381_CURVE_NAME, vk_alpha_1, vk_beta_2, vk_gamma_2, vk_delta_2, IC }); }); } function parseCurve(value) { const curve = value == null ? void 0 : value.curve; if (!curve) { throw new Error("arkworks input requires curve metadata."); } return normalizeBls12381CurveName(curve, "curve"); } function firstString(value, keys, label) { for (const key of keys) { const candidate = value == null ? void 0 : value[key]; if (typeof candidate === "string") return candidate; } throw new Error(`arkworks input requires ${label} hex field.`); } // src/formats/index.js var GNARK_JSON_SOURCE = "gnark-json"; var GNARK_BINARY_SOURCE = "gnark-bin"; var ARKWORKS_JSON_SOURCE = "arkworks-json"; async function loadVerificationKey(inputPath, { logger = null, quiet = false } = {}) { const log = createLogger({ logger, quiet }); const nativeInput = await loadNativeVerificationKeyInput(inputPath); if (nativeInput) return nativeInput; return makeVerifierInput( inputPath, SNARKJS_ZKEY_SOURCE, await loadSnarkjsZkeyVerificationKey(inputPath, { logger: log }) ); } async function loadPlonkTemplateVerificationKey(verifierInput) { return loadSnarkjsPlonkTemplateVerificationKey(verifierInput); } async function loadNativeVerificationKeyInput(inputPath) { const lower = inputPath.toLowerCase(); if (lower.endsWith(".json")) { return loadJsonVerificationKey(inputPath); } if (lower.endsWith(".bin")) { return makeVerifierInput( inputPath, GNARK_BINARY_SOURCE, await loadGnarkBinaryVerificationKey(inputPath) ); } return null; } async function loadJsonVerificationKey(inputPath) { const raw = await readJson(inputPath, "verification key"); const errors = []; try { return makeVerifierInput( inputPath, SNARKJS_JSON_SOURCE, normalizeSnarkjsVerificationKey(raw) ); } catch (err) { errors.push(`snarkjs JSON: ${err.message}`); } try { return makeVerifierInput( inputPath, GNARK_JSON_SOURCE, await normalizeGnarkJsonVerificationKey(raw) ); } catch (err) { errors.push(`gnark JSON: ${err.message}`); } try { return makeVerifierInput( inputPath, ARKWORKS_JSON_SOURCE, await normalizeArkworksVerificationKey(raw) ); } catch (err) { errors.push(`arkworks JSON: ${err.message}`); } throw new Error( `could not auto-detect verification key JSON format: ${errors.join("; ")}` ); } function makeVerifierInput(inputPath, sourceFormat, verificationKey) { return { inputPath, sourceFormat, verificationKey }; } // src/generateVerifiers.js var { unstringifyBigInts: unstringifyBigInts2 } = import_ffjavascript6.utils; async function generateVerifier(inputPath, outputPath, { lang = "tolk", templatesDir = defaultTemplatesDir(), contractName = null, logger = null, quiet = false } = {}) { const log = createLogger({ logger, quiet }); const verifierInput = await loadVerificationKey(inputPath, { logger: log }); const vkRaw = verifierInput.verificationKey; assertTonBlsCurve(vkRaw.curve, "verification_key.curve"); const normalizedContractName = typeof contractName === "string" && contractName.trim() ? normalizeContractName(contractName) : null; const templatePath = await resolveTemplatePath( templatesDir, lang, vkRaw.protocol ); log.log(`Using template for: ${lang} ${vkRaw.protocol}`); let curve; try { if (vkRaw.protocol === "groth16") { const vk = unstringifyBigInts2(vkRaw); curve = await getCurveFromName(vkRaw.curve); log.log("Compressing points..."); const data = { protocol: "groth16", curve: vkRaw.curve, contractName: normalizedContractName, vk_alpha_1: g1Compressed(curve, vk.vk_alpha_1), vk_beta_2: g2Compressed(curve, vk.vk_beta_2), vk_gamma_2: g2Compressed(curve, vk.vk_gamma_2), vk_delta_2: g2Compressed(curve, vk.vk_delta_2), IC: vk.IC.map((x) => g1Compressed(curve, x)), nPublic: vk.IC.length - 1, publicInputKeyLen: 32, _raw: vkRaw }; log.log("Rendering template..."); const template2 = await import_promises4.default.readFile(templatePath, "utf8"); const rendered2 = import_ejs.default.render(template2, data); log.log(`Saving file: ${outputPath}`); await import_promises4.default.writeFile(outputPath, rendered2, "utf8"); log.log("Done."); return "groth16"; } log.log("Rendering template for PLONK..."); const template = await import_promises4.default.readFile(templatePath, "utf8"); const verificationKey = { ...await loadPlonkTemplateVerificationKey(verifierInput), contractName: normalizedContractName }; const rendered = import_ejs.default.render(template, verificationKey); log.log(`Saving file: ${outputPath}`); await import_promises4.default.writeFile(outputPath, rendered, "utf8"); log.log("Done."); return "plonk"; } finally { if (curve && typeof curve.terminate === "function") { await curve.terminate(); } } } // src/export_plonk_calldata.js var import_ffjavascript7 = require("ffjavascript"); var import_core2 = require("@ton/core"); var { unstringifyBigInts: unstringifyBigInts3 } = import_ffjavascript7.utils; function calldataToTupleItems(calldata) { return calldata.map((item) => { if ((item.type === "slice" || item.type === "cell") && item.cell != null) { const c = item.cell; if (typeof c.toBoc === "function") { const ourCell = import_core2.Cell.fromBoc(c.toBoc())[0]; return { type: item.type, cell: ourCell }; } } return item; }); } async function exportPlonkFuncCalldata(_proof, _pub) { return exportPlonkCalldataWithPublicInputs(_proof, _pub, funcPublicInputs); } async function exportPlonkTolkCalldata(_proof, _pub) { return exportPlonkCalldataWithPublicInputs(_proof, _pub, tolkPublicInputs); } async function exportPlonkCalldataWithPublicInputs(_proof, _pub, publicInputItem) { let proof = unstringifyBigInts3(_proof); const pub = unstringifyBigInts3(_pub); if (!Array.isArray(pub)) { throw new Error("public inputs must be an array."); } assertPlonkPublicInputCount(pub.length, "public inputs"); const curve = await getCurveFromName2(proof.curve); try { proof = fromObjectProof(curve, proof); } finally { if (typeof curve.terminate === "function") { await curve.terminate(); } } const hexToCell = (hex) => (0, import_core2.beginCell)().storeBuffer(Buffer.from(hex, "hex")).endCell(); const calldata = [ { type: "slice", cell: (0, import_core2.beginCell)().storeBuffer(Buffer.from(proof.A, "hex")).endCell() }, { type: "slice", cell: (0, import_core2.beginCell)().storeBuffer(Buffer.from(proof.B, "hex")).endCell() }, { type: "slice", cell: (0, import_core2.beginCell)().storeBuffer(Buffer.from(proof.C, "hex")).endCell() }, { type: "slice", cell: (0, import_core2.beginCell)().storeBuffer(Buffer.from(proof.Z, "hex")).endCell() }, { type: "slice", cell: (0, import_core2.beginCell)().storeBuffer(Buffer.from(proof.T1, "hex")).endCell() }, { type: "slice", cell: (0, import_core2.beginCell)().storeBuffer(Buffer.from(proof.T2, "hex")).endCell() }, { type: "slice", cell: (0, import_core2.beginCell)().storeBuffer(Buffer.from(proof.T3, "hex")).endCell() }, { type: "int", value: proof.eval_a }, { type: "int", value: proof.eval_b }, { type: "int", value: proof.eval_c }, { type: "int", value: proof.eval_s1 }, { type: "int", value: proof.eval_s2 }, { type: "int", value: proof.eval_zw }, { type: "slice", cell: (0, import_core2.beginCell)().storeBuffer(Buffer.from(proof.Wxi, "hex")).endCell() }, { type: "slice", cell: (0, import_core2.beginCell)().storeBuffer(Buffer.from(proof.Wxiw, "hex")).endCell() }, publicInputItem(pub), { type: "slice", cell: hexToCell(proof.A_uc) }, { type: "slice", cell: hexToCell(proof.B_uc) }, { type: "slice", cell: hexToCell(proof.C_uc) }, { type: "slice", cell: hexToCell(proof.Z_uc) }, { type: "slice", cell: hexToCell(proof.T1_uc) }, { type: "slice", cell: hexToCell(proof.T2_uc) }, { type: "slice", cell: hexToCell(proof.T3_uc) }, { type: "slice", cell: hexToCell(proof.Wxi_uc) }, { type: "slice", cell: hexToCell(proof.Wxiw_uc) } ]; return calldataToTupleItems(calldata); } function funcPublicInputs(vs) { const d = import_core2.Dictionary.empty( import_core2.Dictionary.Keys.Uint(32), import_core2.Dictionary.Values.BigUint(256) ); for (let i = 0; i < vs.length; i++) { d.set(i, vs[i]); } const b = (0, import_core2.beginCell)(); d.storeDirect(b); return { type: "cell", cell: b.endCell() }; } function tolkPublicInputs(vs) { return { type: "tuple", items: vs.map((value) => ({ type: "int", value })) }; } function ffC2blstC2(a, offset = 0) { if (a[offset] & 128) { a[offset] |= 32; } a[offset] |= 128; } function pointToBlstCHex2(curve, p) { const tmp = new Uint8Array(curve.F.n8); curve.toRprCompressed(tmp, 0, p); ffC2blstC2(tmp, 0); return Buffer.from(tmp).toString("hex"); } function pointToUncompressedHex2(curve, p) { const tmp = new Uint8Array(curve.F.n8 * 2); curve.toRprUncompressed(tmp, 0, p); return Buffer.from(tmp).toString("hex"); } function fromObjectProof(curve, proof) { const G1 = curve.G1; const Fr = curve.Fr; const res = {}; const A = G1.fromObject(proof.A); const B = G1.fromObject(proof.B); const C = G1.fromObject(proof.C); const Z = G1.fromObject(proof.Z); const T1 = G1.fromObject(proof.T1); const T2 = G1.fromObject(proof.T2); const T3 = G1.fromObject(proof.T3); const Wxi = G1.fromObject(proof.Wxi); const Wxiw = G1.fromObject(proof.Wxiw); res.A = pointToBlstCHex2(curve.G1, A); res.B = pointToBlstCHex2(curve.G1, B); res.C = pointToBlstCHex2(curve.G1, C); res.Z = pointToBlstCHex2(curve.G1, Z); res.T1 = pointToBlstCHex2(curve.G1, T1); res.T2 = pointToBlstCHex2(curve.G1, T2); res.T3 = pointToBlstCHex2(curve.G1, T3); res.Wxi = pointToBlstCHex2(curve.G1, Wxi); res.Wxiw = pointToBlstCHex2(curve.G1, Wxiw); res.A_uc = pointToUncompressedHex2(curve.G1, A); res.B_uc = pointToUncompressedHex2(curve.G1, B); res.C_uc = pointToUncompressedHex2(curve.G1, C); res.Z_uc = pointToUncompressedHex2(curve.G1, Z); res.T1_uc = pointToUncompressedHex2(curve.G1, T1); res.T2_uc = pointToUncompressedHex2(curve.G1, T2); res.T3_uc = pointToUncompressedHex2(curve.G1, T3); res.Wxi_uc = pointToUncompressedHex2(curve.G1, Wxi); res.Wxiw_uc = pointToUncompressedHex2(curve.G1, Wxiw); res.eval_a = Fr.toObject(Fr.fromObject(proof.eval_a)); res.eval_b = Fr.toObject(Fr.fromObject(proof.eval_b)); res.eval_c = Fr.toObject(Fr.fromObject(proof.eval_c)); res.eval_s1 = Fr.toObject(Fr.fromObject(proof.eval_s1)); res.eval_s2 = Fr.toObject(Fr.fromObject(proof.eval_s2)); res.eval_zw = Fr.toObject(Fr.fromObject(proof.eval_zw)); return res; } // src/artifactInfo.js var import_path3 = __toESM(require("path"), 1); function check(name, run) { try { const message = run(); return { name, ok: true, message }; } catch (err) { return { name, ok: false, message: (err == null ? void 0 : err.message) || String(err) }; } } function publicInputCount(vkRaw) { if (vkRaw.protocol === "groth16") { return Array.isArray(vkRaw.IC) ? vkRaw.IC.length - 1 : null; } if (vkRaw.protocol === "plonk") { return Number(vkRaw.nPublic); } return null; } async function inspectVerifierInput(inputPath, { lang = "tolk", templatesDir = defaultTemplatesDir() } = {}) { const verifierInput = await loadVerificationKey(inputPath); const vkRaw = verifierInput.verificationKey; const nPublic = publicInputCount(vkRaw); const checks = []; checks.push( check("curve", () => { assertTonBlsCurve(vkRaw.curve, "verification_key.curve"); return "BLS12-381 is supported by TON BLS opcodes."; }) ); if (vkRaw.protocol === "plonk") { checks.push( check("plonk-public-inputs", () => { assertPlonkPublicInputCount(nPublic, "verification_key.nPublic"); return "PLONK public input count fits TVM Keccak tuple limits."; }) ); } let template = null; checks.push( await (async () => { try { template = await resolveTemplatePath(templatesDir, lang, vkRaw.protocol); return { name: "template", ok: true, message: `Template found: ${import_path3.default.basename(template)}.` }; } catch (err) { return { name: "template", ok: false, message: (err == null ? void 0 : err.message) || String(err) }; } })() ); const ok = checks.every((item) => item.ok); return { ok, inputPath, sourceFormat: verifierInput.sourceFormat, protocol: vkRaw.protocol, curve: vkRaw.curve, nPublic, language: lang, template, checks }; } function formatDoctorReport(report) { const lines = [ `Verifier doctor: ${report.ok ? "OK" : "BLOCKED"}`, `Input: ${report.inputPath}`, `Source format: ${report.sourceFormat}`, `Protocol: ${report.protocol}`, `Curve: ${report.curve}`, `Public inputs: ${report.nPublic}`, `Language: ${report.language}`, `Template: ${report.template ?? "not found"}`, "Checks:" ]; for (const item of report.checks) { lines.push(` [${item.ok ? "ok" : "blocked"}] ${item.name}: ${item.message}`); } return `${lines.join("\n")} `; } // src/proofMessages.js var import_core3 = require("@ton/core"); var GROTH16_VERIFY_OP = 993839639; var PLONK_VERIFY_PROOF_OP = 1985103449; var UINT256_ARRAY_CHUNK_SIZE = 3; function normalizeProtocol(proof, protocol) { const detected = protocol ?? (proof == null ? void 0 : proof.protocol); if (detected !== "groth16" && detected !== "plonk") { throw new Error("proof protocol must be 'groth16' or 'plonk'."); } return detected; } function normalizeLang(lang = "tolk") { if (lang !== "tolk" && lang !== "func") { throw new Error("proof-to-message supports --tolk and --func."); } return lang; } function serializeTolkIntArray(list) { if (list.length > 255) { throw new Error("Tolk array<int> wrapper supports at most 255 items."); } let tail = null; for (let i = list.length; i > 0; i -= 3) { const chunk = list.slice(Math.max(0, i - 3), i); const cell = (0, import_core3.beginCell)(); for (const value of chunk) { cell.storeInt(value, 257); } if (tail) { cell.storeRef(tail); } tail = cell.endCell(); } const root = (0, import_core3.beginCell)().storeUint(list.length, 8); if (tail) { root.storeSlice(tail.beginParse()); } return root.endCell(); } function groth16FuncPublicInputs(list) { const dict = import_core3.Dictionary.empty( import_core3.Dictionary.Keys.BigUint(32), import_core3.Dictionary.Values.BigInt(256) ); for (let i = 0; i < list.length; i += 1) { dict.set(BigInt(i), list[i]); } return dict; } async function groth16MessageCell(proof, publicSignals, lang) { const compressed = await groth16CompressProof(proof, publicSignals); const piA = (0, import_core3.beginCell)().storeBuffer(compressed.pi_a).endCell(); const piB = (0, import_core3.beginCell)().storeBuffer(compressed.pi_b).endCell(); const piC = (0, import_core3.beginCell)().storeBuffer(compressed.pi_c).endCell(); const body = (0, import_core3.beginCell)().storeUint(GROTH16_VERIFY_OP, 32).storeRef(piA).storeRef(piB).storeRef(piC); if (lang === "tolk") { body.storeSlice(serializeTolkIntArray(compressed.pubInputs).beginParse()); } else { body.storeDict(groth16FuncPublicInputs(compressed.pubInputs)); } re