Move setup handle to C in node bindings (#177)

* feat(node-bindings): move KzgSettings to c

* fix(node-bindings): typo in comment

* fix(node-bindings): remove unnecessary SetInstanceData

* feat(node-bindings): use C for setting instance data

* docs(node-bindings): fix comment on struct

* refactor(node-bindings): revert export order to minimize diff
This commit is contained in:
Matthew Keil 2023-03-09 08:00:15 -06:00 committed by GitHub
parent 599ae2fe21
commit 87a3e4148d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 154 additions and 230 deletions

View File

@ -9,55 +9,67 @@
#include "c_kzg_4844.h" #include "c_kzg_4844.h"
#include "blst.h" #include "blst.h"
Napi::Value throw_invalid_arguments_count( /**
const unsigned int expected, * Structure containing information needed for the lifetime of the bindings
const unsigned int actual, * instance. It is not safe to use global static data with worker instances.
const Napi::Env env * Native node addons are loaded as a dll's once no matter how many node
) { * instances are using the library. Each node instance will initialize an
Napi::RangeError::New( * instance of the bindings and workers share memory space. In addition
env, * the worker JS thread will be independent of the main JS thread. Global
"Wrong number of arguments. Expected: " * statics are not thread safe and have the potential for initialization and
+ std::to_string(expected) * clean-up overwrites which results in segfault or undefined behavior.
+ ", received " + std::to_string(actual) *
).ThrowAsJavaScriptException(); * An instance of this struct will get created during initialization and it
* will be available from the runtime. It can be retrieved via
* `napi_get_instance_data` or `Napi::Env::GetInstanceData`.
*/
typedef struct {
bool is_setup;
KZGSettings settings;
} KzgAddonData;
return env.Null(); /**
* This cleanup function follows the `napi_finalize` interface and will be
* called by the runtime when the exports object is garbage collected. Is
* passed with napi_set_instance_data call when data is set.
*
* @remark This function should not be called, only the runtime should do
* the cleanup.
*
* @param[in] env (unused)
* @param[in] data Pointer KzgAddonData stored by the runtime
* @param[in] hint (unused)
*/
void delete_kzg_addon_data(napi_env /*env*/, void *data, void* /*hint*/) {
if (((KzgAddonData*)data)->is_setup) {
free_trusted_setup(&((KzgAddonData*)data)->settings);
} }
free(data);
Napi::Value throw_invalid_argument_type(const Napi::Env env, std::string name, std::string expectedType) {
Napi::TypeError::New(
env,
"Invalid argument type: " + name + ". Expected " + expectedType
).ThrowAsJavaScriptException();
return env.Null();
} }
/** /**
* Get kzg_settings from a Napi::External * Get kzg_settings from bindings instance data
* *
* Checks for: * Checks for:
* - arg IsExternal * - loadTrustedSetup has been run
*
* Built to pass in a raw Napi::Value so it can be used like
* `get_kzg_settings(env, info[0])`.
* *
* Designed to raise the correct javascript exception and return a * Designed to raise the correct javascript exception and return a
* valid pointer to the calling context to avoid native stack-frame * valid pointer to the calling context to avoid native stack-frame
* unwinds. Calling context can check for `nullptr` to see if an * unwinds. Calling context can check for `nullptr` to see if an
* exception was raised or a valid pointer was returned from V8. * exception was raised or a valid KZGSettings was returned.
* *
* @param[in] env Passed from calling context * @param[in] env Passed from calling context
* @param[in] val Napi::Value to validate and get pointer from * @param[in] val Napi::Value to validate and get pointer from
* *
* @return - Pointer to the KZGSettings * @return - Pointer to the KZGSettings
*/ */
KZGSettings *get_kzg_settings(const Napi::Env &env, const Napi::Value &val) { KZGSettings *get_kzg_settings(Napi::Env &env, const Napi::CallbackInfo &info) {
if (!val.IsExternal()) { KzgAddonData *data = env.GetInstanceData<KzgAddonData>();
Napi::TypeError::New(env, "Must pass setupHandle as the last function argument").ThrowAsJavaScriptException(); if (!data->is_setup) {
Napi::Error::New(env, "Must run loadTrustedSetup before running any other c-kzg functions").ThrowAsJavaScriptException();
return nullptr; return nullptr;
} }
return val.As<Napi::External<KZGSettings>>().Data(); return &(data->settings);
} }
/** /**
@ -118,62 +130,25 @@ inline Bytes48 *get_bytes48(const Napi::Env &env, const Napi::Value &val, std::s
return reinterpret_cast<Bytes48 *>(get_bytes(env, val, BYTES_PER_COMMITMENT, name)); return reinterpret_cast<Bytes48 *>(get_bytes(env, val, BYTES_PER_COMMITMENT, name));
} }
// loadTrustedSetup: (filePath: string) => SetupHandle;
Napi::Value LoadTrustedSetup(const Napi::CallbackInfo& info) { Napi::Value LoadTrustedSetup(const Napi::CallbackInfo& info) {
auto env = info.Env(); Napi::Env env = info.Env();
KzgAddonData *data = env.GetInstanceData<KzgAddonData>();
size_t argument_count = info.Length(); if (data->is_setup) {
size_t expected_argument_count = 1; Napi::Error::New(env, "kzg bindings are already setup").ThrowAsJavaScriptException();
if (argument_count != expected_argument_count) { return env.Undefined();
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
} }
// the validation checks for this happen in JS
if (!info[0].IsString()) { const std::string file_path = info[0].As<Napi::String>().Utf8Value();
return throw_invalid_argument_type(env, "filePath", "string"); FILE *file_handle = fopen(file_path.c_str(), "r");
} if (file_handle == NULL) {
const std::string file_path = info[0].ToString().Utf8Value();
KZGSettings* kzg_settings = (KZGSettings*)malloc(sizeof(KZGSettings));
if (kzg_settings == NULL) {
Napi::Error::New(env, "Error while allocating memory for KZG settings").ThrowAsJavaScriptException();
return env.Null();
}
FILE* f = fopen(file_path.c_str(), "r");
if (f == NULL) {
free(kzg_settings);
Napi::Error::New(env, "Error opening trusted setup file: " + file_path).ThrowAsJavaScriptException(); Napi::Error::New(env, "Error opening trusted setup file: " + file_path).ThrowAsJavaScriptException();
return env.Null(); return env.Undefined();
} }
if (load_trusted_setup_file(&(data->settings), file_handle) != C_KZG_OK) {
if (load_trusted_setup_file(kzg_settings, f) != C_KZG_OK) { Napi::Error::New(env, "Error loading trusted setup file: " + file_path).ThrowAsJavaScriptException();
free(kzg_settings); return env.Undefined();
Napi::Error::New(env, "Error loading trusted setup file").ThrowAsJavaScriptException();
return env.Null();
} }
data->is_setup = true;
return Napi::External<KZGSettings>::New(info.Env(), kzg_settings);
}
// freeTrustedSetup: (setupHandle: SetupHandle) => void;
Napi::Value FreeTrustedSetup(const Napi::CallbackInfo& info) {
auto env = info.Env();
size_t argument_count = info.Length();
size_t expected_argument_count = 1;
if (argument_count != expected_argument_count) {
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
}
KZGSettings *kzg_settings = get_kzg_settings(env, info[0]);
if (kzg_settings == nullptr) {
return env.Null();
}
free_trusted_setup(kzg_settings);
free(kzg_settings);
return env.Undefined(); return env.Undefined();
} }
@ -188,16 +163,11 @@ Napi::Value FreeTrustedSetup(const Napi::CallbackInfo& info) {
*/ */
Napi::Value BlobToKzgCommitment(const Napi::CallbackInfo& info) { Napi::Value BlobToKzgCommitment(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env(); Napi::Env env = info.Env();
size_t argument_count = info.Length();
size_t expected_argument_count = 2;
if (argument_count != expected_argument_count) {
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
}
Blob *blob = get_blob(env, info[0]); Blob *blob = get_blob(env, info[0]);
if (blob == nullptr) { if (blob == nullptr) {
return env.Null(); return env.Null();
} }
KZGSettings *kzg_settings = get_kzg_settings(env, info[1]); KZGSettings *kzg_settings = get_kzg_settings(env, info);
if (kzg_settings == nullptr) { if (kzg_settings == nullptr) {
return env.Null(); return env.Null();
} }
@ -225,11 +195,6 @@ Napi::Value BlobToKzgCommitment(const Napi::CallbackInfo& info) {
*/ */
Napi::Value ComputeKzgProof(const Napi::CallbackInfo& info) { Napi::Value ComputeKzgProof(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env(); Napi::Env env = info.Env();
size_t argument_count = info.Length();
size_t expected_argument_count = 3;
if (argument_count != expected_argument_count) {
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
}
Blob *blob = get_blob(env, info[0]); Blob *blob = get_blob(env, info[0]);
if (blob == nullptr) { if (blob == nullptr) {
return env.Null(); return env.Null();
@ -238,7 +203,7 @@ Napi::Value ComputeKzgProof(const Napi::CallbackInfo& info) {
if (z_bytes == nullptr) { if (z_bytes == nullptr) {
return env.Null(); return env.Null();
} }
KZGSettings *kzg_settings = get_kzg_settings(env, info[2]); KZGSettings *kzg_settings = get_kzg_settings(env, info);
if (kzg_settings == nullptr) { if (kzg_settings == nullptr) {
return env.Null(); return env.Null();
} }
@ -273,16 +238,11 @@ Napi::Value ComputeKzgProof(const Napi::CallbackInfo& info) {
*/ */
Napi::Value ComputeBlobKzgProof(const Napi::CallbackInfo& info) { Napi::Value ComputeBlobKzgProof(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env(); Napi::Env env = info.Env();
size_t argument_count = info.Length();
size_t expected_argument_count = 2;
if (argument_count != expected_argument_count) {
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
}
Blob *blob = get_blob(env, info[0]); Blob *blob = get_blob(env, info[0]);
if (blob == nullptr) { if (blob == nullptr) {
return env.Null(); return env.Null();
} }
KZGSettings *kzg_settings = get_kzg_settings(env, info[1]); KZGSettings *kzg_settings = get_kzg_settings(env, info);
if (kzg_settings == nullptr) { if (kzg_settings == nullptr) {
return env.Null(); return env.Null();
} }
@ -317,11 +277,6 @@ Napi::Value ComputeBlobKzgProof(const Napi::CallbackInfo& info) {
*/ */
Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) { Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env(); Napi::Env env = info.Env();
size_t argument_count = info.Length();
size_t expected_argument_count = 5;
if (argument_count != expected_argument_count) {
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
}
Bytes48 *commitment_bytes = get_bytes48(env, info[0], "commitmentBytes"); Bytes48 *commitment_bytes = get_bytes48(env, info[0], "commitmentBytes");
if (commitment_bytes == nullptr) { if (commitment_bytes == nullptr) {
return env.Null(); return env.Null();
@ -338,7 +293,7 @@ Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) {
if (proof_bytes == nullptr) { if (proof_bytes == nullptr) {
return env.Null(); return env.Null();
} }
KZGSettings *kzg_settings = get_kzg_settings(env, info[4]); KZGSettings *kzg_settings = get_kzg_settings(env, info);
if (kzg_settings == nullptr) { if (kzg_settings == nullptr) {
return env.Null(); return env.Null();
} }
@ -375,11 +330,6 @@ Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) {
*/ */
Napi::Value VerifyBlobKzgProof(const Napi::CallbackInfo& info) { Napi::Value VerifyBlobKzgProof(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env(); Napi::Env env = info.Env();
size_t argument_count = info.Length();
size_t expected_argument_count = 4;
if (argument_count != expected_argument_count) {
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
}
Blob *blob_bytes = get_blob(env, info[0]); Blob *blob_bytes = get_blob(env, info[0]);
if (blob_bytes == nullptr) { if (blob_bytes == nullptr) {
return env.Null(); return env.Null();
@ -392,7 +342,7 @@ Napi::Value VerifyBlobKzgProof(const Napi::CallbackInfo& info) {
if (proof_bytes == nullptr) { if (proof_bytes == nullptr) {
return env.Null(); return env.Null();
} }
KZGSettings *kzg_settings = get_kzg_settings(env, info[3]); KZGSettings *kzg_settings = get_kzg_settings(env, info);
if (kzg_settings == nullptr) { if (kzg_settings == nullptr) {
return env.Null(); return env.Null();
} }
@ -429,11 +379,6 @@ Napi::Value VerifyBlobKzgProof(const Napi::CallbackInfo& info) {
*/ */
Napi::Value VerifyBlobKzgProofBatch(const Napi::CallbackInfo& info) { Napi::Value VerifyBlobKzgProofBatch(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env(); Napi::Env env = info.Env();
size_t argument_count = info.Length();
size_t expected_argument_count = 4;
if (argument_count != expected_argument_count) {
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
}
C_KZG_RET ret; C_KZG_RET ret;
Blob *blobs = NULL; Blob *blobs = NULL;
Bytes48 *commitments = NULL; Bytes48 *commitments = NULL;
@ -446,7 +391,7 @@ Napi::Value VerifyBlobKzgProofBatch(const Napi::CallbackInfo& info) {
Napi::Array blobs_param = info[0].As<Napi::Array>(); Napi::Array blobs_param = info[0].As<Napi::Array>();
Napi::Array commitments_param = info[1].As<Napi::Array>(); Napi::Array commitments_param = info[1].As<Napi::Array>();
Napi::Array proofs_param = info[2].As<Napi::Array>(); Napi::Array proofs_param = info[2].As<Napi::Array>();
KZGSettings *kzg_settings = get_kzg_settings(env, info[3]); KZGSettings *kzg_settings = get_kzg_settings(env, info);
if (kzg_settings == nullptr) { if (kzg_settings == nullptr) {
return env.Null(); return env.Null();
} }
@ -516,16 +461,28 @@ out:
return result; return result;
} }
Napi::Object Init(Napi::Env env, Napi::Object exports) { Napi::Object Init(Napi::Env env, Napi::Object exports) {
KzgAddonData* data = (KzgAddonData*)malloc(sizeof(KzgAddonData));
if (data == nullptr) {
Napi::Error::New(env, "error allocating memory for kzg setup handle").ThrowAsJavaScriptException();
return exports;
}
data->is_setup = false;
napi_status status = napi_set_instance_data(env, data, delete_kzg_addon_data, NULL);
if (status != napi_ok) {
Napi::Error::New(env, "error setting kzg bindings instance data").ThrowAsJavaScriptException();
return exports;
}
// Functions // Functions
exports["loadTrustedSetup"] = Napi::Function::New(env, LoadTrustedSetup); exports["loadTrustedSetup"] = Napi::Function::New(env, LoadTrustedSetup, "setup");
exports["freeTrustedSetup"] = Napi::Function::New(env, FreeTrustedSetup); exports["blobToKzgCommitment"] = Napi::Function::New(env, BlobToKzgCommitment, "blobToKzgCommitment");
exports["blobToKzgCommitment"] = Napi::Function::New(env, BlobToKzgCommitment); exports["computeKzgProof"] = Napi::Function::New(env, ComputeKzgProof, "computeKzgProof");
exports["computeKzgProof"] = Napi::Function::New(env, ComputeKzgProof); exports["computeBlobKzgProof"] = Napi::Function::New(env, ComputeBlobKzgProof, "computeBlobKzgProof");
exports["computeBlobKzgProof"] = Napi::Function::New(env, ComputeBlobKzgProof); exports["verifyKzgProof"] = Napi::Function::New(env, VerifyKzgProof, "verifyKzgProof");
exports["verifyKzgProof"] = Napi::Function::New(env, VerifyKzgProof); exports["verifyBlobKzgProof"] = Napi::Function::New(env, VerifyBlobKzgProof, "verifyBlobKzgProof");
exports["verifyBlobKzgProof"] = Napi::Function::New(env, VerifyBlobKzgProof); exports["verifyBlobKzgProofBatch"] = Napi::Function::New(env, VerifyBlobKzgProofBatch, "verifyBlobKzgProofBatch");
exports["verifyBlobKzgProofBatch"] = Napi::Function::New(env, VerifyBlobKzgProofBatch);
// Constants // Constants
exports["BYTES_PER_BLOB"] = Napi::Number::New(env, BYTES_PER_BLOB); exports["BYTES_PER_BLOB"] = Napi::Number::New(env, BYTES_PER_BLOB);
@ -533,7 +490,6 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports["BYTES_PER_FIELD_ELEMENT"] = Napi::Number::New(env, BYTES_PER_FIELD_ELEMENT); exports["BYTES_PER_FIELD_ELEMENT"] = Napi::Number::New(env, BYTES_PER_FIELD_ELEMENT);
exports["BYTES_PER_PROOF"] = Napi::Number::New(env, BYTES_PER_PROOF); exports["BYTES_PER_PROOF"] = Napi::Number::New(env, BYTES_PER_PROOF);
exports["FIELD_ELEMENTS_PER_BLOB"] = Napi::Number::New(env, FIELD_ELEMENTS_PER_BLOB); exports["FIELD_ELEMENTS_PER_BLOB"] = Napi::Number::New(env, FIELD_ELEMENTS_PER_BLOB);
return exports; return exports;
} }

View File

@ -3,67 +3,55 @@
* https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#kzg * https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#kzg
*/ */
const kzg: KZG = require("./kzg.node"); const kzg: KZG = require("./kzg.node");
const fs = require("fs"); import * as fs from "fs";
import * as path from "path";
export type Bytes32 = Uint8Array; // 32 bytes export type Bytes32 = Uint8Array; // 32 bytes
export type Bytes48 = Uint8Array; // 48 bytes export type Bytes48 = Uint8Array; // 48 bytes
export type KZGProof = Buffer; // 48 bytes export type KZGProof = Buffer; // 48 bytes
export type KZGCommitment = Buffer; // 48 bytes export type KZGCommitment = Buffer; // 48 bytes
export type Blob = Uint8Array; // 4096 * 32 bytes export type Blob = Uint8Array; // 4096 * 32 bytes
export interface TrustedSetupJson {
type SetupHandle = Object; setup_G1: string[];
setup_G2: string[];
setup_G1_lagrange: string[];
roots_of_unity: string[];
}
// The C++ native addon interface // The C++ native addon interface
type KZG = { interface KZG {
BYTES_PER_BLOB: number; BYTES_PER_BLOB: number;
BYTES_PER_COMMITMENT: number; BYTES_PER_COMMITMENT: number;
BYTES_PER_FIELD_ELEMENT: number; BYTES_PER_FIELD_ELEMENT: number;
BYTES_PER_PROOF: number; BYTES_PER_PROOF: number;
FIELD_ELEMENTS_PER_BLOB: number; FIELD_ELEMENTS_PER_BLOB: number;
loadTrustedSetup: (filePath: string) => SetupHandle; loadTrustedSetup: (filePath: string) => void;
freeTrustedSetup: (setupHandle: SetupHandle) => void; blobToKzgCommitment: (blob: Blob) => KZGCommitment;
blobToKzgCommitment: (blob: Blob, setupHandle: SetupHandle) => KZGCommitment; computeKzgProof: (blob: Blob, zBytes: Bytes32) => KZGProof;
computeKzgProof: ( computeBlobKzgProof: (blob: Blob) => KZGProof;
blob: Blob,
zBytes: Bytes32,
setupHandle: SetupHandle,
) => KZGProof;
computeBlobKzgProof: (blob: Blob, setupHandle: SetupHandle) => KZGProof;
verifyKzgProof: ( verifyKzgProof: (
commitmentBytes: Bytes48, commitmentBytes: Bytes48,
zBytes: Bytes32, zBytes: Bytes32,
yBytes: Bytes32, yBytes: Bytes32,
proofBytes: Bytes48, proofBytes: Bytes48,
setupHandle: SetupHandle,
) => boolean; ) => boolean;
verifyBlobKzgProof: ( verifyBlobKzgProof: (
blob: Blob, blob: Blob,
commitmentBytes: Bytes48, commitmentBytes: Bytes48,
proofBytes: Bytes48, proofBytes: Bytes48,
setupHandle: SetupHandle,
) => boolean; ) => boolean;
verifyBlobKzgProofBatch: ( verifyBlobKzgProofBatch: (
blobs: Blob[], blobs: Blob[],
commitmentsBytes: Bytes48[], commitmentsBytes: Bytes48[],
proofsBytes: Bytes48[], proofsBytes: Bytes48[],
setupHandle: SetupHandle,
) => boolean; ) => boolean;
}; }
type TrustedSetupJSON = {
setup_G1: string[];
setup_G2: string[];
setup_G1_lagrange: string[];
roots_of_unity: string[];
};
export const BYTES_PER_BLOB = kzg.BYTES_PER_BLOB; export const BYTES_PER_BLOB = kzg.BYTES_PER_BLOB;
export const BYTES_PER_COMMITMENT = kzg.BYTES_PER_COMMITMENT; export const BYTES_PER_COMMITMENT = kzg.BYTES_PER_COMMITMENT;
@ -71,55 +59,58 @@ export const BYTES_PER_FIELD_ELEMENT = kzg.BYTES_PER_FIELD_ELEMENT;
export const BYTES_PER_PROOF = kzg.BYTES_PER_PROOF; export const BYTES_PER_PROOF = kzg.BYTES_PER_PROOF;
export const FIELD_ELEMENTS_PER_BLOB = kzg.FIELD_ELEMENTS_PER_BLOB; export const FIELD_ELEMENTS_PER_BLOB = kzg.FIELD_ELEMENTS_PER_BLOB;
// Stored as internal state /**
let setupHandle: SetupHandle | undefined; * Converts JSON formatted trusted setup into the native format that
* the native library requires. Returns the absolute file path to the
function requireSetupHandle(): SetupHandle { * the formatted file. The path will be the same as the origin
if (!setupHandle) { * file but with a ".txt" extension.
throw new Error("You must call loadTrustedSetup to initialize KZG."); *
} * @param {string} filePath - The absolute path of JSON formatted trusted setup
return setupHandle; *
} * @return {string} - The absolute path of the re-formatted trusted setup
*
export async function transformTrustedSetupJSON( * @throws {Error} - For invalid file operations
filePath: string, */
): Promise<string> { function transformTrustedSetupJson(filePath: string): string {
const data: TrustedSetupJSON = JSON.parse(fs.readFileSync(filePath)); const data: TrustedSetupJson = JSON.parse(fs.readFileSync(filePath, "utf8"));
const textFilePath = filePath.replace(".json", ".txt");
const textFilePath = filePath.replace(".json", "") + ".txt"; const setupText =
kzg.FIELD_ELEMENTS_PER_BLOB +
try { "\n65\n" +
fs.unlinkSync(textFilePath); data.setup_G1.map((p) => p.substring(2)).join("\n") +
} catch {} "\n" +
data.setup_G2.map((p) => p.substring(2)).join("\n");
const file = fs.createWriteStream(textFilePath); fs.writeFileSync(textFilePath, setupText);
file.write(`${FIELD_ELEMENTS_PER_BLOB}\n65\n`);
file.write(data.setup_G1.map((p) => p.replace("0x", "")).join("\n"));
file.write("\n");
file.write(data.setup_G2.map((p) => p.replace("0x", "")).join("\n"));
file.end();
const p = new Promise((resolve) => {
file.close(resolve);
});
await p;
return textFilePath; 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 or {@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 { export function loadTrustedSetup(filePath: string): void {
if (setupHandle) { if (!(filePath && typeof filePath === "string")) {
throw new Error( throw new TypeError(
"Call freeTrustedSetup before loading a new trusted setup.", "must initialize kzg with the filePath to a txt/json trusted setup",
); );
} }
if (!fs.existsSync(filePath)) {
setupHandle = kzg.loadTrustedSetup(filePath); throw new Error(`no trusted setup found: ${filePath}`);
} }
if (path.parse(filePath).ext === ".json") {
export function freeTrustedSetup(): void { filePath = transformTrustedSetupJson(filePath);
kzg.freeTrustedSetup(requireSetupHandle()); }
setupHandle = undefined; return kzg.loadTrustedSetup(filePath);
} }
/** /**
@ -132,7 +123,7 @@ export function freeTrustedSetup(): void {
* @throws {TypeError} - For invalid arguments or failure of the native library * @throws {TypeError} - For invalid arguments or failure of the native library
*/ */
export function blobToKzgCommitment(blob: Blob): KZGCommitment { export function blobToKzgCommitment(blob: Blob): KZGCommitment {
return kzg.blobToKzgCommitment(blob, requireSetupHandle()); return kzg.blobToKzgCommitment(blob);
} }
/** /**
@ -146,7 +137,7 @@ export function blobToKzgCommitment(blob: Blob): KZGCommitment {
* @throws {TypeError} - For invalid arguments or failure of the native library * @throws {TypeError} - For invalid arguments or failure of the native library
*/ */
export function computeKzgProof(blob: Blob, zBytes: Bytes32): KZGProof { export function computeKzgProof(blob: Blob, zBytes: Bytes32): KZGProof {
return kzg.computeKzgProof(blob, zBytes, requireSetupHandle()); return kzg.computeKzgProof(blob, zBytes);
} }
/** /**
@ -160,7 +151,7 @@ export function computeKzgProof(blob: Blob, zBytes: Bytes32): KZGProof {
* @throws {TypeError} - For invalid arguments or failure of the native library * @throws {TypeError} - For invalid arguments or failure of the native library
*/ */
export function computeBlobKzgProof(blob: Blob): KZGProof { export function computeBlobKzgProof(blob: Blob): KZGProof {
return kzg.computeBlobKzgProof(blob, requireSetupHandle()); return kzg.computeBlobKzgProof(blob);
} }
/** /**
@ -181,13 +172,7 @@ export function verifyKzgProof(
yBytes: Bytes32, yBytes: Bytes32,
proofBytes: Bytes48, proofBytes: Bytes48,
): boolean { ): boolean {
return kzg.verifyKzgProof( return kzg.verifyKzgProof(commitmentBytes, zBytes, yBytes, proofBytes);
commitmentBytes,
zBytes,
yBytes,
proofBytes,
requireSetupHandle(),
);
} }
/** /**
@ -207,12 +192,7 @@ export function verifyBlobKzgProof(
commitmentBytes: Bytes48, commitmentBytes: Bytes48,
proofBytes: Bytes48, proofBytes: Bytes48,
): boolean { ): boolean {
return kzg.verifyBlobKzgProof( return kzg.verifyBlobKzgProof(blob, commitmentBytes, proofBytes);
blob,
commitmentBytes,
proofBytes,
requireSetupHandle(),
);
} }
/** /**
@ -234,10 +214,5 @@ export function verifyBlobKzgProofBatch(
commitmentsBytes: Bytes48[], commitmentsBytes: Bytes48[],
proofsBytes: Bytes48[], proofsBytes: Bytes48[],
): boolean { ): boolean {
return kzg.verifyBlobKzgProofBatch( return kzg.verifyBlobKzgProofBatch(blobs, commitmentsBytes, proofsBytes);
blobs,
commitmentsBytes,
proofsBytes,
requireSetupHandle(),
);
} }

View File

@ -7,7 +7,6 @@ const yaml = require("js-yaml");
import { import {
loadTrustedSetup, loadTrustedSetup,
freeTrustedSetup,
blobToKzgCommitment, blobToKzgCommitment,
computeKzgProof, computeKzgProof,
computeBlobKzgProof, computeBlobKzgProof,
@ -18,7 +17,6 @@ import {
BYTES_PER_COMMITMENT, BYTES_PER_COMMITMENT,
BYTES_PER_PROOF, BYTES_PER_PROOF,
BYTES_PER_FIELD_ELEMENT, BYTES_PER_FIELD_ELEMENT,
transformTrustedSetupJSON,
} from "./kzg"; } from "./kzg";
const setupFileName = "testing_trusted_setups.json"; const setupFileName = "testing_trusted_setups.json";
@ -79,12 +77,7 @@ function bytesFromHex(hexString: string): Buffer {
describe("C-KZG", () => { describe("C-KZG", () => {
beforeAll(async () => { beforeAll(async () => {
const file = await transformTrustedSetupJSON(SETUP_FILE_PATH); loadTrustedSetup(SETUP_FILE_PATH);
loadTrustedSetup(file);
});
afterAll(() => {
freeTrustedSetup();
}); });
describe("reference tests should pass", () => { describe("reference tests should pass", () => {