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
JavaScript
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
};