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.

212 lines (209 loc) 6.13 kB
import { getCurveFromName } from "./chunk-MCE4ZZVW.js"; import { assertPlonkPublicInputCount } from "./chunk-4I2ZWZKN.js"; // src/export_plonk_calldata.js import { utils } from "ffjavascript"; import { beginCell, Cell, Dictionary } from "@ton/core"; var { unstringifyBigInts } = 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 = 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 = unstringifyBigInts(_proof); const pub = unstringifyBigInts(_pub); if (!Array.isArray(pub)) { throw new Error("public inputs must be an array."); } assertPlonkPublicInputCount(pub.length, "public inputs"); const curve = await getCurveFromName(proof.curve); try { proof = fromObjectProof(curve, proof); } finally { if (typeof curve.terminate === "function") { await curve.terminate(); } } const hexToCell = (hex) => beginCell().storeBuffer(Buffer.from(hex, "hex")).endCell(); const calldata = [ { type: "slice", cell: beginCell().storeBuffer(Buffer.from(proof.A, "hex")).endCell() }, { type: "slice", cell: beginCell().storeBuffer(Buffer.from(proof.B, "hex")).endCell() }, { type: "slice", cell: beginCell().storeBuffer(Buffer.from(proof.C, "hex")).endCell() }, { type: "slice", cell: beginCell().storeBuffer(Buffer.from(proof.Z, "hex")).endCell() }, { type: "slice", cell: beginCell().storeBuffer(Buffer.from(proof.T1, "hex")).endCell() }, { type: "slice", cell: beginCell().storeBuffer(Buffer.from(proof.T2, "hex")).endCell() }, { type: "slice", cell: 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: beginCell().storeBuffer(Buffer.from(proof.Wxi, "hex")).endCell() }, { type: "slice", cell: 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 = Dictionary.empty( Dictionary.Keys.Uint(32), Dictionary.Values.BigUint(256) ); for (let i = 0; i < vs.length; i++) { d.set(i, vs[i]); } const b = beginCell(); d.storeDirect(b); return { type: "cell", cell: b.endCell() }; } function tolkPublicInputs(vs) { return { type: "tuple", items: vs.map((value) => ({ type: "int", value })) }; } function ffC2blstC(a, offset = 0) { if (a[offset] & 128) { a[offset] |= 32; } a[offset] |= 128; } 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 pointToUncompressedHex(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 = pointToBlstCHex(curve.G1, A); res.B = pointToBlstCHex(curve.G1, B); res.C = pointToBlstCHex(curve.G1, C); res.Z = pointToBlstCHex(curve.G1, Z); res.T1 = pointToBlstCHex(curve.G1, T1); res.T2 = pointToBlstCHex(curve.G1, T2); res.T3 = pointToBlstCHex(curve.G1, T3); res.Wxi = pointToBlstCHex(curve.G1, Wxi); res.Wxiw = pointToBlstCHex(curve.G1, Wxiw); res.A_uc = pointToUncompressedHex(curve.G1, A); res.B_uc = pointToUncompressedHex(curve.G1, B); res.C_uc = pointToUncompressedHex(curve.G1, C); res.Z_uc = pointToUncompressedHex(curve.G1, Z); res.T1_uc = pointToUncompressedHex(curve.G1, T1); res.T2_uc = pointToUncompressedHex(curve.G1, T2); res.T3_uc = pointToUncompressedHex(curve.G1, T3); res.Wxi_uc = pointToUncompressedHex(curve.G1, Wxi); res.Wxiw_uc = pointToUncompressedHex(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; } export { calldataToTupleItems, exportPlonkFuncCalldata, exportPlonkTolkCalldata };