diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index a92637da6541..c258870f5437 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -105,6 +105,7 @@ "@chainsafe/prometheus-gc-stats": "^1.0.0", "@chainsafe/ssz": "^0.17.0", "@chainsafe/threads": "^1.11.1", + "@crate-crypto/node-eth-kzg": "0.4.1", "@ethersproject/abi": "^5.7.0", "@fastify/bearer-auth": "^9.0.0", "@fastify/cors": "^8.2.1", @@ -167,4 +168,4 @@ "beacon", "blockchain" ] -} +} \ No newline at end of file diff --git a/packages/beacon-node/src/util/kzg.ts b/packages/beacon-node/src/util/kzg.ts index b5f32d89db76..2ce1b3c41e7c 100644 --- a/packages/beacon-node/src/util/kzg.ts +++ b/packages/beacon-node/src/util/kzg.ts @@ -1,6 +1,7 @@ import path from "node:path"; import fs from "node:fs"; import {fileURLToPath} from "node:url"; +import {DasContextJs} from "@crate-crypto/node-eth-kzg"; import {fromHex, toHex} from "@lodestar/utils"; /* eslint-disable @typescript-eslint/naming-convention */ @@ -8,6 +9,12 @@ import {fromHex, toHex} from "@lodestar/utils"; // "c-kzg" has hardcoded the mainnet value, do not use params export const FIELD_ELEMENTS_PER_BLOB_MAINNET = 4096; +// A constant to switch between the two libraries at compile time +declare let USE_PEERDAS_KZG: boolean | undefined; +if (typeof USE_PEERDAS_KZG === "undefined") { + USE_PEERDAS_KZG = false; // use c-kzg by default, if the constant is not set +} + function ckzgNotLoaded(): never { throw Error("c-kzg library not loaded"); } @@ -19,11 +26,19 @@ export let ckzg: { computeBlobKzgProof(blob: Uint8Array, commitment: Uint8Array): Uint8Array; verifyBlobKzgProof(blob: Uint8Array, commitment: Uint8Array, proof: Uint8Array): boolean; verifyBlobKzgProofBatch(blobs: Uint8Array[], expectedKzgCommitments: Uint8Array[], kzgProofs: Uint8Array[]): boolean; + // TODO:This is deprecated computeCells(blob: Uint8Array): Uint8Array[]; computeCellsAndKzgProofs(blob: Uint8Array): [Uint8Array[], Uint8Array[]]; + // TODO:This is deprecated cellsToBlob(cells: Uint8Array[]): Uint8Array; + // TODO:This is deprecated for recoverCellsAndKzgProofs recoverAllCells(cellIds: number[], cells: Uint8Array[]): Uint8Array[]; + // TODO: The uncommented function `recoverCellsAndKzgProofs` is what the new API should look like. + // recoverCellsAndKzgProofs(cellIndices: number[], cells: Uint8Array[]): [Uint8Array[], Uint8Array[]]; + // TODO: This is deprecated verifyCellKzgProof(commitmentBytes: Uint8Array, cellId: number, cell: Uint8Array, proofBytes: Uint8Array): boolean; + // TODO: This API no longer takes rowIndices. The commitmentBytes are duplicated. + // TODO: To update to the new API, one can do something like `commitmentBytes = rowIndices.map(|index| commitmentBytes[index]).collect()` verifyCellKzgProofBatch( commitmentsBytes: Uint8Array[], rowIndices: number[], @@ -60,6 +75,9 @@ const G1POINT_COUNT = FIELD_ELEMENTS_PER_BLOB_MAINNET; const G2POINT_COUNT = 65; const TOTAL_SIZE = 2 * POINT_COUNT_BYTES + G1POINT_BYTES * G1POINT_COUNT + G2POINT_BYTES * G2POINT_COUNT; +// TODO: We can think of a better way to initialize this +let RustEthKzgContext: DasContextJs; + export async function initCKZG(): Promise { /* eslint-disable @typescript-eslint/ban-ts-comment */ // @ts-ignore @@ -83,6 +101,7 @@ export function loadEthereumTrustedSetup( filePath?: string ): void { try { + RustEthKzgContext = new DasContextJs(); let setupFilePath; if (mode === TrustedFileMode.Bin) { const binPath = filePath ?? TRUSTED_SETUP_BIN_FILEPATH; @@ -183,3 +202,44 @@ function strip0xPrefix(hex: string): string { return hex; } } + +export function computeCellsAndKzgProofs(blob: Uint8Array): [Uint8Array[], Uint8Array[]] { + if (USE_PEERDAS_KZG) { + const cellsAndProofs = RustEthKzgContext.computeCellsAndKzgProofs(blob); + return [cellsAndProofs.cells, cellsAndProofs.proofs]; + } else { + return ckzg.computeCellsAndKzgProofs(blob); + } +} + +export function verifyCellKzgProofBatch( + commitmentsBytes: Uint8Array[], + cellIndices: number[], + cells: Uint8Array[], + proofsBytes: Uint8Array[] +): boolean { + if (USE_PEERDAS_KZG) { + // Note: The library requires `BigInt` since the specs define a u64. + // Left it as `number` in the API to note break anything. + const cellIndicesBigInt: bigint[] = cellIndices.map(BigInt); + return RustEthKzgContext.verifyCellKzgProofBatch(commitmentsBytes, cellIndicesBigInt, cells, proofsBytes); + } else { + // TODO: We need to update the c-kzg dep, it points to `matthewkeil/c-kzg-4844#13aa01464479aa7c1ccafa64d52cbc17699ffa07` + // TODO: I'm not sure how to proceed, so will leave this to lodestar folks. + throw new Error("unimplemented"); + } +} + +export function recoverCellsAndKzgProofs(cellIndices: number[], cells: Uint8Array[]): [Uint8Array[], Uint8Array[]] { + if (USE_PEERDAS_KZG) { + // Note: The library requires `BigInt` since the specs define a u64. + // Left it as `number` in the API to note break anything. + const cellIndicesBigInt: bigint[] = cellIndices.map(BigInt); + const cellsAndProofs = RustEthKzgContext.recoverCellsAndKzgProofs(cellIndicesBigInt, cells); + return [cellsAndProofs.cells, cellsAndProofs.proofs]; + } else { + // TODO: We need to update the c-kzg dep, it points to `matthewkeil/c-kzg-4844#13aa01464479aa7c1ccafa64d52cbc17699ffa07` + // TODO: I'm not sure how to proceed, so will leave this to lodestar folks. + throw new Error("unimplemented"); + } +} diff --git a/yarn.lock b/yarn.lock index 199774826307..7b5ac26f716c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -619,6 +619,48 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== +"@crate-crypto/node-eth-kzg-darwin-arm64@0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@crate-crypto/node-eth-kzg-darwin-arm64/-/node-eth-kzg-darwin-arm64-0.4.1.tgz#dc1e03b253f89e7055a6dca478923d8181c0ab8b" + integrity sha512-+BIDuY2pvV5acHAaIZAJcsEQiaH65dRScNa4hieZLjE7qZ88ju8qss3tvZGvWw1haDPyBSVJPnFoqNhya7U/Dg== + +"@crate-crypto/node-eth-kzg-darwin-x64@0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@crate-crypto/node-eth-kzg-darwin-x64/-/node-eth-kzg-darwin-x64-0.4.1.tgz#d738b2cff467fdedb27689167c994969da538d4d" + integrity sha512-r552VuhqXL0xNynPH7sbdvTwxSlUyg84BazTgkucLPkysg1a8sUcX1Nov3gQommK6PwgmNYC2sE1EhBV4QULyw== + +"@crate-crypto/node-eth-kzg-linux-arm64-gnu@0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@crate-crypto/node-eth-kzg-linux-arm64-gnu/-/node-eth-kzg-linux-arm64-gnu-0.4.1.tgz#74744f6163691621e0c820401b062237335d2458" + integrity sha512-rLeOOb4PWkM6vCXmRPbadKd1nYzIOpRP9EK68N/gzLK+rPAIXzD1esWJ97X8UsA++AERAu1oaMXwwuC763RLMg== + +"@crate-crypto/node-eth-kzg-linux-x64-gnu@0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@crate-crypto/node-eth-kzg-linux-x64-gnu/-/node-eth-kzg-linux-x64-gnu-0.4.1.tgz#87d557a814a85f3f70d7b67e801ef164aa88e1dd" + integrity sha512-yUoG8XxDmz3e9gnXD+8b7YkS0HTruXd3Qta2ttQOhHG4qOuOMql6a4Z2qNPj98FMaRA8K8ehlXA8daPFelrasw== + +"@crate-crypto/node-eth-kzg-win32-arm64-msvc@0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@crate-crypto/node-eth-kzg-win32-arm64-msvc/-/node-eth-kzg-win32-arm64-msvc-0.4.1.tgz#de4305a52412e14d8c6fc4ed12e3f6204a226673" + integrity sha512-HyOfji8N2EXTQ3miKOqdylKMiS2umo2FsoUEB8A3rxwD2EwOYm8Z9Rrez42s9nefZQ1T3hqLoz6U8XWvnl4udA== + +"@crate-crypto/node-eth-kzg-win32-x64-msvc@0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@crate-crypto/node-eth-kzg-win32-x64-msvc/-/node-eth-kzg-win32-x64-msvc-0.4.1.tgz#2fdc66072af322a697daeec0dbddf71f5daa2505" + integrity sha512-9HPs1jTufEwBtyDJHXnhROrsHP+RdV29EvJXdX6/oSkdP/nawp0tDTaVJNsGQOLZaFCis96e2cLlty9Yk9wY5Q== + +"@crate-crypto/node-eth-kzg@0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@crate-crypto/node-eth-kzg/-/node-eth-kzg-0.4.1.tgz#6cd50f9b43888606aff02c247f5e399c4df51231" + integrity sha512-iidXyHI5iV7QVX8eDmLZ7pOrNSOJmaHeb3i8SBK60FHpEAfo48FYO4hNGFakF14djpn2w7EvtoHgO2hmWEvVSA== + optionalDependencies: + "@crate-crypto/node-eth-kzg-darwin-arm64" "0.4.1" + "@crate-crypto/node-eth-kzg-darwin-x64" "0.4.1" + "@crate-crypto/node-eth-kzg-linux-arm64-gnu" "0.4.1" + "@crate-crypto/node-eth-kzg-linux-x64-gnu" "0.4.1" + "@crate-crypto/node-eth-kzg-win32-arm64-msvc" "0.4.1" + "@crate-crypto/node-eth-kzg-win32-x64-msvc" "0.4.1" + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"