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:
parent
599ae2fe21
commit
87a3e4148d
|
@ -9,55 +9,67 @@
|
|||
#include "c_kzg_4844.h"
|
||||
#include "blst.h"
|
||||
|
||||
Napi::Value throw_invalid_arguments_count(
|
||||
const unsigned int expected,
|
||||
const unsigned int actual,
|
||||
const Napi::Env env
|
||||
) {
|
||||
Napi::RangeError::New(
|
||||
env,
|
||||
"Wrong number of arguments. Expected: "
|
||||
+ std::to_string(expected)
|
||||
+ ", received " + std::to_string(actual)
|
||||
).ThrowAsJavaScriptException();
|
||||
/**
|
||||
* Structure containing information needed for the lifetime of the bindings
|
||||
* instance. It is not safe to use global static data with worker instances.
|
||||
* 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
|
||||
* instance of the bindings and workers share memory space. In addition
|
||||
* the worker JS thread will be independent of the main JS thread. Global
|
||||
* statics are not thread safe and have the potential for initialization and
|
||||
* clean-up overwrites which results in segfault or undefined behavior.
|
||||
*
|
||||
* 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();
|
||||
}
|
||||
|
||||
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();
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get kzg_settings from a Napi::External
|
||||
* Get kzg_settings from bindings instance data
|
||||
*
|
||||
* Checks for:
|
||||
* - arg IsExternal
|
||||
*
|
||||
* Built to pass in a raw Napi::Value so it can be used like
|
||||
* `get_kzg_settings(env, info[0])`.
|
||||
* - loadTrustedSetup has been run
|
||||
*
|
||||
* Designed to raise the correct javascript exception and return a
|
||||
* valid pointer to the calling context to avoid native stack-frame
|
||||
* 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] val Napi::Value to validate and get pointer from
|
||||
*
|
||||
* @return - Pointer to the KZGSettings
|
||||
*/
|
||||
KZGSettings *get_kzg_settings(const Napi::Env &env, const Napi::Value &val) {
|
||||
if (!val.IsExternal()) {
|
||||
Napi::TypeError::New(env, "Must pass setupHandle as the last function argument").ThrowAsJavaScriptException();
|
||||
return nullptr;
|
||||
KZGSettings *get_kzg_settings(Napi::Env &env, const Napi::CallbackInfo &info) {
|
||||
KzgAddonData *data = env.GetInstanceData<KzgAddonData>();
|
||||
if (!data->is_setup) {
|
||||
Napi::Error::New(env, "Must run loadTrustedSetup before running any other c-kzg functions").ThrowAsJavaScriptException();
|
||||
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));
|
||||
}
|
||||
|
||||
// loadTrustedSetup: (filePath: string) => SetupHandle;
|
||||
Napi::Value LoadTrustedSetup(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);
|
||||
Napi::Env env = info.Env();
|
||||
KzgAddonData *data = env.GetInstanceData<KzgAddonData>();
|
||||
if (data->is_setup) {
|
||||
Napi::Error::New(env, "kzg bindings are already setup").ThrowAsJavaScriptException();
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
if (!info[0].IsString()) {
|
||||
return throw_invalid_argument_type(env, "filePath", "string");
|
||||
// the validation checks for this happen in JS
|
||||
const std::string file_path = info[0].As<Napi::String>().Utf8Value();
|
||||
FILE *file_handle = fopen(file_path.c_str(), "r");
|
||||
if (file_handle == NULL) {
|
||||
Napi::Error::New(env, "Error opening trusted setup file: " + file_path).ThrowAsJavaScriptException();
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
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();
|
||||
if (load_trusted_setup_file(&(data->settings), file_handle) != C_KZG_OK) {
|
||||
Napi::Error::New(env, "Error loading trusted setup file: " + file_path).ThrowAsJavaScriptException();
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
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();
|
||||
return env.Null();
|
||||
}
|
||||
|
||||
if (load_trusted_setup_file(kzg_settings, f) != C_KZG_OK) {
|
||||
free(kzg_settings);
|
||||
Napi::Error::New(env, "Error loading trusted setup file").ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
|
||||
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);
|
||||
data->is_setup = true;
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
|
@ -188,16 +163,11 @@ Napi::Value FreeTrustedSetup(const Napi::CallbackInfo& info) {
|
|||
*/
|
||||
Napi::Value BlobToKzgCommitment(const Napi::CallbackInfo& info) {
|
||||
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]);
|
||||
if (blob == nullptr) {
|
||||
return env.Null();
|
||||
}
|
||||
KZGSettings *kzg_settings = get_kzg_settings(env, info[1]);
|
||||
KZGSettings *kzg_settings = get_kzg_settings(env, info);
|
||||
if (kzg_settings == nullptr) {
|
||||
return env.Null();
|
||||
}
|
||||
|
@ -225,11 +195,6 @@ Napi::Value BlobToKzgCommitment(const Napi::CallbackInfo& info) {
|
|||
*/
|
||||
Napi::Value ComputeKzgProof(const Napi::CallbackInfo& info) {
|
||||
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]);
|
||||
if (blob == nullptr) {
|
||||
return env.Null();
|
||||
|
@ -238,7 +203,7 @@ Napi::Value ComputeKzgProof(const Napi::CallbackInfo& info) {
|
|||
if (z_bytes == nullptr) {
|
||||
return env.Null();
|
||||
}
|
||||
KZGSettings *kzg_settings = get_kzg_settings(env, info[2]);
|
||||
KZGSettings *kzg_settings = get_kzg_settings(env, info);
|
||||
if (kzg_settings == nullptr) {
|
||||
return env.Null();
|
||||
}
|
||||
|
@ -273,16 +238,11 @@ Napi::Value ComputeKzgProof(const Napi::CallbackInfo& info) {
|
|||
*/
|
||||
Napi::Value ComputeBlobKzgProof(const Napi::CallbackInfo& info) {
|
||||
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]);
|
||||
if (blob == nullptr) {
|
||||
return env.Null();
|
||||
}
|
||||
KZGSettings *kzg_settings = get_kzg_settings(env, info[1]);
|
||||
KZGSettings *kzg_settings = get_kzg_settings(env, info);
|
||||
if (kzg_settings == nullptr) {
|
||||
return env.Null();
|
||||
}
|
||||
|
@ -317,11 +277,6 @@ Napi::Value ComputeBlobKzgProof(const Napi::CallbackInfo& info) {
|
|||
*/
|
||||
Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) {
|
||||
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");
|
||||
if (commitment_bytes == nullptr) {
|
||||
return env.Null();
|
||||
|
@ -338,7 +293,7 @@ Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) {
|
|||
if (proof_bytes == nullptr) {
|
||||
return env.Null();
|
||||
}
|
||||
KZGSettings *kzg_settings = get_kzg_settings(env, info[4]);
|
||||
KZGSettings *kzg_settings = get_kzg_settings(env, info);
|
||||
if (kzg_settings == nullptr) {
|
||||
return env.Null();
|
||||
}
|
||||
|
@ -375,11 +330,6 @@ Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) {
|
|||
*/
|
||||
Napi::Value VerifyBlobKzgProof(const Napi::CallbackInfo& info) {
|
||||
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]);
|
||||
if (blob_bytes == nullptr) {
|
||||
return env.Null();
|
||||
|
@ -392,7 +342,7 @@ Napi::Value VerifyBlobKzgProof(const Napi::CallbackInfo& info) {
|
|||
if (proof_bytes == nullptr) {
|
||||
return env.Null();
|
||||
}
|
||||
KZGSettings *kzg_settings = get_kzg_settings(env, info[3]);
|
||||
KZGSettings *kzg_settings = get_kzg_settings(env, info);
|
||||
if (kzg_settings == nullptr) {
|
||||
return env.Null();
|
||||
}
|
||||
|
@ -429,11 +379,6 @@ Napi::Value VerifyBlobKzgProof(const Napi::CallbackInfo& info) {
|
|||
*/
|
||||
Napi::Value VerifyBlobKzgProofBatch(const Napi::CallbackInfo& info) {
|
||||
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;
|
||||
Blob *blobs = 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 commitments_param = info[1].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) {
|
||||
return env.Null();
|
||||
}
|
||||
|
@ -516,16 +461,28 @@ out:
|
|||
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
|
||||
exports["loadTrustedSetup"] = Napi::Function::New(env, LoadTrustedSetup);
|
||||
exports["freeTrustedSetup"] = Napi::Function::New(env, FreeTrustedSetup);
|
||||
exports["blobToKzgCommitment"] = Napi::Function::New(env, BlobToKzgCommitment);
|
||||
exports["computeKzgProof"] = Napi::Function::New(env, ComputeKzgProof);
|
||||
exports["computeBlobKzgProof"] = Napi::Function::New(env, ComputeBlobKzgProof);
|
||||
exports["verifyKzgProof"] = Napi::Function::New(env, VerifyKzgProof);
|
||||
exports["verifyBlobKzgProof"] = Napi::Function::New(env, VerifyBlobKzgProof);
|
||||
exports["verifyBlobKzgProofBatch"] = Napi::Function::New(env, VerifyBlobKzgProofBatch);
|
||||
exports["loadTrustedSetup"] = Napi::Function::New(env, LoadTrustedSetup, "setup");
|
||||
exports["blobToKzgCommitment"] = Napi::Function::New(env, BlobToKzgCommitment, "blobToKzgCommitment");
|
||||
exports["computeKzgProof"] = Napi::Function::New(env, ComputeKzgProof, "computeKzgProof");
|
||||
exports["computeBlobKzgProof"] = Napi::Function::New(env, ComputeBlobKzgProof, "computeBlobKzgProof");
|
||||
exports["verifyKzgProof"] = Napi::Function::New(env, VerifyKzgProof, "verifyKzgProof");
|
||||
exports["verifyBlobKzgProof"] = Napi::Function::New(env, VerifyBlobKzgProof, "verifyBlobKzgProof");
|
||||
exports["verifyBlobKzgProofBatch"] = Napi::Function::New(env, VerifyBlobKzgProofBatch, "verifyBlobKzgProofBatch");
|
||||
|
||||
// Constants
|
||||
exports["BYTES_PER_BLOB"] = Napi::Number::New(env, BYTES_PER_BLOB);
|
||||
|
@ -533,8 +490,7 @@ 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_PROOF"] = Napi::Number::New(env, BYTES_PER_PROOF);
|
||||
exports["FIELD_ELEMENTS_PER_BLOB"] = Napi::Number::New(env, FIELD_ELEMENTS_PER_BLOB);
|
||||
|
||||
return exports;
|
||||
}
|
||||
|
||||
NODE_API_MODULE(addon, Init)
|
||||
NODE_API_MODULE(addon, Init)
|
|
@ -3,67 +3,55 @@
|
|||
* https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#kzg
|
||||
*/
|
||||
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 Bytes48 = Uint8Array; // 48 bytes
|
||||
export type KZGProof = Buffer; // 48 bytes
|
||||
export type KZGCommitment = Buffer; // 48 bytes
|
||||
export type Blob = Uint8Array; // 4096 * 32 bytes
|
||||
|
||||
type SetupHandle = Object;
|
||||
|
||||
export interface TrustedSetupJson {
|
||||
setup_G1: string[];
|
||||
setup_G2: string[];
|
||||
setup_G1_lagrange: string[];
|
||||
roots_of_unity: string[];
|
||||
}
|
||||
// The C++ native addon interface
|
||||
type KZG = {
|
||||
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) => 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: (
|
||||
blob: Blob,
|
||||
zBytes: Bytes32,
|
||||
setupHandle: SetupHandle,
|
||||
) => KZGProof;
|
||||
|
||||
computeBlobKzgProof: (blob: Blob, setupHandle: SetupHandle) => KZGProof;
|
||||
computeBlobKzgProof: (blob: Blob) => KZGProof;
|
||||
|
||||
verifyKzgProof: (
|
||||
commitmentBytes: Bytes48,
|
||||
zBytes: Bytes32,
|
||||
yBytes: Bytes32,
|
||||
proofBytes: Bytes48,
|
||||
setupHandle: SetupHandle,
|
||||
) => boolean;
|
||||
|
||||
verifyBlobKzgProof: (
|
||||
blob: Blob,
|
||||
commitmentBytes: Bytes48,
|
||||
proofBytes: Bytes48,
|
||||
setupHandle: SetupHandle,
|
||||
) => boolean;
|
||||
|
||||
verifyBlobKzgProofBatch: (
|
||||
blobs: Blob[],
|
||||
commitmentsBytes: Bytes48[],
|
||||
proofsBytes: Bytes48[],
|
||||
setupHandle: SetupHandle,
|
||||
) => 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_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 FIELD_ELEMENTS_PER_BLOB = kzg.FIELD_ELEMENTS_PER_BLOB;
|
||||
|
||||
// Stored as internal state
|
||||
let setupHandle: SetupHandle | undefined;
|
||||
|
||||
function requireSetupHandle(): SetupHandle {
|
||||
if (!setupHandle) {
|
||||
throw new Error("You must call loadTrustedSetup to initialize KZG.");
|
||||
}
|
||||
return setupHandle;
|
||||
}
|
||||
|
||||
export async function transformTrustedSetupJSON(
|
||||
filePath: string,
|
||||
): Promise<string> {
|
||||
const data: TrustedSetupJSON = JSON.parse(fs.readFileSync(filePath));
|
||||
|
||||
const textFilePath = filePath.replace(".json", "") + ".txt";
|
||||
|
||||
try {
|
||||
fs.unlinkSync(textFilePath);
|
||||
} catch {}
|
||||
|
||||
const file = fs.createWriteStream(textFilePath);
|
||||
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;
|
||||
/**
|
||||
* 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 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 {
|
||||
if (setupHandle) {
|
||||
throw new Error(
|
||||
"Call freeTrustedSetup before loading a new trusted setup.",
|
||||
if (!(filePath && typeof filePath === "string")) {
|
||||
throw new TypeError(
|
||||
"must initialize kzg with the filePath to a txt/json trusted setup",
|
||||
);
|
||||
}
|
||||
|
||||
setupHandle = kzg.loadTrustedSetup(filePath);
|
||||
}
|
||||
|
||||
export function freeTrustedSetup(): void {
|
||||
kzg.freeTrustedSetup(requireSetupHandle());
|
||||
setupHandle = undefined;
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,7 +123,7 @@ export function freeTrustedSetup(): void {
|
|||
* @throws {TypeError} - For invalid arguments or failure of the native library
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
export function computeBlobKzgProof(blob: Blob): KZGProof {
|
||||
return kzg.computeBlobKzgProof(blob, requireSetupHandle());
|
||||
return kzg.computeBlobKzgProof(blob);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,13 +172,7 @@ export function verifyKzgProof(
|
|||
yBytes: Bytes32,
|
||||
proofBytes: Bytes48,
|
||||
): boolean {
|
||||
return kzg.verifyKzgProof(
|
||||
commitmentBytes,
|
||||
zBytes,
|
||||
yBytes,
|
||||
proofBytes,
|
||||
requireSetupHandle(),
|
||||
);
|
||||
return kzg.verifyKzgProof(commitmentBytes, zBytes, yBytes, proofBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,12 +192,7 @@ export function verifyBlobKzgProof(
|
|||
commitmentBytes: Bytes48,
|
||||
proofBytes: Bytes48,
|
||||
): boolean {
|
||||
return kzg.verifyBlobKzgProof(
|
||||
blob,
|
||||
commitmentBytes,
|
||||
proofBytes,
|
||||
requireSetupHandle(),
|
||||
);
|
||||
return kzg.verifyBlobKzgProof(blob, commitmentBytes, proofBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -234,10 +214,5 @@ export function verifyBlobKzgProofBatch(
|
|||
commitmentsBytes: Bytes48[],
|
||||
proofsBytes: Bytes48[],
|
||||
): boolean {
|
||||
return kzg.verifyBlobKzgProofBatch(
|
||||
blobs,
|
||||
commitmentsBytes,
|
||||
proofsBytes,
|
||||
requireSetupHandle(),
|
||||
);
|
||||
return kzg.verifyBlobKzgProofBatch(blobs, commitmentsBytes, proofsBytes);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ const yaml = require("js-yaml");
|
|||
|
||||
import {
|
||||
loadTrustedSetup,
|
||||
freeTrustedSetup,
|
||||
blobToKzgCommitment,
|
||||
computeKzgProof,
|
||||
computeBlobKzgProof,
|
||||
|
@ -18,7 +17,6 @@ import {
|
|||
BYTES_PER_COMMITMENT,
|
||||
BYTES_PER_PROOF,
|
||||
BYTES_PER_FIELD_ELEMENT,
|
||||
transformTrustedSetupJSON,
|
||||
} from "./kzg";
|
||||
|
||||
const setupFileName = "testing_trusted_setups.json";
|
||||
|
@ -79,12 +77,7 @@ function bytesFromHex(hexString: string): Buffer {
|
|||
|
||||
describe("C-KZG", () => {
|
||||
beforeAll(async () => {
|
||||
const file = await transformTrustedSetupJSON(SETUP_FILE_PATH);
|
||||
loadTrustedSetup(file);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
freeTrustedSetup();
|
||||
loadTrustedSetup(SETUP_FILE_PATH);
|
||||
});
|
||||
|
||||
describe("reference tests should pass", () => {
|
||||
|
|
Loading…
Reference in New Issue