From da8d5dde4221cbb96f21f8c2346e245c556bf81d Mon Sep 17 00:00:00 2001 From: dancoffman Date: Wed, 2 Nov 2022 15:50:04 -0700 Subject: [PATCH] Try to test VerifyKzgProof (does not work) --- bindings/node.js/Makefile | 3 -- bindings/node.js/kzg.cxx | 64 ++++++++++++++++++++++++++++++++++- bindings/node.js/kzg.ts | 49 ++++++++++++++++++++++++++- bindings/node.js/package.json | 3 +- bindings/node.js/runnable.js | 25 -------------- bindings/node.js/test.ts | 62 +++++++++++++++++++++++++++++---- 6 files changed, 169 insertions(+), 37 deletions(-) delete mode 100644 bindings/node.js/runnable.js diff --git a/bindings/node.js/Makefile b/bindings/node.js/Makefile index 0291875..db0b0f1 100644 --- a/bindings/node.js/Makefile +++ b/bindings/node.js/Makefile @@ -7,6 +7,3 @@ build: kzg.cxx Makefile cd ../../src; make lib yarn build cp build/Release/kzg.node . - -test: - env NODE_PATH=.: node runnable.js diff --git a/bindings/node.js/kzg.cxx b/bindings/node.js/kzg.cxx index cefda60..10728af 100644 --- a/bindings/node.js/kzg.cxx +++ b/bindings/node.js/kzg.cxx @@ -6,6 +6,10 @@ #include "c_kzg_4844.h" #include "blst.h" +#include // std::ostringstream +#include // std::copy +#include // std::ostream_iterator + void blobToKzgCommitment(uint8_t out[48], const uint8_t blob[FIELD_ELEMENTS_PER_BLOB * 32], const KZGSettings *s) { Polynomial p; @@ -83,6 +87,7 @@ int verifyKzgProof(const uint8_t c[48], const uint8_t x[32], const uint8_t y[32] Napi::Value LoadTrustedSetup(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); + if (info.Length() != 1) { Napi::TypeError::New(env, "Wrong number of arguments") .ThrowAsJavaScriptException(); @@ -117,9 +122,11 @@ Napi::Value LoadTrustedSetup(const Napi::CallbackInfo& info) { return env.Null(); } + // Consider making this internal state intead return Napi::External::New(info.Env(), kzgSettings); } +// Maybe this can be done with a finalizer on the thing returned by LoadTrustedSetup, and then the JS garbage collector can just sort it out. void FreeTrustedSetup(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); KZGSettings* kzgSettings = info[0].As>().Data(); @@ -130,23 +137,78 @@ void FreeTrustedSetup(const Napi::CallbackInfo& info) { Napi::Value BlobToKzgCommitment(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); } + Napi::Value VerifyAggregateKzgProof(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); } + Napi::Value ComputeAggregateKzgProof(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); } + Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); + + if (info.Length() != 5) { + Napi::TypeError::New(env, "Wrong number of arguments") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + // const uint8_t c[48] + uint8_t* c = reinterpret_cast(info[0].As().Data()); + + // const uint8_t x[32] + uint8_t* x = reinterpret_cast(info[1].As().Data()); + + // const uint8_t y[32] + uint8_t* y = reinterpret_cast(info[2].As().Data()); + + // const uint8_t p[48] + uint8_t* p = reinterpret_cast(info[3].As().Data()); + + // KZGSettings *s + KZGSettings* kzgSettings = info[4].As>().Data(); + + KZGCommitment commitment; + KZGProof proof; + BLSFieldElement fx, fy; + bool out; + + bytes_to_bls_field(&fx, x); + bytes_to_bls_field(&fy, y); + + C_KZG_RET ret = bytes_to_g1(&commitment, c); + if (ret != C_KZG_OK) { + std::ostringstream ss; + std::copy(c, c+sizeof(c), std::ostream_iterator(ss, ",")); + + Napi::TypeError::New(env, "Failed to parse argument commitment: " + ss.str() + " Return code was: " + std::to_string(ret)).ThrowAsJavaScriptException(); + return env.Null(); + // return -1; + }; + if (bytes_to_g1(&proof, p) != C_KZG_OK) { + Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); + return env.Null(); + // return -1; + } + + if (verify_kzg_proof(&out, &commitment, &fx, &fy, &proof, kzgSettings) != C_KZG_OK) { + return env.Null(); + } + + return env.Null(); } Napi::Object Init(Napi::Env env, Napi::Object exports) { exports.Set(Napi::String::New(env, "loadTrustedSetup"), Napi::Function::New(env, LoadTrustedSetup)); exports.Set(Napi::String::New(env, "freeTrustedSetup"), Napi::Function::New(env, FreeTrustedSetup)); + exports.Set(Napi::String::New(env, "verifyKzgProof"), Napi::Function::New(env, VerifyKzgProof)); + + exports.Set(Napi::String::New(env, "blobToKzgCommitment"), Napi::Function::New(env, BlobToKzgCommitment)); exports.Set(Napi::String::New(env, "verifyAggregateKzgProof"), Napi::Function::New(env, VerifyAggregateKzgProof)); exports.Set(Napi::String::New(env, "computeAggregateKzgProof"), Napi::Function::New(env, ComputeAggregateKzgProof)); - exports.Set(Napi::String::New(env, "verifyKzgProof"), Napi::Function::New(env, VerifyKzgProof)); return exports; } diff --git a/bindings/node.js/kzg.ts b/bindings/node.js/kzg.ts index 6a4c70e..b62a9d2 100644 --- a/bindings/node.js/kzg.ts +++ b/bindings/node.js/kzg.ts @@ -1,6 +1,53 @@ // @ts-expect-error import bindings from 'bindings'; -const kzg = bindings('kzg.node'); +// Consider making this internal state of the native code +// so we don't have to pass it around in the application layer +export type SetupHandle = Object; + +export enum ReturnValue { + /** Success! */ + OK = 0, + /** The supplied data is invalid in some way */ + BADARGS, + /** Internal error - this should never occur and may indicate a bug in the library */ + ERROR, + /** Could not allocate memory */ + MALLOC, +} + +export type Point = Uint8Array; +export type KZGProof = Uint8Array; +export type KZGCommitment = Uint8Array; +export type Blob = Uint8Array[]; +export type Blobs = Blob[]; + +type KZG = { + loadTrustedSetup: (path: string) => SetupHandle; + freeTrustedSetup: (setupHandle: SetupHandle) => void; + blobToKzgCommitment: (blob: Blob) => KZGCommitment; + verifyAggregateKzgProof: (blobs: Blobs) => ReturnValue; + computeAggregateKzgProof: ( + blobs: Blobs, + size: number, + setupHandle: SetupHandle, + ) => KZGProof; + verifyKzgProof: ( + commitment: KZGCommitment, + x: Point, + y: Point, + proof: KZGProof, + setupHandle: SetupHandle, + ) => ReturnValue; +}; + +const kzg: KZG = bindings('kzg.node'); + +export const loadTrustedSetup = kzg.loadTrustedSetup; +export const freeTrustedSetup = kzg.freeTrustedSetup; +export const blobToKzgCommitment = kzg.blobToKzgCommitment; +export const verifyAggregateKzgProof = kzg.verifyAggregateKzgProof; +export const computeAggregateKzgProof = kzg.computeAggregateKzgProof; +export const verifyKzgProof = kzg.verifyKzgProof; export default kzg; diff --git a/bindings/node.js/package.json b/bindings/node.js/package.json index 16046e2..0938f44 100644 --- a/bindings/node.js/package.json +++ b/bindings/node.js/package.json @@ -3,7 +3,8 @@ "version": "0.0.1", "description": "", "author": "Dan Coffman", - "main": "runnable.js", + "license": "MIT", + "main": "test.ts", "gypfile": true, "scripts": { "clean": "node-gyp clean", diff --git a/bindings/node.js/runnable.js b/bindings/node.js/runnable.js deleted file mode 100644 index 83caa63..0000000 --- a/bindings/node.js/runnable.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -var bindings = require('bindings'); -console.log('Bindings', bindings); - -const kzg = bindings('kzg.node'); -console.log('Loaded KZG library with functions:'); -console.log(kzg); - -// console.log('Sanity checking C interop by calling no-op function...'); -// console.log('PASS', kzg.testFunction()); - -// KZGSettings* loadTrustSetup(const char* file); -console.log('Invoking load_trusted_setup...'); -const kzgSettingsHandle = kzg.loadTrustedSetup('../../src/trusted_setup.txt'); -console.log('PASS'); -console.log( - 'load_trusted_setup yielded KZGSettings with handle: ', - kzgSettingsHandle, -); - -// void freeTrustedSetup(KZGSettings *s); -console.log('Invoking free_trusted_setup...'); -const freeResult = kzg.freeTrustedSetup(kzgSettingsHandle); -console.log('PASS', freeResult); diff --git a/bindings/node.js/test.ts b/bindings/node.js/test.ts index e34a5bb..dccaa9e 100644 --- a/bindings/node.js/test.ts +++ b/bindings/node.js/test.ts @@ -1,13 +1,63 @@ -import kzg from './kzg'; +import { + loadTrustedSetup, + freeTrustedSetup, + verifyKzgProof, + ReturnValue, + SetupHandle, +} from './kzg'; describe('C-KZG', () => { - describe('Trusted setup', () => { + let setupHandle: SetupHandle; + + beforeAll(() => { + setupHandle = loadTrustedSetup('../../src/trusted_setup.txt'); + }); + + describe('setup', () => { it('can both load and free', () => { - const kzgSettingsHandle = kzg.loadTrustedSetup( - '../../src/trusted_setup.txt', + expect(freeTrustedSetup(setupHandle)).toBeUndefined(); + }); + }); + + describe('computing a KZG commitment from a blob', () => { + it('returns the expected value', () => { + expect(true).toBe(ReturnValue.OK); + }); + }); + + describe('verifying a KZG proof', () => { + it.only('returns the expected value', () => { + const byteEncoder = new TextEncoder(); + + const commitment = byteEncoder.encode( + 'b91c022acf7bd3b63be69a4c19b781ea7a3d5df1cd66ceb7dd0f399610f0ee04695dace82e04bfb83af2b17d7319f87f', ); - kzg.freeTrustedSetup(kzgSettingsHandle); - expect(kzgSettingsHandle).toBeDefined(); + console.log({ commitment }); + const x = byteEncoder.encode( + '0345f802a75a6c0d9cc5b8a1e71642b8fa80b0a78938edc6da1e591149578d1a', + ); + const y = byteEncoder.encode( + '3b17cab634c3795d311380f3bc93ce8e768efc0e2b9e79496cfc8f351594b472', + ); + const proof = byteEncoder.encode( + 'a5ddd6da04c47a9cd4628beb8d55ebd2e930a64dfa29f876ebf393cfd6574d48a3ce96ac5a2af4a4f9ec9caa47d304d3', + ); + + const result = verifyKzgProof(commitment, y, x, proof, setupHandle); + console.log({ result }); + expect(result).toBe(ReturnValue.OK); + }); + }); + + describe('computing an aggregate KZG proof', () => { + it('returns the expected value', () => { + expect(true).toBe(false); + }); + }); + + describe('verifying an aggregate KZG proof', () => { + it('returns the expected value', () => { + expect(true).toBe(false); }); }); });