mirror of
https://github.com/status-im/c-kzg-4844.git
synced 2025-02-17 04:27:08 +00:00
Merge branch 'main' into feature/kzg-test
This commit is contained in:
commit
cccfc749db
1
bindings/node.js/.gitignore
vendored
1
bindings/node.js/.gitignore
vendored
@ -2,3 +2,4 @@ build
|
||||
dist
|
||||
*.node
|
||||
node_modules
|
||||
testing_trusted_setups.txt
|
||||
|
@ -18,3 +18,5 @@ babel.config.js
|
||||
Dockerfile
|
||||
binding.dist.gyp
|
||||
Makefile
|
||||
testing_trusted_setups.txt
|
||||
testing_trusted_setups.json
|
||||
|
@ -4,7 +4,7 @@ FROM node:16
|
||||
|
||||
COPY ./dist/ /app/dist/
|
||||
COPY test.ts /app
|
||||
COPY trusted_setup.txt /app
|
||||
COPY testing_trusted_setups.json /app
|
||||
COPY kzg.ts /app
|
||||
COPY kzg.cxx /app
|
||||
COPY package.json /app
|
||||
|
@ -32,7 +32,5 @@ publish: bundle
|
||||
|
||||
|
||||
linux-test: bundle
|
||||
cp ../../src/trusted_setup.txt .
|
||||
docker build -t "linux-test" .
|
||||
rm trusted_setup.txt
|
||||
docker logs --follow `docker run -d linux-test`
|
||||
|
@ -1,5 +1,37 @@
|
||||
This package wraps the c-kzg C code in C++ NAPI bindings which allow it to be imported into a NodeJS program.
|
||||
|
||||
Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md
|
||||
|
||||
# Usage
|
||||
|
||||
Install this library with
|
||||
|
||||
```sh
|
||||
yarn add c-kzg
|
||||
```
|
||||
|
||||
Import from it like any other library
|
||||
|
||||
```js
|
||||
import {
|
||||
KZGCommitment,
|
||||
blobToKzgCommitment,
|
||||
verifyAggregateKzgProof,
|
||||
loadTrustedSetup,
|
||||
transformTrustedSetupJSON,
|
||||
} from "c-kzg";
|
||||
```
|
||||
|
||||
Requirements
|
||||
|
||||
- The C and C++ code is compiled by node-gyp on installation, so your environment will need a compiler like GCC or clang
|
||||
|
||||
# Contributing
|
||||
|
||||
This directory contains the code necessary to generate NodeJS bindings for C-KZG.
|
||||
|
||||
The bindings file has the following interface:
|
||||
|
||||
```js
|
||||
|
||||
loadTrustedSetup: (filePath: string) => SetupHandle;
|
||||
@ -21,7 +53,7 @@ This directory contains the code necessary to generate NodeJS bindings for C-KZG
|
||||
) => boolean;
|
||||
```
|
||||
|
||||
Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md
|
||||
But this library wraps it in module with manages the setupHandle internally.
|
||||
|
||||
First,
|
||||
`npm install -g yarn` if you don't have it.
|
||||
|
@ -5,10 +5,10 @@
|
||||
"cflags!": ["-fno-exceptions"],
|
||||
"cflags_cc!": ["-fno-exceptions"],
|
||||
"xcode_settings": {
|
||||
"GCC_ENABLE_CPP_EXCEPTIONS": "YES",
|
||||
"CLANG_CXX_LIBRARY": "libc++",
|
||||
"MACOSX_DEPLOYMENT_TARGET": "13.0"
|
||||
},
|
||||
"defines": ["NAPI_DISABLE_CPP_EXCEPTIONS"],
|
||||
"sources": ["kzg.cxx"],
|
||||
"include_dirs": [
|
||||
"<(module_root_dir)/dist/deps/blst/bindings",
|
||||
@ -20,7 +20,6 @@
|
||||
"<(module_root_dir)/libblst.a"
|
||||
],
|
||||
"dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
|
||||
"defines": ["NAPI_DISABLE_CPP_EXCEPTIONS"],
|
||||
"actions": [
|
||||
{
|
||||
"action_name": "build_blst",
|
||||
|
@ -5,10 +5,10 @@
|
||||
"cflags!": ["-fno-exceptions"],
|
||||
"cflags_cc!": ["-fno-exceptions"],
|
||||
"xcode_settings": {
|
||||
"GCC_ENABLE_CPP_EXCEPTIONS": "YES",
|
||||
"CLANG_CXX_LIBRARY": "libc++",
|
||||
"MACOSX_DEPLOYMENT_TARGET": "13.0"
|
||||
},
|
||||
"defines": ["NAPI_DISABLE_CPP_EXCEPTIONS"],
|
||||
"sources": ["kzg.cxx"],
|
||||
"include_dirs": [
|
||||
"../../inc",
|
||||
@ -19,8 +19,7 @@
|
||||
"<(module_root_dir)/c_kzg_4844.o",
|
||||
"<(module_root_dir)/../../lib/libblst.a"
|
||||
],
|
||||
"dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
|
||||
"defines": ["NAPI_DISABLE_CPP_EXCEPTIONS"]
|
||||
"dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"]
|
||||
},
|
||||
{
|
||||
"target_name": "action_after_build",
|
||||
|
@ -26,7 +26,7 @@ Napi::Value throw_invalid_arguments_count(
|
||||
Napi::Value throw_invalid_argument_type(const Napi::Env env, std::string name, std::string expectedType) {
|
||||
Napi::TypeError::New(
|
||||
env,
|
||||
"Invalid parameter type: " + name + ". Expected " + expectedType
|
||||
"Invalid argument type: " + name + ". Expected " + expectedType
|
||||
).ThrowAsJavaScriptException();
|
||||
|
||||
return env.Null();
|
||||
@ -86,7 +86,7 @@ Napi::Value LoadTrustedSetup(const Napi::CallbackInfo& info) {
|
||||
|
||||
if (f == NULL) {
|
||||
free(kzg_settings);
|
||||
Napi::Error::New(env, "Error opening trusted setup file").ThrowAsJavaScriptException();
|
||||
Napi::Error::New(env, "Error opening trusted setup file: " + file_path).ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ Napi::Value BlobToKzgCommitment(const Napi::CallbackInfo& info) {
|
||||
}
|
||||
|
||||
auto blob_param = info[0].As<Napi::TypedArray>();
|
||||
if (blob_param.TypedArrayType() != napi_uint8_array) {
|
||||
if (!blob_param.IsTypedArray() || blob_param.TypedArrayType() != napi_uint8_array) {
|
||||
return throw_invalid_argument_type(env, "blob", "UInt8Array");
|
||||
}
|
||||
auto blob = blob_param.As<Napi::Uint8Array>().Data();
|
||||
|
@ -3,6 +3,7 @@
|
||||
* https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#kzg
|
||||
*/
|
||||
const kzg: KZG = require("./kzg.node");
|
||||
const fs = require("fs");
|
||||
|
||||
export type BLSFieldElement = Uint8Array; // 32 bytes
|
||||
export type KZGProof = Uint8Array; // 48 bytes
|
||||
@ -44,6 +45,13 @@ type KZG = {
|
||||
) => boolean;
|
||||
};
|
||||
|
||||
type TrustedSetupJSON = {
|
||||
setup_G1: string[];
|
||||
setup_G2: string[];
|
||||
setup_G1_lagrange: string[];
|
||||
roots_of_unity: string[];
|
||||
};
|
||||
|
||||
export const FIELD_ELEMENTS_PER_BLOB = kzg.FIELD_ELEMENTS_PER_BLOB;
|
||||
export const BYTES_PER_FIELD_ELEMENT = kzg.BYTES_PER_FIELD_ELEMENT;
|
||||
|
||||
@ -57,12 +65,38 @@ function requireSetupHandle(): SetupHandle {
|
||||
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(data.setup_G2.map((p) => p.replace("0x", "")).join("\n"));
|
||||
file.end();
|
||||
|
||||
const p = new Promise((resolve) => {
|
||||
file.close(resolve);
|
||||
});
|
||||
|
||||
await p;
|
||||
return textFilePath;
|
||||
}
|
||||
|
||||
export function loadTrustedSetup(filePath: string): void {
|
||||
if (setupHandle) {
|
||||
throw new Error(
|
||||
"Call freeTrustedSetup before loading a new trusted setup.",
|
||||
);
|
||||
}
|
||||
|
||||
setupHandle = kzg.loadTrustedSetup(filePath);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "c-kzg",
|
||||
"version": "0.0.9",
|
||||
"version": "1.0.5",
|
||||
"description": "NodeJS bindings for C-KZG",
|
||||
"author": "Dan Coffman",
|
||||
"license": "MIT",
|
||||
|
@ -9,9 +9,10 @@ import {
|
||||
verifyAggregateKzgProof,
|
||||
BYTES_PER_FIELD_ELEMENT,
|
||||
FIELD_ELEMENTS_PER_BLOB,
|
||||
transformTrustedSetupJSON,
|
||||
} from "./kzg";
|
||||
|
||||
const setupFileName = "trusted_setup.txt";
|
||||
const setupFileName = "testing_trusted_setups.json";
|
||||
|
||||
const SETUP_FILE_PATH = existsSync(setupFileName)
|
||||
? setupFileName
|
||||
@ -22,8 +23,9 @@ const BLOB_BYTE_COUNT = FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT;
|
||||
const generateRandomBlob = () => new Uint8Array(randomBytes(BLOB_BYTE_COUNT));
|
||||
|
||||
describe("C-KZG", () => {
|
||||
beforeAll(() => {
|
||||
loadTrustedSetup(SETUP_FILE_PATH);
|
||||
beforeAll(async () => {
|
||||
const file = await transformTrustedSetupJSON(SETUP_FILE_PATH);
|
||||
loadTrustedSetup(file);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
@ -37,9 +39,21 @@ describe("C-KZG", () => {
|
||||
expect(verifyAggregateKzgProof(blobs, commitments, proof)).toBe(true);
|
||||
});
|
||||
|
||||
it("throws an error when blobs is an empty array", () => {
|
||||
expect(() => computeAggregateKzgProof([])).toThrowError(
|
||||
"Failed to compute proof",
|
||||
it("returns the identity (aka zero, aka neutral) element when blobs is an empty array", () => {
|
||||
const aggregateProofOfNothing = computeAggregateKzgProof([]);
|
||||
expect(aggregateProofOfNothing.toString()).toEqual(
|
||||
[
|
||||
192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
].toString(),
|
||||
);
|
||||
});
|
||||
|
||||
// Just don't call verifyAggregateKzgProof when there are no blobs or commitments
|
||||
it.skip("verifies the aggregate proof of empty blobs and commitments", () => {
|
||||
expect(verifyAggregateKzgProof([], [], computeAggregateKzgProof([]))).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
@ -59,4 +73,13 @@ describe("C-KZG", () => {
|
||||
verifyAggregateKzgProof(blobs, commitments, proof),
|
||||
).toThrowError("Invalid commitment data");
|
||||
});
|
||||
|
||||
describe("computing commitment from blobs", () => {
|
||||
it("throws as expected when given an argument of invalid type", () => {
|
||||
// @ts-expect-error
|
||||
expect(() => blobToKzgCommitment("wrong type")).toThrowError(
|
||||
"Invalid argument type: blob. Expected UInt8Array",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
1
bindings/node.js/testing_trusted_setups.json
Normal file
1
bindings/node.js/testing_trusted_setups.json
Normal file
File diff suppressed because one or more lines are too long
@ -826,9 +826,9 @@ void free_trusted_setup(KZGSettings *s) {
|
||||
}
|
||||
|
||||
static void compute_powers(fr_t out[], uint64_t n) {
|
||||
uint64_t i = 0;
|
||||
out[i++] = fr_one;
|
||||
while (++i < n) fr_mul(&out[i], &out[i-1], &out[1]);
|
||||
out[0] = fr_one;
|
||||
for (uint64_t i = 2; i < n; i++)
|
||||
fr_mul(&out[i], &out[i-1], &out[1]);
|
||||
}
|
||||
|
||||
void bytes_to_bls_field(BLSFieldElement *out, const uint8_t bytes[32]) {
|
||||
@ -1065,7 +1065,7 @@ void sha256_init(SHA256_CTX *ctx);
|
||||
void sha256_update(SHA256_CTX *ctx, const void *_inp, size_t len);
|
||||
void sha256_final(unsigned char md[32], SHA256_CTX *ctx);
|
||||
|
||||
void hash(uint8_t md[32], uint8_t input[], size_t n) {
|
||||
void hash(uint8_t md[32], const uint8_t input[], size_t n) {
|
||||
SHA256_CTX ctx;
|
||||
sha256_init(&ctx);
|
||||
sha256_update(&ctx, input, n);
|
||||
@ -1089,12 +1089,12 @@ static C_KZG_RET hash_to_bytes(uint8_t out[32],
|
||||
if (bytes == NULL) return C_KZG_MALLOC;
|
||||
|
||||
memcpy(bytes, FIAT_SHAMIR_PROTOCOL_DOMAIN, 16);
|
||||
bytes_of_uint64(&bytes[16], n);
|
||||
bytes_of_uint64(&bytes[16 + 8], FIELD_ELEMENTS_PER_BLOB);
|
||||
bytes_of_uint64(&bytes[16], FIELD_ELEMENTS_PER_BLOB);
|
||||
bytes_of_uint64(&bytes[16 + 8], n);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
for (j = 0; j < FIELD_ELEMENTS_PER_BLOB; j++)
|
||||
bytes_from_bls_field(&bytes[ni + i * BYTES_PER_FIELD_ELEMENT], &polys[i][j]);
|
||||
bytes_from_bls_field(&bytes[ni + BYTES_PER_FIELD_ELEMENT * (i * FIELD_ELEMENTS_PER_BLOB + j)], &polys[i][j]);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
bytes_from_g1(&bytes[np + i * 48], &comms[i]);
|
||||
@ -1117,28 +1117,22 @@ static C_KZG_RET compute_aggregated_poly_and_commitment(Polynomial poly_out, KZG
|
||||
ret = hash_to_bytes(hash, polys, kzg_commitments, n);
|
||||
if (ret != C_KZG_OK) { free(hash); return ret; }
|
||||
|
||||
if (n == 1) {
|
||||
bytes_to_bls_field(chal_out, hash);
|
||||
poly_lincomb(poly_out, polys, chal_out, n);
|
||||
g1_lincomb(comm_out, kzg_commitments, chal_out, n);
|
||||
free(hash);
|
||||
return C_KZG_OK;
|
||||
}
|
||||
|
||||
BLSFieldElement* r_powers = calloc(n, sizeof(BLSFieldElement));
|
||||
BLSFieldElement* r_powers = calloc(n + 1, sizeof(BLSFieldElement));
|
||||
if (r_powers == NULL) { free(hash); return C_KZG_MALLOC; }
|
||||
|
||||
bytes_to_bls_field(&r_powers[1], hash);
|
||||
free(hash);
|
||||
|
||||
compute_powers(r_powers, n);
|
||||
fr_mul(chal_out, &r_powers[1], &r_powers[n - 1]);
|
||||
compute_powers(r_powers, n + 1);
|
||||
|
||||
*chal_out = r_powers[n];
|
||||
|
||||
poly_lincomb(poly_out, polys, r_powers, n);
|
||||
|
||||
g1_lincomb(comm_out, kzg_commitments, r_powers, n);
|
||||
|
||||
free(r_powers);
|
||||
|
||||
return C_KZG_OK;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user