Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bindings/node.js/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ build
dist
*.node
node_modules
testing_trusted_setups.txt
2 changes: 2 additions & 0 deletions bindings/node.js/.npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ babel.config.js
Dockerfile
binding.dist.gyp
Makefile
testing_trusted_setups.txt
testing_trusted_setups.json
2 changes: 1 addition & 1 deletion bindings/node.js/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions bindings/node.js/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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`
34 changes: 33 additions & 1 deletion bindings/node.js/README.md
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion bindings/node.js/kzg.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
34 changes: 34 additions & 0 deletions bindings/node.js/kzg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand All @@ -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);
}

Expand Down
2 changes: 1 addition & 1 deletion bindings/node.js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "c-kzg",
"version": "1.0.3",
"version": "1.0.5",
"description": "NodeJS bindings for C-KZG",
"author": "Dan Coffman",
"license": "MIT",
Expand Down
18 changes: 14 additions & 4 deletions bindings/node.js/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(() => {
Expand All @@ -38,7 +40,8 @@ describe("C-KZG", () => {
});

it("returns the identity (aka zero, aka neutral) element when blobs is an empty array", () => {
expect(computeAggregateKzgProof([]).toString()).toEqual(
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,
Expand All @@ -47,6 +50,13 @@ describe("C-KZG", () => {
);
});

// 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,
);
});
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently throws verify_aggregate_kzg_proof failed with error code: 1 which means verify_aggregate_kzg_proof returned C_KZG_BADARGS

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine while ethereum/consensus-specs#3093 has not been merged


it("computes the aggregate proof when for a single blob", () => {
let blobs = new Array(1).fill(0).map(generateRandomBlob);
let commitments = blobs.map(blobToKzgCommitment);
Expand Down
1 change: 1 addition & 0 deletions bindings/node.js/testing_trusted_setups.json

Large diffs are not rendered by default.