/** * The public interface of this module exposes the functions as specified by * https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#kzg */ const kzg: KZG = require("bindings")("kzg"); import * as fs from "fs"; import * as path from "path"; export type Bytes32 = Uint8Array; // 32 bytes export type Bytes48 = Uint8Array; // 48 bytes export type KZGProof = Buffer; // 48 bytes export type KZGCommitment = Buffer; // 48 bytes export type Blob = Uint8Array; // 4096 * 32 bytes export type ProofResult = [KZGProof, Bytes32]; export interface TrustedSetupJson { setup_G1: string[]; setup_G2: string[]; setup_G1_lagrange: string[]; roots_of_unity: string[]; } // The C++ native addon interface interface KZG { BYTES_PER_BLOB: number; BYTES_PER_COMMITMENT: number; BYTES_PER_FIELD_ELEMENT: number; BYTES_PER_PROOF: number; FIELD_ELEMENTS_PER_BLOB: number; loadTrustedSetup: (filePath: string) => void; blobToKzgCommitment: (blob: Blob) => KZGCommitment; computeKzgProof: (blob: Blob, zBytes: Bytes32) => ProofResult; computeBlobKzgProof: (blob: Blob, commitmentBytes: Bytes48) => KZGProof; verifyKzgProof: ( commitmentBytes: Bytes48, zBytes: Bytes32, yBytes: Bytes32, proofBytes: Bytes48, ) => boolean; verifyBlobKzgProof: ( blob: Blob, commitmentBytes: Bytes48, proofBytes: Bytes48, ) => boolean; verifyBlobKzgProofBatch: ( blobs: Blob[], commitmentsBytes: Bytes48[], proofsBytes: Bytes48[], ) => boolean; } export const BYTES_PER_BLOB = kzg.BYTES_PER_BLOB; export const BYTES_PER_COMMITMENT = kzg.BYTES_PER_COMMITMENT; export const BYTES_PER_FIELD_ELEMENT = kzg.BYTES_PER_FIELD_ELEMENT; export const BYTES_PER_PROOF = kzg.BYTES_PER_PROOF; export const FIELD_ELEMENTS_PER_BLOB = kzg.FIELD_ELEMENTS_PER_BLOB; /** * Converts JSON formatted trusted setup into the native format that * the native library requires. Returns the absolute file path to the * the formatted file. The path will be the same as the origin * file but with a ".txt" extension. * * @param {string} filePath - The absolute path of JSON formatted trusted setup * * @return {string} - The absolute path of the re-formatted trusted setup * * @throws {Error} - For invalid file operations */ function transformTrustedSetupJson(filePath: string): string { const data: TrustedSetupJson = JSON.parse(fs.readFileSync(filePath, "utf8")); const textFilePath = filePath.replace(".json", ".txt"); const setupText = kzg.FIELD_ELEMENTS_PER_BLOB + "\n65\n" + data.setup_G1.map((p) => p.substring(2)).join("\n") + "\n" + data.setup_G2.map((p) => p.substring(2)).join("\n"); fs.writeFileSync(textFilePath, setupText); return textFilePath; } /** * Sets up the c-kzg library. Pass in a properly formatted trusted setup file * to configure the library. File must be in json format, see {@link TrustedSetupJson} * interface for more details, or as a properly formatted utf-8 encoded file. * * @remark This function must be run before any other functions in this * library can be run. * * @param {string} filePath - The absolute path of the trusted setup * * @return {void} * * @throws {Error} - For invalid file operations */ export function loadTrustedSetup(filePath: string): void { if (!(filePath && typeof filePath === "string")) { throw new TypeError( "must initialize kzg with the filePath to a txt/json trusted setup", ); } if (!fs.existsSync(filePath)) { throw new Error(`no trusted setup found: ${filePath}`); } if (path.parse(filePath).ext === ".json") { filePath = transformTrustedSetupJson(filePath); } return kzg.loadTrustedSetup(filePath); } /** * Convert a blob to a KZG commitment. * * @param {Blob} blob - The blob representing the polynomial to be committed to * * @return {KZGCommitment} - The resulting commitment * * @throws {TypeError} - For invalid arguments or failure of the native library */ export function blobToKzgCommitment(blob: Blob): KZGCommitment { return kzg.blobToKzgCommitment(blob); } /** * Compute KZG proof for polynomial in Lagrange form at position z. * * @param {Blob} blob - The blob (polynomial) to generate a proof for * @param {Bytes32} zBytes - The generator z-value for the evaluation points * * @return {ProofResult} - Tuple containing the resulting proof and evaluation * of the polynomial at the evaluation point z * * @throws {TypeError} - For invalid arguments or failure of the native library */ export function computeKzgProof(blob: Blob, zBytes: Bytes32): ProofResult { return kzg.computeKzgProof(blob, zBytes); } /** * Given a blob, return the KZG proof that is used to verify it against the * commitment. * * @param {Blob} blob - The blob (polynomial) to generate a proof for * @param {Bytes48} commitmentBytes - Commitment to verify * * @return {KZGProof} - The resulting proof * * @throws {TypeError} - For invalid arguments or failure of the native library */ export function computeBlobKzgProof( blob: Blob, commitmentBytes: Bytes48, ): KZGProof { return kzg.computeBlobKzgProof(blob, commitmentBytes); } /** * Verify a KZG poof claiming that `p(z) == y`. * * @param {Bytes48} commitmentBytes - The serialized commitment corresponding to polynomial p(x) * @param {Bytes32} zBytes - The serialized evaluation point * @param {Bytes32} yBytes - The serialized claimed evaluation result * @param {Bytes48} proofBytes - The serialized KZG proof * * @return {boolean} - true/false depending on proof validity * * @throws {TypeError} - For invalid arguments or failure of the native library */ export function verifyKzgProof( commitmentBytes: Bytes48, zBytes: Bytes32, yBytes: Bytes32, proofBytes: Bytes48, ): boolean { return kzg.verifyKzgProof(commitmentBytes, zBytes, yBytes, proofBytes); } /** * Given a blob and its proof, verify that it corresponds to the provided * commitment. * * @param {Blob} blob - The serialized blob to verify * @param {Bytes48} commitmentBytes - The serialized commitment to verify * @param {Bytes48} proofBytes - The serialized KZG proof for verification * * @return {boolean} - true/false depending on proof validity * * @throws {TypeError} - For invalid arguments or failure of the native library */ export function verifyBlobKzgProof( blob: Blob, commitmentBytes: Bytes48, proofBytes: Bytes48, ): boolean { return kzg.verifyBlobKzgProof(blob, commitmentBytes, proofBytes); } /** * Given an array of blobs and their proofs, verify that they corresponds to their * provided commitment. * * Note: blobs[0] relates to commitmentBytes[0] and proofBytes[0] * * @param {Blob} blobs - An array of serialized blobs to verify * @param {Bytes48} commitmentBytes - An array of serialized commitments to verify * @param {Bytes48} proofBytes - An array of serialized KZG proofs for verification * * @return {boolean} - true/false depending on batch validity * * @throws {TypeError} - For invalid arguments or failure of the native library */ export function verifyBlobKzgProofBatch( blobs: Blob[], commitmentsBytes: Bytes48[], proofsBytes: Bytes48[], ): boolean { return kzg.verifyBlobKzgProofBatch(blobs, commitmentsBytes, proofsBytes); }