diff --git a/barretenberg/cpp/src/barretenberg/vm2/constraining/relations/ecc.test.cpp b/barretenberg/cpp/src/barretenberg/vm2/constraining/relations/ecc.test.cpp index 2b48de127f6b..3cf261321934 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/constraining/relations/ecc.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/constraining/relations/ecc.test.cpp @@ -559,6 +559,85 @@ TEST(ScalarMulConstrainingTest, BasicMul) check_relation(trace); } +// Edge case: Verify that 0 * P = infinity (point at infinity) +TEST(ScalarMulConstrainingTest, MulByZero) +{ + EccTraceBuilder builder; + + EventEmitter ecc_add_event_emitter; + EventEmitter scalar_mul_event_emitter; + NoopEventEmitter ecc_add_memory_event_emitter; + + StrictMock execution_id_manager; + StrictMock gt; + PureToRadix to_radix_simulator = PureToRadix(); + EccSimulator ecc_simulator(execution_id_manager, + gt, + to_radix_simulator, + ecc_add_event_emitter, + scalar_mul_event_emitter, + ecc_add_memory_event_emitter); + + // Multiply by zero - result should be point at infinity + FF scalar = FF(0); + EmbeddedCurvePoint result = ecc_simulator.scalar_mul(p, scalar); + + // Verify result is infinity + ASSERT_TRUE(result.is_infinity()); + + TestTraceContainer trace({ + { { C::precomputed_first_row, 1 } }, + }); + + builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace); + builder.process_add(ecc_add_event_emitter.dump_events(), trace); + + EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 254); + check_relation(trace); + check_relation(trace); +} + +// Edge case: Verify scalar multiplication works with a large scalar near field modulus +TEST(ScalarMulConstrainingTest, MulByLargeScalar) +{ + EccTraceBuilder builder; + + EventEmitter ecc_add_event_emitter; + EventEmitter scalar_mul_event_emitter; + NoopEventEmitter ecc_add_memory_event_emitter; + + StrictMock execution_id_manager; + StrictMock gt; + PureToRadix to_radix_simulator = PureToRadix(); + EccSimulator ecc_simulator(execution_id_manager, + gt, + to_radix_simulator, + ecc_add_event_emitter, + scalar_mul_event_emitter, + ecc_add_memory_event_emitter); + + // Use a large scalar (p - 1, where p is the field modulus) + // BN254 scalar field modulus - 1: 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000 + FF scalar = FF("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff"); + EmbeddedCurvePoint result = ecc_simulator.scalar_mul(p, scalar); + + // Verify result is a valid point (not infinity for non-zero scalar with non-infinity point) + // The exact result depends on the scalar and point, but it should be deterministic + EmbeddedCurvePoint expected_result = p * Fq(scalar); + EXPECT_EQ(result, expected_result); + + TestTraceContainer trace({ + { { C::precomputed_first_row, 1 } }, + }); + + builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace); + builder.process_add(ecc_add_event_emitter.dump_events(), trace); + + // Note: Row count varies based on number of ECC operations (depends on scalar bit pattern) + check_relation(trace); + check_relation(trace); +} + TEST(ScalarMulConstrainingTest, MultipleInvocations) { EccTraceBuilder builder;