diff --git a/bindings/node.js/kzg.cxx b/bindings/node.js/kzg.cxx index 9e81079..487b0b2 100644 --- a/bindings/node.js/kzg.cxx +++ b/bindings/node.js/kzg.cxx @@ -59,6 +59,15 @@ Napi::TypedArrayOf napi_typed_array_from_bytes(uint8_t* array, size_t l return Napi::Uint8Array::New(env, length, buffer, 0); } +const uint8_t * extract_byte_array_from_param(const Napi::CallbackInfo& info, const int index, const std::string name) { + auto param = info[index].As(); + if (!param.IsTypedArray() || param.TypedArrayType() != napi_uint8_array) { + throw_invalid_argument_type(info.Env(), name, "UInt8Array"); + } + return param.As().Data(); +} + + // loadTrustedSetup: (filePath: string) => SetupHandle; Napi::Value LoadTrustedSetup(const Napi::CallbackInfo& info) { auto env = info.Env(); @@ -125,11 +134,10 @@ Napi::Value BlobToKzgCommitment(const Napi::CallbackInfo& info) { return throw_invalid_arguments_count(expected_argument_count, argument_count, env); } - auto blob_param = info[0].As(); - if (!blob_param.IsTypedArray() || blob_param.TypedArrayType() != napi_uint8_array) { - return throw_invalid_argument_type(env, "blob", "UInt8Array"); + auto blob = extract_byte_array_from_param(info, 0, "blob"); + if (env.IsExceptionPending()) { + return env.Null(); } - auto blob = blob_param.As().Data(); auto kzg_settings = info[1].As>().Data(); @@ -280,32 +288,16 @@ Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) { return throw_invalid_arguments_count(expected_argument_count, argument_count, env); } - auto c_param = info[0].As(); - if (c_param.TypedArrayType() != napi_uint8_array) { - return throw_invalid_argument_type(env, "polynomialKzg", "UInt8Array"); - } - auto polynomial_kzg = c_param.As().Data(); - - auto z_param = info[1].As(); - if (z_param.TypedArrayType() != napi_uint8_array) { - return throw_invalid_argument_type(env, "z", "UInt8Array"); - } - auto z = z_param.As().Data(); - - auto y_param = info[2].As(); - if (y_param.TypedArrayType() != napi_uint8_array) { - return throw_invalid_argument_type(env, "y", "UInt8Array"); - } - auto y = y_param.As().Data(); - - auto proof_param = info[3].As(); - if (proof_param.TypedArrayType() != napi_uint8_array) { - return throw_invalid_argument_type(env, "kzgProof", "UInt8Array"); - } - auto kzg_proof = proof_param.As().Data(); - + auto polynomial_kzg = extract_byte_array_from_param(info, 0, "polynomialKzg"); + auto z = extract_byte_array_from_param(info, 1, "z"); + auto y = extract_byte_array_from_param(info, 2, "y"); + auto kzg_proof = extract_byte_array_from_param(info, 3, "kzgProof"); auto kzg_settings = info[4].As>().Data(); + if (env.IsExceptionPending()) { + return env.Null(); + } + KZGCommitment commitment; auto ret = bytes_to_g1(&commitment, polynomial_kzg); if (ret != C_KZG_OK) { diff --git a/bindings/node.js/kzg.ts b/bindings/node.js/kzg.ts index 334ab9a..257852d 100644 --- a/bindings/node.js/kzg.ts +++ b/bindings/node.js/kzg.ts @@ -35,7 +35,6 @@ type KZG = { setupHandle: SetupHandle, ) => boolean; - // Currently unused -- not exported verifyKzgProof: ( polynomialKzg: KZGCommitment, z: BLSFieldElement, @@ -113,6 +112,21 @@ export function computeAggregateKzgProof(blobs: Blob[]): KZGProof { return kzg.computeAggregateKzgProof(blobs, requireSetupHandle()); } +export function verifyKzgProof( + polynomialKzg: KZGCommitment, + z: BLSFieldElement, + y: BLSFieldElement, + kzgProof: KZGProof, +): boolean { + return kzg.verifyKzgProof( + polynomialKzg, + z, + y, + kzgProof, + requireSetupHandle(), + ); +} + export function verifyAggregateKzgProof( blobs: Blob[], expectedKzgCommitments: KZGCommitment[], diff --git a/bindings/node.js/package.json b/bindings/node.js/package.json index 5dfd4ea..db0f3e3 100644 --- a/bindings/node.js/package.json +++ b/bindings/node.js/package.json @@ -1,6 +1,6 @@ { "name": "c-kzg", - "version": "1.0.7", + "version": "1.0.8", "description": "NodeJS bindings for C-KZG", "author": "Dan Coffman", "license": "MIT", diff --git a/bindings/node.js/test.ts b/bindings/node.js/test.ts index b60f302..e29be4e 100644 --- a/bindings/node.js/test.ts +++ b/bindings/node.js/test.ts @@ -5,6 +5,7 @@ import { loadTrustedSetup, freeTrustedSetup, blobToKzgCommitment, + verifyKzgProof, computeAggregateKzgProof, verifyAggregateKzgProof, BYTES_PER_FIELD_ELEMENT, @@ -68,6 +69,28 @@ describe("C-KZG", () => { ); }); + it("verifies a valid KZG proof", () => { + const commitment = new Uint8Array(48).fill(0); + commitment[0] = 0xc0; + const z = new Uint8Array(32).fill(0); + const y = new Uint8Array(32).fill(0); + const proof = new Uint8Array(48).fill(0); + proof[0] = 0xc0; + + expect(verifyKzgProof(commitment, z, y, proof)).toBe(true); + }); + + it("verifies an invalid valid KZG proof", () => { + const commitment = new Uint8Array(48).fill(0); + commitment[0] = 0xc0; + const z = new Uint8Array(32).fill(1); + const y = new Uint8Array(32).fill(1); + const proof = new Uint8Array(48).fill(0); + proof[0] = 0xc0; + + expect(verifyKzgProof(commitment, z, y, proof)).toBe(false); + }); + it("computes the aggregate proof when for a single blob", () => { let blobs = new Array(1).fill(0).map(generateRandomBlob); let commitments = blobs.map(blobToKzgCommitment);