From e8d0d619c4bf56813e77984e7b286bce77ad6bca Mon Sep 17 00:00:00 2001 From: aritkulova Date: Thu, 11 Jun 2026 19:34:40 +0300 Subject: [PATCH 1/2] added safe functions for u8, u16, u32, u64 --- simf/u16.simf | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ simf/u32.simf | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ simf/u64.simf | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ simf/u8.simf | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+) create mode 100644 simf/u16.simf create mode 100644 simf/u32.simf create mode 100644 simf/u64.simf create mode 100644 simf/u8.simf diff --git a/simf/u16.simf b/simf/u16.simf new file mode 100644 index 0000000..f4f7dd4 --- /dev/null +++ b/simf/u16.simf @@ -0,0 +1,61 @@ +/// Returns the sum of two u16 values wrapped in Some, or None if the result overflows u16 +fn checked_add_16(a: u16, b: u16) -> Option { + let (carry, sum): (bool, u16) = jet::add_16(a, b); + + match carry { + true => None, + false => Some(sum), + } +} + +/// Returns the sum of two u16 values, panics if the result overflows u16 +fn safe_add_16(a: u16, b: u16) -> u16 { + unwrap(checked_add_16(a, b)) +} + +/// Returns the difference of two u16 values wrapped in Some, or None if the result overflows u16 +fn checked_sub_16(a: u16, b: u16) -> Option { + let (borrow, diff): (bool, u16) = jet::subtract_16(a, b); + match borrow { + true => None, + false => Some(diff), + } +} + +/// Returns the difference of two u16 values, panics if the result overflows u16 +fn safe_sub_16(a: u16, b: u16) -> u16 { + unwrap(checked_sub_16(a, b)) +} + +/// Returns the product of two u16 values wrapped in Some, or None if the result overflows u16 +fn checked_mul_16(a: u16, b: u16) -> Option { + let result: u32 = jet::multiply_16(a, b); + + let (high, low): (u16, u16) = ::into(result); + + match jet::is_zero_16(high) { + true => Some(low), + false => None, + } +} + +/// Returns the product of two u16 values, panics if the result overflows u16 +fn safe_mul_16(a: u16, b: u16) -> u16 { + unwrap(checked_mul_16(a, b)) +} + +/// Returns the quotient of two u16 values wrapped in Some, or None if the result overflows u16 +fn checked_div_16(a: u16, b: u16) -> Option { + match jet::is_zero_16(b) { + true => None, + false => Some(jet::divide_16(a, b)), + } +} + +/// Returns the quotient of two u16 values, panics if the result overflows u16 +fn safe_div_16(a: u16, b: u16) -> u16 { + unwrap(checked_div_16(a, b)) +} + +// todo: remove after module functionality is implemented +fn main() {} diff --git a/simf/u32.simf b/simf/u32.simf new file mode 100644 index 0000000..500e9cb --- /dev/null +++ b/simf/u32.simf @@ -0,0 +1,62 @@ +/// Returns the sum of two u32 values wrapped in Some, or None if the result overflows u32 +fn checked_add_32(a: u32, b: u32) -> Option { + let (carry, sum): (bool, u32) = jet::add_32(a, b); + + match carry { + true => None, + false => Some(sum), + } +} + +/// Returns the sum of two u32 values, panics if the result overflows u32 +fn safe_add_32(a: u32, b: u32) -> u32 { + unwrap(checked_add_32(a, b)) +} + +/// Returns the sum of two u32 values, panics if the result overflows u32 +fn checked_sub_32(a: u32, b: u32) -> Option { + let (borrow, diff): (bool, u32) = jet::subtract_32(a, b); + + match borrow { + true => None, + false => Some(diff), + } +} + +/// Returns the difference of two u32 values, panics if the result overflows u32 +fn safe_sub_32(a: u32, b: u32) -> u32 { + unwrap(checked_sub_32(a, b)) +} + +/// Returns the product of two u32 values wrapped in Some, or None if the result overflows u32 +fn checked_mul_32(a: u32, b: u32) -> Option { + let result: u64 = jet::multiply_32(a, b); + + let (high, low): (u32, u32) = ::into(result); + + match jet::is_zero_32(high) { + true => Some(low), + false => None, + } +} + +/// Returns the product of two u32 values, panics if the result overflows u32 +fn safe_mul_32(a: u32, b: u32) -> u32 { + unwrap(checked_mul_32(a, b)) +} + +/// Returns the quotient of two u32 values wrapped in Some, or None if the result overflows u32 +fn checked_div_32(a: u32, b: u32) -> Option { + match jet::is_zero_32(b) { + true => None, + false => Some(jet::divide_32(a, b)), + } +} + +/// Returns the quotient of two u32 values, panics if the result overflows u32 +fn safe_div_32(a: u32, b: u32) -> u32 { + unwrap(checked_div_32(a, b)) +} + +// todo: remove after module functionality is implemented +fn main() {} diff --git a/simf/u64.simf b/simf/u64.simf new file mode 100644 index 0000000..e4bf114 --- /dev/null +++ b/simf/u64.simf @@ -0,0 +1,62 @@ +/// Returns the sum of two u64 values wrapped in Some, or None if the result overflows u64 +fn checked_add_64(a: u64, b: u64) -> Option { + let (carry, sum): (bool, u64) = jet::add_64(a, b); + + match carry { + true => None, + false => Some(sum), + } +} + +/// Returns the sum of two u64 values, panics if the result overflows u64 +fn safe_add_64(a: u64, b: u64) -> u64 { + unwrap(checked_add_64(a, b)) +} + +/// Returns the sum of two u64 values, panics if the result overflows u64 +fn checked_sub_64(a: u64, b: u64) -> Option { + let (borrow, diff): (bool, u64) = jet::subtract_64(a, b); + + match borrow { + true => None, + false => Some(diff), + } +} + +/// Returns the difference of two u64 values, panics if the result overflows u64 +fn safe_sub_64(a: u64, b: u64) -> u64 { + unwrap(checked_sub_64(a, b)) +} + +/// Returns the product of two u64 values wrapped in Some, or None if the result overflows u64 +fn checked_mul_64(a: u64, b: u64) -> Option { + let result: u128 = jet::multiply_64(a, b); + + let (high, low): (u64, u64) = ::into(result); + + match jet::is_zero_64(high) { + true => Some(low), + false => None, + } +} + +/// Returns the product of two u64 values, panics if the result overflows u64 +fn safe_mul_64(a: u64, b: u64) -> u64 { + unwrap(checked_mul_64(a, b)) +} + +/// Returns the quotient of two u64 values wrapped in Some, or None if the result overflows u64 +fn checked_div_64(a: u64, b: u64) -> Option { + match jet::is_zero_64(b) { + true => None, + false => Some(jet::divide_64(a, b)), + } +} + +/// Returns the quotient of two u64 values, panics if the result overflows u64 +fn safe_div_64(a: u64, b: u64) -> u64 { + unwrap(checked_div_64(a, b)) +} + +// todo: remove after module functionality is implemented +fn main() {} diff --git a/simf/u8.simf b/simf/u8.simf new file mode 100644 index 0000000..c5ea0ec --- /dev/null +++ b/simf/u8.simf @@ -0,0 +1,62 @@ +/// Returns the sum of two u8 values wrapped in Some, or None if the result overflows u8 +fn checked_add_8(a: u8, b: u8) -> Option { + let (carry, sum): (bool, u8) = jet::add_8(a, b); + + match carry { + true => None, + false => Some(sum), + } +} + +/// Returns the sum of two u8 values, panics if the result overflows u8 +fn safe_add_8(a: u8, b: u8) -> u8 { + unwrap(checked_add_8(a, b)) +} + +/// Returns the difference of two u8 values wrapped in Some, or None if the result overflows u8 +fn checked_sub_8(a: u8, b: u8) -> Option { + let (borrow, diff): (bool, u8) = jet::subtract_8(a, b); + + match borrow { + true => None, + false => Some(diff), + } +} + +/// Returns the difference of two u8 values, panics if the result overflows u8 +fn safe_sub_8(a: u8, b: u8) -> u8 { + unwrap(checked_sub_8(a, b)) +} + +/// Returns the product of two u8 values wrapped in Some, or None if the result overflows u8 +fn checked_mul_8(a: u8, b: u8) -> Option { + let result: u16 = jet::multiply_8(a, b); + + let (high, low): (u8, u8) = ::into(result); + + match jet::is_zero_8(high) { + true => Some(low), + false => None, + } +} + +/// Returns the product of two u8 values, panics if the result overflows u8 +fn safe_mul_8(a: u8, b: u8) -> u8 { + unwrap(checked_mul_8(a, b)) +} + +/// Returns the quotient of two u8 values wrapped in Some, or None if the result overflows u8 +fn checked_div_8(a: u8, b: u8) -> Option { + match jet::is_zero_8(b) { + true => None, + false => Some(jet::divide_8(a, b)), + } +} + +/// Returns the quotient of two u8 values, panics if the result overflows u8 +fn safe_div_8(a: u8, b: u8) -> u8 { + unwrap(checked_div_8(a, b)) +} + +// todo: remove after module functionality is implemented +fn main() {} From 179b042834a1d9e05c4bd0f5979dbccfb47c6798 Mon Sep 17 00:00:00 2001 From: aritkulova Date: Thu, 11 Jun 2026 19:35:22 +0300 Subject: [PATCH 2/2] added mocks and tests for uints --- Cargo.lock | 1 + Cargo.toml | 1 + simf/mock/u16_mock.simf | 193 ++++++++++++++++++ simf/mock/u32_mock.simf | 194 ++++++++++++++++++ simf/mock/u64_mock.simf | 194 ++++++++++++++++++ simf/mock/u8_mock.simf | 194 ++++++++++++++++++ tests/helper.rs | 9 + tests/u16_test.rs | 438 ++++++++++++++++++++++++++++++++++++++++ tests/u32_test.rs | 438 ++++++++++++++++++++++++++++++++++++++++ tests/u64_test.rs | 438 ++++++++++++++++++++++++++++++++++++++++ tests/u8_test.rs | 436 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 2536 insertions(+) create mode 100644 simf/mock/u16_mock.simf create mode 100644 simf/mock/u32_mock.simf create mode 100644 simf/mock/u64_mock.simf create mode 100644 simf/mock/u8_mock.simf create mode 100644 tests/helper.rs create mode 100644 tests/u16_test.rs create mode 100644 tests/u32_test.rs create mode 100644 tests/u64_test.rs create mode 100644 tests/u8_test.rs diff --git a/Cargo.lock b/Cargo.lock index 97599e2..c59c2ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1233,6 +1233,7 @@ name = "simplicityhl_std" version = "0.1.0" dependencies = [ "anyhow", + "rand", "smplx-std", ] diff --git a/Cargo.toml b/Cargo.toml index 074643e..c2cd2be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ version = "0.1.0" smplx-std = { version = ">=0.0.6, <0.1.0" } anyhow = { version = "1.0.101" } +rand = { version = "0.8.6" } diff --git a/simf/mock/u16_mock.simf b/simf/mock/u16_mock.simf new file mode 100644 index 0000000..577e802 --- /dev/null +++ b/simf/mock/u16_mock.simf @@ -0,0 +1,193 @@ +// todo: switch to function import when available +fn checked_add_16(a: u16, b: u16) -> Option { + let (carry, sum): (bool, u16) = jet::add_16(a, b); + + match carry { + true => None, + false => Some(sum), + } +} + +fn safe_add_16(a: u16, b: u16) -> u16 { + unwrap(checked_add_16(a, b)) +} + +fn checked_sub_16(a: u16, b: u16) -> Option { + let (borrow, diff): (bool, u16) = jet::subtract_16(a, b); + match borrow { + true => None, + false => Some(diff), + } +} + +fn safe_sub_16(a: u16, b: u16) -> u16 { + unwrap(checked_sub_16(a, b)) +} + +fn checked_mul_16(a: u16, b: u16) -> Option { + let result: u32 = jet::multiply_16(a, b); + + let (high, low): (u16, u16) = ::into(result); + + match jet::is_zero_16(high) { + true => Some(low), + false => None, + } +} + +fn safe_mul_16(a: u16, b: u16) -> u16 { + unwrap(checked_mul_16(a, b)) +} + +fn checked_div_16(a: u16, b: u16) -> Option { + match jet::is_zero_16(b) { + true => None, + false => Some(jet::divide_16(a, b)), + } +} + +fn safe_div_16(a: u16, b: u16) -> u16 { + unwrap(checked_div_16(a, b)) +} + +// helper +fn if_test_this_function(index: u8, flag: u8) -> bool { + jet::eq_8(index, flag) +} + +fn main() { + let function_index: u8 = witness::FUNCTION_INDEX; + let if_test_overflow: bool = witness::IF_TEST_OVERFLOW; + + let first_arg: u16 = witness::FIRST_ARG; + let second_arg: u16 = witness::SECOND_ARG; + let result: u16 = witness::RESULT; + + // add + match if_test_this_function(0, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u16: Option = checked_add_16(first_arg, second_arg); + assert!(is_none::(overflowing_u16)); + }, + false => { + let fitting_u16: Option = checked_add_16(first_arg, second_arg); + assert!(jet::eq_16(unwrap(fitting_u16), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(1, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u16: u16 = safe_add_16(first_arg, second_arg); + }, + false => { + let fitting_u16: u16 = safe_add_16(first_arg, second_arg); + assert!(jet::eq_16(fitting_u16, result)); + } + } + }, + false => (), + }; + + // subtract + match if_test_this_function(2, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u16: Option = checked_sub_16(first_arg, second_arg); + assert!(is_none::(overflowing_u16)); + }, + false => { + let fitting_u16: Option = checked_sub_16(first_arg, second_arg); + assert!(jet::eq_16(unwrap(fitting_u16), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(3, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u16: u16 = safe_sub_16(first_arg, second_arg); + }, + false => { + let fitting_u16: u16 = safe_sub_16(first_arg, second_arg); + assert!(jet::eq_16(fitting_u16, result)); + } + } + }, + false => (), + }; + + // multiply + match if_test_this_function(4, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u16: Option = checked_mul_16(first_arg, second_arg); + assert!(is_none::(overflowing_u16)); + }, + false => { + let fitting_u16: Option = checked_mul_16(first_arg, second_arg); + assert!(jet::eq_16(unwrap(fitting_u16), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(5, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u16: u16 = safe_mul_16(first_arg, second_arg); + }, + false => { + let fitting_u16: u16 = safe_mul_16(first_arg, second_arg); + assert!(jet::eq_16(fitting_u16, result)); + } + } + }, + false => (), + }; + + // divide + match if_test_this_function(6, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u16: Option = checked_div_16(first_arg, second_arg); + assert!(is_none::(overflowing_u16)); + }, + false => { + let fitting_u16: Option = checked_div_16(first_arg, second_arg); + assert!(jet::eq_16(unwrap(fitting_u16), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(7, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u16: u16 = safe_div_16(first_arg, second_arg); + }, + false => { + let fitting_u16: u16 = safe_div_16(first_arg, second_arg); + assert!(jet::eq_16(fitting_u16, result)); + } + } + }, + false => (), + }; +} diff --git a/simf/mock/u32_mock.simf b/simf/mock/u32_mock.simf new file mode 100644 index 0000000..2c14b28 --- /dev/null +++ b/simf/mock/u32_mock.simf @@ -0,0 +1,194 @@ +// todo: switch to function import when available +fn checked_add_32(a: u32, b: u32) -> Option { + let (carry, sum): (bool, u32) = jet::add_32(a, b); + + match carry { + true => None, + false => Some(sum), + } +} + +fn safe_add_32(a: u32, b: u32) -> u32 { + unwrap(checked_add_32(a, b)) +} + +fn checked_sub_32(a: u32, b: u32) -> Option { + let (borrow, diff): (bool, u32) = jet::subtract_32(a, b); + + match borrow { + true => None, + false => Some(diff), + } +} + +fn safe_sub_32(a: u32, b: u32) -> u32 { + unwrap(checked_sub_32(a, b)) +} + +fn checked_mul_32(a: u32, b: u32) -> Option { + let result: u64 = jet::multiply_32(a, b); + + let (high, low): (u32, u32) = ::into(result); + + match jet::is_zero_32(high) { + true => Some(low), + false => None, + } +} + +fn safe_mul_32(a: u32, b: u32) -> u32 { + unwrap(checked_mul_32(a, b)) +} + +fn checked_div_32(a: u32, b: u32) -> Option { + match jet::is_zero_32(b) { + true => None, + false => Some(jet::divide_32(a, b)), + } +} + +fn safe_div_32(a: u32, b: u32) -> u32 { + unwrap(checked_div_32(a, b)) +} + +// helper +fn if_test_this_function(index: u8, flag: u8) -> bool { + jet::eq_8(index, flag) +} + +fn main() { + let function_index: u8 = witness::FUNCTION_INDEX; + let if_test_overflow: bool = witness::IF_TEST_OVERFLOW; + + let first_arg: u32 = witness::FIRST_ARG; + let second_arg: u32 = witness::SECOND_ARG; + let result: u32 = witness::RESULT; + + // add + match if_test_this_function(0, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u32: Option = checked_add_32(first_arg, second_arg); + assert!(is_none::(overflowing_u32)); + }, + false => { + let fitting_u32: Option = checked_add_32(first_arg, second_arg); + assert!(jet::eq_32(unwrap(fitting_u32), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(1, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u32: u32 = safe_add_32(first_arg, second_arg); + }, + false => { + let fitting_u32: u32 = safe_add_32(first_arg, second_arg); + assert!(jet::eq_32(fitting_u32, result)); + } + } + }, + false => (), + }; + + // subtract + match if_test_this_function(2, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u32: Option = checked_sub_32(first_arg, second_arg); + assert!(is_none::(overflowing_u32)); + }, + false => { + let fitting_u32: Option = checked_sub_32(first_arg, second_arg); + assert!(jet::eq_32(unwrap(fitting_u32), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(3, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u32: u32 = safe_sub_32(first_arg, second_arg); + }, + false => { + let fitting_u32: u32 = safe_sub_32(first_arg, second_arg); + assert!(jet::eq_32(fitting_u32, result)); + } + } + }, + false => (), + }; + + // multiply + match if_test_this_function(4, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u32: Option = checked_mul_32(first_arg, second_arg); + assert!(is_none::(overflowing_u32)); + }, + false => { + let fitting_u32: Option = checked_mul_32(first_arg, second_arg); + assert!(jet::eq_32(unwrap(fitting_u32), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(5, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u32: u32 = safe_mul_32(first_arg, second_arg); + }, + false => { + let fitting_u32: u32 = safe_mul_32(first_arg, second_arg); + assert!(jet::eq_32(fitting_u32, result)); + } + } + }, + false => (), + }; + + // divide + match if_test_this_function(6, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u32: Option = checked_div_32(first_arg, second_arg); + assert!(is_none::(overflowing_u32)); + }, + false => { + let fitting_u32: Option = checked_div_32(first_arg, second_arg); + assert!(jet::eq_32(unwrap(fitting_u32), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(7, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u32: u32 = safe_div_32(first_arg, second_arg); + }, + false => { + let fitting_u32: u32 = safe_div_32(first_arg, second_arg); + assert!(jet::eq_32(fitting_u32, result)); + } + } + }, + false => (), + }; +} diff --git a/simf/mock/u64_mock.simf b/simf/mock/u64_mock.simf new file mode 100644 index 0000000..55ae8e0 --- /dev/null +++ b/simf/mock/u64_mock.simf @@ -0,0 +1,194 @@ +// todo: switch to function import when available +fn checked_add_64(a: u64, b: u64) -> Option { + let (carry, sum): (bool, u64) = jet::add_64(a, b); + + match carry { + true => None, + false => Some(sum), + } +} + +fn safe_add_64(a: u64, b: u64) -> u64 { + unwrap(checked_add_64(a, b)) +} + +fn checked_sub_64(a: u64, b: u64) -> Option { + let (borrow, diff): (bool, u64) = jet::subtract_64(a, b); + + match borrow { + true => None, + false => Some(diff), + } +} + +fn safe_sub_64(a: u64, b: u64) -> u64 { + unwrap(checked_sub_64(a, b)) +} + +fn checked_mul_64(a: u64, b: u64) -> Option { + let result: u128 = jet::multiply_64(a, b); + + let (high, low): (u64, u64) = ::into(result); + + match jet::is_zero_64(high) { + true => Some(low), + false => None, + } +} + +fn safe_mul_64(a: u64, b: u64) -> u64 { + unwrap(checked_mul_64(a, b)) +} + +fn checked_div_64(a: u64, b: u64) -> Option { + match jet::is_zero_64(b) { + true => None, + false => Some(jet::divide_64(a, b)), + } +} + +fn safe_div_64(a: u64, b: u64) -> u64 { + unwrap(checked_div_64(a, b)) +} + +// helper +fn if_test_this_function(index: u8, flag: u8) -> bool { + jet::eq_8(index, flag) +} + +fn main() { + let function_index: u8 = witness::FUNCTION_INDEX; + let if_test_overflow: bool = witness::IF_TEST_OVERFLOW; + + let first_arg: u64 = witness::FIRST_ARG; + let second_arg: u64 = witness::SECOND_ARG; + let result: u64 = witness::RESULT; + + // add + match if_test_this_function(0, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u64: Option = checked_add_64(first_arg, second_arg); + assert!(is_none::(overflowing_u64)); + }, + false => { + let fitting_u64: Option = checked_add_64(first_arg, second_arg); + assert!(jet::eq_64(unwrap(fitting_u64), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(1, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u64: u64 = safe_add_64(first_arg, second_arg); + }, + false => { + let fitting_u64: u64 = safe_add_64(first_arg, second_arg); + assert!(jet::eq_64(fitting_u64, result)); + } + } + }, + false => (), + }; + + // subtract + match if_test_this_function(2, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u64: Option = checked_sub_64(first_arg, second_arg); + assert!(is_none::(overflowing_u64)); + }, + false => { + let fitting_u64: Option = checked_sub_64(first_arg, second_arg); + assert!(jet::eq_64(unwrap(fitting_u64), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(3, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u64: u64 = safe_sub_64(first_arg, second_arg); + }, + false => { + let fitting_u64: u64 = safe_sub_64(first_arg, second_arg); + assert!(jet::eq_64(fitting_u64, result)); + } + } + }, + false => (), + }; + + // multiply + match if_test_this_function(4, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u64: Option = checked_mul_64(first_arg, second_arg); + assert!(is_none::(overflowing_u64)); + }, + false => { + let fitting_u64: Option = checked_mul_64(first_arg, second_arg); + assert!(jet::eq_64(unwrap(fitting_u64), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(5, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u64: u64 = safe_mul_64(first_arg, second_arg); + }, + false => { + let fitting_u64: u64 = safe_mul_64(first_arg, second_arg); + assert!(jet::eq_64(fitting_u64, result)); + } + } + }, + false => (), + }; + + // divide + match if_test_this_function(6, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u64: Option = checked_div_64(first_arg, second_arg); + assert!(is_none::(overflowing_u64)); + }, + false => { + let fitting_u64: Option = checked_div_64(first_arg, second_arg); + assert!(jet::eq_64(unwrap(fitting_u64), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(7, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u64: u64 = safe_div_64(first_arg, second_arg); + }, + false => { + let fitting_u64: u64 = safe_div_64(first_arg, second_arg); + assert!(jet::eq_64(fitting_u64, result)); + } + } + }, + false => (), + }; +} diff --git a/simf/mock/u8_mock.simf b/simf/mock/u8_mock.simf new file mode 100644 index 0000000..8f03ab1 --- /dev/null +++ b/simf/mock/u8_mock.simf @@ -0,0 +1,194 @@ +// todo: switch to function import when available +fn checked_add_8(a: u8, b: u8) -> Option { + let (carry, sum): (bool, u8) = jet::add_8(a, b); + + match carry { + true => None, + false => Some(sum), + } +} + +fn safe_add_8(a: u8, b: u8) -> u8 { + unwrap(checked_add_8(a, b)) +} + +fn checked_sub_8(a: u8, b: u8) -> Option { + let (borrow, diff): (bool, u8) = jet::subtract_8(a, b); + + match borrow { + true => None, + false => Some(diff), + } +} + +fn safe_sub_8(a: u8, b: u8) -> u8 { + unwrap(checked_sub_8(a, b)) +} + +fn checked_mul_8(a: u8, b: u8) -> Option { + let result: u16 = jet::multiply_8(a, b); + + let (high, low): (u8, u8) = ::into(result); + + match jet::is_zero_8(high) { + true => Some(low), + false => None, + } +} + +fn safe_mul_8(a: u8, b: u8) -> u8 { + unwrap(checked_mul_8(a, b)) +} + +fn checked_div_8(a: u8, b: u8) -> Option { + match jet::is_zero_8(b) { + true => None, + false => Some(jet::divide_8(a, b)), + } +} + +fn safe_div_8(a: u8, b: u8) -> u8 { + unwrap(checked_div_8(a, b)) +} + +// helper +fn if_test_this_function(index: u8, flag: u8) -> bool { + jet::eq_8(index, flag) +} + +fn main() { + let function_index: u8 = witness::FUNCTION_INDEX; + let if_test_overflow: bool = witness::IF_TEST_OVERFLOW; + + let first_arg: u8 = witness::FIRST_ARG; + let second_arg: u8 = witness::SECOND_ARG; + let result: u8 = witness::RESULT; + + // add + match if_test_this_function(0, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u8: Option = checked_add_8(first_arg, second_arg); + assert!(is_none::(overflowing_u8)); + }, + false => { + let fitting_u8: Option = checked_add_8(first_arg, second_arg); + assert!(jet::eq_8(unwrap(fitting_u8), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(1, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u8: u8 = safe_add_8(first_arg, second_arg); + }, + false => { + let fitting_u8: u8 = safe_add_8(first_arg, second_arg); + assert!(jet::eq_8(fitting_u8, result)); + } + } + }, + false => (), + }; + + // subtract + match if_test_this_function(2, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u8: Option = checked_sub_8(first_arg, second_arg); + assert!(is_none::(overflowing_u8)); + }, + false => { + let fitting_u8: Option = checked_sub_8(first_arg, second_arg); + assert!(jet::eq_8(unwrap(fitting_u8), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(3, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u8: u8 = safe_sub_8(first_arg, second_arg); + }, + false => { + let fitting_u8: u8 = safe_sub_8(first_arg, second_arg); + assert!(jet::eq_8(fitting_u8, result)); + } + } + }, + false => (), + }; + + // multiply + match if_test_this_function(4, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u8: Option = checked_mul_8(first_arg, second_arg); + assert!(is_none::(overflowing_u8)); + }, + false => { + let fitting_u8: Option = checked_mul_8(first_arg, second_arg); + assert!(jet::eq_8(unwrap(fitting_u8), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(5, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u8: u8 = safe_mul_8(first_arg, second_arg); + }, + false => { + let fitting_u8: u8 = safe_mul_8(first_arg, second_arg); + assert!(jet::eq_8(fitting_u8, result)); + } + } + }, + false => (), + }; + + // divide + match if_test_this_function(6, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u8: Option = checked_div_8(first_arg, second_arg); + assert!(is_none::(overflowing_u8)); + }, + false => { + let fitting_u8: Option = checked_div_8(first_arg, second_arg); + assert!(jet::eq_8(unwrap(fitting_u8), result)); + } + } + }, + false => (), + }; + + match if_test_this_function(7, function_index) { + true => { + match if_test_overflow { + true => { + let overflowing_u8: u8 = safe_div_8(first_arg, second_arg); + }, + false => { + let fitting_u8: u8 = safe_div_8(first_arg, second_arg); + assert!(jet::eq_8(fitting_u8, result)); + } + } + }, + false => (), + }; +} diff --git a/tests/helper.rs b/tests/helper.rs new file mode 100644 index 0000000..a94a76b --- /dev/null +++ b/tests/helper.rs @@ -0,0 +1,9 @@ +#[allow(dead_code)] +pub enum IfTestOverflow { + NotOverflow, + Overflow, +} + +pub fn cast_to_bool(flag: u8) -> bool { + flag == 1 +} diff --git a/tests/u16_test.rs b/tests/u16_test.rs new file mode 100644 index 0000000..1f99a0a --- /dev/null +++ b/tests/u16_test.rs @@ -0,0 +1,438 @@ +use simplex::simplicityhl::elements::Script; + +use simplex::transaction::{FinalTransaction, PartialInput, ProgramInput, RequiredSignature}; + +use simplicityhl_std::artifacts::mock::u16_mock::U16MockProgram; +use simplicityhl_std::artifacts::mock::u16_mock::derived_u16_mock::{ + U16MockArguments, U16MockWitness, +}; + +use rand::Rng; + +mod helper; +use crate::helper::{IfTestOverflow, cast_to_bool}; + +enum FunctionToTest { + CheckedAdd16, + SafeAdd16, + CheckedSub16, + SafeSub16, + CheckedMul16, + SafeMul16, + CheckedDiv16, + SafeDiv16, +} + +fn get_script(context: &simplex::TestContext) -> (U16MockProgram, Script) { + let arguments = U16MockArguments {}; + + let logical_operations_program = U16MockProgram::new(arguments); + + let logical_operations_script = + logical_operations_program.get_script_pubkey(context.get_network()); + + (logical_operations_program, logical_operations_script) +} + +fn fund_script(context: &simplex::TestContext) -> anyhow::Result<()> { + let signer = context.get_default_signer(); + + let (_, logical_operations_script) = get_script(context); + + let tx_receipt = signer.send(logical_operations_script.clone(), 50)?; + println!("Broadcast: {}", tx_receipt); + + Ok(()) +} + +fn spend_script( + context: &simplex::TestContext, + function_index: FunctionToTest, + if_test_overflow: IfTestOverflow, + first_arg: u16, + second_arg: u16, + result: u16, +) -> anyhow::Result<()> { + let signer = context.get_default_signer(); + let provider = context.get_default_provider(); + + let (logical_operations_program, logical_operations_script) = get_script(context); + + let asserts_utxos = provider.fetch_scripthash_utxos(&logical_operations_script)?; + + let mut ft = FinalTransaction::new(); + + let witness = U16MockWitness { + function_index: function_index as u8, + if_test_overflow: cast_to_bool(if_test_overflow as u8), + first_arg, + second_arg, + result, + }; + + ft.add_program_input( + PartialInput::new(asserts_utxos[0].clone()), + ProgramInput::new( + Box::new(logical_operations_program.as_ref().clone()), + Box::new(witness.clone()), + ), + RequiredSignature::None, + ); + + let tx_receipt = signer.broadcast(&ft)?; + println!("Broadcast: {}", tx_receipt); + + Ok(()) +} + +#[simplex::test] +fn u16_test_checked_add_16_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u16::MAX / 2); + let second_arg = rand::thread_rng().gen_range(0..=u16::MAX / 2); + let result = first_arg + second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedAdd16, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u16_test_checked_add_16_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u16::MAX; + let second_arg = rand::thread_rng().gen_range(1..=u16::MAX); + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedAdd16, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u16_test_safe_add_16_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u16::MAX / 2); + let second_arg = rand::thread_rng().gen_range(0..=u16::MAX / 2); + let result = first_arg + second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeAdd16, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u16_test_safe_add_16_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u16::MAX; + let second_arg = rand::thread_rng().gen_range(1..=u16::MAX); + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeAdd16, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} + +#[simplex::test] +fn u16_test_checked_sub_16_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u16::MAX); + let second_arg = rand::thread_rng().gen_range(0..=first_arg); + let result = first_arg - second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedSub16, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u16_test_checked_sub_16_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u16::MAX - 1); + let second_arg = rand::thread_rng().gen_range(first_arg + 1..=u16::MAX); + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedSub16, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u16_test_safe_sub_16_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u16::MAX); + let second_arg = rand::thread_rng().gen_range(0..=first_arg); + let result = first_arg - second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeSub16, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u16_test_safe_sub_16_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u16::MAX - 1); + let second_arg = rand::thread_rng().gen_range(first_arg + 1..=u16::MAX); + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeSub16, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} + +#[simplex::test] +fn u16_test_checked_mul_16_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..2_u16.pow(16 / 2)); + let second_arg = rand::thread_rng().gen_range(0..2_u16.pow(16 / 2)); + let result = first_arg * second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedMul16, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u16_test_checked_mul_16_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u16::MAX; + let second_arg = rand::thread_rng().gen_range(2..=u16::MAX); + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedMul16, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u16_test_safe_mul_16_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..2_u16.pow(16 / 2)); + let second_arg = rand::thread_rng().gen_range(0..2_u16.pow(16 / 2)); + let result = first_arg * second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeMul16, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u16_test_safe_mul_16_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u16::MAX; + let second_arg = rand::thread_rng().gen_range(2..=u16::MAX); + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeMul16, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} + +#[simplex::test] +fn u16_test_checked_div_16_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u16::MAX); + let second_arg = rand::thread_rng().gen_range(1..=u16::MAX); + let result = first_arg / second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedDiv16, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u16_test_checked_div_16_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u16::MAX); + let second_arg = 0; + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedDiv16, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u16_test_safe_div_16_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u16::MAX); + let second_arg = rand::thread_rng().gen_range(1..=u16::MAX); + let result = first_arg / second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeDiv16, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u16_test_safe_div_16_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u16::MAX); + let second_arg = 0; + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeDiv16, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} diff --git a/tests/u32_test.rs b/tests/u32_test.rs new file mode 100644 index 0000000..41d0b7a --- /dev/null +++ b/tests/u32_test.rs @@ -0,0 +1,438 @@ +use simplex::simplicityhl::elements::Script; + +use simplex::transaction::{FinalTransaction, PartialInput, ProgramInput, RequiredSignature}; + +use simplicityhl_std::artifacts::mock::u32_mock::U32MockProgram; +use simplicityhl_std::artifacts::mock::u32_mock::derived_u32_mock::{ + U32MockArguments, U32MockWitness, +}; + +use rand::Rng; + +mod helper; +use crate::helper::{IfTestOverflow, cast_to_bool}; + +enum FunctionToTest { + CheckedAdd32, + SafeAdd32, + CheckedSub32, + SafeSub32, + CheckedMul32, + SafeMul32, + CheckedDiv32, + SafeDiv32, +} + +fn get_script(context: &simplex::TestContext) -> (U32MockProgram, Script) { + let arguments = U32MockArguments {}; + + let logical_operations_program = U32MockProgram::new(arguments); + + let logical_operations_script = + logical_operations_program.get_script_pubkey(context.get_network()); + + (logical_operations_program, logical_operations_script) +} + +fn fund_script(context: &simplex::TestContext) -> anyhow::Result<()> { + let signer = context.get_default_signer(); + + let (_, logical_operations_script) = get_script(context); + + let tx_receipt = signer.send(logical_operations_script.clone(), 50)?; + println!("Broadcast: {}", tx_receipt); + + Ok(()) +} + +fn spend_script( + context: &simplex::TestContext, + function_index: FunctionToTest, + if_test_overflow: IfTestOverflow, + first_arg: u32, + second_arg: u32, + result: u32, +) -> anyhow::Result<()> { + let signer = context.get_default_signer(); + let provider = context.get_default_provider(); + + let (logical_operations_program, logical_operations_script) = get_script(context); + + let asserts_utxos = provider.fetch_scripthash_utxos(&logical_operations_script)?; + + let mut ft = FinalTransaction::new(); + + let witness = U32MockWitness { + function_index: function_index as u8, + if_test_overflow: cast_to_bool(if_test_overflow as u8), + first_arg, + second_arg, + result, + }; + + ft.add_program_input( + PartialInput::new(asserts_utxos[0].clone()), + ProgramInput::new( + Box::new(logical_operations_program.as_ref().clone()), + Box::new(witness.clone()), + ), + RequiredSignature::None, + ); + + let tx_receipt = signer.broadcast(&ft)?; + println!("Broadcast: {}", tx_receipt); + + Ok(()) +} + +#[simplex::test] +fn u32_test_checked_add_32_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u32::MAX / 2); + let second_arg = rand::thread_rng().gen_range(0..=u32::MAX / 2); + let result = first_arg + second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedAdd32, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u32_test_checked_add_32_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u32::MAX; + let second_arg = rand::thread_rng().gen_range(1..=u32::MAX); + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedAdd32, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u32_test_safe_add_32_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u32::MAX / 2); + let second_arg = rand::thread_rng().gen_range(0..=u32::MAX / 2); + let result = first_arg + second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeAdd32, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u32_test_safe_add_32_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u32::MAX; + let second_arg = rand::thread_rng().gen_range(1..=u32::MAX); + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeAdd32, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} + +#[simplex::test] +fn u32_test_checked_sub_32_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u32::MAX); + let second_arg = rand::thread_rng().gen_range(0..=first_arg); + let result = first_arg - second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedSub32, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u32_test_checked_sub_32_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u32::MAX - 1); + let second_arg = rand::thread_rng().gen_range(first_arg + 1..=u32::MAX); + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedSub32, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u32_test_safe_sub_32_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u32::MAX); + let second_arg = rand::thread_rng().gen_range(0..=first_arg); + let result = first_arg - second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeSub32, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u32_test_safe_sub_32_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u32::MAX - 1); + let second_arg = rand::thread_rng().gen_range(first_arg + 1..=u32::MAX); + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeSub32, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} + +#[simplex::test] +fn u32_test_checked_mul_32_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..2_u32.pow(32 / 2)); + let second_arg = rand::thread_rng().gen_range(0..2_u32.pow(32 / 2)); + let result = first_arg * second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedMul32, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u32_test_checked_mul_32_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u32::MAX; + let second_arg = rand::thread_rng().gen_range(2..=u32::MAX); + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedMul32, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u32_test_safe_mul_32_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..2_u32.pow(32 / 2)); + let second_arg = rand::thread_rng().gen_range(0..2_u32.pow(32 / 2)); + let result = first_arg * second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeMul32, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u32_test_safe_mul_32_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u32::MAX; + let second_arg = rand::thread_rng().gen_range(2..=u32::MAX); + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeMul32, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} + +#[simplex::test] +fn u32_test_checked_div_32_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u32::MAX); + let second_arg = rand::thread_rng().gen_range(1..=u32::MAX); + let result = first_arg / second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedDiv32, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u32_test_checked_div_32_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u32::MAX); + let second_arg = 0; + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedDiv32, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u32_test_safe_div_32_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u32::MAX); + let second_arg = rand::thread_rng().gen_range(1..=u32::MAX); + let result = first_arg / second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeDiv32, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u32_test_safe_div_32_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u32::MAX); + let second_arg = 0; + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeDiv32, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} diff --git a/tests/u64_test.rs b/tests/u64_test.rs new file mode 100644 index 0000000..85e9ba2 --- /dev/null +++ b/tests/u64_test.rs @@ -0,0 +1,438 @@ +use simplex::simplicityhl::elements::Script; + +use simplex::transaction::{FinalTransaction, PartialInput, ProgramInput, RequiredSignature}; + +use simplicityhl_std::artifacts::mock::u64_mock::U64MockProgram; +use simplicityhl_std::artifacts::mock::u64_mock::derived_u64_mock::{ + U64MockArguments, U64MockWitness, +}; + +use rand::Rng; + +mod helper; +use crate::helper::{IfTestOverflow, cast_to_bool}; + +enum FunctionToTest { + CheckedAdd64, + SafeAdd64, + CheckedSub64, + SafeSub64, + CheckedMul64, + SafeMul64, + CheckedDiv64, + SafeDiv64, +} + +fn get_script(context: &simplex::TestContext) -> (U64MockProgram, Script) { + let arguments = U64MockArguments {}; + + let logical_operations_program = U64MockProgram::new(arguments); + + let logical_operations_script = + logical_operations_program.get_script_pubkey(context.get_network()); + + (logical_operations_program, logical_operations_script) +} + +fn fund_script(context: &simplex::TestContext) -> anyhow::Result<()> { + let signer = context.get_default_signer(); + + let (_, logical_operations_script) = get_script(context); + + let tx_receipt = signer.send(logical_operations_script.clone(), 50)?; + println!("Broadcast: {}", tx_receipt); + + Ok(()) +} + +fn spend_script( + context: &simplex::TestContext, + function_index: FunctionToTest, + if_test_overflow: IfTestOverflow, + first_arg: u64, + second_arg: u64, + result: u64, +) -> anyhow::Result<()> { + let signer = context.get_default_signer(); + let provider = context.get_default_provider(); + + let (logical_operations_program, logical_operations_script) = get_script(context); + + let asserts_utxos = provider.fetch_scripthash_utxos(&logical_operations_script)?; + + let mut ft = FinalTransaction::new(); + + let witness = U64MockWitness { + function_index: function_index as u8, + if_test_overflow: cast_to_bool(if_test_overflow as u8), + first_arg, + second_arg, + result, + }; + + ft.add_program_input( + PartialInput::new(asserts_utxos[0].clone()), + ProgramInput::new( + Box::new(logical_operations_program.as_ref().clone()), + Box::new(witness.clone()), + ), + RequiredSignature::None, + ); + + let tx_receipt = signer.broadcast(&ft)?; + println!("Broadcast: {}", tx_receipt); + + Ok(()) +} + +#[simplex::test] +fn u64_test_checked_add_64_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u64::MAX / 2); + let second_arg = rand::thread_rng().gen_range(0..=u64::MAX / 2); + let result = first_arg + second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedAdd64, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u64_test_checked_add_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u64::MAX; + let second_arg = rand::thread_rng().gen_range(1..=u64::MAX); + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedAdd64, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u64_test_safe_add_64_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u64::MAX / 2); + let second_arg = rand::thread_rng().gen_range(0..=u64::MAX / 2); + let result = first_arg + second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeAdd64, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u64_test_safe_add_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u64::MAX; + let second_arg = rand::thread_rng().gen_range(1..=u64::MAX); + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeAdd64, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} + +#[simplex::test] +fn u64_test_checked_sub_64_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u64::MAX); + let second_arg = rand::thread_rng().gen_range(0..=first_arg); + let result = first_arg - second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedSub64, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u64_test_checked_sub_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u64::MAX - 1); + let second_arg = rand::thread_rng().gen_range(first_arg + 1..=u64::MAX); + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedSub64, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u64_test_safe_sub_64_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u64::MAX); + let second_arg = rand::thread_rng().gen_range(0..=first_arg); + let result = first_arg - second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeSub64, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u64_test_safe_sub_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u64::MAX - 1); + let second_arg = rand::thread_rng().gen_range(first_arg + 1..=u64::MAX); + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeSub64, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} + +#[simplex::test] +fn u64_test_checked_mul_64_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..2_u64.pow(64 / 2)); + let second_arg = rand::thread_rng().gen_range(0..2_u64.pow(64 / 2)); + let result = first_arg * second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedMul64, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u64_test_checked_mul_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u64::MAX; + let second_arg = rand::thread_rng().gen_range(2..=u64::MAX); + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedMul64, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u64_test_safe_mul_64_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..2_u64.pow(64 / 2)); + let second_arg = rand::thread_rng().gen_range(0..2_u64.pow(64 / 2)); + let result = first_arg * second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeMul64, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u64_test_safe_mul_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u64::MAX; + let second_arg = rand::thread_rng().gen_range(2..=u64::MAX); + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeMul64, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} + +#[simplex::test] +fn u64_test_checked_div_64_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u64::MAX); + let second_arg = rand::thread_rng().gen_range(1..=u64::MAX); + let result = first_arg / second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedDiv64, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u64_test_checked_div_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u64::MAX); + let second_arg = 0; + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedDiv64, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u64_test_safe_div_64_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u64::MAX); + let second_arg = rand::thread_rng().gen_range(1..=u64::MAX); + let result = first_arg / second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeDiv64, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u64_test_safe_div_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u64::MAX); + let second_arg = 0; + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeDiv64, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} diff --git a/tests/u8_test.rs b/tests/u8_test.rs new file mode 100644 index 0000000..aa0ddf4 --- /dev/null +++ b/tests/u8_test.rs @@ -0,0 +1,436 @@ +use simplex::simplicityhl::elements::Script; + +use simplex::transaction::{FinalTransaction, PartialInput, ProgramInput, RequiredSignature}; + +use simplicityhl_std::artifacts::mock::u8_mock::U8MockProgram; +use simplicityhl_std::artifacts::mock::u8_mock::derived_u8_mock::{U8MockArguments, U8MockWitness}; + +use rand::Rng; + +mod helper; +use crate::helper::{IfTestOverflow, cast_to_bool}; + +enum FunctionToTest { + CheckedAdd8, + SafeAdd8, + CheckedSub8, + SafeSub8, + CheckedMul8, + SafeMul8, + CheckedDiv8, + SafeDiv8, +} + +fn get_script(context: &simplex::TestContext) -> (U8MockProgram, Script) { + let arguments = U8MockArguments {}; + + let logical_operations_program = U8MockProgram::new(arguments); + + let logical_operations_script = + logical_operations_program.get_script_pubkey(context.get_network()); + + (logical_operations_program, logical_operations_script) +} + +fn fund_script(context: &simplex::TestContext) -> anyhow::Result<()> { + let signer = context.get_default_signer(); + + let (_, logical_operations_script) = get_script(context); + + let tx_receipt = signer.send(logical_operations_script.clone(), 50)?; + println!("Broadcast: {}", tx_receipt); + + Ok(()) +} + +fn spend_script( + context: &simplex::TestContext, + function_index: FunctionToTest, + if_test_overflow: IfTestOverflow, + first_arg: u8, + second_arg: u8, + result: u8, +) -> anyhow::Result<()> { + let signer = context.get_default_signer(); + let provider = context.get_default_provider(); + + let (logical_operations_program, logical_operations_script) = get_script(context); + + let asserts_utxos = provider.fetch_scripthash_utxos(&logical_operations_script)?; + + let mut ft = FinalTransaction::new(); + + let witness = U8MockWitness { + function_index: function_index as u8, + if_test_overflow: cast_to_bool(if_test_overflow as u8), + first_arg, + second_arg, + result, + }; + + ft.add_program_input( + PartialInput::new(asserts_utxos[0].clone()), + ProgramInput::new( + Box::new(logical_operations_program.as_ref().clone()), + Box::new(witness.clone()), + ), + RequiredSignature::None, + ); + + let tx_receipt = signer.broadcast(&ft)?; + println!("Broadcast: {}", tx_receipt); + + Ok(()) +} + +#[simplex::test] +fn u8_test_checked_add_8_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u8::MAX / 2); + let second_arg = rand::thread_rng().gen_range(0..=u8::MAX / 2); + let result = first_arg + second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedAdd8, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u8_test_checked_add_8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u8::MAX; + let second_arg = rand::thread_rng().gen_range(1..=u8::MAX); + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedAdd8, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u8_test_safe_add_8_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u8::MAX / 2); + let second_arg = rand::thread_rng().gen_range(0..=u8::MAX / 2); + let result = first_arg + second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeAdd8, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u8_test_safe_add_8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u8::MAX; + let second_arg = rand::thread_rng().gen_range(1..=u8::MAX); + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeAdd8, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} + +#[simplex::test] +fn u8_test_checked_sub_8_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u8::MAX); + let second_arg = rand::thread_rng().gen_range(0..=first_arg); + let result = first_arg - second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedSub8, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u8_test_checked_sub_8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u8::MAX - 1); + let second_arg = rand::thread_rng().gen_range(first_arg + 1..=u8::MAX); + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedSub8, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u8_test_safe_sub_8_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u8::MAX); + let second_arg = rand::thread_rng().gen_range(0..=first_arg); + let result = first_arg - second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeSub8, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u8_test_safe_sub_8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u8::MAX - 1); + let second_arg = rand::thread_rng().gen_range(first_arg + 1..=u8::MAX); + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeSub8, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} + +#[simplex::test] +fn u8_test_checked_mul_8_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..2_u8.pow(8 / 2)); + let second_arg = rand::thread_rng().gen_range(0..2_u8.pow(8 / 2)); + let result = first_arg * second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedMul8, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u8_test_checked_mul_8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u8::MAX; + let second_arg = rand::thread_rng().gen_range(2..=u8::MAX); + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedMul8, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u8_test_safe_mul_8_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..2_u8.pow(8 / 2)); + let second_arg = rand::thread_rng().gen_range(0..2_u8.pow(8 / 2)); + let result = first_arg * second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeMul8, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u8_test_safe_mul_8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = u8::MAX; + let second_arg = rand::thread_rng().gen_range(2..=u8::MAX); + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeMul8, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +} + +#[simplex::test] +fn u8_test_checked_div_8_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u8::MAX); + let second_arg = rand::thread_rng().gen_range(1..=u8::MAX); + let result = first_arg / second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedDiv8, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u8_test_checked_div_8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u8::MAX); + let second_arg = 0; + let result = 0; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::CheckedDiv8, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u8_test_safe_div_8_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u8::MAX); + let second_arg = rand::thread_rng().gen_range(1..=u8::MAX); + let result = first_arg / second_arg; + + fund_script(&context)?; + spend_script( + &context, + FunctionToTest::SafeDiv8, + IfTestOverflow::NotOverflow, + first_arg, + second_arg, + result, + )?; + + Ok(()) +} + +#[simplex::test] +fn u8_test_safe_div_8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let first_arg = rand::thread_rng().gen_range(0..=u8::MAX); + let second_arg = 0; + let result = 0; + + fund_script(&context)?; + + let txid_result = spend_script( + &context, + FunctionToTest::SafeDiv8, + IfTestOverflow::Overflow, + first_arg, + second_arg, + result, + ); + + assert!( + txid_result.is_err(), + "Expected this test to fail but it succeeded" + ); + + let err: String = txid_result.unwrap_err().to_string(); + assert_eq!( + err, + "Failed to prune program: Execution reached a pruned branch: 744339c859e7ff6f8d33f9afa73734e1c908684feedc8c4d0a6112d3bf361317" + ); + + Ok(()) +}