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.

147 lines (144 loc) 5.05 kB
import { readHeaderPlonk } from "./chunk-TB4DFXWQ.js"; import { getCurveFromName } from "./chunk-I7S4EEHA.js"; import { assertPlonkPublicInputCount } from "./chunk-4I2ZWZKN.js"; // src/export_plonk_vk.js import * as binFileUtils from "@iden3/binfileutils"; import { utils } from "ffjavascript"; var { stringifyBigInts, unstringifyBigInts } = 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 binFileUtils.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(); } } } export { zkeyExportPlonkVerificationKey, normalizePlonkVerificationKey };