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);
|
exports["verifyAggregateKzgProof"] = Napi::Function::New(env, VerifyAggregateKzgProof);
|
||||||
|
|
||||||
// Constants
|
// 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_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;
|
return exports;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,11 @@ type SetupHandle = Object;
|
||||||
|
|
||||||
// The C++ native addon interface
|
// The C++ native addon interface
|
||||||
type KZG = {
|
type KZG = {
|
||||||
FIELD_ELEMENTS_PER_BLOB: number;
|
BYTES_PER_BLOB: number;
|
||||||
|
BYTES_PER_COMMITMENT: number;
|
||||||
BYTES_PER_FIELD_ELEMENT: number;
|
BYTES_PER_FIELD_ELEMENT: number;
|
||||||
|
BYTES_PER_PROOF: number;
|
||||||
|
FIELD_ELEMENTS_PER_BLOB: number;
|
||||||
|
|
||||||
loadTrustedSetup: (filePath: string) => SetupHandle;
|
loadTrustedSetup: (filePath: string) => SetupHandle;
|
||||||
|
|
||||||
|
@ -58,8 +61,11 @@ type TrustedSetupJSON = {
|
||||||
roots_of_unity: string[];
|
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_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
|
// Stored as internal state
|
||||||
let setupHandle: SetupHandle | undefined;
|
let setupHandle: SetupHandle | undefined;
|
||||||
|
@ -71,6 +77,50 @@ function requireSetupHandle(): SetupHandle {
|
||||||
return 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(
|
export async function transformTrustedSetupJSON(
|
||||||
filePath: string,
|
filePath: string,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
|
@ -113,14 +163,18 @@ export function freeTrustedSetup(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function blobToKzgCommitment(blob: Blob): KZGCommitment {
|
export function blobToKzgCommitment(blob: Blob): KZGCommitment {
|
||||||
|
checkBlob(blob);
|
||||||
return kzg.blobToKzgCommitment(blob, requireSetupHandle());
|
return kzg.blobToKzgCommitment(blob, requireSetupHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function computeKzgProof(blob: Blob, zBytes: Bytes32): KZGProof {
|
export function computeKzgProof(blob: Blob, zBytes: Bytes32): KZGProof {
|
||||||
|
checkBlob(blob);
|
||||||
|
checkFieldElement(zBytes);
|
||||||
return kzg.computeKzgProof(blob, zBytes, requireSetupHandle());
|
return kzg.computeKzgProof(blob, zBytes, requireSetupHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function computeAggregateKzgProof(blobs: Blob[]): KZGProof {
|
export function computeAggregateKzgProof(blobs: Blob[]): KZGProof {
|
||||||
|
checkBlobs(blobs);
|
||||||
return kzg.computeAggregateKzgProof(blobs, requireSetupHandle());
|
return kzg.computeAggregateKzgProof(blobs, requireSetupHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +184,10 @@ export function verifyKzgProof(
|
||||||
yBytes: Bytes32,
|
yBytes: Bytes32,
|
||||||
proofBytes: Bytes48,
|
proofBytes: Bytes48,
|
||||||
): boolean {
|
): boolean {
|
||||||
|
checkCommitment(commitmentBytes);
|
||||||
|
checkFieldElement(zBytes);
|
||||||
|
checkFieldElement(yBytes);
|
||||||
|
checkProof(proofBytes);
|
||||||
return kzg.verifyKzgProof(
|
return kzg.verifyKzgProof(
|
||||||
commitmentBytes,
|
commitmentBytes,
|
||||||
zBytes,
|
zBytes,
|
||||||
|
@ -144,6 +202,9 @@ export function verifyAggregateKzgProof(
|
||||||
commitmentsBytes: Bytes48[],
|
commitmentsBytes: Bytes48[],
|
||||||
proofBytes: Bytes48,
|
proofBytes: Bytes48,
|
||||||
): boolean {
|
): boolean {
|
||||||
|
checkBlobs(blobs);
|
||||||
|
checkCommitments(commitmentsBytes);
|
||||||
|
checkProof(proofBytes);
|
||||||
return kzg.verifyAggregateKzgProof(
|
return kzg.verifyAggregateKzgProof(
|
||||||
blobs,
|
blobs,
|
||||||
commitmentsBytes,
|
commitmentsBytes,
|
||||||
|
|
|
@ -9,8 +9,10 @@ import {
|
||||||
computeKzgProof,
|
computeKzgProof,
|
||||||
computeAggregateKzgProof,
|
computeAggregateKzgProof,
|
||||||
verifyAggregateKzgProof,
|
verifyAggregateKzgProof,
|
||||||
|
BYTES_PER_BLOB,
|
||||||
|
BYTES_PER_COMMITMENT,
|
||||||
|
BYTES_PER_PROOF,
|
||||||
BYTES_PER_FIELD_ELEMENT,
|
BYTES_PER_FIELD_ELEMENT,
|
||||||
FIELD_ELEMENTS_PER_BLOB,
|
|
||||||
transformTrustedSetupJSON,
|
transformTrustedSetupJSON,
|
||||||
} from "./kzg";
|
} from "./kzg";
|
||||||
|
|
||||||
|
@ -20,13 +22,11 @@ const SETUP_FILE_PATH = existsSync(setupFileName)
|
||||||
? setupFileName
|
? setupFileName
|
||||||
: `../../src/${setupFileName}`;
|
: `../../src/${setupFileName}`;
|
||||||
|
|
||||||
const BLOB_BYTE_COUNT = FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT;
|
|
||||||
|
|
||||||
const MAX_TOP_BYTE = 114;
|
const MAX_TOP_BYTE = 114;
|
||||||
|
|
||||||
const generateRandomBlob = () => {
|
const generateRandomBlob = () => {
|
||||||
return new Uint8Array(
|
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
|
// 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) {
|
if (x > MAX_TOP_BYTE && i % BYTES_PER_FIELD_ELEMENT == 31) {
|
||||||
return Math.floor(Math.random() * MAX_TOP_BYTE);
|
return Math.floor(Math.random() * MAX_TOP_BYTE);
|
||||||
|
@ -48,7 +48,7 @@ describe("C-KZG", () => {
|
||||||
|
|
||||||
it("computes a proof from blob", () => {
|
it("computes a proof from blob", () => {
|
||||||
let blob = generateRandomBlob();
|
let blob = generateRandomBlob();
|
||||||
const zBytes = new Uint8Array(32).fill(0);
|
const zBytes = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(0);
|
||||||
computeKzgProof(blob, zBytes);
|
computeKzgProof(blob, zBytes);
|
||||||
// No check, just make sure it doesn't crash.
|
// No check, just make sure it doesn't crash.
|
||||||
});
|
});
|
||||||
|
@ -78,22 +78,22 @@ describe("C-KZG", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("verifies a valid KZG proof", () => {
|
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;
|
commitment[0] = 0xc0;
|
||||||
const z = new Uint8Array(32).fill(0);
|
const z = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(0);
|
||||||
const y = new Uint8Array(32).fill(0);
|
const y = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(0);
|
||||||
const proof = new Uint8Array(48).fill(0);
|
const proof = new Uint8Array(BYTES_PER_PROOF).fill(0);
|
||||||
proof[0] = 0xc0;
|
proof[0] = 0xc0;
|
||||||
|
|
||||||
expect(verifyKzgProof(commitment, z, y, proof)).toBe(true);
|
expect(verifyKzgProof(commitment, z, y, proof)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("verifies an invalid valid KZG proof", () => {
|
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;
|
commitment[0] = 0xc0;
|
||||||
const z = new Uint8Array(32).fill(1);
|
const z = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(1);
|
||||||
const y = new Uint8Array(32).fill(1);
|
const y = new Uint8Array(BYTES_PER_FIELD_ELEMENT).fill(1);
|
||||||
const proof = new Uint8Array(48).fill(0);
|
const proof = new Uint8Array(BYTES_PER_PROOF).fill(0);
|
||||||
proof[0] = 0xc0;
|
proof[0] = 0xc0;
|
||||||
|
|
||||||
expect(verifyKzgProof(commitment, z, y, proof)).toBe(false);
|
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", () => {
|
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(
|
||||||
"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