computeAggregateKzgProof + verifyAggregateKzgProof test passes

This commit is contained in:
dancoffman 2022-11-03 16:20:33 -07:00
parent b8151db670
commit 1514d5b826
No known key found for this signature in database
GPG Key ID: 47B1F53E36A9B3CC
4 changed files with 72 additions and 55 deletions

View File

@ -163,7 +163,7 @@ Napi::Value ComputeAggregateKzgProof(const Napi::CallbackInfo& info) {
return napi_typed_array_from_bytes(proofBytes, BYTES_PER_PROOF, env);
}
// verifyAggregateKzgProof: (blobs: Blob[], expectedKzgCommitments: KZGCommitment[], kzgAggregatedProof: KZGProof) => boolean;
// verifyAggregateKzgProof: (blobs: Blob[], expectedKzgCommitments: KZGCommitment[], kzgAggregatedProof: KZGProof, setupHandle: SetupHandle) => boolean;
Napi::Value VerifyAggregateKzgProof(const Napi::CallbackInfo& info) {
auto env = info.Env();
@ -189,23 +189,29 @@ Napi::Value VerifyAggregateKzgProof(const Napi::CallbackInfo& info) {
C_KZG_RET ret;
for (uint32_t blobIndex = 0; blobIndex < numberOfBlobs; blobIndex++) {
// Extract blob bytes from parameter
Napi::Value blob = blobs_param[blobIndex];
auto blobBytes = blob.As<Napi::Uint8Array>().Data();
Napi::Value commitment = comittments_param[blobIndex];
auto commitmentBytes = commitment.As<Napi::Uint8Array>().Data();
// Populate the polynomial with a BLS field for each field element in the blob
for (uint32_t fieldIndex = 0; fieldIndex < FIELD_ELEMENTS_PER_BLOB; fieldIndex++) {
bytes_to_bls_field(&polynomial[blobIndex][fieldIndex], &blobBytes[fieldIndex * BYTES_PER_FIELD]);
}
ret = bytes_to_g1(&commitments[blobIndex], &commitmentBytes[blobIndex * BYTES_PER_COMMITMENT]);
// Extract a G1 point for each commitment
Napi::Value commitment = comittments_param[blobIndex];
auto commitmentBytes = commitment.As<Napi::Uint8Array>().Data();
ret = bytes_to_g1(&commitments[blobIndex], commitmentBytes);
if (ret != C_KZG_OK) {
std::ostringstream ss;
std::copy(commitmentBytes, commitmentBytes + BYTES_PER_COMMITMENT, std::ostream_iterator<int>(ss, ","));
Napi::TypeError::New(env, "Error parsing commitment. Error code was: " + std::to_string(ret) + ". Commitment bytes: " + ss.str()).ThrowAsJavaScriptException();
free(commitments);
free(polynomial);
Napi::TypeError::New(env, "Error parsing blobs and commitments")
.ThrowAsJavaScriptException();
return env.Null();
}
}
@ -260,15 +266,15 @@ Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) {
.ThrowAsJavaScriptException();
return env.Undefined();
}
auto c = c_param.As<Napi::Uint8Array>().Data();
auto polynomialKzg = c_param.As<Napi::Uint8Array>().Data();
auto x_param = info[0].As<Napi::TypedArray>();
if (x_param.TypedArrayType() != napi_uint8_array) {
auto z_param = info[0].As<Napi::TypedArray>();
if (z_param.TypedArrayType() != napi_uint8_array) {
Napi::Error::New(env, "Expected an Uint8Array")
.ThrowAsJavaScriptException();
return env.Undefined();
}
auto x = x_param.As<Napi::Uint8Array>().Data();
auto z = z_param.As<Napi::Uint8Array>().Data();
auto y_param = info[0].As<Napi::TypedArray>();
if (y_param.TypedArrayType() != napi_uint8_array) {
@ -278,37 +284,36 @@ Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) {
}
auto y = y_param.As<Napi::Uint8Array>().Data();
auto p_param = info[0].As<Napi::TypedArray>();
if (p_param.TypedArrayType() != napi_uint8_array) {
auto proof_param = info[0].As<Napi::TypedArray>();
if (proof_param.TypedArrayType() != napi_uint8_array) {
Napi::Error::New(info.Env(), "Expected an Uint8Array")
.ThrowAsJavaScriptException();
return info.Env().Undefined();
}
auto p = p_param.As<Napi::Uint8Array>().Data();
auto kzgProof = proof_param.As<Napi::Uint8Array>().Data();
auto kzgSettings = info[4].As<Napi::External<KZGSettings>>().Data();
KZGCommitment commitment;
KZGProof proof;
BLSFieldElement fx, fy;
bool out;
bytes_to_bls_field(&fx, x);
bytes_to_bls_field(&fx, z);
bytes_to_bls_field(&fy, y);
auto ret = bytes_to_g1(&commitment, c);
KZGCommitment commitment;
auto ret = bytes_to_g1(&commitment, polynomialKzg);
if (ret != C_KZG_OK) {
std::ostringstream ss;
std::copy(c, c+sizeof(c), std::ostream_iterator<int>(ss, ","));
std::copy(polynomialKzg, polynomialKzg + BYTES_PER_COMMITMENT, std::ostream_iterator<int>(ss, ","));
Napi::TypeError::New(env, "Failed to parse argument commitment: " + ss.str() + " Return code was: " + std::to_string(ret)).ThrowAsJavaScriptException();
return env.Null();
};
if (bytes_to_g1(&proof, p) != C_KZG_OK) {
Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
KZGProof proof;
if (bytes_to_g1(&proof, kzgProof) != C_KZG_OK) {
Napi::TypeError::New(env, "Invalid kzgProof").ThrowAsJavaScriptException();
return env.Null();
}
bool out;
if (verify_kzg_proof(&out, &commitment, &fx, &fy, &proof, kzgSettings) != C_KZG_OK) {
return Napi::Boolean::New(env, false);
}
@ -317,12 +322,18 @@ Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) {
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
// Functions
exports["loadTrustedSetup"] = Napi::Function::New(env, LoadTrustedSetup);
exports["freeTrustedSetup"] = Napi::Function::New(env, FreeTrustedSetup);
exports["verifyKzgProof"] = Napi::Function::New(env, VerifyKzgProof);
exports["blobToKzgCommitment"] = Napi::Function::New(env, BlobToKzgCommitment);
exports["computeAggregateKzgProof"] = Napi::Function::New(env, ComputeAggregateKzgProof);
exports["verifyAggregateKzgProof"] = Napi::Function::New(env, VerifyAggregateKzgProof);
// Constants
exports["FIELD_ELEMENTS_PER_BLOB"] = Napi::Number::New(env, FIELD_ELEMENTS_PER_BLOB);
exports["BYTES_PER_FIELD"] = Napi::Number::New(env, BYTES_PER_FIELD);
return exports;
}

View File

@ -1,17 +1,23 @@
// @ts-expect-error
import bindings from "bindings";
export const BLOB_SIZE = 4096;
export const NUMBER_OF_FIELDS = 32;
/**
* The public interface of this module exposes the functions as specified by
* https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md#kzg
*/
export type SetupHandle = Object;
export type BLSFieldElement = Uint8Array; // 32 bytes
export type KZGProof = Uint8Array; // 48 bytes
export type KZGCommitment = Uint8Array; // 48 bytes
export type Blob = Uint8Array; // 4096 * 32 bytes
export type BLSFieldElement = Uint8Array;
export type KZGProof = Uint8Array;
export type KZGCommitment = Uint8Array;
export type Blob = Uint8Array;
type SetupHandle = Object;
// The C++ native addon interface
type KZG = {
FIELD_ELEMENTS_PER_BLOB: number;
BYTES_PER_FIELD: number;
loadTrustedSetup: (filePath: string) => SetupHandle;
freeTrustedSetup: (setupHandle: SetupHandle) => void;
@ -41,6 +47,9 @@ type KZG = {
const kzg: KZG = bindings("kzg.node");
export const FIELD_ELEMENTS_PER_BLOB = kzg.FIELD_ELEMENTS_PER_BLOB;
export const BYTES_PER_FIELD = kzg.BYTES_PER_FIELD;
// Stored as internal state
let setupHandle: SetupHandle | undefined;
@ -83,7 +92,7 @@ export function verifyKzgProof(
z: BLSFieldElement,
y: BLSFieldElement,
kzgProof: KZGProof
) {
): boolean {
if (!setupHandle) {
throw new Error("You must call loadTrustedSetup to initialize KZG.");
}

View File

@ -2,46 +2,43 @@ import { randomBytes } from "crypto";
import {
loadTrustedSetup,
freeTrustedSetup,
verifyKzgProof,
blobToKzgCommitment,
Blob,
BLOB_SIZE,
NUMBER_OF_FIELDS,
computeAggregateKzgProof,
verifyAggregateKzgProof,
BYTES_PER_FIELD,
FIELD_ELEMENTS_PER_BLOB,
verifyKzgProof,
} from "./kzg";
const SETUP_FILE_PATH = "../../src/trusted_setup.txt";
const BLOB_BYTE_COUNT = FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD;
function generateRandomBlob(): Blob {
return new Uint8Array(randomBytes(BLOB_SIZE * NUMBER_OF_FIELDS));
}
const generateRandomBlob = () => new Uint8Array(randomBytes(BLOB_BYTE_COUNT));
describe("C-KZG", () => {
beforeEach(() => {
beforeAll(() => {
loadTrustedSetup(SETUP_FILE_PATH);
});
afterEach(() => {
afterAll(() => {
freeTrustedSetup();
});
it("computes and verifies an aggregate KZG proof", async () => {
const blob1 = generateRandomBlob();
const blob2 = generateRandomBlob();
const blobs = [blob1, blob2];
it.skip("verifies a proof at a given commitment point", async () => {
const blob = generateRandomBlob();
const commitment = blobToKzgCommitment(blob);
const proof = computeAggregateKzgProof([blob]);
const z = Uint8Array.from(new Array(32).fill(0));
const y = Uint8Array.from(new Array(32).fill(0));
expect(verifyKzgProof(commitment, z, y, proof)).toBe(true);
});
it("computes the correct aggregate commitment from blobs", async () => {
const blobs = new Array(2).fill(0).map(generateRandomBlob);
const commitments = blobs.map(blobToKzgCommitment);
const proof = computeAggregateKzgProof(blobs);
console.log({
commitments,
proof,
});
const result = verifyAggregateKzgProof(blobs, commitments, proof);
expect(result).toBe(true);
expect(verifyAggregateKzgProof(blobs, commitments, proof)).toBe(true);
});
});

View File

@ -1,7 +1,7 @@
INCLUDE_DIRS = ../inc
CFLAGS += -O2
c_kzg_4844.o: c_kzg_4844.c Makefile
c_kzg_4844.o: c_kzg_4844.c sha256.c Makefile
clang -Wall -I$(INCLUDE_DIRS) $(CFLAGS) -c c_kzg_4844.c sha256.c
lib: c_kzg_4844.o Makefile