Skip to content

Commit

Permalink
Bug: ArithmeticOverflow when multiplying two large U256 numbers (Fue…
Browse files Browse the repository at this point in the history
…lLabs#4390)

## Description

Closes FuelLabs#4376 

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [x] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.

---------

Co-authored-by: Mohammad Fawaz <[email protected]>
  • Loading branch information
rostyslavtyshko and mohammadfawaz authored Apr 4, 2023
1 parent 32022b4 commit 14d8ead
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 3 deletions.
18 changes: 15 additions & 3 deletions sway-lib-std/src/u256.sw
Original file line number Diff line number Diff line change
Expand Up @@ -478,15 +478,27 @@ impl core::ops::Multiply for U256 {
result_d_d.lower,
))
} else {
// note, that `self.a`, `self.b`, `other.a`, `other.b` are all equal to 0
let result_c_c = other.c.overflowing_mul(self.c);
let result_c_d = self.c.overflowing_mul(other.d);
let result_d_c = self.d.overflowing_mul(other.c);
let result_d_d = self.d.overflowing_mul(other.d);

let (overflow_of_c_to_b_1, mut c) = result_d_d.upper.overflowing_add(result_c_d.lower).into();

let (mut overflow_of_c_to_b_2, c) = c.overflowing_add(result_d_c.lower).into();

let (overflow_of_b_to_a_0, overflow_of_c_to_b_2) = overflow_of_c_to_b_1.overflowing_add(overflow_of_c_to_b_2).into();

let (overflow_of_b_to_a_1, mut b) = result_c_c.lower.overflowing_add(result_c_d.upper).into();
let (overflow_of_b_to_a_2, b) = b.overflowing_add(result_d_c.upper).into();
let (overflow_of_b_to_a_3, b) = b.overflowing_add(overflow_of_c_to_b_2).into();

U256::from((
result_c_c.upper,
result_c_c.lower + result_c_d.upper + result_d_c.upper,
result_d_d.upper + result_c_d.lower + result_d_c.lower,
// as overflow for a means overflow for the whole number, we are adding as is, not using `overflowing_add`
result_c_c.upper + overflow_of_b_to_a_3 + overflow_of_b_to_a_2 + overflow_of_b_to_a_1 + overflow_of_b_to_a_0,
b,
c,
result_d_d.lower,
))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,10 @@ fn main() -> bool {
assert(a_2_61_mul_5.a == (1 << 61) * 5);
assert(a_2_61_mul_5.b == 0);

let x = U256::from((0, 0, 6, 10319535557742690304));
let sq = x * x;
let expected = U256::from((0, 43, 480205198502801427, 2874424729911951360));
assert(sq == expected);

true
}

0 comments on commit 14d8ead

Please sign in to comment.