diff --git a/tests/core/pyspec/eth2spec/test/utils/kzg_tests.py b/tests/core/pyspec/eth2spec/test/utils/kzg_tests.py new file mode 100644 index 000000000..c6bbfef56 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/utils/kzg_tests.py @@ -0,0 +1,155 @@ +from hashlib import sha256 + +from eth_utils import ( + encode_hex, + int_to_big_endian, +) + +from eth2spec.utils import bls +from eth2spec.eip7594 import spec + + +############################################################################### +# Helper functions +############################################################################### + +def expect_exception(func, *args): + try: + func(*args) + except Exception: + pass + else: + raise Exception("should have raised exception") + + +def bls_add_one(x): + """ + Adds "one" (actually bls.G1()) to a compressed group element. + Useful to compute definitely incorrect proofs. + """ + return bls.G1_to_bytes48( + bls.add(bls.bytes48_to_G1(x), bls.G1()) + ) + + +def hash(x): + return sha256(x).digest() + + +def make_id(*args): + values_str = "_".join(str(arg) for arg in args) + return hash(bytes(values_str, "utf-8"))[:8].hex() + + +def field_element_bytes(x): + return int.to_bytes(x % spec.BLS_MODULUS, 32, spec.KZG_ENDIANNESS) + + +def field_element_bytes_unchecked(x): + return int.to_bytes(x, 32, spec.KZG_ENDIANNESS) + + +def encode_hex_list(a): + return [encode_hex(x) for x in a] + + +def int_to_hex(n: int, byte_length: int = None) -> str: + byte_value = int_to_big_endian(n) + if byte_length: + byte_value = byte_value.rjust(byte_length, b'\x00') + return encode_hex(byte_value) + + +def evaluate_blob_at(blob, z): + return field_element_bytes( + spec.evaluate_polynomial_in_evaluation_form(spec.blob_to_polynomial(blob), spec.bytes_to_bls_field(z)) + ) + + +############################################################################### +# Global variables +############################################################################### + +BLS_MODULUS_BYTES = spec.BLS_MODULUS.to_bytes(32, spec.KZG_ENDIANNESS) + +# Field Elements + +FE_VALID1 = field_element_bytes(0) +FE_VALID2 = field_element_bytes(1) +FE_VALID3 = field_element_bytes(2) +FE_VALID4 = field_element_bytes(pow(5, 1235, spec.BLS_MODULUS)) +FE_VALID5 = field_element_bytes(spec.BLS_MODULUS - 1) +FE_VALID6 = field_element_bytes(spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB)[1]) +VALID_FIELD_ELEMENTS = [FE_VALID1, FE_VALID2, FE_VALID3, FE_VALID4, FE_VALID5, FE_VALID6] + +FE_INVALID_EQUAL_TO_MODULUS = field_element_bytes_unchecked(spec.BLS_MODULUS) +FE_INVALID_MODULUS_PLUS_ONE = field_element_bytes_unchecked(spec.BLS_MODULUS + 1) +FE_INVALID_UINT256_MAX = field_element_bytes_unchecked(2**256 - 1) +FE_INVALID_UINT256_MID = field_element_bytes_unchecked(2**256 - 2**128) +FE_INVALID_LENGTH_PLUS_ONE = VALID_FIELD_ELEMENTS[0] + b"\x00" +FE_INVALID_LENGTH_MINUS_ONE = VALID_FIELD_ELEMENTS[0][:-1] +INVALID_FIELD_ELEMENTS = [FE_INVALID_EQUAL_TO_MODULUS, FE_INVALID_MODULUS_PLUS_ONE, + FE_INVALID_UINT256_MAX, FE_INVALID_UINT256_MID, + FE_INVALID_LENGTH_PLUS_ONE, FE_INVALID_LENGTH_MINUS_ONE] + +# Blobs + +BLOB_ALL_ZEROS = spec.Blob() +BLOB_ALL_TWOS = spec.Blob(b''.join([field_element_bytes(2) for n in range(4096)])) +BLOB_RANDOM_VALID1 = spec.Blob(b''.join([field_element_bytes(pow(2, n + 256, spec.BLS_MODULUS)) for n in range(4096)])) +BLOB_RANDOM_VALID2 = spec.Blob(b''.join([field_element_bytes(pow(3, n + 256, spec.BLS_MODULUS)) for n in range(4096)])) +BLOB_RANDOM_VALID3 = spec.Blob(b''.join([field_element_bytes(pow(5, n + 256, spec.BLS_MODULUS)) for n in range(4096)])) +BLOB_ALL_MODULUS_MINUS_ONE = spec.Blob(b''.join([field_element_bytes(spec.BLS_MODULUS - 1) for n in range(4096)])) +BLOB_ALMOST_ZERO = spec.Blob(b''.join([field_element_bytes(1 if n == 3211 else 0) for n in range(4096)])) + +BLOB_INVALID = spec.Blob(b'\xFF' * 4096 * 32) +BLOB_INVALID_CLOSE = spec.Blob(b''.join( + [BLS_MODULUS_BYTES if n == 2111 else field_element_bytes(0) for n in range(4096)] +)) +BLOB_INVALID_LENGTH_PLUS_ONE = BLOB_RANDOM_VALID1 + b"\x00" +BLOB_INVALID_LENGTH_MINUS_ONE = BLOB_RANDOM_VALID1[:-1] + +VALID_BLOBS = [BLOB_ALL_ZEROS, BLOB_ALL_TWOS, BLOB_RANDOM_VALID1, BLOB_RANDOM_VALID2, + BLOB_RANDOM_VALID3, BLOB_ALL_MODULUS_MINUS_ONE, BLOB_ALMOST_ZERO] +INVALID_BLOBS = [BLOB_INVALID, BLOB_INVALID_CLOSE, BLOB_INVALID_LENGTH_PLUS_ONE, BLOB_INVALID_LENGTH_MINUS_ONE] + +# Commitments + +VALID_COMMITMENTS = [spec.blob_to_kzg_commitment(blob) for blob in VALID_BLOBS] + +# Points + +G1 = bls.G1_to_bytes48(bls.G1()) +G1_INVALID_TOO_FEW_BYTES = G1[:-1] +G1_INVALID_TOO_MANY_BYTES = G1 + b"\x00" +G1_INVALID_P1_NOT_IN_G1 = bytes.fromhex("8123456789abcdef0123456789abcdef0123456789abcdef" + + "0123456789abcdef0123456789abcdef0123456789abcdef") +G1_INVALID_P1_NOT_ON_CURVE = bytes.fromhex("8123456789abcdef0123456789abcdef0123456789abcdef" + + "0123456789abcdef0123456789abcdef0123456789abcde0") +INVALID_G1_POINTS = [G1_INVALID_TOO_FEW_BYTES, G1_INVALID_TOO_MANY_BYTES, + G1_INVALID_P1_NOT_IN_G1, G1_INVALID_P1_NOT_ON_CURVE] + +# Individual Cells + +CELL_RANDOM_VALID1 = b"".join([field_element_bytes(pow(2, n + 256, spec.BLS_MODULUS)) + for n in range(spec.FIELD_ELEMENTS_PER_CELL)]) +CELL_RANDOM_VALID2 = b"".join([field_element_bytes(pow(3, n + 256, spec.BLS_MODULUS)) + for n in range(spec.FIELD_ELEMENTS_PER_CELL)]) +CELL_RANDOM_VALID3 = b"".join([field_element_bytes(pow(5, n + 256, spec.BLS_MODULUS)) + for n in range(spec.FIELD_ELEMENTS_PER_CELL)]) + +CELL_ALL_MAX_VALUE = b"".join([field_element_bytes_unchecked(2 ** 256 - 1) + for n in range(spec.FIELD_ELEMENTS_PER_CELL)]) +CELL_ONE_INVALID_FIELD = b"".join([field_element_bytes_unchecked(spec.BLS_MODULUS) + if n == 7 else field_element_bytes(0) + for n in range(spec.FIELD_ELEMENTS_PER_CELL)]) +CELL_INVALID_TOO_FEW_BYTES = CELL_RANDOM_VALID1[:-1] +CELL_INVALID_TOO_MANY_BYTES = CELL_RANDOM_VALID2 + b"\x00" + +VALID_INDIVIDUAL_RANDOM_CELL_BYTES = [CELL_RANDOM_VALID1, CELL_RANDOM_VALID2, CELL_RANDOM_VALID3] +INVALID_INDIVIDUAL_CELL_BYTES = [CELL_ALL_MAX_VALUE, CELL_ONE_INVALID_FIELD, CELL_INVALID_TOO_FEW_BYTES, + CELL_INVALID_TOO_MANY_BYTES] + +# Cells & Proofs + +VALID_CELLS_AND_PROOFS = [] # Saved in case02_compute_cells_and_proofs diff --git a/tests/generators/kzg_4844/main.py b/tests/generators/kzg_4844/main.py index 165b287e9..a4d3544bd 100644 --- a/tests/generators/kzg_4844/main.py +++ b/tests/generators/kzg_4844/main.py @@ -1,118 +1,37 @@ """ -KZG 4844 test vectors generator +KZG test vectors generator for EIP-4844 """ -from hashlib import sha256 from typing import Tuple, Iterable, Any, Callable, Dict -from eth_utils import ( - encode_hex, - int_to_big_endian, -) +from eth_utils import encode_hex -from eth2spec.utils import bls +from eth2spec.deneb import spec +from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing from eth2spec.test.helpers.constants import DENEB from eth2spec.test.helpers.typing import SpecForkName -from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing -from eth2spec.deneb import spec +from eth2spec.test.utils.kzg_tests import ( + BLOB_ALL_TWOS, + BLOB_ALL_ZEROS, + BLOB_RANDOM_VALID1, + G1, + INVALID_BLOBS, + INVALID_FIELD_ELEMENTS, + INVALID_G1_POINTS, + VALID_BLOBS, + VALID_FIELD_ELEMENTS, + bls_add_one, + encode_hex_list, + expect_exception, + field_element_bytes, + hash, +) +from eth2spec.utils import bls -def expect_exception(func, *args): - try: - func(*args) - except Exception: - pass - else: - raise Exception("should have raised exception") - - -def field_element_bytes(x): - return int.to_bytes(x % spec.BLS_MODULUS, 32, spec.KZG_ENDIANNESS) - - -def field_element_bytes_unchecked(x): - return int.to_bytes(x, 32, spec.KZG_ENDIANNESS) - - -def encode_hex_list(a): - return [encode_hex(x) for x in a] - - -def bls_add_one(x): - """ - Adds "one" (actually bls.G1()) to a compressed group element. - Useful to compute definitely incorrect proofs. - """ - return bls.G1_to_bytes48( - bls.add(bls.bytes48_to_G1(x), bls.G1()) - ) - - -def evaluate_blob_at(blob, z): - return field_element_bytes( - spec.evaluate_polynomial_in_evaluation_form(spec.blob_to_polynomial(blob), spec.bytes_to_bls_field(z)) - ) - - -BLS_MODULUS_BYTES = spec.BLS_MODULUS.to_bytes(32, spec.KZG_ENDIANNESS) - -G1 = bls.G1_to_bytes48(bls.G1()) -G1_INVALID_TOO_FEW_BYTES = G1[:-1] -G1_INVALID_TOO_MANY_BYTES = G1 + b"\x00" -G1_INVALID_P1_NOT_IN_G1 = bytes.fromhex("8123456789abcdef0123456789abcdef0123456789abcdef" + - "0123456789abcdef0123456789abcdef0123456789abcdef") -G1_INVALID_P1_NOT_ON_CURVE = bytes.fromhex("8123456789abcdef0123456789abcdef0123456789abcdef" + - "0123456789abcdef0123456789abcdef0123456789abcde0") -INVALID_G1_POINTS = [G1_INVALID_TOO_FEW_BYTES, G1_INVALID_TOO_MANY_BYTES, - G1_INVALID_P1_NOT_IN_G1, G1_INVALID_P1_NOT_ON_CURVE] - -BLOB_ALL_ZEROS = spec.Blob() -BLOB_ALL_TWOS = spec.Blob(b''.join([field_element_bytes(2) for n in range(4096)])) -BLOB_RANDOM_VALID1 = spec.Blob(b''.join([field_element_bytes(pow(2, n + 256, spec.BLS_MODULUS)) for n in range(4096)])) -BLOB_RANDOM_VALID2 = spec.Blob(b''.join([field_element_bytes(pow(3, n + 256, spec.BLS_MODULUS)) for n in range(4096)])) -BLOB_RANDOM_VALID3 = spec.Blob(b''.join([field_element_bytes(pow(5, n + 256, spec.BLS_MODULUS)) for n in range(4096)])) -BLOB_ALL_MODULUS_MINUS_ONE = spec.Blob(b''.join([field_element_bytes(spec.BLS_MODULUS - 1) for n in range(4096)])) -BLOB_ALMOST_ZERO = spec.Blob(b''.join([field_element_bytes(1 if n == 3211 else 0) for n in range(4096)])) -BLOB_INVALID = spec.Blob(b'\xFF' * 4096 * 32) -BLOB_INVALID_CLOSE = spec.Blob(b''.join( - [BLS_MODULUS_BYTES if n == 2111 else field_element_bytes(0) for n in range(4096)] -)) -BLOB_INVALID_LENGTH_PLUS_ONE = BLOB_RANDOM_VALID1 + b"\x00" -BLOB_INVALID_LENGTH_MINUS_ONE = BLOB_RANDOM_VALID1[:-1] - -VALID_BLOBS = [BLOB_ALL_ZEROS, BLOB_ALL_TWOS, BLOB_RANDOM_VALID1, BLOB_RANDOM_VALID2, - BLOB_RANDOM_VALID3, BLOB_ALL_MODULUS_MINUS_ONE, BLOB_ALMOST_ZERO] -INVALID_BLOBS = [BLOB_INVALID, BLOB_INVALID_CLOSE, BLOB_INVALID_LENGTH_PLUS_ONE, BLOB_INVALID_LENGTH_MINUS_ONE] - -FE_VALID1 = field_element_bytes(0) -FE_VALID2 = field_element_bytes(1) -FE_VALID3 = field_element_bytes(2) -FE_VALID4 = field_element_bytes(pow(5, 1235, spec.BLS_MODULUS)) -FE_VALID5 = field_element_bytes(spec.BLS_MODULUS - 1) -FE_VALID6 = field_element_bytes(spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB)[1]) -VALID_FIELD_ELEMENTS = [FE_VALID1, FE_VALID2, FE_VALID3, FE_VALID4, FE_VALID5, FE_VALID6] - -FE_INVALID_EQUAL_TO_MODULUS = field_element_bytes_unchecked(spec.BLS_MODULUS) -FE_INVALID_MODULUS_PLUS_ONE = field_element_bytes_unchecked(spec.BLS_MODULUS + 1) -FE_INVALID_UINT256_MAX = field_element_bytes_unchecked(2**256 - 1) -FE_INVALID_UINT256_MID = field_element_bytes_unchecked(2**256 - 2**128) -FE_INVALID_LENGTH_PLUS_ONE = VALID_FIELD_ELEMENTS[0] + b"\x00" -FE_INVALID_LENGTH_MINUS_ONE = VALID_FIELD_ELEMENTS[0][:-1] -INVALID_FIELD_ELEMENTS = [FE_INVALID_EQUAL_TO_MODULUS, FE_INVALID_MODULUS_PLUS_ONE, - FE_INVALID_UINT256_MAX, FE_INVALID_UINT256_MID, - FE_INVALID_LENGTH_PLUS_ONE, FE_INVALID_LENGTH_MINUS_ONE] - - -def hash(x): - return sha256(x).digest() - - -def int_to_hex(n: int, byte_length: int = None) -> str: - byte_value = int_to_big_endian(n) - if byte_length: - byte_value = byte_value.rjust(byte_length, b'\x00') - return encode_hex(byte_value) - +############################################################################### +# Test cases for blob_to_kzg_commitment +############################################################################### def case01_blob_to_kzg_commitment(): # Valid cases @@ -138,6 +57,10 @@ def case01_blob_to_kzg_commitment(): } +############################################################################### +# Test cases for compute_kzg_proof +############################################################################### + def case02_compute_kzg_proof(): # Valid cases for blob in VALID_BLOBS: @@ -179,6 +102,10 @@ def case02_compute_kzg_proof(): } +############################################################################### +# Test cases for verify_kzg_proof +############################################################################### + def case03_verify_kzg_proof(): # Valid cases for blob in VALID_BLOBS: @@ -341,6 +268,10 @@ def case03_verify_kzg_proof(): } +############################################################################### +# Test cases for compute_blob_kzg_proof +############################################################################### + def case04_compute_blob_kzg_proof(): # Valid cases for blob in VALID_BLOBS: @@ -382,6 +313,10 @@ def case04_compute_blob_kzg_proof(): } +############################################################################### +# Test cases for verify_blob_kzg_proof +############################################################################### + def case05_verify_blob_kzg_proof(): # Valid cases for blob in VALID_BLOBS: @@ -503,6 +438,10 @@ def case05_verify_blob_kzg_proof(): } +############################################################################### +# Test cases for verify_blob_kzg_proof_batch +############################################################################### + def case06_verify_blob_kzg_proof_batch(): # Valid cases proofs = [] @@ -627,6 +566,10 @@ def case06_verify_blob_kzg_proof_batch(): } +############################################################################### +# Main logic +############################################################################### + def create_provider(fork_name: SpecForkName, handler_name: str, test_case_fn: Callable[[], Iterable[Tuple[str, Dict[str, Any]]]]) -> gen_typing.TestProvider: diff --git a/tests/generators/kzg_7594/README.md b/tests/generators/kzg_7594/README.md new file mode 100644 index 000000000..5336255ce --- /dev/null +++ b/tests/generators/kzg_7594/README.md @@ -0,0 +1,3 @@ +# KZG Test Generator for EIP-7594 + +These tests are specific to the API required for implementing PeerDAS polynomial commitment sampling. \ No newline at end of file diff --git a/tests/generators/kzg_7594/main.py b/tests/generators/kzg_7594/main.py new file mode 100644 index 000000000..670ed29ee --- /dev/null +++ b/tests/generators/kzg_7594/main.py @@ -0,0 +1,837 @@ +""" +KZG test vectors generator for EIP-7594 +""" + +from typing import Tuple, Iterable, Any, Callable, Dict + +from eth_utils import encode_hex + +from eth2spec.eip7594 import spec +from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing +from eth2spec.test.helpers.constants import EIP7594 +from eth2spec.test.helpers.typing import SpecForkName +from eth2spec.test.utils.kzg_tests import ( + BLOB_RANDOM_VALID1, + BLOB_RANDOM_VALID2, + BLOB_RANDOM_VALID3, + CELL_RANDOM_VALID1, + CELL_RANDOM_VALID2, + INVALID_BLOBS, + INVALID_G1_POINTS, + INVALID_INDIVIDUAL_CELL_BYTES, + VALID_BLOBS, + VALID_CELLS_AND_PROOFS, + VALID_COMMITMENTS, + VALID_INDIVIDUAL_RANDOM_CELL_BYTES, + bls_add_one, + encode_hex_list, + expect_exception, + make_id, +) +from eth2spec.utils import bls + + +############################################################################### +# Test cases for compute_cells +############################################################################### + +def case01_compute_cells(): + # Valid cases + for blob in VALID_BLOBS: + cells = spec.compute_cells(blob) + identifier = make_id(blob) + yield f'compute_cells_case_valid_{identifier}', { + 'input': { + 'blob': encode_hex(blob), + }, + 'output': encode_hex_list(cells) + } + + # Edge case: Invalid blobs + for blob in INVALID_BLOBS: + expect_exception(spec.compute_cells, blob) + identifier = make_id(blob) + yield f'compute_cells_case_invalid_blob_{identifier}', { + 'input': { + 'blob': encode_hex(blob) + }, + 'output': None + } + + +############################################################################### +# Test cases for compute_cells_and_proofs +############################################################################### + +def case02_compute_cells_and_proofs(): + # Valid cases + for blob in VALID_BLOBS: + cells, proofs = spec.compute_cells_and_proofs(blob) + # Save cells & proofs here to save on time. + VALID_CELLS_AND_PROOFS.append((cells, proofs)) + identifier = make_id(blob) + yield f'compute_cells_and_proofs_case_valid_{identifier}', { + 'input': { + 'blob': encode_hex(blob), + }, + 'output': (encode_hex_list(cells), encode_hex_list(proofs)) + } + + # Edge case: Invalid blobs + for blob in INVALID_BLOBS: + expect_exception(spec.compute_cells_and_proofs, blob) + identifier = make_id(blob) + yield f'compute_cells_and_proofs_case_invalid_blob_{identifier}', { + 'input': { + 'blob': encode_hex(blob) + }, + 'output': None + } + + +############################################################################### +# Test cases for verify_cell_proof +############################################################################### + +def case03_verify_cell_proof(): + # Valid cases + for i in range(len(VALID_BLOBS)): + cells, proofs = VALID_CELLS_AND_PROOFS[i] + commitment = VALID_COMMITMENTS[i] + cell_id = (2 ** i - 1) % spec.CELLS_PER_EXT_BLOB + cell = cells[cell_id] + proof = proofs[cell_id] + assert spec.verify_cell_proof(commitment, cell_id, cell, proof) + identifier = make_id(commitment, cell_id, cell, proof) + yield f'verify_cell_proof_case_valid_{identifier}', { + 'input': { + 'commitment': encode_hex(commitment), + 'cell_id': cell_id, + 'cell': encode_hex(cell), + 'proof': encode_hex(proof), + }, + 'output': True + } + + # Incorrect commitment + for i in range(len(VALID_BLOBS)): + cells, proofs = VALID_CELLS_AND_PROOFS[i] + commitment = bls_add_one(VALID_COMMITMENTS[i]) + cell_id = 99 % spec.CELLS_PER_EXT_BLOB + cell = cells[cell_id] + proof = proofs[cell_id] + assert not spec.verify_cell_proof(commitment, cell_id, cell, proof) + identifier = make_id(commitment, cell_id, cell, proof) + yield f'verify_cell_proof_case_incorrect_commitment_{identifier}', { + 'input': { + 'commitment': encode_hex(commitment), + 'cell_id': cell_id, + 'cell': encode_hex(cell), + 'proof': encode_hex(proof), + }, + 'output': False + } + + # Incorrect cell + for i in range(len(VALID_INDIVIDUAL_RANDOM_CELL_BYTES)): + cell_id = 16 % spec.CELLS_PER_EXT_BLOB + commitment = VALID_COMMITMENTS[i] + cells, proofs = VALID_CELLS_AND_PROOFS[i] + cell = VALID_INDIVIDUAL_RANDOM_CELL_BYTES[i] + proof = proofs[cell_id] + assert not spec.verify_cell_proof(commitment, cell_id, cell, proof) + identifier = make_id(commitment, cell_id, cell, proof) + yield f'verify_cell_proof_case_incorrect_cell_{identifier}', { + 'input': { + 'commitment': encode_hex(commitment), + 'cell_id': cell_id, + 'cell': encode_hex(cell), + 'proof': encode_hex(proof), + }, + 'output': False + } + + # Incorrect proof + for i in range(len(VALID_BLOBS)): + cell_id = 91 % spec.CELLS_PER_EXT_BLOB + commitment = VALID_COMMITMENTS[i] + cells, proofs = VALID_CELLS_AND_PROOFS[i] + cell = cells[cell_id] + proof = bls_add_one(proofs[cell_id]) + assert not spec.verify_cell_proof(commitment, cell_id, cell, proof) + identifier = make_id(commitment, cell_id, cell, proof) + yield f'verify_cell_proof_case_incorrect_proof_{identifier}', { + 'input': { + 'commitment': encode_hex(commitment), + 'cell_id': cell_id, + 'cell': encode_hex(cell), + 'proof': encode_hex(proof), + }, + 'output': False + } + + # Edge case: Invalid commitment + for commitment in INVALID_G1_POINTS: + cells, proofs = VALID_CELLS_AND_PROOFS[0] + cell_id = 81 % spec.CELLS_PER_EXT_BLOB + cell = cells[cell_id] + proof = proofs[cell_id] + expect_exception(spec.verify_cell_proof, commitment, cell_id, cell, proof) + identifier = make_id(commitment, cell_id, cell, proof) + yield f'verify_cell_proof_case_invalid_commitment_{identifier}', { + 'input': { + 'commitment': encode_hex(commitment), + 'cell_id': cell_id, + 'cell': encode_hex(cell), + 'proof': encode_hex(proof), + }, + 'output': None + } + + # Edge case: Invalid cell_id + for cell_id in [spec.CELLS_PER_EXT_BLOB, spec.CELLS_PER_EXT_BLOB + 1]: + cells, proofs = VALID_CELLS_AND_PROOFS[1] + commitment = VALID_COMMITMENTS[1] + cell = cells[0] + proof = proofs[0] + expect_exception(spec.verify_cell_proof, commitment, cell_id, cell, proof) + identifier = make_id(commitment, cell_id, cell, proof) + yield f'verify_cell_proof_case_invalid_cell_id_{identifier}', { + 'input': { + 'commitment': encode_hex(commitment), + 'cell_id': cell_id, + 'cell': encode_hex(cell), + 'proof': encode_hex(proof), + }, + 'output': None + } + + # Edge case: Invalid cell + for cell in INVALID_INDIVIDUAL_CELL_BYTES: + cell_id = 32 % spec.CELLS_PER_EXT_BLOB + commitment = VALID_COMMITMENTS[2] + cells, proofs = VALID_CELLS_AND_PROOFS[2] + proof = proofs[cell_id] + expect_exception(spec.verify_cell_proof, commitment, cell_id, cell, proof) + identifier = make_id(commitment, cell_id, cell, proof) + yield f'verify_cell_proof_case_invalid_cell_{identifier}', { + 'input': { + 'commitment': encode_hex(commitment), + 'cell_id': cell_id, + 'cell': encode_hex(cell), + 'proof': encode_hex(proof), + }, + 'output': None + } + + # Edge case: Invalid proof + for proof in INVALID_G1_POINTS: + cells, _ = VALID_CELLS_AND_PROOFS[3] + commitment = VALID_COMMITMENTS[3] + cell_id = 36 % spec.CELLS_PER_EXT_BLOB + cell = cells[cell_id] + expect_exception(spec.verify_cell_proof, commitment, cell_id, cell, proof) + identifier = make_id(commitment, cell_id, cell, proof) + yield f'verify_cell_proof_case_invalid_proof_{identifier}', { + 'input': { + 'commitment': encode_hex(commitment), + 'cell_id': cell_id, + 'cell': encode_hex(cell), + 'proof': encode_hex(proof), + }, + 'output': None + } + + +############################################################################### +# Test cases for verify_cell_proof_batch +############################################################################### + +def case04_verify_cell_proof_batch(): + # Valid cases + for i in range(len(VALID_BLOBS)): + cells, proofs = VALID_CELLS_AND_PROOFS[i] + row_commitments = [VALID_COMMITMENTS[i]] + row_indices = [0] * spec.CELLS_PER_EXT_BLOB + column_indices = list(range(spec.CELLS_PER_EXT_BLOB)) + assert spec.verify_cell_proof_batch(row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_valid_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': True + } + + # Valid: zero cells + cells, row_commitments, row_indices, column_indices, proofs = [], [], [], [], [] + assert spec.verify_cell_proof_batch(row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_valid_zero_cells_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': True + } + + # Valid: Verify cells from multiple blobs + cells0, proofs0 = VALID_CELLS_AND_PROOFS[0] + cells1, proofs1 = VALID_CELLS_AND_PROOFS[1] + row_commitments = VALID_COMMITMENTS[:2] + row_indices = [0, 1] + column_indices = [0, 0] + cells = [cells0[0], cells1[0]] + proofs = [proofs0[0], proofs1[0]] + assert spec.verify_cell_proof_batch(row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_valid_multiple_blobs_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': True + } + + # Valid: Unused row commitments + cells, proofs = VALID_CELLS_AND_PROOFS[2] + cells, proofs = cells[:3], proofs[:3] + # Provide list of all commitments + row_commitments = VALID_COMMITMENTS + row_indices = [2] * len(cells) + column_indices = list(range(len(cells))) + assert spec.verify_cell_proof_batch(row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_valid_unused_row_commitments_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': True + } + + # Valid: Same cell multiple times + row_commitments = [VALID_COMMITMENTS[3]] + num_duplicates = 3 + row_indices = [0] * num_duplicates + column_indices = [0] * num_duplicates + cells = [VALID_CELLS_AND_PROOFS[3][0][0]] * num_duplicates + proofs = [VALID_CELLS_AND_PROOFS[3][1][0]] * num_duplicates + assert spec.verify_cell_proof_batch(row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_valid_same_cell_multiple_times_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': True + } + + # Incorrect row commitment + cells, proofs = VALID_CELLS_AND_PROOFS[5] + cells, proofs = cells[:1], proofs[:1] + # Change commitment so it's wrong + row_commitments = [bls_add_one(VALID_COMMITMENTS[5])] + row_indices = [0] * len(cells) + column_indices = list(range(len(cells))) + assert not spec.verify_cell_proof_batch(row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_incorrect_row_commitment_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': False + } + + # Incorrect cell + cells, proofs = VALID_CELLS_AND_PROOFS[6] + cells, proofs = cells[:1], proofs[:1] + row_commitments = [VALID_COMMITMENTS[6]] + row_indices = [0] * len(cells) + column_indices = list(range(len(cells))) + # Change last cell so it's wrong + cells[-1] = CELL_RANDOM_VALID2 + assert not spec.verify_cell_proof_batch(row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_incorrect_cell_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': False + } + + # Incorrect proof + cells, proofs = VALID_CELLS_AND_PROOFS[0] + cells, proofs = cells[:1], proofs[:1] + row_commitments = [VALID_COMMITMENTS[0]] + row_indices = [0] * len(cells) + column_indices = list(range(len(cells))) + # Change last proof so it's wrong + proofs[-1] = bls_add_one(proofs[-1]) + assert not spec.verify_cell_proof_batch(row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_incorrect_proof_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': False + } + + # Edge case: Invalid row commitment + for i, commitment in enumerate(INVALID_G1_POINTS): + cells, proofs = VALID_CELLS_AND_PROOFS[i % len(INVALID_G1_POINTS)] + cells, proofs = cells[:1], proofs[:1] + # Set row_commitments to the invalid commitment + row_commitments = [commitment] + row_indices = [0] * len(cells) + column_indices = list(range(len(cells))) + expect_exception(spec.verify_cell_proof_batch, row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_invalid_row_commitment_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': None + } + + # Edge case: Invalid row_index + cells, proofs = VALID_CELLS_AND_PROOFS[0] + cells, proofs = cells[:1], proofs[:1] + row_commitments = [VALID_COMMITMENTS[0]] + row_indices = [0] * len(cells) + # Set first row index to an invalid value + row_indices[0] = 1 + column_indices = list(range(len(cells))) + expect_exception(spec.verify_cell_proof_batch, row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_invalid_row_index_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': None + } + + # Edge case: Invalid column_index + cells, proofs = VALID_CELLS_AND_PROOFS[1] + cells, proofs = cells[:1], proofs[:1] + row_commitments = [VALID_COMMITMENTS[1]] + row_indices = [0] * len(cells) + column_indices = list(range(len(cells))) + # Set first column index to an invalid value + column_indices[0] = spec.CELLS_PER_EXT_BLOB + expect_exception(spec.verify_cell_proof_batch, row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_invalid_column_index_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': None + } + + # Edge case: Invalid cell + for i, cell in enumerate(INVALID_INDIVIDUAL_CELL_BYTES): + cells, proofs = VALID_CELLS_AND_PROOFS[i % len(INVALID_INDIVIDUAL_CELL_BYTES)] + cells, proofs = cells[:1], proofs[:1] + row_commitments = [VALID_COMMITMENTS[i % len(INVALID_INDIVIDUAL_CELL_BYTES)]] + row_indices = [0] * len(cells) + column_indices = list(range(len(cells))) + # Set first cell to the invalid cell + cells[0] = cell + expect_exception(spec.verify_cell_proof_batch, row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_invalid_cell_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': None + } + + # Edge case: Invalid proof + for i, proof in enumerate(INVALID_G1_POINTS): + cells, proofs = VALID_CELLS_AND_PROOFS[i % len(INVALID_G1_POINTS)] + cells, proofs = cells[:1], proofs[:1] + row_commitments = [VALID_COMMITMENTS[i % len(INVALID_G1_POINTS)]] + row_indices = [0] * len(cells) + column_indices = list(range(len(cells))) + # Set first proof to the invalid proof + proofs[0] = proof + expect_exception(spec.verify_cell_proof_batch, row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_invalid_proof_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': None + } + + # Edge case: Missing a row commitment + cells, proofs = VALID_CELLS_AND_PROOFS[0] + cells, proofs = cells[:1], proofs[:1] + # Do not include the row commitment + row_commitments = [] + row_indices = [0] * len(cells) + column_indices = list(range(len(cells))) + expect_exception(spec.verify_cell_proof_batch, row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_invalid_missing_row_commitment_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': None + } + + # Edge case: Missing a row index + cells, proofs = VALID_CELLS_AND_PROOFS[1] + cells, proofs = cells[:2], proofs[:2] + row_commitments = [VALID_COMMITMENTS[1]] + # Leave off one of the row indices + row_indices = [0] * (len(cells) - 1) + column_indices = list(range(len(cells))) + expect_exception(spec.verify_cell_proof_batch, row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_invalid_missing_row_index_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': None + } + + # Edge case: Missing a column index + cells, proofs = VALID_CELLS_AND_PROOFS[2] + cells, proofs = cells[:2], proofs[:2] + row_commitments = [VALID_COMMITMENTS[2]] + row_indices = [0] * len(cells) + # Leave off one of the column indices + column_indices = list(range(len(cells) - 1)) + expect_exception(spec.verify_cell_proof_batch, row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_invalid_missing_column_index_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': None + } + + # Edge case: Missing a cell + cells, proofs = VALID_CELLS_AND_PROOFS[3] + cells, proofs = cells[:2], proofs[:2] + row_commitments = [VALID_COMMITMENTS[3]] + row_indices = [0] * len(cells) + column_indices = list(range(len(cells))) + # Remove the last proof + cells = cells[:-1] + expect_exception(spec.verify_cell_proof_batch, row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_invalid_missing_cell_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': None + } + + # Edge case: Missing a proof + cells, proofs = VALID_CELLS_AND_PROOFS[4] + cells, proofs = cells[:2], proofs[:2] + row_commitments = [VALID_COMMITMENTS[4]] + row_indices = [0] * len(cells) + column_indices = list(range(len(cells))) + # Remove the last proof + proofs = proofs[:-1] + expect_exception(spec.verify_cell_proof_batch, row_commitments, row_indices, column_indices, cells, proofs) + identifier = make_id(row_commitments, row_indices, column_indices, cells, proofs) + yield f'verify_cell_proof_batch_case_invalid_missing_proof_{identifier}', { + 'input': { + 'row_commitments': encode_hex_list(row_commitments), + 'row_indices': row_indices, + 'column_indices': column_indices, + 'cells': encode_hex_list(cells), + 'proofs': encode_hex_list(proofs), + }, + 'output': None + } + + +############################################################################### +# Test cases for recover_all_cells +############################################################################### + +def case05_recover_all_cells(): + # Valid: No missing cells + blob = BLOB_RANDOM_VALID1 + cells = spec.compute_cells(blob) + cell_ids = list(range(spec.CELLS_PER_EXT_BLOB)) + recovered_cells = spec.recover_all_cells(cell_ids, cells) + assert recovered_cells == cells + identifier = make_id(cell_ids, cells) + yield f'recover_all_cells_case_valid_no_missing_{identifier}', { + 'input': { + 'cell_ids': cell_ids, + 'cells': encode_hex_list(cells), + }, + 'output': encode_hex_list(recovered_cells) + } + + # Valid: Half missing cells (every other cell) + blob = BLOB_RANDOM_VALID2 + cells = spec.compute_cells(blob) + cell_ids = list(range(0, spec.CELLS_PER_EXT_BLOB, 2)) + partial_cells = [cells[cell_id] for cell_id in cell_ids] + recovered_cells = spec.recover_all_cells(cell_ids, partial_cells) + assert recovered_cells == cells + identifier = make_id(cell_ids, partial_cells) + yield f'recover_all_cells_case_valid_half_missing_every_other_cell_{identifier}', { + 'input': { + 'cell_ids': cell_ids, + 'cells': encode_hex_list(partial_cells), + }, + 'output': encode_hex_list(recovered_cells) + } + + # Valid: Half missing cells (first half) + blob = BLOB_RANDOM_VALID3 + cells = spec.compute_cells(blob) + cell_ids = list(range(0, spec.CELLS_PER_EXT_BLOB // 2)) + partial_cells = [cells[cell_id] for cell_id in cell_ids] + recovered_cells = spec.recover_all_cells(cell_ids, partial_cells) + assert recovered_cells == cells + identifier = make_id(cell_ids, partial_cells) + yield f'recover_all_cells_case_valid_half_missing_first_half_{identifier}', { + 'input': { + 'cell_ids': cell_ids, + 'cells': encode_hex_list(partial_cells), + }, + 'output': encode_hex_list(recovered_cells) + } + + # Valid: Half missing cells (second half) + blob = BLOB_RANDOM_VALID1 + cells = spec.compute_cells(blob) + cell_ids = list(range(spec.CELLS_PER_EXT_BLOB // 2, spec.CELLS_PER_EXT_BLOB)) + partial_cells = [cells[cell_id] for cell_id in cell_ids] + recovered_cells = spec.recover_all_cells(cell_ids, partial_cells) + assert recovered_cells == cells + identifier = make_id(cell_ids, partial_cells) + yield f'recover_all_cells_case_valid_half_missing_second_half_{identifier}', { + 'input': { + 'cell_ids': cell_ids, + 'cells': encode_hex_list(partial_cells), + }, + 'output': encode_hex_list(recovered_cells) + } + + # Edge case: All cells are missing + cell_ids, partial_cells = [], [] + expect_exception(spec.recover_all_cells, cell_ids, partial_cells) + identifier = make_id(cell_ids, partial_cells) + yield f'recover_all_cells_case_invalid_all_cells_are_missing_{identifier}', { + 'input': { + 'cell_ids': cell_ids, + 'cells': encode_hex_list(partial_cells), + }, + 'output': None + } + + # Edge case: More than half missing + blob = BLOB_RANDOM_VALID2 + cells = spec.compute_cells(blob) + cell_ids = list(range(spec.CELLS_PER_EXT_BLOB // 2 - 1)) + partial_cells = [cells[cell_id] for cell_id in cell_ids] + expect_exception(spec.recover_all_cells, cell_ids, partial_cells) + identifier = make_id(cell_ids, partial_cells) + yield f'recover_all_cells_case_invalid_more_than_half_missing_{identifier}', { + 'input': { + 'cell_ids': cell_ids, + 'cells': encode_hex_list(partial_cells), + }, + 'output': None + } + + # Edge case: Invalid cell_id + blob = BLOB_RANDOM_VALID1 + cells = spec.compute_cells(blob) + cell_ids = list(range(spec.CELLS_PER_EXT_BLOB // 2)) + partial_cells = [cells[cell_id] for cell_id in cell_ids] + # Replace first cell_id with an invalid value + cell_ids[0] = spec.CELLS_PER_EXT_BLOB + expect_exception(spec.recover_all_cells, cell_ids, partial_cells) + identifier = make_id(cell_ids, partial_cells) + yield f'recover_all_cells_case_invalid_cell_id_{identifier}', { + 'input': { + 'cell_ids': cell_ids, + 'cells': encode_hex_list(partial_cells), + }, + 'output': None + } + + # Edge case: Invalid cell + blob = BLOB_RANDOM_VALID2 + for cell in INVALID_INDIVIDUAL_CELL_BYTES: + cells = spec.compute_cells(blob) + cell_ids = list(range(spec.CELLS_PER_EXT_BLOB // 2)) + partial_cells = [cells[cell_id] for cell_id in cell_ids] + # Replace first cell with an invalid value + partial_cells[0] = cell + expect_exception(spec.recover_all_cells, cell_ids, partial_cells) + identifier = make_id(cell_ids, partial_cells) + yield f'recover_all_cells_case_invalid_cell_{identifier}', { + 'input': { + 'cell_ids': cell_ids, + 'cells': encode_hex_list(partial_cells), + }, + 'output': None + } + + # Edge case: More cell_ids than cells + blob = BLOB_RANDOM_VALID3 + cells = spec.compute_cells(blob) + cell_ids = list(range(0, spec.CELLS_PER_EXT_BLOB, 2)) + partial_cells = [cells[cell_id] for cell_id in cell_ids] + # Add another cell_id + cell_ids.append(spec.CELLS_PER_EXT_BLOB - 1) + expect_exception(spec.recover_all_cells, cell_ids, partial_cells) + identifier = make_id(cell_ids, partial_cells) + yield f'recover_all_cells_case_invalid_more_cell_ids_than_cells_{identifier}', { + 'input': { + 'cell_ids': cell_ids, + 'cells': encode_hex_list(partial_cells), + }, + 'output': None + } + + # Edge case: More cells than cell_ids + blob = BLOB_RANDOM_VALID1 + cells = spec.compute_cells(blob) + cell_ids = list(range(0, spec.CELLS_PER_EXT_BLOB, 2)) + partial_cells = [cells[cell_id] for cell_id in cell_ids] + # Add another cell + partial_cells.append(CELL_RANDOM_VALID1) + expect_exception(spec.recover_all_cells, cell_ids, partial_cells) + identifier = make_id(cell_ids, partial_cells) + yield f'recover_all_cells_case_invalid_more_cells_than_cell_ids_{identifier}', { + 'input': { + 'cell_ids': cell_ids, + 'cells': encode_hex_list(partial_cells), + }, + 'output': None + } + + # Edge case: Duplicate cell_id + blob = BLOB_RANDOM_VALID2 + cells = spec.compute_cells(blob) + cell_ids = list(range(spec.CELLS_PER_EXT_BLOB // 2)) + partial_cells = [cells[cell_id] for cell_id in cell_ids] + # Replace first cell_id with the second cell_id + cell_ids[0] = cell_ids[1] + expect_exception(spec.recover_all_cells, cell_ids, partial_cells) + identifier = make_id(cell_ids, partial_cells) + yield f'recover_all_cells_case_invalid_duplicate_cell_id_{identifier}', { + 'input': { + 'cell_ids': cell_ids, + 'cells': encode_hex_list(partial_cells), + }, + 'output': None + } + + +############################################################################### +# Main logic +############################################################################### + +def create_provider(fork_name: SpecForkName, + handler_name: str, + test_case_fn: Callable[[], Iterable[Tuple[str, Dict[str, Any]]]]) -> gen_typing.TestProvider: + def prepare_fn() -> None: + # Nothing to load / change in spec. Maybe in future forks. + # Put the tests into the general config category, to not require any particular configuration. + return + + def cases_fn() -> Iterable[gen_typing.TestCase]: + for data in test_case_fn(): + (case_name, case_content) = data + yield gen_typing.TestCase( + fork_name=fork_name, + preset_name='general', + runner_name='kzg', + handler_name=handler_name, + suite_name='kzg-mainnet', + case_name=case_name, + case_fn=lambda: [('data', 'data', case_content)] + ) + + return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn) + + +if __name__ == "__main__": + bls.use_arkworks() + gen_runner.run_generator("kzg_7594", [ + # EIP-7594 + create_provider(EIP7594, 'compute_cells', case01_compute_cells), + create_provider(EIP7594, 'compute_cells_and_proofs', case02_compute_cells_and_proofs), + create_provider(EIP7594, 'verify_cell_proof', case03_verify_cell_proof), + create_provider(EIP7594, 'verify_cell_proof_batch', case04_verify_cell_proof_batch), + create_provider(EIP7594, 'recover_all_cells', case05_recover_all_cells), + ]) diff --git a/tests/generators/kzg_7594/requirements.txt b/tests/generators/kzg_7594/requirements.txt new file mode 100644 index 000000000..182248686 --- /dev/null +++ b/tests/generators/kzg_7594/requirements.txt @@ -0,0 +1,2 @@ +pytest>=4.4 +../../../[generator]