Skip to content

Commit d821dcb

Browse files
bitzoicIGI-111
andauthored
Merge commit from fork
* Ensure U128 Pow reverts on overflow * Add comments * Add upper and lower edge case --------- Co-authored-by: IGI-111 <igi-111@protonmail.com>
1 parent f6be125 commit d821dcb

File tree

2 files changed

+119
-16
lines changed
  • sway-lib-std/src
  • test/src/in_language_tests/test_programs/u128_inline_tests/src

2 files changed

+119
-16
lines changed

sway-lib-std/src/u128.sw

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use ::registers::{flags, overflow};
1313
use ::math::*;
1414
use ::result::Result::{self, *};
1515
use ::option::Option::{self, None, Some};
16+
use ::revert::revert;
1617
use ::ops::*;
1718
use ::codec::*;
1819

@@ -723,7 +724,7 @@ fn u128_checked_mul(a: U128, b: U128) -> Option<U128> {
723724
// in case both of the `U128` upper parts are bigger than zero,
724725
// it automatically means overflow, as any `U128` value
725726
// is upper part multiplied by 2 ^ 64 + lower part
726-
if a.upper != 0 || b.upper != 0 {
727+
if a.upper != 0 && b.upper != 0 {
727728
return None
728729
}
729730

@@ -765,7 +766,14 @@ impl Power for U128 {
765766

766767
while exp & 1 == 0 {
767768
match u128_checked_mul(value, value) {
768-
None => return U128::zero(),
769+
None => {
770+
if panic_on_overflow_enabled() {
771+
revert(0);
772+
} else {
773+
// Return zero on overflow as per the Fuel VM Specifications
774+
return U128::zero()
775+
}
776+
},
769777
Some(v) => value = v,
770778
};
771779
exp >>= 1;
@@ -779,12 +787,22 @@ impl Power for U128 {
779787
while exp > 1 {
780788
exp >>= 1;
781789
match u128_checked_mul(value, value) {
782-
None => return U128::zero(),
790+
None => if panic_on_overflow_enabled() {
791+
revert(0);
792+
} else {
793+
// Return zero on overflow as per the Fuel VM Specifications
794+
return U128::zero()
795+
},
783796
Some(v) => value = v,
784797
};
785798
if exp & 1 == 1 {
786799
match u128_checked_mul(acc, value) {
787-
None => return U128::zero(),
800+
None => if panic_on_overflow_enabled() {
801+
revert(0);
802+
} else {
803+
// Return zero on overflow as per the Fuel VM Specifications
804+
return U128::zero()
805+
},
788806
Some(v) => acc = v,
789807
};
790808
}

test/src/in_language_tests/test_programs/u128_inline_tests/src/main.sw

Lines changed: 97 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -643,14 +643,18 @@ fn u128_multiply() {
643643
let mul_128_max = max_u64 * max_u64;
644644
assert(mul_128_max.upper() == u64::max() - 1);
645645
assert(mul_128_max.lower() == 1);
646+
647+
let upper_u128 = U128::from((1, 0));
648+
assert(upper_u128 * U128::from(2u64) == U128::from((2,0)));
646649
}
647650

648651
#[test(should_revert)]
649652
fn revert_u128_multiply() {
650653
let first = U128::from((0, 2));
651654
let second = U128::from((u64::max(), 1));
652655

653-
let _result = first * second;
656+
let result = first * second;
657+
log(result);
654658
}
655659

656660
#[test(should_revert)]
@@ -766,19 +770,22 @@ fn u128_pow() {
766770
u_128 = U128::from((0, 13));
767771
u_128 = u_128.pow(1u32);
768772
assert(u_128 == U128::from((0, 13)));
769-
}
770-
771-
#[test]
772-
fn u128_overflowing_pow() {
773-
// Overflow on pow should return 0 if panic is disabled
774-
let prior_flags = disable_panic_on_overflow();
775-
let a = U128::max();
776773

777-
let res = a.pow(2);
774+
let max_u64_u128 = U128::from(u64::max());
775+
let max_pow = max_u64_u128.pow(2);
776+
let expected_result = U128::from((18446744073709551614, 1));
777+
assert(max_pow == expected_result);
778778

779-
assert(res == U128::from((0, 0)));
779+
let u128_upper_and_lower_not_zero = U128::from((1, 1));
780+
let upper_and_lower_result = u128_upper_and_lower_not_zero.pow(1);
781+
assert(upper_and_lower_result == u128_upper_and_lower_not_zero);
782+
}
780783

781-
set_flags(prior_flags);
784+
#[test(should_revert)]
785+
fn revert_u128_pow_overflow() {
786+
let max_u64_u128 = U128::from(u64::max());
787+
let max_pow = max_u64_u128.pow(3);
788+
log(max_pow);
782789
}
783790

784791
#[test]
@@ -1327,6 +1334,84 @@ fn parity_u128_log_with_ruint() {
13271334
assert(prior_flags == flags());
13281335
}
13291336

1337+
#[test]
1338+
fn u128_overflowing_add() {
1339+
let prior_flags = disable_panic_on_overflow();
1340+
let a = U128::max();
1341+
let b = U128::from((0, 1));
1342+
let c = a + b;
1343+
1344+
assert(c == U128::from((0, 0)));
1345+
1346+
set_flags(prior_flags);
1347+
}
1348+
1349+
#[test]
1350+
fn u128_underflowing_sub() {
1351+
let prior_flags = disable_panic_on_overflow();
1352+
let a = U128::from((0, 1));
1353+
let b = U128::from((0, 2));
1354+
let c = a - b;
1355+
1356+
assert(c == U128::max());
1357+
1358+
set_flags(prior_flags);
1359+
}
1360+
1361+
#[test]
1362+
fn u128_overflowing_mul() {
1363+
let prior_flags = disable_panic_on_overflow();
1364+
let a = U128::max();
1365+
let b = U128::from((0, 2));
1366+
let c = a * b;
1367+
1368+
// 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE
1369+
assert(c == U128::from((0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE)));
1370+
1371+
set_flags(prior_flags);
1372+
}
1373+
1374+
#[test]
1375+
fn u128_overflowing_pow() {
1376+
// Overflow on pow should return 0 if panic is disabled
1377+
let prior_flags = disable_panic_on_overflow();
1378+
let a = U128::max();
1379+
1380+
let res = a.pow(2);
1381+
1382+
assert(res == U128::from((0, 0)));
1383+
1384+
assert(U128::from(u64::max()).pow(100) == U128::zero());
1385+
1386+
assert(U128::from(2u32).pow(150) == U128::zero());
1387+
1388+
let lower_max = U128::from((0, u64::max()));
1389+
let with_upper_1 = lower_max + U128::from(1u32);
1390+
assert(with_upper_1 == U128::from((1, 0)));
1391+
assert(with_upper_1 > lower_max);
1392+
let powered_to_zero = with_upper_1.pow(2);
1393+
assert(powered_to_zero == U128::zero());
1394+
1395+
1396+
let u128_upper_and_lower_not_zero = U128::from((1, 1));
1397+
let upper_and_lower_result = u128_upper_and_lower_not_zero.pow(2);
1398+
assert(upper_and_lower_result == U128::zero());
1399+
1400+
set_flags(prior_flags);
1401+
}
1402+
1403+
#[test]
1404+
fn u128_unsafemath_log2() {
1405+
let prior_flags = disable_panic_on_unsafe_math();
1406+
// 0 is not a valid operand for log2
1407+
let a = U128::zero();
1408+
let res = a.log2();
1409+
1410+
assert(res == U128::zero());
1411+
1412+
set_flags(prior_flags);
1413+
}
1414+
13301415
#[test]
13311416
fn u128_as_u256() {
13321417
let mut vals = Vec::new();
@@ -1361,4 +1446,4 @@ fn u128_as_u256() {
13611446
assert(u256_val == asm_val);
13621447
}
13631448
}
1364-
}
1449+
}

0 commit comments

Comments
 (0)