Update nodejs bindings
This commit is contained in:
parent
9a764de619
commit
21b3139dc8
|
@ -152,51 +152,6 @@ Napi::Value BlobToKzgCommitment(const Napi::CallbackInfo& info) {
|
||||||
return napi_typed_array_from_bytes((uint8_t *)(&commitment), BYTES_PER_COMMITMENT, env);
|
return napi_typed_array_from_bytes((uint8_t *)(&commitment), BYTES_PER_COMMITMENT, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
// computeAggregateKzgProof: (blobs: Blob[], setupHandle: SetupHandle) => KZGProof;
|
|
||||||
Napi::Value ComputeAggregateKzgProof(const Napi::CallbackInfo& info) {
|
|
||||||
auto env = info.Env();
|
|
||||||
|
|
||||||
size_t argument_count = info.Length();
|
|
||||||
size_t expected_argument_count = 2;
|
|
||||||
if (argument_count != expected_argument_count) {
|
|
||||||
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto blobs_param = info[0].As<Napi::Array>();
|
|
||||||
auto kzg_settings = info[1].As<Napi::External<KZGSettings>>().Data();
|
|
||||||
|
|
||||||
auto blobs_count = blobs_param.Length();
|
|
||||||
|
|
||||||
auto blobs = (Blob*)calloc(blobs_count, sizeof(Blob));
|
|
||||||
if (blobs == NULL) {
|
|
||||||
Napi::Error::New(env, "Error while allocating memory for blobs").ThrowAsJavaScriptException();
|
|
||||||
return env.Null();
|
|
||||||
};
|
|
||||||
|
|
||||||
for (uint32_t blob_index = 0; blob_index < blobs_count; blob_index++) {
|
|
||||||
Napi::Value blob = blobs_param[blob_index];
|
|
||||||
auto blob_bytes = blob.As<Napi::Uint8Array>().Data();
|
|
||||||
memcpy(blobs[blob_index].bytes, blob_bytes, BYTES_PER_BLOB);
|
|
||||||
}
|
|
||||||
|
|
||||||
KZGProof proof;
|
|
||||||
C_KZG_RET ret = compute_aggregate_kzg_proof(
|
|
||||||
&proof,
|
|
||||||
blobs,
|
|
||||||
blobs_count,
|
|
||||||
kzg_settings
|
|
||||||
);
|
|
||||||
free(blobs);
|
|
||||||
|
|
||||||
if (ret != C_KZG_OK) {
|
|
||||||
Napi::Error::New(env, "Failed to compute aggregated proof")
|
|
||||||
.ThrowAsJavaScriptException();
|
|
||||||
return env.Undefined();
|
|
||||||
};
|
|
||||||
|
|
||||||
return napi_typed_array_from_bytes((uint8_t *)(&proof), BYTES_PER_PROOF, env);
|
|
||||||
}
|
|
||||||
|
|
||||||
// computeKzgProof: (blob: Blob, zBytes: Bytes32, setupHandle: SetupHandle) => KZGProof;
|
// computeKzgProof: (blob: Blob, zBytes: Bytes32, setupHandle: SetupHandle) => KZGProof;
|
||||||
Napi::Value ComputeKzgProof(const Napi::CallbackInfo& info) {
|
Napi::Value ComputeKzgProof(const Napi::CallbackInfo& info) {
|
||||||
auto env = info.Env();
|
auto env = info.Env();
|
||||||
|
@ -228,80 +183,33 @@ Napi::Value ComputeKzgProof(const Napi::CallbackInfo& info) {
|
||||||
return napi_typed_array_from_bytes((uint8_t *)(&proof), BYTES_PER_PROOF, env);
|
return napi_typed_array_from_bytes((uint8_t *)(&proof), BYTES_PER_PROOF, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyAggregateKzgProof: (blobs: Blob[], commitmentsBytes: Bytes48[], aggregatedProofBytes: Bytes48, setupHandle: SetupHandle) => boolean;
|
// computeBlobKzgProof: (blob: Blob, setupHandle: SetupHandle) => KZGProof;
|
||||||
Napi::Value VerifyAggregateKzgProof(const Napi::CallbackInfo& info) {
|
Napi::Value ComputeBlobKzgProof(const Napi::CallbackInfo& info) {
|
||||||
auto env = info.Env();
|
auto env = info.Env();
|
||||||
|
|
||||||
size_t argument_count = info.Length();
|
size_t argument_count = info.Length();
|
||||||
size_t expected_argument_count = 4;
|
size_t expected_argument_count = 2;
|
||||||
if (argument_count != expected_argument_count) {
|
if (argument_count != expected_argument_count) {
|
||||||
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
|
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto blobs_param = info[0].As<Napi::Array>();
|
auto blob = extract_byte_array_from_param(info, 0, "blob");
|
||||||
auto commitments_param = info[1].As<Napi::Array>();
|
auto kzg_settings = info[1].As<Napi::External<KZGSettings>>().Data();
|
||||||
auto proof_param = info[2].As<Napi::TypedArray>();
|
|
||||||
auto kzg_settings = info[3].As<Napi::External<KZGSettings>>().Data();
|
|
||||||
|
|
||||||
auto proof_bytes = proof_param.As<Napi::Uint8Array>().Data();
|
KZGProof proof;
|
||||||
auto blobs_count = blobs_param.Length();
|
C_KZG_RET ret = compute_blob_kzg_proof(
|
||||||
auto commitments_count = commitments_param.Length();
|
&proof,
|
||||||
|
(Blob *)blob,
|
||||||
if (blobs_count != commitments_count) {
|
|
||||||
Napi::Error::New(env, "verifyAggregateKzgProof requires blobs count to match expectedKzgCommitments count")
|
|
||||||
.ThrowAsJavaScriptException();
|
|
||||||
return env.Undefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto blobs = (Blob*)calloc(blobs_count, sizeof(Blob));
|
|
||||||
if (blobs == NULL) {
|
|
||||||
Napi::Error::New(env, "Error while allocating memory for blobs").ThrowAsJavaScriptException();
|
|
||||||
return env.Null();
|
|
||||||
};
|
|
||||||
|
|
||||||
auto commitments = (Bytes48*)calloc(blobs_count, sizeof(Bytes48));
|
|
||||||
if (commitments == NULL) {
|
|
||||||
free(blobs);
|
|
||||||
Napi::Error::New(env, "Error while allocating memory for commitments").ThrowAsJavaScriptException();
|
|
||||||
return env.Null();
|
|
||||||
};
|
|
||||||
|
|
||||||
C_KZG_RET ret;
|
|
||||||
|
|
||||||
for (uint32_t blob_index = 0; blob_index < blobs_count; blob_index++) {
|
|
||||||
// Extract blob bytes from parameter
|
|
||||||
Napi::Value blob = blobs_param[blob_index];
|
|
||||||
auto blob_bytes = blob.As<Napi::Uint8Array>().Data();
|
|
||||||
memcpy(blobs[blob_index].bytes, blob_bytes, BYTES_PER_BLOB);
|
|
||||||
|
|
||||||
// Extract commitment from parameter
|
|
||||||
Napi::Value commitment = commitments_param[blob_index];
|
|
||||||
auto commitment_bytes = commitment.As<Napi::Uint8Array>().Data();
|
|
||||||
memcpy(&commitments[blob_index], commitment_bytes, BYTES_PER_COMMITMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool verification_result;
|
|
||||||
ret = verify_aggregate_kzg_proof(
|
|
||||||
&verification_result,
|
|
||||||
blobs,
|
|
||||||
commitments,
|
|
||||||
blobs_count,
|
|
||||||
(Bytes48 *)proof_bytes,
|
|
||||||
kzg_settings
|
kzg_settings
|
||||||
);
|
);
|
||||||
|
|
||||||
free(commitments);
|
|
||||||
free(blobs);
|
|
||||||
|
|
||||||
if (ret != C_KZG_OK) {
|
if (ret != C_KZG_OK) {
|
||||||
Napi::Error::New(
|
Napi::Error::New(env, "Error in computeBlobKzgProof")
|
||||||
env,
|
.ThrowAsJavaScriptException();
|
||||||
"verify_aggregate_kzg_proof failed with error code: " + std::to_string(ret)
|
return env.Undefined();
|
||||||
).ThrowAsJavaScriptException();
|
};
|
||||||
return env.Null();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Napi::Boolean::New(env, verification_result);
|
return napi_typed_array_from_bytes((uint8_t *)(&proof), BYTES_PER_PROOF, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyKzgProof: (commitmentBytes: Bytes48, zBytes: Bytes32, yBytes: Bytes32, proofBytes: Bytes48, setupHandle: SetupHandle) => boolean;
|
// verifyKzgProof: (commitmentBytes: Bytes48, zBytes: Bytes32, yBytes: Bytes32, proofBytes: Bytes48, setupHandle: SetupHandle) => boolean;
|
||||||
|
@ -342,15 +250,133 @@ Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) {
|
||||||
return Napi::Boolean::New(env, out);
|
return Napi::Boolean::New(env, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// verifyBlobKzgProof: (blob: Blob, commitmentBytes: Bytes48, proofBytes: Bytes48, setupHandle: SetupHandle) => boolean;
|
||||||
|
Napi::Value VerifyBlobKzgProof(const Napi::CallbackInfo& info) {
|
||||||
|
auto env = info.Env();
|
||||||
|
|
||||||
|
size_t argument_count = info.Length();
|
||||||
|
size_t expected_argument_count = 4;
|
||||||
|
if (argument_count != expected_argument_count) {
|
||||||
|
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto blob_bytes = extract_byte_array_from_param(info, 0, "blob");
|
||||||
|
auto commitment_bytes = extract_byte_array_from_param(info, 1, "commitmentBytes");
|
||||||
|
auto proof_bytes = extract_byte_array_from_param(info, 2, "proofBytes");
|
||||||
|
auto kzg_settings = info[3].As<Napi::External<KZGSettings>>().Data();
|
||||||
|
|
||||||
|
if (env.IsExceptionPending()) {
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool out;
|
||||||
|
C_KZG_RET ret = verify_blob_kzg_proof(
|
||||||
|
&out,
|
||||||
|
(Blob *)blob_bytes,
|
||||||
|
(Bytes48 *)commitment_bytes,
|
||||||
|
(Bytes48 *)proof_bytes,
|
||||||
|
kzg_settings
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ret != C_KZG_OK) {
|
||||||
|
Napi::TypeError::New(env, "Error in verifyBlobKzgProof").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Napi::Boolean::New(env, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyBlobKzgProofBatch: (blobs: Blob[], commitmentsBytes: Bytes48[], proofsBytes: Bytes48[], setupHandle: SetupHandle) => boolean;
|
||||||
|
Napi::Value VerifyBlobKzgProofBatch(const Napi::CallbackInfo& info) {
|
||||||
|
auto env = info.Env();
|
||||||
|
|
||||||
|
size_t argument_count = info.Length();
|
||||||
|
size_t expected_argument_count = 4;
|
||||||
|
if (argument_count != expected_argument_count) {
|
||||||
|
return throw_invalid_arguments_count(expected_argument_count, argument_count, env);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto blobs_param = info[0].As<Napi::Array>();
|
||||||
|
auto commitments_param = info[1].As<Napi::Array>();
|
||||||
|
auto proofs_param = info[2].As<Napi::Array>();
|
||||||
|
auto kzg_settings = info[3].As<Napi::External<KZGSettings>>().Data();
|
||||||
|
|
||||||
|
auto blobs_count = blobs_param.Length();
|
||||||
|
auto commitments_count = commitments_param.Length();
|
||||||
|
auto proofs_count = proofs_param.Length();
|
||||||
|
|
||||||
|
if (blobs_count != commitments_count || blobs_count != proofs_count) {
|
||||||
|
Napi::Error::New(env, "verifyBlobKzgProofBatch requires equal number of blobs/commitments/proofs")
|
||||||
|
.ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto blobs = (Blob*)calloc(blobs_count, sizeof(Blob));
|
||||||
|
if (blobs == NULL) {
|
||||||
|
Napi::Error::New(env, "Error while allocating memory for blobs").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto commitments = (Bytes48*)calloc(commitments_count, sizeof(Bytes48));
|
||||||
|
if (commitments == NULL) {
|
||||||
|
free(blobs);
|
||||||
|
Napi::Error::New(env, "Error while allocating memory for commitments").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto proofs = (Bytes48*)calloc(proofs_count, sizeof(Bytes48));
|
||||||
|
if (proofs == NULL) {
|
||||||
|
free(blobs);
|
||||||
|
free(commitments);
|
||||||
|
Napi::Error::New(env, "Error while allocating memory for proofs").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uint32_t index = 0; index < blobs_count; index++) {
|
||||||
|
// Extract blob bytes from parameter
|
||||||
|
Napi::Value blob = blobs_param[index];
|
||||||
|
auto blob_bytes = blob.As<Napi::Uint8Array>().Data();
|
||||||
|
memcpy(blobs[index].bytes, blob_bytes, BYTES_PER_BLOB);
|
||||||
|
|
||||||
|
// Extract commitment from parameter
|
||||||
|
Napi::Value commitment = commitments_param[index];
|
||||||
|
auto commitment_bytes = commitment.As<Napi::Uint8Array>().Data();
|
||||||
|
memcpy(&commitments[index], commitment_bytes, BYTES_PER_COMMITMENT);
|
||||||
|
|
||||||
|
// Extract proof from parameter
|
||||||
|
Napi::Value proof = proofs_param[index];
|
||||||
|
auto proof_bytes = proof.As<Napi::Uint8Array>().Data();
|
||||||
|
memcpy(&proofs[index], proof_bytes, BYTES_PER_PROOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool out;
|
||||||
|
C_KZG_RET ret = verify_blob_kzg_proof_batch(
|
||||||
|
&out,
|
||||||
|
blobs,
|
||||||
|
commitments,
|
||||||
|
proofs,
|
||||||
|
blobs_count,
|
||||||
|
kzg_settings
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ret != C_KZG_OK) {
|
||||||
|
Napi::TypeError::New(env, "Error in verifyBlobKzgProofBatch").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Napi::Boolean::New(env, out);
|
||||||
|
}
|
||||||
|
|
||||||
Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
||||||
// Functions
|
// Functions
|
||||||
exports["loadTrustedSetup"] = Napi::Function::New(env, LoadTrustedSetup);
|
exports["loadTrustedSetup"] = Napi::Function::New(env, LoadTrustedSetup);
|
||||||
exports["freeTrustedSetup"] = Napi::Function::New(env, FreeTrustedSetup);
|
exports["freeTrustedSetup"] = Napi::Function::New(env, FreeTrustedSetup);
|
||||||
exports["blobToKzgCommitment"] = Napi::Function::New(env, BlobToKzgCommitment);
|
exports["blobToKzgCommitment"] = Napi::Function::New(env, BlobToKzgCommitment);
|
||||||
exports["computeKzgProof"] = Napi::Function::New(env, ComputeKzgProof);
|
exports["computeKzgProof"] = Napi::Function::New(env, ComputeKzgProof);
|
||||||
|
exports["computeBlobKzgProof"] = Napi::Function::New(env, ComputeBlobKzgProof);
|
||||||
exports["verifyKzgProof"] = Napi::Function::New(env, VerifyKzgProof);
|
exports["verifyKzgProof"] = Napi::Function::New(env, VerifyKzgProof);
|
||||||
exports["computeAggregateKzgProof"] = Napi::Function::New(env, ComputeAggregateKzgProof);
|
exports["verifyBlobKzgProof"] = Napi::Function::New(env, VerifyBlobKzgProof);
|
||||||
exports["verifyAggregateKzgProof"] = Napi::Function::New(env, VerifyAggregateKzgProof);
|
exports["verifyBlobKzgProofBatch"] = Napi::Function::New(env, VerifyBlobKzgProofBatch);
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
exports["BYTES_PER_BLOB"] = Napi::Number::New(env, BYTES_PER_BLOB);
|
exports["BYTES_PER_BLOB"] = Napi::Number::New(env, BYTES_PER_BLOB);
|
||||||
|
|
|
@ -33,17 +33,7 @@ type KZG = {
|
||||||
setupHandle: SetupHandle,
|
setupHandle: SetupHandle,
|
||||||
) => KZGProof;
|
) => KZGProof;
|
||||||
|
|
||||||
computeAggregateKzgProof: (
|
computeBlobKzgProof: (blob: Blob, setupHandle: SetupHandle) => KZGProof;
|
||||||
blobs: Blob[],
|
|
||||||
setupHandle: SetupHandle,
|
|
||||||
) => KZGProof;
|
|
||||||
|
|
||||||
verifyAggregateKzgProof: (
|
|
||||||
blobs: Blob[],
|
|
||||||
commitmentsBytes: Bytes48[],
|
|
||||||
aggregatedProofBytes: Bytes48,
|
|
||||||
setupHandle: SetupHandle,
|
|
||||||
) => boolean;
|
|
||||||
|
|
||||||
verifyKzgProof: (
|
verifyKzgProof: (
|
||||||
commitmentBytes: Bytes48,
|
commitmentBytes: Bytes48,
|
||||||
|
@ -52,6 +42,20 @@ type KZG = {
|
||||||
proofBytes: Bytes48,
|
proofBytes: Bytes48,
|
||||||
setupHandle: SetupHandle,
|
setupHandle: SetupHandle,
|
||||||
) => boolean;
|
) => boolean;
|
||||||
|
|
||||||
|
verifyBlobKzgProof: (
|
||||||
|
blob: Blob,
|
||||||
|
commitmentBytes: Bytes48,
|
||||||
|
proofBytes: Bytes48,
|
||||||
|
setupHandle: SetupHandle,
|
||||||
|
) => boolean;
|
||||||
|
|
||||||
|
verifyBlobKzgProofBatch: (
|
||||||
|
blobs: Blob[],
|
||||||
|
commitmentsBytes: Bytes48[],
|
||||||
|
proofsBytes: Bytes48[],
|
||||||
|
setupHandle: SetupHandle,
|
||||||
|
) => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type TrustedSetupJSON = {
|
type TrustedSetupJSON = {
|
||||||
|
@ -113,6 +117,12 @@ function checkProof(proof: KZGProof) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkProofs(proofs: KZGProof[]) {
|
||||||
|
for (let proof of proofs) {
|
||||||
|
checkProof(proof);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkFieldElement(field: Bytes32) {
|
function checkFieldElement(field: Bytes32) {
|
||||||
if (field.length != BYTES_PER_FIELD_ELEMENT) {
|
if (field.length != BYTES_PER_FIELD_ELEMENT) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -173,9 +183,9 @@ export function computeKzgProof(blob: Blob, zBytes: Bytes32): KZGProof {
|
||||||
return kzg.computeKzgProof(blob, zBytes, requireSetupHandle());
|
return kzg.computeKzgProof(blob, zBytes, requireSetupHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function computeAggregateKzgProof(blobs: Blob[]): KZGProof {
|
export function computeBlobKzgProof(blob: Blob): KZGProof {
|
||||||
checkBlobs(blobs);
|
checkBlob(blob);
|
||||||
return kzg.computeAggregateKzgProof(blobs, requireSetupHandle());
|
return kzg.computeBlobKzgProof(blob, requireSetupHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function verifyKzgProof(
|
export function verifyKzgProof(
|
||||||
|
@ -197,18 +207,34 @@ export function verifyKzgProof(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function verifyAggregateKzgProof(
|
export function verifyBlobKzgProof(
|
||||||
blobs: Blob[],
|
blob: Blob,
|
||||||
commitmentsBytes: Bytes48[],
|
commitmentBytes: Bytes48,
|
||||||
proofBytes: Bytes48,
|
proofBytes: Bytes48,
|
||||||
): boolean {
|
): boolean {
|
||||||
checkBlobs(blobs);
|
checkBlob(blob);
|
||||||
checkCommitments(commitmentsBytes);
|
checkCommitment(commitmentBytes);
|
||||||
checkProof(proofBytes);
|
checkProof(proofBytes);
|
||||||
return kzg.verifyAggregateKzgProof(
|
return kzg.verifyBlobKzgProof(
|
||||||
blobs,
|
blob,
|
||||||
commitmentsBytes,
|
commitmentBytes,
|
||||||
proofBytes,
|
proofBytes,
|
||||||
requireSetupHandle(),
|
requireSetupHandle(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function verifyBlobKzgProofBatch(
|
||||||
|
blobs: Blob[],
|
||||||
|
commitmentsBytes: Bytes48[],
|
||||||
|
proofsBytes: Bytes48[],
|
||||||
|
): boolean {
|
||||||
|
checkBlobs(blobs);
|
||||||
|
checkCommitments(commitmentsBytes);
|
||||||
|
checkProofs(proofsBytes);
|
||||||
|
return kzg.verifyBlobKzgProofBatch(
|
||||||
|
blobs,
|
||||||
|
commitmentsBytes,
|
||||||
|
proofsBytes,
|
||||||
|
requireSetupHandle(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import { randomBytes } from "crypto";
|
import { randomBytes } from "crypto";
|
||||||
import { existsSync } from "fs";
|
import { existsSync } from "fs";
|
||||||
|
import path = require("path");
|
||||||
|
import fs = require("fs");
|
||||||
|
|
||||||
import {
|
import {
|
||||||
loadTrustedSetup,
|
loadTrustedSetup,
|
||||||
freeTrustedSetup,
|
freeTrustedSetup,
|
||||||
blobToKzgCommitment,
|
blobToKzgCommitment,
|
||||||
verifyKzgProof,
|
|
||||||
computeKzgProof,
|
computeKzgProof,
|
||||||
computeAggregateKzgProof,
|
computeBlobKzgProof,
|
||||||
verifyAggregateKzgProof,
|
verifyKzgProof,
|
||||||
|
verifyBlobKzgProof,
|
||||||
|
verifyBlobKzgProofBatch,
|
||||||
BYTES_PER_BLOB,
|
BYTES_PER_BLOB,
|
||||||
BYTES_PER_COMMITMENT,
|
BYTES_PER_COMMITMENT,
|
||||||
BYTES_PER_PROOF,
|
BYTES_PER_PROOF,
|
||||||
|
@ -24,6 +27,36 @@ const SETUP_FILE_PATH = existsSync(setupFileName)
|
||||||
|
|
||||||
const MAX_TOP_BYTE = 114;
|
const MAX_TOP_BYTE = 114;
|
||||||
|
|
||||||
|
const TEST_DIR = "../../tests";
|
||||||
|
const BLOB_TO_KZG_COMMITMENT_TESTS = path.join(
|
||||||
|
TEST_DIR,
|
||||||
|
"blob_to_kzg_commitment",
|
||||||
|
);
|
||||||
|
const COMPUTE_KZG_PROOF_TESTS = path.join(TEST_DIR, "compute_kzg_proof");
|
||||||
|
const COMPUTE_BLOB_KZG_PROOF_TESTS = path.join(
|
||||||
|
TEST_DIR,
|
||||||
|
"compute_blob_kzg_proof",
|
||||||
|
);
|
||||||
|
const VERIFY_KZG_PROOF_TESTS = path.join(TEST_DIR, "verify_kzg_proof");
|
||||||
|
const VERIFY_BLOB_KZG_PROOF_TESTS = path.join(
|
||||||
|
TEST_DIR,
|
||||||
|
"verify_blob_kzg_proof",
|
||||||
|
);
|
||||||
|
const VERIFY_BLOB_KZG_PROOF_BATCH_TESTS = path.join(
|
||||||
|
TEST_DIR,
|
||||||
|
"verify_blob_kzg_proof_batch",
|
||||||
|
);
|
||||||
|
|
||||||
|
function getBytes(file: String): Uint8Array {
|
||||||
|
const data = require("fs").readFileSync(file, "ascii");
|
||||||
|
return Buffer.from(data, "hex");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBoolean(file: String): boolean {
|
||||||
|
const data = require("fs").readFileSync(file, "ascii");
|
||||||
|
return data.includes("true");
|
||||||
|
}
|
||||||
|
|
||||||
const generateRandomBlob = () => {
|
const generateRandomBlob = () => {
|
||||||
return new Uint8Array(
|
return new Uint8Array(
|
||||||
randomBytes(BYTES_PER_BLOB).map((x, i) => {
|
randomBytes(BYTES_PER_BLOB).map((x, i) => {
|
||||||
|
@ -46,88 +79,129 @@ describe("C-KZG", () => {
|
||||||
freeTrustedSetup();
|
freeTrustedSetup();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("computes a proof from blob", () => {
|
describe("reference tests", () => {
|
||||||
let blob = generateRandomBlob();
|
it("blobToKzgCommitment", () => {
|
||||||
const zBytes = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(0);
|
let tests = fs.readdirSync(BLOB_TO_KZG_COMMITMENT_TESTS);
|
||||||
computeKzgProof(blob, zBytes);
|
tests.forEach((test) => {
|
||||||
// No check, just make sure it doesn't crash.
|
let testPath = path.join(BLOB_TO_KZG_COMMITMENT_TESTS, test);
|
||||||
|
let blob = getBytes(path.join(testPath, "blob.txt"));
|
||||||
|
try {
|
||||||
|
let commitment = blobToKzgCommitment(blob);
|
||||||
|
let expectedCommitment = getBytes(
|
||||||
|
path.join(testPath, "commitment.txt"),
|
||||||
|
);
|
||||||
|
expect(commitment.buffer).toEqual(expectedCommitment.buffer);
|
||||||
|
} catch (err) {
|
||||||
|
expect(fs.existsSync(path.join(testPath, "commitment.txt"))).toBe(
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("computeKzgProof", () => {
|
||||||
|
let tests = fs.readdirSync(COMPUTE_KZG_PROOF_TESTS);
|
||||||
|
tests.forEach((test) => {
|
||||||
|
let testPath = path.join(COMPUTE_KZG_PROOF_TESTS, test);
|
||||||
|
let blob = getBytes(path.join(testPath, "blob.txt"));
|
||||||
|
let inputPoint = getBytes(path.join(testPath, "input_point.txt"));
|
||||||
|
try {
|
||||||
|
let proof = computeKzgProof(blob, inputPoint);
|
||||||
|
let expectedProof = getBytes(path.join(testPath, "proof.txt"));
|
||||||
|
expect(proof.buffer).toEqual(expectedProof.buffer);
|
||||||
|
} catch (err) {
|
||||||
|
expect(fs.existsSync(path.join(testPath, "proof.txt"))).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("computeBlobKzgProof", () => {
|
||||||
|
let tests = fs.readdirSync(COMPUTE_BLOB_KZG_PROOF_TESTS);
|
||||||
|
tests.forEach((test) => {
|
||||||
|
let testPath = path.join(COMPUTE_BLOB_KZG_PROOF_TESTS, test);
|
||||||
|
let blob = getBytes(path.join(testPath, "blob.txt"));
|
||||||
|
try {
|
||||||
|
let proof = computeBlobKzgProof(blob);
|
||||||
|
let expectedProof = getBytes(path.join(testPath, "proof.txt"));
|
||||||
|
expect(proof.buffer).toEqual(expectedProof.buffer);
|
||||||
|
} catch (err) {
|
||||||
|
expect(fs.existsSync(path.join(testPath, "proof.txt"))).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("verifyKzgProof", () => {
|
||||||
|
let tests = fs.readdirSync(VERIFY_KZG_PROOF_TESTS);
|
||||||
|
tests.forEach((test) => {
|
||||||
|
let testPath = path.join(VERIFY_KZG_PROOF_TESTS, test);
|
||||||
|
let commitment = getBytes(path.join(testPath, "commitment.txt"));
|
||||||
|
let inputPoint = getBytes(path.join(testPath, "input_point.txt"));
|
||||||
|
let claimedValue = getBytes(path.join(testPath, "claimed_value.txt"));
|
||||||
|
let proof = getBytes(path.join(testPath, "proof.txt"));
|
||||||
|
try {
|
||||||
|
let ok = verifyKzgProof(commitment, inputPoint, claimedValue, proof);
|
||||||
|
let expectedOk = getBoolean(path.join(testPath, "ok.txt"));
|
||||||
|
expect(ok).toEqual(expectedOk);
|
||||||
|
} catch (err) {
|
||||||
|
expect(fs.existsSync(path.join(testPath, "ok.txt"))).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("verifyBlobKzgProof", () => {
|
||||||
|
let tests = fs.readdirSync(VERIFY_BLOB_KZG_PROOF_TESTS);
|
||||||
|
tests.forEach((test) => {
|
||||||
|
let testPath = path.join(VERIFY_BLOB_KZG_PROOF_TESTS, test);
|
||||||
|
let blob = getBytes(path.join(testPath, "blob.txt"));
|
||||||
|
let commitment = getBytes(path.join(testPath, "commitment.txt"));
|
||||||
|
let proof = getBytes(path.join(testPath, "proof.txt"));
|
||||||
|
try {
|
||||||
|
let ok = verifyBlobKzgProof(blob, commitment, proof);
|
||||||
|
let expectedOk = getBoolean(path.join(testPath, "ok.txt"));
|
||||||
|
expect(ok).toEqual(expectedOk);
|
||||||
|
} catch (err) {
|
||||||
|
expect(fs.existsSync(path.join(testPath, "ok.txt"))).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("verifyBlobKzgProofBatch", () => {
|
||||||
|
let tests = fs.readdirSync(VERIFY_BLOB_KZG_PROOF_BATCH_TESTS);
|
||||||
|
tests.forEach((test) => {
|
||||||
|
let testPath = path.join(VERIFY_BLOB_KZG_PROOF_BATCH_TESTS, test);
|
||||||
|
let blobs = fs
|
||||||
|
.readdirSync(path.join(testPath, "blobs"))
|
||||||
|
.sort()
|
||||||
|
.map((filename) => {
|
||||||
|
return path.join(testPath, "blobs", filename);
|
||||||
|
})
|
||||||
|
.map(getBytes);
|
||||||
|
let commitments = fs
|
||||||
|
.readdirSync(path.join(testPath, "commitments"))
|
||||||
|
.sort()
|
||||||
|
.map((filename) => {
|
||||||
|
return path.join(testPath, "commitments", filename);
|
||||||
|
})
|
||||||
|
.map(getBytes);
|
||||||
|
let proofs = fs
|
||||||
|
.readdirSync(path.join(testPath, "proofs"))
|
||||||
|
.sort()
|
||||||
|
.map((filename) => {
|
||||||
|
return path.join(testPath, "proofs", filename);
|
||||||
|
})
|
||||||
|
.map(getBytes);
|
||||||
|
try {
|
||||||
|
let ok = verifyBlobKzgProofBatch(blobs, commitments, proofs);
|
||||||
|
let expectedOk = getBoolean(path.join(testPath, "ok.txt"));
|
||||||
|
expect(ok).toEqual(expectedOk);
|
||||||
|
} catch (err) {
|
||||||
|
expect(fs.existsSync(path.join(testPath, "ok.txt"))).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("computes the correct commitments and aggregate proof from blobs", () => {
|
describe("blobToKzgCommitment", () => {
|
||||||
let blobs = new Array(2).fill(0).map(generateRandomBlob);
|
|
||||||
let commitments = blobs.map(blobToKzgCommitment);
|
|
||||||
let proof = computeAggregateKzgProof(blobs);
|
|
||||||
expect(verifyAggregateKzgProof(blobs, commitments, proof)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
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(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("verifies the aggregate proof of empty blobs and commitments", () => {
|
|
||||||
expect(verifyAggregateKzgProof([], [], computeAggregateKzgProof([]))).toBe(
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("verifies a valid KZG proof", () => {
|
|
||||||
const commitment = new Uint8Array(BYTES_PER_COMMITMENT).fill(0);
|
|
||||||
commitment[0] = 0xc0;
|
|
||||||
const z = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(0);
|
|
||||||
const y = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(0);
|
|
||||||
const proof = new Uint8Array(BYTES_PER_PROOF).fill(0);
|
|
||||||
proof[0] = 0xc0;
|
|
||||||
|
|
||||||
expect(verifyKzgProof(commitment, z, y, proof)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("verifies an invalid valid KZG proof", () => {
|
|
||||||
const commitment = new Uint8Array(BYTES_PER_COMMITMENT).fill(0);
|
|
||||||
commitment[0] = 0xc0;
|
|
||||||
const z = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(1);
|
|
||||||
const y = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(1);
|
|
||||||
const proof = new Uint8Array(BYTES_PER_PROOF).fill(0);
|
|
||||||
proof[0] = 0xc0;
|
|
||||||
|
|
||||||
expect(verifyKzgProof(commitment, z, y, proof)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("computes the aggregate proof when for a single blob", () => {
|
|
||||||
let blobs = new Array(1).fill(0).map(generateRandomBlob);
|
|
||||||
let commitments = blobs.map(blobToKzgCommitment);
|
|
||||||
let proof = computeAggregateKzgProof(blobs);
|
|
||||||
expect(verifyAggregateKzgProof(blobs, commitments, proof)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("fails when given incorrect commitments", () => {
|
|
||||||
const blobs = new Array(2).fill(0).map(generateRandomBlob);
|
|
||||||
const commitments = blobs.map(blobToKzgCommitment);
|
|
||||||
commitments[0][0] = commitments[0][0] === 0 ? 1 : 0; // Mutate the commitment
|
|
||||||
const proof = computeAggregateKzgProof(blobs);
|
|
||||||
expect(() =>
|
|
||||||
verifyAggregateKzgProof(blobs, commitments, proof),
|
|
||||||
).toThrowError("verify_aggregate_kzg_proof failed with error code: 1");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("throws the expected error when given fewer commitments than blobs", () => {
|
|
||||||
let blobs = new Array(1).fill(0).map(generateRandomBlob);
|
|
||||||
let commitments = [] as Uint8Array[];
|
|
||||||
let proof = computeAggregateKzgProof(blobs);
|
|
||||||
expect(() =>
|
|
||||||
verifyAggregateKzgProof(blobs, commitments, proof),
|
|
||||||
).toThrowError(
|
|
||||||
"verifyAggregateKzgProof requires blobs count to match expectedKzgCommitments count",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("computing commitment from blobs", () => {
|
|
||||||
it("throws as expected when given an argument of invalid type", () => {
|
it("throws as expected when given an argument of invalid type", () => {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
expect(() => blobToKzgCommitment("wrong type")).toThrowError(
|
expect(() => blobToKzgCommitment("wrong type")).toThrowError(
|
||||||
|
@ -141,4 +215,96 @@ describe("C-KZG", () => {
|
||||||
).toThrowError("Expected blob to be UInt8Array of 131072 bytes");
|
).toThrowError("Expected blob to be UInt8Array of 131072 bytes");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("computeKzgProof", () => {
|
||||||
|
it("computes a proof from blob/field element", () => {
|
||||||
|
let blob = generateRandomBlob();
|
||||||
|
const zBytes = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(0);
|
||||||
|
computeKzgProof(blob, zBytes);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("computeBlobKzgProof", () => {
|
||||||
|
it("computes a proof from blob", () => {
|
||||||
|
let blob = generateRandomBlob();
|
||||||
|
computeBlobKzgProof(blob);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("verifyKzgProof", () => {
|
||||||
|
it("valid proof", () => {
|
||||||
|
const commitment = new Uint8Array(BYTES_PER_COMMITMENT).fill(0);
|
||||||
|
commitment[0] = 0xc0;
|
||||||
|
const z = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(0);
|
||||||
|
const y = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(0);
|
||||||
|
const proof = new Uint8Array(BYTES_PER_PROOF).fill(0);
|
||||||
|
proof[0] = 0xc0;
|
||||||
|
|
||||||
|
expect(verifyKzgProof(commitment, z, y, proof)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("invalid proof", () => {
|
||||||
|
const commitment = new Uint8Array(BYTES_PER_COMMITMENT).fill(0);
|
||||||
|
commitment[0] = 0xc0;
|
||||||
|
const z = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(1);
|
||||||
|
const y = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(1);
|
||||||
|
const proof = new Uint8Array(BYTES_PER_PROOF).fill(0);
|
||||||
|
proof[0] = 0xc0;
|
||||||
|
|
||||||
|
expect(verifyKzgProof(commitment, z, y, proof)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("verifyBlobKzgProof", () => {
|
||||||
|
it("correct blob/commitment/proof", () => {
|
||||||
|
let blob = generateRandomBlob();
|
||||||
|
let commitment = blobToKzgCommitment(blob);
|
||||||
|
let proof = computeBlobKzgProof(blob);
|
||||||
|
expect(verifyBlobKzgProof(blob, commitment, proof)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("incorrect commitment", () => {
|
||||||
|
let blob = generateRandomBlob();
|
||||||
|
let commitment = blobToKzgCommitment(generateRandomBlob());
|
||||||
|
let proof = computeBlobKzgProof(blob);
|
||||||
|
expect(verifyBlobKzgProof(blob, commitment, proof)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("incorrect proof", () => {
|
||||||
|
let blob = generateRandomBlob();
|
||||||
|
let commitment = blobToKzgCommitment(blob);
|
||||||
|
let proof = computeBlobKzgProof(generateRandomBlob());
|
||||||
|
expect(verifyBlobKzgProof(blob, commitment, proof)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("verifyBlobKzgProofBatch", () => {
|
||||||
|
it("zero blobs/commitments/proofs", () => {
|
||||||
|
expect(verifyBlobKzgProofBatch([], [], [])).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("mismatching blobs/commitments/proofs count", () => {
|
||||||
|
let count = 3;
|
||||||
|
let blobs = new Array(count);
|
||||||
|
let commitments = new Array(count);
|
||||||
|
let proofs = new Array(count);
|
||||||
|
|
||||||
|
for (let [i, _] of blobs.entries()) {
|
||||||
|
blobs[i] = generateRandomBlob();
|
||||||
|
commitments[i] = blobToKzgCommitment(blobs[i]);
|
||||||
|
proofs[i] = computeBlobKzgProof(blobs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(verifyBlobKzgProofBatch(blobs, commitments, proofs)).toBe(true);
|
||||||
|
expect(() =>
|
||||||
|
verifyBlobKzgProofBatch(blobs.slice(0, 1), commitments, proofs),
|
||||||
|
).toThrowError("requires equal number of blobs/commitments/proofs");
|
||||||
|
expect(() =>
|
||||||
|
verifyBlobKzgProofBatch(blobs, commitments.slice(0, 1), proofs),
|
||||||
|
).toThrowError("requires equal number of blobs/commitments/proofs");
|
||||||
|
expect(() =>
|
||||||
|
verifyBlobKzgProofBatch(blobs, commitments, proofs.slice(0, 1)),
|
||||||
|
).toThrowError("requires equal number of blobs/commitments/proofs");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue