Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 27 additions & 24 deletions compiler/noirc_evaluator/src/ssa/opt/check_u128_mul_overflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,23 +72,17 @@ fn check_u128_mul_overflow(
let lhs_value = dfg.get_numeric_constant(lhs);
let rhs_value = dfg.get_numeric_constant(rhs);

let two_pow_64 = 1_u128 << 64;

// If lhs is less than 2^64 then the condition trivially holds.
if let Some(value) = lhs_value {
if value.to_u128() < two_pow_64 {
return;
}
}

// Same goes for rhs
if let Some(value) = rhs_value {
if value.to_u128() < two_pow_64 {
return;
}
// If we multiply a constant value 2^n by an unknown u128 value we get at most `2^(n+128) - 2`.
// If `n+128` does not overflow the maximum Field element value, there's no need to check for overflow.
let max_const_value_that_does_not_overflow = 1_u128 << (FieldElement::max_num_bits() - 128);
if lhs_value.is_some_and(|value| value.to_u128() < max_const_value_that_does_not_overflow)
|| rhs_value.is_some_and(|value| value.to_u128() < max_const_value_that_does_not_overflow)
{
return;
}

let u128 = NumericType::unsigned(128);
let two_pow_64 = 1_u128 << 64;
let two_pow_64 = dfg.make_constant(two_pow_64.into(), u128);
let mul = BinaryOp::Mul { unchecked: true };

Expand Down Expand Up @@ -146,23 +140,27 @@ mod tests {
};

#[test]
fn does_not_insert_check_if_lhs_is_less_than_two_pow_64() {
fn does_not_insert_check_if_multiplying_lhs_will_not_overflow_field_element() {
// The big value here is 2^254 - 2^128 - 1, which, when multiplied by any u128
// won't overflow a Field element max value.
let src = "
acir(inline) fn main f0 {
b0(v0: u128):
v2 = mul u128 18446744073709551615, v0
v2 = mul u128 85070591730234615865843651857942052863, v0
return
}
";
assert_ssa_does_not_change(src, Ssa::check_u128_mul_overflow);
}

#[test]
fn does_not_insert_check_if_rhs_is_less_than_two_pow_64() {
fn does_not_insert_check_if_multiplying_rhs_will_not_overflow_field_element() {
// The big value here is 2^254 - 2^128 - 1, which, when multiplied by any u128
// won't overflow a Field element max value.
let src = "
acir(inline) fn main f0 {
b0(v0: u128):
v2 = mul v0, u128 18446744073709551615
v2 = mul v0, u128 85070591730234615865843651857942052863
return
}
";
Expand All @@ -171,10 +169,12 @@ mod tests {

#[test]
fn inserts_check_for_lhs() {
// The big value here is 2^254 - 2^128, which, when multiplied by any u128
// might overflow a Field element max value.
let src = "
acir(inline) fn main f0 {
b0(v0: u128):
v2 = mul v0, u128 18446744073709551617
v2 = mul v0, u128 85070591730234615865843651857942052864
return
}
";
Expand All @@ -184,7 +184,7 @@ mod tests {
assert_ssa_snapshot!(ssa, @r#"
acir(inline) fn main f0 {
b0(v0: u128):
v2 = mul v0, u128 18446744073709551617
v2 = mul v0, u128 85070591730234615865843651857942052864
v4 = div v0, u128 18446744073709551616
constrain v4 == u128 0, "attempt to multiply with overflow"
return
Expand All @@ -194,10 +194,12 @@ mod tests {

#[test]
fn inserts_check_for_rhs() {
// The big value here is 2^254 - 2^128, which, when multiplied by any u128
// might overflow a Field element max value.
let src = "
acir(inline) fn main f0 {
b0(v0: u128):
v2 = mul u128 18446744073709551617, v0
v2 = mul u128 85070591730234615865843651857942052864, v0
return
}
";
Expand All @@ -207,7 +209,7 @@ mod tests {
assert_ssa_snapshot!(ssa, @r#"
acir(inline) fn main f0 {
b0(v0: u128):
v2 = mul u128 18446744073709551617, v0
v2 = mul u128 85070591730234615865843651857942052864, v0
v4 = div v0, u128 18446744073709551616
constrain v4 == u128 0, "attempt to multiply with overflow"
return
Expand Down Expand Up @@ -245,7 +247,7 @@ mod tests {
let src = "
acir(inline) fn main f0 {
b0():
v2 = mul u128 18446744073709551617, u128 18446744073709551616
v2 = mul u128 85070591730234615865843651857942052864, u128 85070591730234615865843651857942052865
return
}
";
Expand All @@ -256,7 +258,7 @@ mod tests {
assert_ssa_snapshot!(ssa, @r#"
acir(inline) fn main f0 {
b0():
v2 = mul u128 18446744073709551617, u128 18446744073709551616
v2 = mul u128 85070591730234615865843651857942052864, u128 85070591730234615865843651857942052865
constrain u128 1 == u128 0, "attempt to multiply with overflow"
return
}
Expand All @@ -274,6 +276,7 @@ mod tests {
";
assert_ssa_does_not_change(src, Ssa::check_u128_mul_overflow);
}

#[test]
fn predicate_overflow() {
// This code performs a u128 multiplication that overflows, under a condition.
Expand Down
Loading