@pytest.mark.parametrize(
"input_data",
# Test vectors from the reference spec (from the cryptography team)
vectors_from_file("fail-msm_G1_bls.json")
+ [
pytest.param(
Spec.P1_NOT_IN_SUBGROUP + Scalar(Spec.Q),
id="not_in_subgroup_1_pos_0",
),
pytest.param(
Spec.P1_NOT_IN_SUBGROUP_TIMES_2 + Scalar(Spec.Q),
id="not_in_subgroup_2_pos_0",
),
pytest.param(
Spec.G1 + Scalar(1) + Spec.P1_NOT_IN_SUBGROUP + Scalar(Spec.Q),
id="not_in_subgroup_1_pos_1",
),
pytest.param(
Spec.G1
+ Scalar(1)
+ Spec.P1_NOT_IN_SUBGROUP_TIMES_2
+ Scalar(Spec.Q),
id="not_in_subgroup_2_pos_1",
),
pytest.param(
Spec.G1,
id="bls_g1_truncated_input",
),
pytest.param(
G1_POINTS_NOT_IN_SUBGROUP[0] + Scalar(0),
id="rand_not_in_subgroup_0_pos_0",
),
pytest.param(
G1_POINTS_NOT_IN_SUBGROUP[1] + Scalar(1),
id="rand_not_in_subgroup_1_pos_0",
),
pytest.param(
Spec.G1 + Scalar(1) + G1_POINTS_NOT_IN_SUBGROUP[0] + Scalar(0),
id="rand_not_in_subgroup_0_pos_1",
),
pytest.param(
Spec.G1 + Scalar(1) + G1_POINTS_NOT_IN_SUBGROUP[1] + Scalar(1),
id="rand_not_in_subgroup_1_pos_1",
),
pytest.param(
G1_POINTS_NOT_ON_CURVE[0] + Scalar(0),
id="not_on_curve_0_pos_0",
),
pytest.param(
G1_POINTS_NOT_ON_CURVE[1] + Scalar(1),
id="not_on_curve_1_pos_0",
),
pytest.param(
Spec.G1 + Scalar(1) + G1_POINTS_NOT_ON_CURVE[0] + Scalar(0),
id="not_on_curve_0_pos_1",
),
pytest.param(
Spec.G1 + Scalar(1) + G1_POINTS_NOT_ON_CURVE[1] + Scalar(1),
id="not_on_curve_1_pos_1",
),
pytest.param(
Spec.G1 + Scalar(1) + Spec.G1,
id="incomplete_input_missing_scalar",
),
pytest.param(
Spec.G1 + Scalar(1) + bytes([0]),
id="incomplete_input_extra_byte",
),
pytest.param(
Spec.G1 + Scalar(1) + Spec.G2 + Scalar(1),
id="mixing_g1_with_g2",
),
pytest.param(
Spec.G1 + (b"\x01" + b"\x00" * 32), # Scalar > UINT256_MAX
id="scalar_too_large",
),
pytest.param(
# Invalid scalar length
Spec.G1 + Scalar(1).x.to_bytes(16, byteorder="big"),
id="scalar_too_short",
),
pytest.param(
bytes([0]) * 159, # Just under minimum valid length
id="input_too_short_by_1",
),
# Coordinates above modulus p cases.
pytest.param(
PointG1(Spec.P1.x + Spec.P, Spec.P1.y) + Scalar(1),
id="x_above_p_pos_0",
),
pytest.param(
PointG1(Spec.P1.x, Spec.P1.y + Spec.P) + Scalar(1),
id="y_above_p_pos_0",
),
pytest.param(
Spec.G1
+ Scalar(1)
+ PointG1(Spec.P1.x + Spec.P, Spec.P1.y)
+ Scalar(0),
id="x_above_p_pos_1",
),
pytest.param(
Spec.G1
+ Scalar(1)
+ PointG1(Spec.P1.x, Spec.P1.y + Spec.P)
+ Scalar(0),
id="y_above_p_pos_1",
),
pytest.param(
Spec.G1
+ Scalar(1)
+ PointG1(Spec.P1.x | Spec.MAX_FP_BIT_SET, Spec.P1.y)
+ Scalar(0),
id="non_zero_byte_16_boundary_violation_x_pos_1",
),
# BLS serialization flag byte in coordinate: values >= p whose first
# coordinate byte has BLS flag bits set. Implementations that parse
# BLS serialization flags before validating the field modulus may
# misinterpret these as valid special-case points (e.g. point at
# infinity) instead of rejecting them.
# See: https://github.com/lambdaclass/ethrex/pull/6287
pytest.param(
Spec.G1 + Scalar(1) + PointG1(0x40 << (47 * 8), 0) + Scalar(0),
id="x_bls_infinity_flag_pos_1",
),
],
# Input length tests can be found in
# ./test_bls12_variable_length_input_contracts.py
)
@pytest.mark.parametrize(
"precompile_gas_modifier", [100_000], ids=[""]
) # Add gas so that won't be the cause of failure
@pytest.mark.parametrize("expected_output", [Spec.INVALID], ids=[""])
@pytest.mark.eels_base_coverage
def test_invalid(
state_test: StateTestFiller,
pre: Alloc,
post: dict,
tx: Transaction,
) -> None:
"""Test invalid calls to the BLS12_G1MSM precompile."""
state_test(
env=Environment(),
pre=pre,
tx=tx,
post=post,
)