From 29e370e3687fbbdabb6613bc31641cba152345f0 Mon Sep 17 00:00:00 2001 From: Agnish Ghosh Date: Wed, 5 Jun 2024 12:55:02 +0530 Subject: [PATCH] add: EF test harness for KZG EIP7594 (Peerdas) --- tests/consensus_spec/test_fixture_kzg.nim | 173 ++++++++++++++++++++++ vendor/nim-kzg4844 | 2 +- 2 files changed, 174 insertions(+), 1 deletion(-) diff --git a/tests/consensus_spec/test_fixture_kzg.nim b/tests/consensus_spec/test_fixture_kzg.nim index 74ed97f11..6f0c44432 100644 --- a/tests/consensus_spec/test_fixture_kzg.nim +++ b/tests/consensus_spec/test_fixture_kzg.nim @@ -12,6 +12,7 @@ import std/json, yaml, kzg4844/kzg_ex, + stint, stew/[byteutils, results], ../testutil, ./fixtures_utils, ./os_ops @@ -19,6 +20,14 @@ import from std/sequtils import anyIt, mapIt, toSeq from std/strutils import rsplit +func toUInt64(s: int): Opt[uint64] = + if s < 0: + return Opt.none uint64 + try: + Opt.some uint64(s) + except ValueError: + Opt.none uint64 + func fromHex[N: static int](s: string): Opt[array[N, byte]] = if s.len != 2*(N+1): # 0x prefix @@ -183,6 +192,132 @@ proc runComputeBlobKzgProofTest(suiteName, suitePath, path: string) = else: check p.get == fromHex[48](output.getStr).get +proc runComputeCellsTest(suiteName2, suitePath2, path: string) = + let relativePathComponent = path.relativeTestPathComponent(suitePath2) + test "KZG - Compute Cells - " & relativePathComponent: + let + data = yaml.loadToJson(os_ops.readFile(path/"data.yaml"))[0] + output = data["output"] + blob = fromHex[131072](data["input"]["blob"].getStr) + + # https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.2/tests/formats/kzg_7594/verify_cell_kzg_proof.md#condition + # If the blob is invalid (e.g. incorrect length or one of the 32-byte + # blocks does not represent a BLS field element) it should error, i.e. the + # the output should be `null`. + if blob.isNone: + check output.kind == JNull + else: + let p = computeCells(blob.get) + if p.isErr: + check output.kind == JNull + else: + for i in 0..<128: + check p.get[i] == fromHex[2048](output.getStr).get + +proc runComputeCellsAndProofsTest(suiteName2, suitePath2, path: string) = + let relativePathComponent = path.relativeTestPathComponent(suitePath2) + test "KZG - Compute Cells And Proofs - " & relativePathComponent: + let + data = yaml.loadToJson(os_ops.readFile(path/"data.yaml"))[0] + output = data["output"] + blob = fromHex[131072](data["input"]["blob"].getStr) + + # https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.2/tests/formats/kzg_7594/verify_cell_kzg_proof.md#condition + # If the blob is invalid (e.g. incorrect length or one of the 32-byte + # blocks does not represent a BLS field element) it should error, i.e. the + # the output should be `null`. + if blob.isNone: + check output.kind == JNull + else: + let p = computeCellsAndProofs(blob.get) + if p.isErr: + check output.kind == JNull + else: + for i in 0..<128: + check p.get.cells[i] == fromHex[2048](output["cells"].getStr).get + check p.get.proofs[i] == fromHex[48](output["proofs"].getStr).get + +proc runVerifyCellKzgProofsTest(suiteName2, suitePath2, path: string) = + let relativePathComponent = path.relativeTestPathComponent(suitePath2) + test "KZG - Verify Cell Kzg Proof - " & relativePathComponent: + let + data = yaml.loadToJson(os_ops.readFile(path/"data.yaml"))[0] + output = data["output"] + commitment = fromHex[48](data["input"]["commitment"].getStr) + proof = fromHex[48](data["input"]["proof"].getStr) + cell = fromHex[2048](data["input"]["cell"].getStr) + cell_id = toUInt64(data["input"]["cell_id"].getInt) + + # https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.2/tests/formats/kzg_7594/verify_cell_kzg_proof.md#condition + # If the blob is invalid (e.g. incorrect length or one of the 32-byte + # blocks does not represent a BLS field element) it should error, i.e. the + # the output should be `null`. + if commitment.isNone or proof.isNone or cell.isNone or cell_id.isNone: + check output.kind == JNull + else: + let p = verifyCellKzgProof(commitment.get, cell_id.get, cell.get, proof.get) + if p.isErr: + check output.kind == JNull + else: + check p.get == output.getBool + +proc runVerifyCellKzgProofBatchTest(suiteName2, suitePath2, path: string) = + let relativePathCompnent = path.relativeTestPathComponent(suitePath2) + test "KZG - Verify Cell Kzg Proof Batch - " & relativePathCompnent: + let + data = yaml.loadToJson(os_ops.readFile(path/"data.yaml"))[0] + output = data["output"] + row_commitments = data["input"]["row_commitments"].mapIt(fromHex[48](it.getStr)) + row_indices = data["input"]["row_indices"].mapIt(toUInt64(it.getInt)) + column_indices = data["input"]["column_indices"].mapIt(toUInt64(it.getInt)) + cells = data["input"]["cells"].mapIt(fromHex[2048](it.getStr)) + proofs = data["input"]["proofs"].mapIt(fromHex[48](it.getStr)) + + # https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.2/tests/formats/kzg_7594/verify_cell_kzg_proof_batch.md#condition + # If the blob is invalid (e.g. incorrect length or one of the 32-byte + # blocks does not represent a BLS field element) it should error, i.e. the + # the output should be `null`. + if row_commitments.anyIt(it.isNone) or row_indices.anyIt(it.isNone) or + column_indices.anyIt(it.isNone) or proofs.anyIt(it.isNone) or + cells.anyIt(it.isNone): + check output.kind == JNull + else: + let v = verifyCellKzgProofBatch( + row_commitments.mapIt(it.get), + row_indices.mapIt(it.get), + column_indices.mapIt(it.get), + cells.mapIt(it.get), + proofs.mapIt(it.get) + ) + check: + if v.isErr: + output.kind == JNull + else: + v.get == output.getBool + +proc runRecoverAllCellsTest(suiteName2, suitePath2, path: string) = + let relativePathComponent = path.relativeTestPathComponent(suitePath2) + test "KZG - Recover All Cells - " & relativePathComponent: + let + data = yaml.loadToJson(os_ops.readFile(path/"data.yaml"))[0] + output = data["output"] + cell_ids = data["input"]["cell_ids"].mapIt(toUInt64(it.getInt)) + cells = data["input"]["cells"].mapIt(fromHex[2048](it.getStr)) + + # https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.2/tests/formats/kzg_7594/recover_all_cells.md#condition + # If the blob is invalid (e.g. incorrect length or one of the 32-byte + # blocks does not represent a BLS field element) it should error, i.e. the + # the output should be `null`. + if cell_ids.anyIt(it.isNone) or cells.anyIt(it.isNone): + check output.kind == JNull + else: + let v = recoverAllCells(cell_ids.mapIt(it.get), cells.mapIt(it.get)) + if v.isErr: + check output.kind == JNull + else: + for i in 0..<128: + check v.get[i] == fromHex[2048](output.getStr).get + from std/algorithm import sorted const suiteName = "EF - KZG" @@ -227,4 +362,42 @@ suite suiteName: for kind, path in walkDir(testsDir, relative = true, checkDir = true): runComputeBlobKzgProofTest(suiteName, testsDir, testsDir / path) +doAssert Kzg.freeTrustedSetup().isOk + +const suiteName2 = "EF - KZG - EIP7594" + +suite suiteName2: + const suitePath2 = SszTestsDir/"general"/"eip7594"/"kzg" + + # TODO also check that the only direct subdirectory of each is kzg-mainnet + doAssert sorted(mapIt( + toSeq(walkDir(suitePath2, relative = true, checkDir = true)), it.path)) == + ["compute_cells", "compute_cells_and_kzg_proofs", "recover_all_cells", + "verify_cell_kzg_proof", "verify_cell_kzg_proof_batch"] + + block: + let testsDir = suitePath2/"compute_cells"/"kzg-mainnet" + for kind, path in walkDir(testsDir, relative = true, checkDir = true): + runComputeCellsTest(suiteName2, testsDir, testsDir/path) + + block: + let testsDir = suitePath2/"compute_cells_and_kzg_proofs"/"kzg-mainnet" + for kind, path in walkDir(testsDir, relative = true, checkDir = true): + runComputeCellsAndProofsTest(suiteName2, testsDir, testsDir/path) + + block: + let testsDir = suitePath2/"recover_all_cells"/"kzg-mainnet" + for kind, path in walkDir(testsDir, relative = true, checkDir = true): + runRecoverAllCellsTest(suiteName2, testsDir, testsDir/path) + + block: + let testsDir = suitePath2/"verify_cell_kzg_proof"/"kzg-mainnet" + for kind, path in walkDir(testsDir, relative = true, checkDir = true): + runVerifyCellKzgProofsTest(suiteName2, testsDir, testsDir/path) + + block: + let testsDir = suitePath2/"verify_cell_kzg_proof_batch"/"kzg-mainnet" + for kind, path in walkDir(testsDir, relative = true, checkDir = true): + runVerifyCellKzgProofBatchTest(suiteName2, testsDir, testsDir/path) + doAssert Kzg.freeTrustedSetup().isOk \ No newline at end of file diff --git a/vendor/nim-kzg4844 b/vendor/nim-kzg4844 index b3612edd2..4687dea4d 160000 --- a/vendor/nim-kzg4844 +++ b/vendor/nim-kzg4844 @@ -1 +1 @@ -Subproject commit b3612edd296137e6d383223a080d6dbe8370eebb +Subproject commit 4687dea4d423b508b673e775f66a2d20596604d1