computeAggregateKzgProof + verifyAggregateKzgProof test passes
This commit is contained in:
parent
b8151db670
commit
1514d5b826
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
|
|
|
@ -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 commitments = blobs.map(blobToKzgCommitment);
|
||||
const z = Uint8Array.from(new Array(32).fill(0));
|
||||
const y = Uint8Array.from(new Array(32).fill(0));
|
||||
|
||||
const proof = computeAggregateKzgProof(blobs);
|
||||
|
||||
console.log({
|
||||
commitments,
|
||||
proof,
|
||||
expect(verifyKzgProof(commitment, z, y, proof)).toBe(true);
|
||||
});
|
||||
|
||||
const result = verifyAggregateKzgProof(blobs, commitments, proof);
|
||||
|
||||
expect(result).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);
|
||||
expect(verifyAggregateKzgProof(blobs, commitments, proof)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue