Check UInt8Array lengths (#126)
This commit is contained in:
parent
128dd3eb1f
commit
8aa78231f2
|
@ -353,8 +353,11 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
|||
exports["verifyAggregateKzgProof"] = Napi::Function::New(env, VerifyAggregateKzgProof);
|
||||
|
||||
// Constants
|
||||
exports["FIELD_ELEMENTS_PER_BLOB"] = Napi::Number::New(env, FIELD_ELEMENTS_PER_BLOB);
|
||||
exports["BYTES_PER_BLOB"] = Napi::Number::New(env, BYTES_PER_BLOB);
|
||||
exports["BYTES_PER_COMMITMENT"] = Napi::Number::New(env, BYTES_PER_COMMITMENT);
|
||||
exports["BYTES_PER_FIELD_ELEMENT"] = Napi::Number::New(env, BYTES_PER_FIELD_ELEMENT);
|
||||
exports["BYTES_PER_PROOF"] = Napi::Number::New(env, BYTES_PER_PROOF);
|
||||
exports["FIELD_ELEMENTS_PER_BLOB"] = Napi::Number::New(env, FIELD_ELEMENTS_PER_BLOB);
|
||||
|
||||
return exports;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,11 @@ type SetupHandle = Object;
|
|||
|
||||
// The C++ native addon interface
|
||||
type KZG = {
|
||||
FIELD_ELEMENTS_PER_BLOB: number;
|
||||
BYTES_PER_BLOB: number;
|
||||
BYTES_PER_COMMITMENT: number;
|
||||
BYTES_PER_FIELD_ELEMENT: number;
|
||||
BYTES_PER_PROOF: number;
|
||||
FIELD_ELEMENTS_PER_BLOB: number;
|
||||
|
||||
loadTrustedSetup: (filePath: string) => SetupHandle;
|
||||
|
||||
|
@ -58,8 +61,11 @@ type TrustedSetupJSON = {
|
|||
roots_of_unity: string[];
|
||||
};
|
||||
|
||||
export const FIELD_ELEMENTS_PER_BLOB = kzg.FIELD_ELEMENTS_PER_BLOB;
|
||||
export const BYTES_PER_BLOB = kzg.BYTES_PER_BLOB;
|
||||
export const BYTES_PER_COMMITMENT = kzg.BYTES_PER_COMMITMENT;
|
||||
export const BYTES_PER_FIELD_ELEMENT = kzg.BYTES_PER_FIELD_ELEMENT;
|
||||
export const BYTES_PER_PROOF = kzg.BYTES_PER_PROOF;
|
||||
export const FIELD_ELEMENTS_PER_BLOB = kzg.FIELD_ELEMENTS_PER_BLOB;
|
||||
|
||||
// Stored as internal state
|
||||
let setupHandle: SetupHandle | undefined;
|
||||
|
@ -71,6 +77,50 @@ function requireSetupHandle(): SetupHandle {
|
|||
return setupHandle;
|
||||
}
|
||||
|
||||
function checkBlob(blob: Blob) {
|
||||
if (blob.length != BYTES_PER_BLOB) {
|
||||
throw new Error(
|
||||
`Expected blob to be UInt8Array of ${BYTES_PER_BLOB} bytes.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function checkBlobs(blobs: Blob[]) {
|
||||
for (let blob of blobs) {
|
||||
checkBlob(blob);
|
||||
}
|
||||
}
|
||||
|
||||
function checkCommitment(commitment: KZGCommitment) {
|
||||
if (commitment.length != BYTES_PER_COMMITMENT) {
|
||||
throw new Error(
|
||||
`Expected commitment to be UInt8Array of ${BYTES_PER_COMMITMENT} bytes.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function checkCommitments(commitments: KZGCommitment[]) {
|
||||
for (let commitment of commitments) {
|
||||
checkCommitment(commitment);
|
||||
}
|
||||
}
|
||||
|
||||
function checkProof(proof: KZGProof) {
|
||||
if (proof.length != BYTES_PER_PROOF) {
|
||||
throw new Error(
|
||||
`Expected proof to be UInt8Array of ${BYTES_PER_PROOF} bytes.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function checkFieldElement(field: Bytes32) {
|
||||
if (field.length != BYTES_PER_FIELD_ELEMENT) {
|
||||
throw new Error(
|
||||
`Expected field element to be UInt8Array of ${BYTES_PER_FIELD_ELEMENT} bytes.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function transformTrustedSetupJSON(
|
||||
filePath: string,
|
||||
): Promise<string> {
|
||||
|
@ -113,14 +163,18 @@ export function freeTrustedSetup(): void {
|
|||
}
|
||||
|
||||
export function blobToKzgCommitment(blob: Blob): KZGCommitment {
|
||||
checkBlob(blob);
|
||||
return kzg.blobToKzgCommitment(blob, requireSetupHandle());
|
||||
}
|
||||
|
||||
export function computeKzgProof(blob: Blob, zBytes: Bytes32): KZGProof {
|
||||
checkBlob(blob);
|
||||
checkFieldElement(zBytes);
|
||||
return kzg.computeKzgProof(blob, zBytes, requireSetupHandle());
|
||||
}
|
||||
|
||||
export function computeAggregateKzgProof(blobs: Blob[]): KZGProof {
|
||||
checkBlobs(blobs);
|
||||
return kzg.computeAggregateKzgProof(blobs, requireSetupHandle());
|
||||
}
|
||||
|
||||
|
@ -130,6 +184,10 @@ export function verifyKzgProof(
|
|||
yBytes: Bytes32,
|
||||
proofBytes: Bytes48,
|
||||
): boolean {
|
||||
checkCommitment(commitmentBytes);
|
||||
checkFieldElement(zBytes);
|
||||
checkFieldElement(yBytes);
|
||||
checkProof(proofBytes);
|
||||
return kzg.verifyKzgProof(
|
||||
commitmentBytes,
|
||||
zBytes,
|
||||
|
@ -144,6 +202,9 @@ export function verifyAggregateKzgProof(
|
|||
commitmentsBytes: Bytes48[],
|
||||
proofBytes: Bytes48,
|
||||
): boolean {
|
||||
checkBlobs(blobs);
|
||||
checkCommitments(commitmentsBytes);
|
||||
checkProof(proofBytes);
|
||||
return kzg.verifyAggregateKzgProof(
|
||||
blobs,
|
||||
commitmentsBytes,
|
||||
|
|
|
@ -9,8 +9,10 @@ import {
|
|||
computeKzgProof,
|
||||
computeAggregateKzgProof,
|
||||
verifyAggregateKzgProof,
|
||||
BYTES_PER_BLOB,
|
||||
BYTES_PER_COMMITMENT,
|
||||
BYTES_PER_PROOF,
|
||||
BYTES_PER_FIELD_ELEMENT,
|
||||
FIELD_ELEMENTS_PER_BLOB,
|
||||
transformTrustedSetupJSON,
|
||||
} from "./kzg";
|
||||
|
||||
|
@ -20,13 +22,11 @@ const SETUP_FILE_PATH = existsSync(setupFileName)
|
|||
? setupFileName
|
||||
: `../../src/${setupFileName}`;
|
||||
|
||||
const BLOB_BYTE_COUNT = FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT;
|
||||
|
||||
const MAX_TOP_BYTE = 114;
|
||||
|
||||
const generateRandomBlob = () => {
|
||||
return new Uint8Array(
|
||||
randomBytes(BLOB_BYTE_COUNT).map((x, i) => {
|
||||
randomBytes(BYTES_PER_BLOB).map((x, i) => {
|
||||
// Set the top byte to be low enough that the field element doesn't overflow the BLS modulus
|
||||
if (x > MAX_TOP_BYTE && i % BYTES_PER_FIELD_ELEMENT == 31) {
|
||||
return Math.floor(Math.random() * MAX_TOP_BYTE);
|
||||
|
@ -48,7 +48,7 @@ describe("C-KZG", () => {
|
|||
|
||||
it("computes a proof from blob", () => {
|
||||
let blob = generateRandomBlob();
|
||||
const zBytes = new Uint8Array(32).fill(0);
|
||||
const zBytes = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(0);
|
||||
computeKzgProof(blob, zBytes);
|
||||
// No check, just make sure it doesn't crash.
|
||||
});
|
||||
|
@ -78,22 +78,22 @@ describe("C-KZG", () => {
|
|||
});
|
||||
|
||||
it("verifies a valid KZG proof", () => {
|
||||
const commitment = new Uint8Array(48).fill(0);
|
||||
const commitment = new Uint8Array(BYTES_PER_COMMITMENT).fill(0);
|
||||
commitment[0] = 0xc0;
|
||||
const z = new Uint8Array(32).fill(0);
|
||||
const y = new Uint8Array(32).fill(0);
|
||||
const proof = new Uint8Array(48).fill(0);
|
||||
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(48).fill(0);
|
||||
const commitment = new Uint8Array(BYTES_PER_COMMITMENT).fill(0);
|
||||
commitment[0] = 0xc0;
|
||||
const z = new Uint8Array(32).fill(1);
|
||||
const y = new Uint8Array(32).fill(1);
|
||||
const proof = new Uint8Array(48).fill(0);
|
||||
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);
|
||||
|
@ -131,8 +131,14 @@ describe("C-KZG", () => {
|
|||
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",
|
||||
"Expected blob to be UInt8Array of 131072 bytes",
|
||||
);
|
||||
});
|
||||
|
||||
it("throws as expected when given an argument of invalid length", () => {
|
||||
expect(() =>
|
||||
blobToKzgCommitment(randomBytes(BYTES_PER_BLOB - 1)),
|
||||
).toThrowError("Expected blob to be UInt8Array of 131072 bytes");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue