diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index da161af..f1a9958 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,6 +17,7 @@ concurrency: env: CARGO_TERM_COLOR: always RUST_BACKTRACE: full + SIMPLEX_VERSION: 0.0.11 jobs: simplex-tests: @@ -40,6 +41,7 @@ jobs: uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ matrix.toolchain }} + components: rustfmt, clippy - name: Use Rust cache uses: Swatinem/rust-cache@v2 @@ -47,13 +49,21 @@ jobs: - name: Install simplex-cli uses: BlockstreamResearch/simplicityhl-toolchain@v0.0.2 with: - components: simplex + components: simplex@${{ env.SIMPLEX_VERSION }} - name: Generate contract artifacts shell: bash run: | simplex build + - name: Check formatting + run: | + cargo fmt --all --check + + - name: Run clippy + run: | + cargo clippy --workspace --all-targets --all-features -- -D warnings + - name: Build run: | cargo build --workspace --all-features --verbose diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fdee6fd..cc14879 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ When submitting a feature request, please provide as many details as possible fo ## Pull Requests -If you're interested in contributing code to the library, start by [forking the repository](https://github.com/BlockstreamResearch/simplicityhl-std/fork) and submitting a pull request. +If you're interested in contributing code to the library, start by [forking the repository](https://github.com/BlockstreamResearch/simplicityhl-std/fork) and submitting a pull request. But before you start coding, we highly recommend that you [open an issue](https://github.com/BlockstreamResearch/simplicityhl-std/issues/new/choose) first to discuss the changes you want to make. diff --git a/simf/asserts_test.simf b/simf/asserts_test.simf deleted file mode 100644 index 36e1708..0000000 --- a/simf/asserts_test.simf +++ /dev/null @@ -1,62 +0,0 @@ -use crate::lib::asserts::{ - assert_eq_1, - assert_eq_8, - assert_eq_16, - assert_eq_32, - assert_eq_64, - assert_eq_128, - assert_eq_256, - assert_eq_bool, - assert_none_1, - assert_none_8, - assert_none_16, - assert_none_32, - assert_none_64, - assert_none_128, - assert_none_256 -}; -use crate::helper::if_test_this_function; - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a_u1: Option = witness::FIRST_ARG_U1; - let b_u1: Option = witness::SECOND_ARG_U1; - - let a_u8: Option = witness::FIRST_ARG_U8; - let b_u8: Option = witness::SECOND_ARG_U8; - - let a_u16: Option = witness::FIRST_ARG_U16; - let b_u16: Option = witness::SECOND_ARG_U16; - - let a_u32: Option = witness::FIRST_ARG_U32; - let b_u32: Option = witness::SECOND_ARG_U32; - - let a_u64: Option = witness::FIRST_ARG_U64; - let b_u64: Option = witness::SECOND_ARG_U64; - - let a_u128: Option = witness::FIRST_ARG_U128; - let b_u128: Option = witness::SECOND_ARG_U128; - - let a_u256: Option = witness::FIRST_ARG_U256; - let b_u256: Option = witness::SECOND_ARG_U256; - - // Assert Eq - match if_test_this_function(0, fn_idx) { true => { assert_eq_1(unwrap(a_u1), unwrap(b_u1)); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert_eq_8(unwrap(a_u8), unwrap(b_u8)); }, false => (), }; - match if_test_this_function(2, fn_idx) { true => { assert_eq_16(unwrap(a_u16), unwrap(b_u16)); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => { assert_eq_32(unwrap(a_u32), unwrap(b_u32)); }, false => (), }; - match if_test_this_function(4, fn_idx) { true => { assert_eq_64(unwrap(a_u64), unwrap(b_u64)); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert_eq_128(unwrap(a_u128), unwrap(b_u128)); }, false => (), }; - match if_test_this_function(6, fn_idx) { true => { assert_eq_256(unwrap(a_u256), unwrap(b_u256)); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert_eq_bool(::into(unwrap(a_u1)), ::into(unwrap(b_u1))); }, false => (), }; - - // Assert None - match if_test_this_function(8, fn_idx) { true => { assert_none_1(a_u1); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_none_8(a_u8); }, false => (), }; - match if_test_this_function(10, fn_idx) { true => { assert_none_16(a_u16); }, false => (), }; - match if_test_this_function(11, fn_idx) { true => { assert_none_32(a_u32); }, false => (), }; - match if_test_this_function(12, fn_idx) { true => { assert_none_64(a_u64); }, false => (), }; - match if_test_this_function(13, fn_idx) { true => { assert_none_128(a_u128); }, false => (), }; - match if_test_this_function(14, fn_idx) { true => { assert_none_256(a_u256); }, false => (), }; -} diff --git a/simf/binary_test.simf b/simf/binary_test.simf deleted file mode 100644 index ec4ab30..0000000 --- a/simf/binary_test.simf +++ /dev/null @@ -1,21 +0,0 @@ -use crate::lib::binary::{not, or, and, xor}; - -fn main() { - assert!(not(false)); - assert!(not(not(true))); - - assert!(or(true, false)); - assert!(or(false, true)); - assert!(or(true, true)); - assert!(not(or(false, false))); - - assert!(and(true, true)); - assert!(not(and(true, false))); - assert!(not(and(false, true))); - assert!(not(and(false, false))); - - assert!(xor(true, false)); - assert!(xor(false, true)); - assert!(not(xor(true, true))); - assert!(not(xor(false, false))); -} diff --git a/simf/helper.simf b/simf/helper.simf deleted file mode 100644 index 4bfc650..0000000 --- a/simf/helper.simf +++ /dev/null @@ -1,13 +0,0 @@ -use crate::lib::binary::not; - -pub fn if_test_this_function(index: u8, flag: u8) -> bool { - jet::eq_8(index, flag) -} - -/// Asserts a result equals the expected bool value. -pub fn assert_bool(result: bool, expected_bool: bool) { - match expected_bool { - true => assert!(result), - false => assert!(not(result)), - } -} diff --git a/simf/lib/binary.simf b/simf/lib/binary.simf index 85f67d0..9042811 100644 --- a/simf/lib/binary.simf +++ b/simf/lib/binary.simf @@ -1,19 +1,19 @@ /// Returns the result of the NOT operation on the provided value pub fn not(bit: bool) -> bool { - ::into(jet::complement_1(::into(bit))) + ::into(jet::complement_1(::into(bit))) } /// Returns the result of the OR operation on the provided values pub fn or(a: bool, b: bool) -> bool { - ::into(jet::or_1(::into(a), ::into(b))) + ::into(jet::or_1(::into(a), ::into(b))) } /// Returns the result of the AND operation on the provided values pub fn and(a: bool, b: bool) -> bool { - ::into(jet::and_1(::into(a), ::into(b))) + ::into(jet::and_1(::into(a), ::into(b))) } /// Returns the result of the XOR operation on the provided values pub fn xor(a: bool, b: bool) -> bool { - and(or(a, b), not(and(a, b))) + and(or(a, b), not(and(a, b))) } diff --git a/simf/lib/op_return.simf b/simf/lib/op_return.simf index 2f71087..d6e1d85 100644 --- a/simf/lib/op_return.simf +++ b/simf/lib/op_return.simf @@ -8,5 +8,5 @@ pub fn is_output_op_return(output_index: u32) -> bool { /// Asserts that the specified output is an OP_RETURN (null data) output pub fn assert_output_is_op_return(output_index: u32) { - assert!(is_output_op_return(output_index)); + assert!(is_output_op_return(output_index)); } diff --git a/simf/lib/secp256k1/operations.simf b/simf/lib/secp256k1/operations.simf index 0cfabbe..b4a2fcd 100644 --- a/simf/lib/secp256k1/operations.simf +++ b/simf/lib/secp256k1/operations.simf @@ -79,7 +79,7 @@ pub fn assert_scalar_eq(a: Scalar, b: Scalar) { pub fn assert_ge_eq(a: Ge, b: Ge) { let (ax, ay): (Fe, Fe) = a; let (bx, by): (Fe, Fe) = b; - + assert_fe_eq(ax, bx); assert_fe_eq(ay, by); } diff --git a/simf/lib/u128/bit.simf b/simf/lib/u128/bit.simf index 1e4f0e9..7b8e208 100644 --- a/simf/lib/u128/bit.simf +++ b/simf/lib/u128/bit.simf @@ -35,7 +35,10 @@ pub fn left_shift_128(shift: u8, a: u128) -> u128 { match jet::lt_8(shift, 64) { true => { - let (_, low_to_high_amount): (bool, u8) = jet::subtract_8(64, shift); // shift < 64 + let ( + _, + low_to_high_amount + ): (bool, u8) = jet::subtract_8(64, shift); // shift < 64 let shifted_bits: u64 = jet::right_shift_64(low_to_high_amount, a_low); let res_high: u64 = jet::or_64(jet::left_shift_64(shift, a_high), shifted_bits); @@ -46,9 +49,9 @@ pub fn left_shift_128(shift: u8, a: u128) -> u128 { let (_, shift): (bool, u8) = jet::subtract_8(shift, 64); // shift >= 64 <(u64, u64)>::into((jet::left_shift_64(shift, a_low), 0)) - } + }, } - } + }, } } @@ -61,7 +64,10 @@ pub fn right_shift_128(shift: u8, a: u128) -> u128 { match jet::lt_8(shift, 64) { true => { - let (_, high_to_low_amount): (bool, u8) = jet::subtract_8(64, shift); // shift < 64 + let ( + _, + high_to_low_amount + ): (bool, u8) = jet::subtract_8(64, shift); // shift < 64 let shifted_bits: u64 = jet::left_shift_64(high_to_low_amount, a_high); let res_low: u64 = jet::or_64(jet::right_shift_64(shift, a_low), shifted_bits); @@ -72,8 +78,8 @@ pub fn right_shift_128(shift: u8, a: u128) -> u128 { let (_, shift): (bool, u8) = jet::subtract_8(shift, 64); // shift >= 64 <(u64, u64)>::into((0, jet::right_shift_64(shift, a_high))) - } + }, } - } + }, } } diff --git a/simf/lib/u128/math.simf b/simf/lib/u128/math.simf index 38a679d..313eff7 100644 --- a/simf/lib/u128/math.simf +++ b/simf/lib/u128/math.simf @@ -193,9 +193,12 @@ pub fn calculate_normalizer_base_64(b: u128, is_b_u128: bool) -> u64 { match jet::is_zero_64(remainder) { true => norm, false => { - let (_, norm): (bool, u64) = jet::add_64(norm, 1); // norm <= 2^63, so norm + 1 can not overflow + let ( + _, + norm + ): (bool, u64) = jet::add_64(norm, 1); // norm <= 2^63, so norm + 1 can not overflow norm - } + }, } } @@ -221,7 +224,11 @@ fn normalize_to_threshold_128_63(a: u128, b: u128, is_b_u128: bool) -> (u256, u1 /// Returns the quotient digit to use in the subsequent multiply-and-subtract step. /// Expects result to fit into u64 pub fn estimate_quotient_digit_base_64(u2: u64, u1: u64, u0: u64, v1: u64, v0: u64) -> u64 { - let (q_hat, r_hat, carry): (u64, u64, bool) = match jet::lt_64(u2, v1) { + let ( + q_hat, + r_hat, + carry + ): (u64, u64, bool) = match jet::lt_64(u2, v1) { true => { let (q_hat, r_hat): (u64, u64) = jet::div_mod_128_64(<(u64, u64)>::into((u2, u1)), v1); (q_hat, r_hat, false) @@ -309,11 +316,7 @@ pub fn div_mod_128_64(a: u128, b: u64) -> (u128, u64) { a_normalized, b_normalized, norm - ): (u256, u128, u64) = normalize_to_threshold_128_63( - a_prime, - u64_to_u128(b), - false - ); + ): (u256, u128, u64) = normalize_to_threshold_128_63(a_prime, u64_to_u128(b), false); // a_normalized fits into u128, because remainder < b and b_normalized fits into u64 let (_, a_normalized): (u128, u128) = ::into(a_normalized); diff --git a/simf/lib/u16/math.simf b/simf/lib/u16/math.simf index e146253..b87d435 100644 --- a/simf/lib/u16/math.simf +++ b/simf/lib/u16/math.simf @@ -16,7 +16,7 @@ pub fn safe_add_16(a: u16, b: u16) -> u16 { /// Returns the difference of two u16 values wrapped in Some, or None if the result overflows u16 pub 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), diff --git a/simf/lib/u256/bit.simf b/simf/lib/u256/bit.simf index 2df63a7..372ebbc 100644 --- a/simf/lib/u256/bit.simf +++ b/simf/lib/u256/bit.simf @@ -27,7 +27,10 @@ pub fn left_shift_256(shift: u8, a: u256) -> u256 { match jet::lt_8(shift, 128) { true => { - let (_, low_to_high_amount): (bool, u8) = jet::subtract_8(128, shift); // shift < 128 + let ( + _, + low_to_high_amount + ): (bool, u8) = jet::subtract_8(128, shift); // shift < 128 let shifted_bits: u128 = right_shift_128(low_to_high_amount, a_low); let res_high: u128 = or_128(left_shift_128(shift, a_high), shifted_bits); @@ -38,9 +41,9 @@ pub fn left_shift_256(shift: u8, a: u256) -> u256 { let (_, shift): (bool, u8) = jet::subtract_8(shift, 128); // shift >= 128 <(u128, u128)>::into((left_shift_128(shift, a_low), 0)) - } + }, } - } + }, } } @@ -53,7 +56,10 @@ pub fn right_shift_256(shift: u8, a: u256) -> u256 { match jet::lt_8(shift, 128) { true => { - let (_, high_to_low_amount): (bool, u8) = jet::subtract_8(128, shift); // shift < 128 + let ( + _, + high_to_low_amount + ): (bool, u8) = jet::subtract_8(128, shift); // shift < 128 let shifted_bits: u128 = left_shift_128(high_to_low_amount, a_high); let res_low: u128 = or_128(right_shift_128(shift, a_low), shifted_bits); @@ -64,8 +70,8 @@ pub fn right_shift_256(shift: u8, a: u256) -> u256 { let (_, shift): (bool, u8) = jet::subtract_8(shift, 128); // shift >= 128 <(u128, u128)>::into((0, right_shift_128(shift, a_high))) - } + }, } - } + }, } } diff --git a/simf/lib/u256/math.simf b/simf/lib/u256/math.simf index f06ea7c..ed193fb 100644 --- a/simf/lib/u256/math.simf +++ b/simf/lib/u256/math.simf @@ -239,7 +239,13 @@ pub fn calculate_normalizer_base_128(b: u256) -> u128 { match is_zero_128(remainder) { true => norm, false => { - let (_, norm): (bool, u128) = add_128(norm, 1); // norm <= 2^127, so norm + 1 can not overflow + let ( + _, + norm + ): (bool, u128) = add_128( + norm, + 1 + ); // norm <= 2^127, so norm + 1 can not overflow norm }, } diff --git a/simf/lib/u256/mul_div.simf b/simf/lib/u256/mul_div.simf index 52ad6ef..f80fd14 100644 --- a/simf/lib/u256/mul_div.simf +++ b/simf/lib/u256/mul_div.simf @@ -23,10 +23,22 @@ use crate::lib::u256::comparison::{is_zero_256, lt_256}; /// Returns the quotient digit to use in the subsequent multiply-and-subtract step. /// Expects result to fit into u128 fn estimate_quotient_digit_base_128(u2: u128, u1: u128, u0: u128, v1: u128, v0: u128) -> u128 { - let (q_hat, r_hat, carry): (u128, u128, bool) = match lt_128(u2, v1) { + let ( + q_hat, + r_hat, + carry + ): (u128, u128, bool) = match lt_128(u2, v1) { true => { - let (q_hat, r_hat) : (u256, u128) = algorithm_d_256_128(<(u128, u128)>::into((u2, u1)), v1); - let (_, q_hat): (u128, u128) = split_u256_into_u128(q_hat); // skip the check for optimization. u2 < v1, so q_hat fits into u128 + let ( + q_hat, + r_hat + ): (u256, u128) = algorithm_d_256_128(<(u128, u128)>::into((u2, u1)), v1); + let ( + _, + q_hat + ): (u128, u128) = split_u256_into_u128( + q_hat + ); // skip the check for optimization. u2 < v1, so q_hat fits into u128 (q_hat, r_hat, false) }, @@ -123,7 +135,9 @@ fn algorithm_d_512_256(dividend_high: u256, dividend_low: u256, divisor: u256) - norm_dividend_high, norm_dividend_low, norm_divisor - ): (u128, u256, u256, u256) = (normalize_to_threshold_512_127(dividend_high, dividend_low, divisor)); + ): (u128, u256, u256, u256) = ( + normalize_to_threshold_512_127(dividend_high, dividend_low, divisor) + ); let (u3, u2): (u128, u128) = split_u256_into_u128(norm_dividend_high); let (u1, u0): (u128, u128) = split_u256_into_u128(norm_dividend_low); @@ -158,14 +172,29 @@ pub fn mul_div_256(a: u256, b: u256, denominator: u256) -> u256 { // result_high < denominator, denominator fits into u128, so result_high fits too. // split_u256_into_u128 is used instead of safe_u256_to_u128 to avoid the unnecessary check let (_, result_2): (u128, u128) = split_u256_into_u128(result_high); - let (result_1, result_0): (u128, u128) = split_u256_into_u128(result_low); + let ( + result_1, + result_0 + ): (u128, u128) = split_u256_into_u128(result_low); // result_high < denominator, so result_2 < denom_low and q1 fits into u128 - let (q1, r): (u256, u128) = div_mod_256_128(<(u128, u128)>::into((result_2, result_1)), denom_low); + let ( + q1, + r + ): (u256, u128) = div_mod_256_128( + <(u128, u128)>::into((result_2, result_1)), + denom_low + ); let (_, q1): (u128, u128) = split_u256_into_u128(q1); // r < denom_low, so q0 fits into u128 - let (q0, _): (u256, u128) = div_mod_256_128(<(u128, u128)>::into((r, result_0)), denom_low); + let ( + q0, + _ + ): (u256, u128) = div_mod_256_128( + <(u128, u128)>::into((r, result_0)), + denom_low + ); let (_, q0): (u128, u128) = split_u256_into_u128(q0); <(u128, u128)>::into((q1, q0)) diff --git a/simf/lib/u64/math.simf b/simf/lib/u64/math.simf index 77fc4aa..7617725 100644 --- a/simf/lib/u64/math.simf +++ b/simf/lib/u64/math.simf @@ -31,7 +31,7 @@ pub fn safe_sub_64(a: u64, b: u64) -> u64 { /// Returns the product of two u64 values wrapped in Some, or None if the result overflows u64 pub 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) { diff --git a/simf/op_return_test.simf b/simf/op_return_test.simf deleted file mode 100644 index d847d8e..0000000 --- a/simf/op_return_test.simf +++ /dev/null @@ -1,12 +0,0 @@ -use crate::lib::op_return::{is_output_op_return, assert_output_is_op_return}; -use crate::helper::{if_test_this_function, assert_bool}; - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let index: u32 = witness::INDEX; - let expected: bool = witness::EXPECTED; - - match if_test_this_function(0, fn_idx) { true => { assert_bool(is_output_op_return(index), expected); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert_output_is_op_return(index); }, false => (), }; -} diff --git a/simf/secp256k1_operations_test.simf b/simf/secp256k1_operations_test.simf deleted file mode 100644 index 991eae8..0000000 --- a/simf/secp256k1_operations_test.simf +++ /dev/null @@ -1,35 +0,0 @@ -use crate::lib::secp256k1::operations::{ - ge_to_point, point_to_gej, fe_sub, scalar_sub, gej_sub, - fe_eq, scalar_eq, ge_eq, gej_point_eq, safe_gej_normalize, - assert_fe_eq, assert_scalar_eq, assert_ge_eq, assert_point_eq, assert_gej_point_eq, assert_gej_eq -}; -use crate::helper::if_test_this_function; - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - // Interpreted as Fe or Scalar depending on the function index - let uint_a: u256 = witness::FIRST_UINT; - let uint_b: u256 = witness::SECOND_UINT; - let ge_a: Ge = witness::FIRST_GE; - let ge_b: Ge = witness::SECOND_GE; - let gej_a: Gej = witness::FIRST_GEJ; - let gej_b: Gej = witness::SECOND_GEJ; - let point_a: Point = witness::FIRST_POINT; - - let exp_uint: u256 = witness::EXPECTED_UINT; - let exp_ge: Ge = witness::EXPECTED_GE; - let exp_gej: Gej = witness::EXPECTED_GEJ; - let exp_point: Point = witness::EXPECTED_POINT; - - match if_test_this_function(0, fn_idx) { true => { assert_point_eq(ge_to_point(ge_a), exp_point); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert_gej_point_eq(point_to_gej(point_a), exp_point); }, false => (), }; - match if_test_this_function(2, fn_idx) { true => { assert_fe_eq(fe_sub(uint_a, uint_b), exp_uint); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => { assert_scalar_eq(scalar_sub(uint_a, uint_b), exp_uint); }, false => (), }; - match if_test_this_function(4, fn_idx) { true => { assert_gej_eq(gej_sub(gej_a, gej_b), exp_gej); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert!(fe_eq(uint_a, uint_b)); }, false => (), }; - match if_test_this_function(6, fn_idx) { true => { assert!(scalar_eq(uint_a, uint_b)); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert!(ge_eq(ge_a, ge_b)); }, false => (), }; - match if_test_this_function(8, fn_idx) { true => { assert!(gej_point_eq(gej_a, point_a)); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_ge_eq(safe_gej_normalize(gej_a), exp_ge); }, false => (), }; -} diff --git a/simf/tests/asserts.simf b/simf/tests/asserts.simf new file mode 100644 index 0000000..f66bb03 --- /dev/null +++ b/simf/tests/asserts.simf @@ -0,0 +1,137 @@ +use crate::lib::asserts::{ + assert_eq_1, + assert_eq_8, + assert_eq_16, + assert_eq_32, + assert_eq_64, + assert_eq_128, + assert_eq_256, + assert_eq_bool, + assert_none_1, + assert_none_8, + assert_none_16, + assert_none_32, + assert_none_64, + assert_none_128, + assert_none_256 +}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a_u1: Option = witness::FIRST_ARG_U1; + let b_u1: Option = witness::SECOND_ARG_U1; + + let a_u8: Option = witness::FIRST_ARG_U8; + let b_u8: Option = witness::SECOND_ARG_U8; + + let a_u16: Option = witness::FIRST_ARG_U16; + let b_u16: Option = witness::SECOND_ARG_U16; + + let a_u32: Option = witness::FIRST_ARG_U32; + let b_u32: Option = witness::SECOND_ARG_U32; + + let a_u64: Option = witness::FIRST_ARG_U64; + let b_u64: Option = witness::SECOND_ARG_U64; + + let a_u128: Option = witness::FIRST_ARG_U128; + let b_u128: Option = witness::SECOND_ARG_U128; + + let a_u256: Option = witness::FIRST_ARG_U256; + let b_u256: Option = witness::SECOND_ARG_U256; + + // Assert Eq + match is_selected(0, fn_idx) { + true => { + assert_eq_1(unwrap(a_u1), unwrap(b_u1)); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_eq_8(unwrap(a_u8), unwrap(b_u8)); + }, + false => (), + }; + match is_selected(2, fn_idx) { + true => { + assert_eq_16(unwrap(a_u16), unwrap(b_u16)); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert_eq_32(unwrap(a_u32), unwrap(b_u32)); + }, + false => (), + }; + match is_selected(4, fn_idx) { + true => { + assert_eq_64(unwrap(a_u64), unwrap(b_u64)); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert_eq_128(unwrap(a_u128), unwrap(b_u128)); + }, + false => (), + }; + match is_selected(6, fn_idx) { + true => { + assert_eq_256(unwrap(a_u256), unwrap(b_u256)); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert_eq_bool(::into(unwrap(a_u1)), ::into(unwrap(b_u1))); + }, + false => (), + }; + + // Assert None + match is_selected(8, fn_idx) { + true => { + assert_none_1(a_u1); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_none_8(a_u8); + }, + false => (), + }; + match is_selected(10, fn_idx) { + true => { + assert_none_16(a_u16); + }, + false => (), + }; + match is_selected(11, fn_idx) { + true => { + assert_none_32(a_u32); + }, + false => (), + }; + match is_selected(12, fn_idx) { + true => { + assert_none_64(a_u64); + }, + false => (), + }; + match is_selected(13, fn_idx) { + true => { + assert_none_128(a_u128); + }, + false => (), + }; + match is_selected(14, fn_idx) { + true => { + assert_none_256(a_u256); + }, + false => (), + }; +} diff --git a/simf/tests/binary.simf b/simf/tests/binary.simf new file mode 100644 index 0000000..e348d91 --- /dev/null +++ b/simf/tests/binary.simf @@ -0,0 +1,21 @@ +use crate::lib::binary::{not, or, and, xor}; + +fn main() { + assert!(not(false)); + assert!(not(not(true))); + + assert!(or(true, false)); + assert!(or(false, true)); + assert!(or(true, true)); + assert!(not(or(false, false))); + + assert!(and(true, true)); + assert!(not(and(true, false))); + assert!(not(and(false, true))); + assert!(not(and(false, false))); + + assert!(xor(true, false)); + assert!(xor(false, true)); + assert!(not(xor(true, true))); + assert!(not(xor(false, false))); +} diff --git a/simf/tests/op_return.simf b/simf/tests/op_return.simf new file mode 100644 index 0000000..0b812ff --- /dev/null +++ b/simf/tests/op_return.simf @@ -0,0 +1,23 @@ +use crate::lib::op_return::{is_output_op_return, assert_output_is_op_return}; +use crate::tests::support::dispatch::is_selected; +use crate::tests::support::expect::assert_bool; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let index: u32 = witness::INDEX; + let expected: bool = witness::EXPECTED; + + match is_selected(0, fn_idx) { + true => { + assert_bool(is_output_op_return(index), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_output_is_op_return(index); + }, + false => (), + }; +} diff --git a/simf/tests/secp256k1/operations.simf b/simf/tests/secp256k1/operations.simf new file mode 100644 index 0000000..8e7485d --- /dev/null +++ b/simf/tests/secp256k1/operations.simf @@ -0,0 +1,98 @@ +use crate::lib::secp256k1::operations::{ + ge_to_point, + point_to_gej, + fe_sub, + scalar_sub, + gej_sub, + fe_eq, + scalar_eq, + ge_eq, + gej_point_eq, + safe_gej_normalize, + assert_fe_eq, + assert_scalar_eq, + assert_ge_eq, + assert_point_eq, + assert_gej_point_eq, + assert_gej_eq +}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + // Interpreted as Fe or Scalar depending on the function index + let uint_a: u256 = witness::FIRST_UINT; + let uint_b: u256 = witness::SECOND_UINT; + let ge_a: Ge = witness::FIRST_GE; + let ge_b: Ge = witness::SECOND_GE; + let gej_a: Gej = witness::FIRST_GEJ; + let gej_b: Gej = witness::SECOND_GEJ; + let point_a: Point = witness::FIRST_POINT; + + let exp_uint: u256 = witness::EXPECTED_UINT; + let exp_ge: Ge = witness::EXPECTED_GE; + let exp_gej: Gej = witness::EXPECTED_GEJ; + let exp_point: Point = witness::EXPECTED_POINT; + + match is_selected(0, fn_idx) { + true => { + assert_point_eq(ge_to_point(ge_a), exp_point); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_gej_point_eq(point_to_gej(point_a), exp_point); + }, + false => (), + }; + match is_selected(2, fn_idx) { + true => { + assert_fe_eq(fe_sub(uint_a, uint_b), exp_uint); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert_scalar_eq(scalar_sub(uint_a, uint_b), exp_uint); + }, + false => (), + }; + match is_selected(4, fn_idx) { + true => { + assert_gej_eq(gej_sub(gej_a, gej_b), exp_gej); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert!(fe_eq(uint_a, uint_b)); + }, + false => (), + }; + match is_selected(6, fn_idx) { + true => { + assert!(scalar_eq(uint_a, uint_b)); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert!(ge_eq(ge_a, ge_b)); + }, + false => (), + }; + match is_selected(8, fn_idx) { + true => { + assert!(gej_point_eq(gej_a, point_a)); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_ge_eq(safe_gej_normalize(gej_a), exp_ge); + }, + false => (), + }; +} diff --git a/simf/tests/support/dispatch.simf b/simf/tests/support/dispatch.simf new file mode 100644 index 0000000..721d949 --- /dev/null +++ b/simf/tests/support/dispatch.simf @@ -0,0 +1,6 @@ +/// Indices `0..192` belong to the operations shared by all unsigned widths and +/// stay in lockstep with `CommonOp` on the Rust side. `192..256` are free for +/// operations specific to a single width. +pub fn is_selected(index: u8, fn_idx: u8) -> bool { + jet::eq_8(index, fn_idx) +} diff --git a/simf/tests/support/expect.simf b/simf/tests/support/expect.simf new file mode 100644 index 0000000..73b0365 --- /dev/null +++ b/simf/tests/support/expect.simf @@ -0,0 +1,136 @@ +//! Assertions shared by the test programs. +//! +//! SimplicityHL has no generics, so each family is written once per width and +//! named with that width's suffix, exactly like `crate::lib::asserts`. + +use crate::lib::asserts::{ + assert_eq_8, + assert_eq_16, + assert_eq_32, + assert_eq_64, + assert_eq_128, + assert_eq_256, + assert_none_8, + assert_none_16, + assert_none_32, + assert_none_64, + assert_none_128, + assert_none_256 +}; +use crate::lib::binary::not; +use crate::lib::u128::bit::eq_128; + +/// Asserts a result equals the expected bool value. +pub fn assert_bool(result: bool, expected_bool: bool) { + match expected_bool { + true => assert!(result), + false => assert!(not(result)), + } +} + +/// Asserts a `checked_*` result equals the expected Option. +/// `None` encodes the overflow case, `Some(e)` the fitting case, so a single +/// witness value carries both, removing the need for a separate overflow flag. +pub fn assert_eq_opt_8(result: Option, expected: Option) { + match expected { + Some(e: u8) => assert_eq_8(unwrap(result), e), + None => assert_none_8(result), + } +} + +pub fn assert_eq_opt_16(result: Option, expected: Option) { + match expected { + Some(e: u16) => assert_eq_16(unwrap(result), e), + None => assert_none_16(result), + } +} + +pub fn assert_eq_opt_32(result: Option, expected: Option) { + match expected { + Some(e: u32) => assert_eq_32(unwrap(result), e), + None => assert_none_32(result), + } +} + +pub fn assert_eq_opt_64(result: Option, expected: Option) { + match expected { + Some(e: u64) => assert_eq_64(unwrap(result), e), + None => assert_none_64(result), + } +} + +pub fn assert_eq_opt_128(result: Option, expected: Option) { + match expected { + Some(e: u128) => assert_eq_128(unwrap(result), e), + None => assert_none_128(result), + } +} + +pub fn assert_eq_opt_256(result: Option, expected: Option) { + match expected { + Some(e: u256) => assert_eq_256(unwrap(result), e), + None => assert_none_256(result), + } +} + +/// Asserts a result equals the expected bool value. +/// `None` encodes `false`, and `Some(_)` encodes `true`. +pub fn assert_bool_by_opt_8(result: bool, expected: Option) { + match expected { + Some(_: u8) => assert!(result), + None => assert!(not(result)), + } +} + +pub fn assert_bool_by_opt_16(result: bool, expected: Option) { + match expected { + Some(_: u16) => assert!(result), + None => assert!(not(result)), + } +} + +pub fn assert_bool_by_opt_32(result: bool, expected: Option) { + match expected { + Some(_: u32) => assert!(result), + None => assert!(not(result)), + } +} + +pub fn assert_bool_by_opt_64(result: bool, expected: Option) { + match expected { + Some(_: u64) => assert!(result), + None => assert!(not(result)), + } +} + +pub fn assert_bool_by_opt_128(result: bool, expected: Option) { + match expected { + Some(_: u128) => assert!(result), + None => assert!(not(result)), + } +} + +pub fn assert_bool_by_opt_256(result: bool, expected: Option) { + match expected { + Some(_: u256) => assert!(result), + None => assert!(not(result)), + } +} + +/// Asserts a `(carry, value)` result equals the expected pair. Used by the +/// primitives that return an out-of-band carry or borrow alongside the result. +pub fn assert_eq_uint_bool_128(result: (bool, u128), expected: u128, expected_bool: bool) { + let (bool_res, uint_res): (bool, u128) = result; + + assert_bool(bool_res, expected_bool); + + assert!(eq_128(uint_res, expected)); +} + +pub fn assert_eq_uint_bool_256(result: (bool, u256), expected: u256, expected_bool: bool) { + let (bool_res, uint_res): (bool, u256) = result; + + assert_bool(bool_res, expected_bool); + + assert_eq_256(uint_res, expected); +} diff --git a/simf/u1_convert_test.simf b/simf/tests/u1/convert.simf similarity index 83% rename from simf/u1_convert_test.simf rename to simf/tests/u1/convert.simf index 8263efc..a9b4f18 100644 --- a/simf/u1_convert_test.simf +++ b/simf/tests/u1/convert.simf @@ -7,7 +7,6 @@ use crate::lib::u1::convert::{ u1_to_u256, u1_to_bool }; -use crate::lib::u128::bit::eq_128; use crate::lib::asserts::{ assert_eq_bool, assert_eq_8, @@ -17,7 +16,7 @@ use crate::lib::asserts::{ assert_eq_128, assert_eq_256 }; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -26,7 +25,7 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); @@ -37,7 +36,7 @@ fn main() { false => (), }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); @@ -47,7 +46,7 @@ fn main() { false => (), }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, expected): (u32, u32) = ::into(expected); @@ -57,7 +56,7 @@ fn main() { false => (), }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); @@ -66,7 +65,7 @@ fn main() { false => (), }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (_, expected): (u128, u128) = ::into(expected); @@ -75,14 +74,14 @@ fn main() { false => (), }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { assert_eq_256(u1_to_u256(a), expected); }, false => (), }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let expected_bool: bool = jet::eq_256(expected, 1); assert_eq_bool(u1_to_bool(a), expected_bool); diff --git a/simf/u128_test_bits.simf b/simf/tests/u128/bit.simf similarity index 51% rename from simf/u128_test_bits.simf rename to simf/tests/u128/bit.simf index b3ea239..831e69a 100644 --- a/simf/u128_test_bits.simf +++ b/simf/tests/u128/bit.simf @@ -1,5 +1,6 @@ use crate::lib::u128::bit::{and_128, or_128, eq_128, left_shift_128, right_shift_128}; -use crate::helper::{if_test_this_function, assert_bool}; +use crate::tests::support::dispatch::is_selected; +use crate::tests::support::expect::assert_bool; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -12,25 +13,42 @@ fn main() { /// Bit logic - match if_test_this_function(0, fn_idx) { true => { assert!(eq_128(and_128(a, b), unwrap(expected))); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert!(eq_128(or_128(a, b), unwrap(expected))); }, false => (), }; - match if_test_this_function(2, fn_idx) { true => { assert_bool(eq_128(a, b), expected_bool); }, false => (), }; + match is_selected(0, fn_idx) { + true => { + assert!(eq_128(and_128(a, b), unwrap(expected))); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert!(eq_128(or_128(a, b), unwrap(expected))); + }, + false => (), + }; + match is_selected(2, fn_idx) { + true => { + assert_bool(eq_128(a, b), expected_bool); + }, + false => (), + }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (_, a): (u64, u64) = ::into(a); let shift: u8 = jet::rightmost_64_8(a); - assert!(eq_128(left_shift_128(shift, b), unwrap(expected))); - }, false => (), + assert!(eq_128(left_shift_128(shift, b), unwrap(expected))); + }, + false => (), }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (_, a): (u64, u64) = ::into(a); let shift: u8 = jet::rightmost_64_8(a); - assert!(eq_128(right_shift_128(shift, b), unwrap(expected))); - }, false => (), + assert!(eq_128(right_shift_128(shift, b), unwrap(expected))); + }, + false => (), }; } diff --git a/simf/tests/u128/comparison.simf b/simf/tests/u128/comparison.simf new file mode 100644 index 0000000..c1f2ab4 --- /dev/null +++ b/simf/tests/u128/comparison.simf @@ -0,0 +1,32 @@ +use crate::lib::u128::comparison::{is_zero_128, lt_128, le_128}; +use crate::tests::support::dispatch::is_selected; +use crate::tests::support::expect::assert_bool; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u128 = witness::FIRST_ARG; + let b: u128 = witness::SECOND_ARG; + let expected_bool: bool = witness::EXPECTED_BOOL; + + /// Comparison operations + + match is_selected(0, fn_idx) { + true => { + assert_bool(is_zero_128(a), expected_bool); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_bool(lt_128(a, b), expected_bool); + }, + false => (), + }; + match is_selected(2, fn_idx) { + true => { + assert_bool(le_128(a, b), expected_bool); + }, + false => (), + }; +} diff --git a/simf/u128_convert_test.simf b/simf/tests/u128/convert.simf similarity index 92% rename from simf/u128_convert_test.simf rename to simf/tests/u128/convert.simf index 0d70dcf..62706f0 100644 --- a/simf/u128_convert_test.simf +++ b/simf/tests/u128/convert.simf @@ -18,7 +18,7 @@ use crate::lib::asserts::{ assert_eq_64, assert_eq_256 }; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -27,14 +27,14 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { assert_eq_256(u128_to_u256(a), expected); }, false => {}, }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let ( a15, @@ -121,7 +121,7 @@ fn main() { false => {}, }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let ( a7, @@ -161,7 +161,7 @@ fn main() { false => {}, }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (a3, a2, a1, a0): (u32, u32, u32, u32) = split_u128_into_u32(a); @@ -177,7 +177,7 @@ fn main() { false => {}, }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (a1, a0): (u64, u64) = split_u128_into_u64(a); @@ -189,7 +189,7 @@ fn main() { false => {}, }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u1 = jet::rightmost_64_1(expected); @@ -199,7 +199,7 @@ fn main() { false => {}, }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u8 = jet::rightmost_64_8(expected); @@ -209,7 +209,7 @@ fn main() { false => {}, }; - match if_test_this_function(7, fn_idx) { + match is_selected(7, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u16 = jet::rightmost_64_16(expected); @@ -219,7 +219,7 @@ fn main() { false => {}, }; - match if_test_this_function(8, fn_idx) { + match is_selected(8, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u32 = jet::rightmost_64_32(expected); @@ -229,7 +229,7 @@ fn main() { false => {}, }; - match if_test_this_function(9, fn_idx) { + match is_selected(9, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); diff --git a/simf/tests/u128/math/api.simf b/simf/tests/u128/math/api.simf new file mode 100644 index 0000000..cf3e904 --- /dev/null +++ b/simf/tests/u128/math/api.simf @@ -0,0 +1,94 @@ +use crate::lib::u128::math::{ + checked_add_128, + safe_add_128, + checked_sub_128, + safe_sub_128, + checked_mul_128, + safe_mul_128, + checked_div_128, + safe_div_128 +}; +use crate::lib::u128::comparison::{gt_128, ge_128}; +use crate::lib::asserts::assert_eq_128; +use crate::tests::support::expect::{assert_bool_by_opt_128, assert_eq_opt_128}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u128 = witness::FIRST_ARG; + let b: u128 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + /// Safe functions + + // add + match is_selected(0, fn_idx) { + true => { + assert_eq_opt_128(checked_add_128(a, b), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_eq_128(safe_add_128(a, b), unwrap(expected)); + }, + false => (), + }; + + // sub + match is_selected(2, fn_idx) { + true => { + assert_eq_opt_128(checked_sub_128(a, b), expected); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert_eq_128(safe_sub_128(a, b), unwrap(expected)); + }, + false => (), + }; + + // mul + match is_selected(4, fn_idx) { + true => { + assert_eq_opt_128(checked_mul_128(a, b), expected); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert_eq_128(safe_mul_128(a, b), unwrap(expected)); + }, + false => (), + }; + + // div + match is_selected(6, fn_idx) { + true => { + assert_eq_opt_128(checked_div_128(a, b), expected); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert_eq_128(safe_div_128(a, b), unwrap(expected)); + }, + false => (), + }; + + // gt, ge + match is_selected(8, fn_idx) { + true => { + assert_bool_by_opt_128(gt_128(a, b), expected); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_bool_by_opt_128(ge_128(a, b), expected); + }, + false => (), + }; +} diff --git a/simf/u128_basic_math_test.simf b/simf/tests/u128/math/primitives.simf similarity index 54% rename from simf/u128_basic_math_test.simf rename to simf/tests/u128/math/primitives.simf index 17d5992..b85246a 100644 --- a/simf/u128_basic_math_test.simf +++ b/simf/tests/u128/math/primitives.simf @@ -13,17 +13,8 @@ use crate::lib::u128::math::{ div_128 }; use crate::lib::u128::bit::eq_128; -use crate::helper::{if_test_this_function, assert_bool}; - -/// Asserts a result equals expected u128 and bool values. -/// Used for functions that return carry or borrow bool value. -fn assert_eq_uint_bool(result: (bool, u128), expected: u128, expected_bool: bool) { - let (bool_res, uint_res): (bool, u128) = result; - - assert_bool(bool_res, expected_bool); - - assert!(eq_128(uint_res, expected)); -} +use crate::tests::support::expect::assert_eq_uint_bool_128; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -37,14 +28,48 @@ fn main() { /// Arithmetic - match if_test_this_function(0, fn_idx) { true => { assert_eq_uint_bool(add_128(a, b), unwrap(expected), expected_bool); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { let (_, b): (u64, u64) = ::into(b); assert_eq_uint_bool(add_128_64(a, b), unwrap(expected), expected_bool); }, false => (), }; - match if_test_this_function(2, fn_idx) { true => { assert_eq_uint_bool(full_add_128(eq_128(second_expected, 1), a, b), unwrap(expected), expected_bool); }, false => (), }; + match is_selected(0, fn_idx) { + true => { + assert_eq_uint_bool_128(add_128(a, b), unwrap(expected), expected_bool); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + let (_, b): (u64, u64) = ::into(b); + assert_eq_uint_bool_128(add_128_64(a, b), unwrap(expected), expected_bool); + }, + false => (), + }; + match is_selected(2, fn_idx) { + true => { + assert_eq_uint_bool_128( + full_add_128(eq_128(second_expected, 1), a, b), + unwrap(expected), + expected_bool + ); + }, + false => (), + }; - match if_test_this_function(3, fn_idx) { true => { assert_eq_uint_bool(sub_128(a, b), unwrap(expected), expected_bool); }, false => (), }; - match if_test_this_function(4, fn_idx) { true => { assert_eq_uint_bool(full_sub_128(eq_128(second_expected, 1), a, b), unwrap(expected), expected_bool); }, false => (), }; + match is_selected(3, fn_idx) { + true => { + assert_eq_uint_bool_128(sub_128(a, b), unwrap(expected), expected_bool); + }, + false => (), + }; + match is_selected(4, fn_idx) { + true => { + assert_eq_uint_bool_128( + full_sub_128(eq_128(second_expected, 1), a, b), + unwrap(expected), + expected_bool + ); + }, + false => (), + }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let result: u256 = mul_128(a, b); @@ -56,7 +81,7 @@ fn main() { false => (), }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, b): (u64, u64) = ::into(b); let result: u256 = mul_128_64(a, b); @@ -69,18 +94,18 @@ fn main() { false => (), }; - match if_test_this_function(7, fn_idx) { + match is_selected(7, fn_idx) { true => { let norm: u64 = calculate_normalizer_base_64(b, expected_bool); let (_, expected_norm): (u64, u64) = ::into(unwrap(expected)); - assert!(jet::eq_64(norm, expected_norm)); + assert!(jet::eq_64(norm, expected_norm)); }, false => (), }; - match if_test_this_function(8, fn_idx) { + match is_selected(8, fn_idx) { true => { let (_, u2): (u64, u64) = ::into(a); let (u1, u0): (u64, u64) = ::into(b); @@ -90,33 +115,38 @@ fn main() { let (_, expected_q): (u64, u64) = ::into(unwrap(expected)); - assert!(jet::eq_64(q, expected_q)); + assert!(jet::eq_64(q, expected_q)); }, false => (), }; - match if_test_this_function(9, fn_idx) { + match is_selected(9, fn_idx) { true => { let (_, b): (u64, u64) = ::into(b); let (_, expected_r): (u64, u64) = ::into(second_expected); let (q, r): (u128, u64) = div_mod_128_64(a, b); - assert!(eq_128(q, unwrap(expected))); - assert!(jet::eq_64(r, expected_r)); + assert!(eq_128(q, unwrap(expected))); + assert!(jet::eq_64(r, expected_r)); }, false => (), }; - match if_test_this_function(10, fn_idx) { + match is_selected(10, fn_idx) { true => { let (q, r): (u128, u128) = div_mod_128(a, b); - assert!(eq_128(q, unwrap(expected))); - assert!(eq_128(r, second_expected)); + assert!(eq_128(q, unwrap(expected))); + assert!(eq_128(r, second_expected)); }, false => (), }; - match if_test_this_function(11, fn_idx) { true => { assert!(eq_128(div_128(a, b), unwrap(expected))); }, false => (), }; + match is_selected(11, fn_idx) { + true => { + assert!(eq_128(div_128(a, b), unwrap(expected))); + }, + false => (), + }; } diff --git a/simf/u128_mul_div_test.simf b/simf/tests/u128/mul_div.simf similarity index 83% rename from simf/u128_mul_div_test.simf rename to simf/tests/u128/mul_div.simf index 614349a..7458355 100644 --- a/simf/u128_mul_div_test.simf +++ b/simf/tests/u128/mul_div.simf @@ -1,7 +1,7 @@ use crate::lib::u128::mul_div::mul_div_128; use crate::lib::asserts::assert_eq_128; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -12,7 +12,7 @@ fn main() { let expected: Option = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { assert_eq_128(mul_div_128(a, b, c), unwrap(expected)); }, diff --git a/simf/u16_convert_test.simf b/simf/tests/u16/convert.simf similarity index 84% rename from simf/u16_convert_test.simf rename to simf/tests/u16/convert.simf index 847d4f3..afd07c8 100644 --- a/simf/u16_convert_test.simf +++ b/simf/tests/u16/convert.simf @@ -7,7 +7,6 @@ use crate::lib::u16::convert::{ safe_u16_to_u1, safe_u16_to_u8 }; -use crate::lib::u128::bit::eq_128; use crate::lib::asserts::{ assert_eq_1, assert_eq_8, @@ -16,7 +15,7 @@ use crate::lib::asserts::{ assert_eq_128, assert_eq_256 }; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -25,7 +24,7 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, expected): (u32, u32) = ::into(expected); @@ -35,7 +34,7 @@ fn main() { false => {}, }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); @@ -44,7 +43,7 @@ fn main() { false => {}, }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let (_, expected): (u128, u128) = ::into(expected); @@ -53,14 +52,14 @@ fn main() { false => {}, }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { assert_eq_256(u16_to_u256(a), expected); }, false => {}, }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (a1, a0): (u8, u8) = split_u16_into_u8(a); @@ -74,7 +73,7 @@ fn main() { false => {}, }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u1 = jet::rightmost_64_1(expected); @@ -84,7 +83,7 @@ fn main() { false => {}, }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u8 = jet::rightmost_64_8(expected); diff --git a/simf/tests/u16/math.simf b/simf/tests/u16/math.simf new file mode 100644 index 0000000..e555d3a --- /dev/null +++ b/simf/tests/u16/math.simf @@ -0,0 +1,92 @@ +use crate::lib::u16::math::{ + checked_add_16, + safe_add_16, + checked_sub_16, + safe_sub_16, + checked_mul_16, + safe_mul_16, + checked_div_16, + safe_div_16, + gt_16, + ge_16 +}; +use crate::tests::support::expect::{assert_bool_by_opt_16, assert_eq_opt_16}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u16 = witness::FIRST_ARG; + let b: u16 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + // add + match is_selected(0, fn_idx) { + true => { + assert_eq_opt_16(checked_add_16(a, b), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert!(jet::eq_16(safe_add_16(a, b), unwrap(expected))); + }, + false => (), + }; + + // sub + match is_selected(2, fn_idx) { + true => { + assert_eq_opt_16(checked_sub_16(a, b), expected); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert!(jet::eq_16(safe_sub_16(a, b), unwrap(expected))); + }, + false => (), + }; + + // mul + match is_selected(4, fn_idx) { + true => { + assert_eq_opt_16(checked_mul_16(a, b), expected); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert!(jet::eq_16(safe_mul_16(a, b), unwrap(expected))); + }, + false => (), + }; + + // div + match is_selected(6, fn_idx) { + true => { + assert_eq_opt_16(checked_div_16(a, b), expected); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert!(jet::eq_16(safe_div_16(a, b), unwrap(expected))); + }, + false => (), + }; + + // gt, ge + match is_selected(8, fn_idx) { + true => { + assert_bool_by_opt_16(gt_16(a, b), expected); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_bool_by_opt_16(ge_16(a, b), expected); + }, + false => (), + }; +} diff --git a/simf/u16_mul_div_test.simf b/simf/tests/u16/mul_div.simf similarity index 83% rename from simf/u16_mul_div_test.simf rename to simf/tests/u16/mul_div.simf index 646fde3..d710ffc 100644 --- a/simf/u16_mul_div_test.simf +++ b/simf/tests/u16/mul_div.simf @@ -1,7 +1,7 @@ use crate::lib::u16::mul_div::mul_div_16; use crate::lib::asserts::assert_eq_16; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -12,7 +12,7 @@ fn main() { let expected: Option = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { assert_eq_16(mul_div_16(a, b, c), unwrap(expected)); }, diff --git a/simf/u256_test_bits.simf b/simf/tests/u256/bit.simf similarity index 62% rename from simf/u256_test_bits.simf rename to simf/tests/u256/bit.simf index 797c0e8..1325bfd 100644 --- a/simf/u256_test_bits.simf +++ b/simf/tests/u256/bit.simf @@ -1,7 +1,7 @@ use crate::lib::u256::bit::{and_256, or_256, left_shift_256, right_shift_256}; use crate::lib::u256::convert::split_u256_into_u64; use crate::lib::asserts::assert_eq_256; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -12,24 +12,36 @@ fn main() { /// Bit logic - match if_test_this_function(0, fn_idx) { true => { assert_eq_256(and_256(a, b), unwrap(expected)); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert_eq_256(or_256(a, b), unwrap(expected)); }, false => (), }; + match is_selected(0, fn_idx) { + true => { + assert_eq_256(and_256(a, b), unwrap(expected)); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_eq_256(or_256(a, b), unwrap(expected)); + }, + false => (), + }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let (_, _, _, a): (u64, u64, u64, u64) = split_u256_into_u64(a); let shift: u8 = jet::rightmost_64_8(a); - assert_eq_256(left_shift_256(shift, b), unwrap(expected)); - }, false => (), + assert_eq_256(left_shift_256(shift, b), unwrap(expected)); + }, + false => (), }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (_, _, _, a): (u64, u64, u64, u64) = split_u256_into_u64(a); let shift: u8 = jet::rightmost_64_8(a); - assert_eq_256(right_shift_256(shift, b), unwrap(expected)); - }, false => (), + assert_eq_256(right_shift_256(shift, b), unwrap(expected)); + }, + false => (), }; } diff --git a/simf/tests/u256/comparison.simf b/simf/tests/u256/comparison.simf new file mode 100644 index 0000000..5b2b84d --- /dev/null +++ b/simf/tests/u256/comparison.simf @@ -0,0 +1,32 @@ +use crate::lib::u256::comparison::{is_zero_256, lt_256, le_256}; +use crate::tests::support::dispatch::is_selected; +use crate::tests::support::expect::assert_bool; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u256 = witness::FIRST_ARG; + let b: u256 = witness::SECOND_ARG; + let expected_bool: bool = witness::EXPECTED_BOOL; + + /// Comparison operations + + match is_selected(0, fn_idx) { + true => { + assert_bool(is_zero_256(a), expected_bool); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_bool(lt_256(a, b), expected_bool); + }, + false => (), + }; + match is_selected(2, fn_idx) { + true => { + assert_bool(le_256(a, b), expected_bool); + }, + false => (), + }; +} diff --git a/simf/u256_convert_test.simf b/simf/tests/u256/convert.simf similarity index 95% rename from simf/u256_convert_test.simf rename to simf/tests/u256/convert.simf index fe659dd..589476c 100644 --- a/simf/u256_convert_test.simf +++ b/simf/tests/u256/convert.simf @@ -19,7 +19,7 @@ use crate::lib::asserts::{ assert_eq_64, assert_eq_128 }; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -28,7 +28,7 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let ( a31, @@ -185,7 +185,7 @@ fn main() { false => {}, }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let ( a15, @@ -275,7 +275,7 @@ fn main() { false => {}, }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let ( a7, @@ -315,7 +315,7 @@ fn main() { false => {}, }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (a3, a2, a1, a0): (u64, u64, u64, u64) = split_u256_into_u64(a); @@ -334,7 +334,7 @@ fn main() { false => {}, }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (a1, a0): (u128, u128) = split_u256_into_u128(a); @@ -346,7 +346,7 @@ fn main() { false => {}, }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u1 = jet::rightmost_64_1(expected); @@ -356,7 +356,7 @@ fn main() { false => {}, }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u8 = jet::rightmost_64_8(expected); @@ -366,7 +366,7 @@ fn main() { false => {}, }; - match if_test_this_function(7, fn_idx) { + match is_selected(7, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u16 = jet::rightmost_64_16(expected); @@ -376,7 +376,7 @@ fn main() { false => {}, }; - match if_test_this_function(8, fn_idx) { + match is_selected(8, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u32 = jet::rightmost_64_32(expected); @@ -386,7 +386,7 @@ fn main() { false => {}, }; - match if_test_this_function(9, fn_idx) { + match is_selected(9, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); @@ -395,7 +395,7 @@ fn main() { false => {}, }; - match if_test_this_function(10, fn_idx) { + match is_selected(10, fn_idx) { true => { let (_, expected): (u128, u128) = ::into(expected); diff --git a/simf/tests/u256/math/add.simf b/simf/tests/u256/math/add.simf new file mode 100644 index 0000000..44180eb --- /dev/null +++ b/simf/tests/u256/math/add.simf @@ -0,0 +1,37 @@ +use crate::lib::u256::math::{add_256, add_256_128, full_add_256}; +use crate::tests::support::expect::assert_eq_uint_bool_256; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u256 = witness::FIRST_ARG; + let b: u256 = witness::SECOND_ARG; + let carry_in: bool = witness::THIRD_ARG; + let expected: Option = witness::EXPECTED; + let expected_bool: bool = witness::EXPECTED_BOOL; + + /// Arithmetic + + match is_selected(0, fn_idx) { + true => { + assert_eq_uint_bool_256(add_256(a, b), unwrap(expected), expected_bool); + }, + false => (), + }; + + match is_selected(1, fn_idx) { + true => { + let (_, b): (u128, u128) = ::into(b); + assert_eq_uint_bool_256(add_256_128(a, b), unwrap(expected), expected_bool); + }, + false => (), + }; + + match is_selected(2, fn_idx) { + true => { + assert_eq_uint_bool_256(full_add_256(carry_in, a, b), unwrap(expected), expected_bool); + }, + false => (), + }; +} diff --git a/simf/tests/u256/math/api.simf b/simf/tests/u256/math/api.simf new file mode 100644 index 0000000..141ff52 --- /dev/null +++ b/simf/tests/u256/math/api.simf @@ -0,0 +1,94 @@ +use crate::lib::u256::math::{ + checked_add_256, + safe_add_256, + checked_sub_256, + safe_sub_256, + checked_mul_256, + safe_mul_256, + checked_div_256, + safe_div_256 +}; +use crate::lib::u256::comparison::{gt_256, ge_256}; +use crate::lib::asserts::assert_eq_256; +use crate::tests::support::expect::{assert_bool_by_opt_256, assert_eq_opt_256}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u256 = witness::FIRST_ARG; + let b: u256 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + /// Safe functions + + // add + match is_selected(0, fn_idx) { + true => { + assert_eq_opt_256(checked_add_256(a, b), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert_eq_256(safe_add_256(a, b), unwrap(expected)); + }, + false => (), + }; + + // sub + match is_selected(2, fn_idx) { + true => { + assert_eq_opt_256(checked_sub_256(a, b), expected); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert_eq_256(safe_sub_256(a, b), unwrap(expected)); + }, + false => (), + }; + + // mul + match is_selected(4, fn_idx) { + true => { + assert_eq_opt_256(checked_mul_256(a, b), expected); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert_eq_256(safe_mul_256(a, b), unwrap(expected)); + }, + false => (), + }; + + // div + match is_selected(6, fn_idx) { + true => { + assert_eq_opt_256(checked_div_256(a, b), expected); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert_eq_256(safe_div_256(a, b), unwrap(expected)); + }, + false => (), + }; + + // gt, ge + match is_selected(8, fn_idx) { + true => { + assert_bool_by_opt_256(gt_256(a, b), expected); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_bool_by_opt_256(ge_256(a, b), expected); + }, + false => (), + }; +} diff --git a/simf/u256_test_div.simf b/simf/tests/u256/math/div.simf similarity index 84% rename from simf/u256_test_div.simf rename to simf/tests/u256/math/div.simf index 854a857..3d178cf 100644 --- a/simf/u256_test_div.simf +++ b/simf/tests/u256/math/div.simf @@ -8,7 +8,7 @@ use crate::lib::u256::math::{ }; use crate::lib::u256::convert::split_u256_into_u64; use crate::lib::asserts::{assert_eq_128, assert_eq_256}; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -21,7 +21,7 @@ fn main() { /// Arithmetic - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let result: u128 = calculate_normalizer_base_128(a); @@ -32,7 +32,7 @@ fn main() { false => (), }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let (_, _, _, b): (u64, u64, u64, u64) = split_u256_into_u64(b); let (_, _, _, expected_r): (u64, u64, u64, u64) = split_u256_into_u64(second_expected); @@ -45,7 +45,7 @@ fn main() { false => (), }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let (_, b): (u128, u128) = ::into(b); let (_, expected_r): (u128, u128) = ::into(second_expected); @@ -58,7 +58,7 @@ fn main() { false => (), }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (_, b): (u128, u128) = ::into(b); let (_, expected_r): (u128, u128) = ::into(second_expected); @@ -71,7 +71,7 @@ fn main() { false => (), }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (q, r): (u256, u256) = div_mod_256(a, b); @@ -81,5 +81,10 @@ fn main() { false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert_eq_256(div_256(a, b), unwrap(expected)); }, false => (), }; + match is_selected(5, fn_idx) { + true => { + assert_eq_256(div_256(a, b), unwrap(expected)); + }, + false => (), + }; } diff --git a/simf/u256_test_sub_mul.simf b/simf/tests/u256/math/sub_mul.simf similarity index 75% rename from simf/u256_test_sub_mul.simf rename to simf/tests/u256/math/sub_mul.simf index bbadd85..de05dcc 100644 --- a/simf/u256_test_sub_mul.simf +++ b/simf/tests/u256/math/sub_mul.simf @@ -8,17 +8,8 @@ use crate::lib::u256::math::{ }; use crate::lib::u256::convert::split_u256_into_u64; use crate::lib::asserts::{assert_eq_64, assert_eq_128, assert_eq_256}; -use crate::helper::{if_test_this_function, assert_bool}; - -/// Asserts a result equals expected u256 and bool values. -/// Used for functions that return carry or borrow bool value. -fn assert_eq_uint_bool(result: (bool, u256), expected: u256, expected_bool: bool) { - let (bool_res, uint_res): (bool, u256) = result; - - assert_bool(bool_res, expected_bool); - - assert_eq_256(uint_res, expected); -} +use crate::tests::support::expect::assert_eq_uint_bool_256; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -34,14 +25,14 @@ fn main() { /// Arithmetic - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { - assert_eq_uint_bool(sub_256(a, b), unwrap(expected), expected_bool); + assert_eq_uint_bool_256(sub_256(a, b), unwrap(expected), expected_bool); }, false => (), }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let (result_high, result_low): (u256, u256) = mul_256(a, b); @@ -51,7 +42,7 @@ fn main() { false => (), }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let (_, _, _, b): (u64, u64, u64, u64) = split_u256_into_u64(b); let (_, _, _, expected): (u64, u64, u64, u64) = split_u256_into_u64(unwrap(expected)); @@ -64,7 +55,7 @@ fn main() { false => (), }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (_, b): (u128, u128) = ::into(b); let (_, expected): (u128, u128) = ::into(unwrap(expected)); @@ -77,7 +68,7 @@ fn main() { false => (), }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (result_2, result_1, result_0): (u128, u256, u256) = mul_512_128(a, b, c); @@ -90,7 +81,7 @@ fn main() { false => (), }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let (_, b): (u128, u128) = ::into(b); let result: u256 = safe_mul_256_128(a, b); diff --git a/simf/u256_mul_div_test.simf b/simf/tests/u256/mul_div.simf similarity index 83% rename from simf/u256_mul_div_test.simf rename to simf/tests/u256/mul_div.simf index aeddd10..6b66e23 100644 --- a/simf/u256_mul_div_test.simf +++ b/simf/tests/u256/mul_div.simf @@ -1,7 +1,7 @@ use crate::lib::u256::mul_div::mul_div_256; use crate::lib::asserts::assert_eq_256; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -12,7 +12,7 @@ fn main() { let expected: Option = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { assert_eq_256(mul_div_256(a, b, c), unwrap(expected)); }, diff --git a/simf/u32_convert_test.simf b/simf/tests/u32/convert.simf similarity index 86% rename from simf/u32_convert_test.simf rename to simf/tests/u32/convert.simf index 658cc58..e7b4c65 100644 --- a/simf/u32_convert_test.simf +++ b/simf/tests/u32/convert.simf @@ -8,7 +8,6 @@ use crate::lib::u32::convert::{ safe_u32_to_u8, safe_u32_to_u16 }; -use crate::lib::u128::bit::eq_128; use crate::lib::asserts::{ assert_eq_1, assert_eq_8, @@ -17,7 +16,7 @@ use crate::lib::asserts::{ assert_eq_128, assert_eq_256 }; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -26,7 +25,7 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); @@ -35,7 +34,7 @@ fn main() { false => {}, }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let (_, expected): (u128, u128) = ::into(expected); @@ -44,14 +43,14 @@ fn main() { false => {}, }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { assert_eq_256(u32_to_u256(a), expected); }, false => {}, }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (a3, a2, a1, a0): (u8, u8, u8, u8) = split_u32_into_u8(a); @@ -72,7 +71,7 @@ fn main() { false => {}, }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (a1, a0): (u16, u16) = split_u32_into_u16(a); @@ -86,7 +85,7 @@ fn main() { false => {}, }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u1 = jet::rightmost_64_1(expected); @@ -96,7 +95,7 @@ fn main() { false => {}, }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u8 = jet::rightmost_64_8(expected); @@ -106,7 +105,7 @@ fn main() { false => {}, }; - match if_test_this_function(7, fn_idx) { + match is_selected(7, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u16 = jet::rightmost_64_16(expected); diff --git a/simf/tests/u32/math.simf b/simf/tests/u32/math.simf new file mode 100644 index 0000000..ed85426 --- /dev/null +++ b/simf/tests/u32/math.simf @@ -0,0 +1,92 @@ +use crate::lib::u32::math::{ + checked_add_32, + safe_add_32, + checked_sub_32, + safe_sub_32, + checked_mul_32, + safe_mul_32, + checked_div_32, + safe_div_32, + gt_32, + ge_32 +}; +use crate::tests::support::expect::{assert_bool_by_opt_32, assert_eq_opt_32}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u32 = witness::FIRST_ARG; + let b: u32 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + // add + match is_selected(0, fn_idx) { + true => { + assert_eq_opt_32(checked_add_32(a, b), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert!(jet::eq_32(safe_add_32(a, b), unwrap(expected))); + }, + false => (), + }; + + // sub + match is_selected(2, fn_idx) { + true => { + assert_eq_opt_32(checked_sub_32(a, b), expected); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert!(jet::eq_32(safe_sub_32(a, b), unwrap(expected))); + }, + false => (), + }; + + // mul + match is_selected(4, fn_idx) { + true => { + assert_eq_opt_32(checked_mul_32(a, b), expected); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert!(jet::eq_32(safe_mul_32(a, b), unwrap(expected))); + }, + false => (), + }; + + // div + match is_selected(6, fn_idx) { + true => { + assert_eq_opt_32(checked_div_32(a, b), expected); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert!(jet::eq_32(safe_div_32(a, b), unwrap(expected))); + }, + false => (), + }; + + // gt, ge + match is_selected(8, fn_idx) { + true => { + assert_bool_by_opt_32(gt_32(a, b), expected); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_bool_by_opt_32(ge_32(a, b), expected); + }, + false => (), + }; +} diff --git a/simf/u32_mul_div_test.simf b/simf/tests/u32/mul_div.simf similarity index 83% rename from simf/u32_mul_div_test.simf rename to simf/tests/u32/mul_div.simf index b41fb21..72bd99a 100644 --- a/simf/u32_mul_div_test.simf +++ b/simf/tests/u32/mul_div.simf @@ -1,7 +1,7 @@ use crate::lib::u32::mul_div::mul_div_32; use crate::lib::asserts::assert_eq_32; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -12,7 +12,7 @@ fn main() { let expected: Option = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { assert_eq_32(mul_div_32(a, b, c), unwrap(expected)); }, diff --git a/simf/u64_convert_test.simf b/simf/tests/u64/convert.simf similarity index 89% rename from simf/u64_convert_test.simf rename to simf/tests/u64/convert.simf index 00d651e..362d2fc 100644 --- a/simf/u64_convert_test.simf +++ b/simf/tests/u64/convert.simf @@ -17,7 +17,7 @@ use crate::lib::asserts::{ assert_eq_128, assert_eq_256 }; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -26,7 +26,7 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let (_, expected): (u128, u128) = ::into(expected); @@ -35,14 +35,14 @@ fn main() { false => {}, }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { assert_eq_256(u64_to_u256(a), expected); }, false => {}, }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let ( a7, @@ -79,7 +79,7 @@ fn main() { false => {}, }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (a3, a2, a1, a0): (u16, u16, u16, u16) = split_u64_into_u16(a); @@ -99,7 +99,7 @@ fn main() { false => {}, }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { let (a1, a0): (u32, u32) = split_u64_into_u32(a); @@ -112,7 +112,7 @@ fn main() { false => {}, }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u1 = jet::rightmost_64_1(expected); @@ -122,7 +122,7 @@ fn main() { false => {}, }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u8 = jet::rightmost_64_8(expected); @@ -132,7 +132,7 @@ fn main() { false => {}, }; - match if_test_this_function(7, fn_idx) { + match is_selected(7, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u16 = jet::rightmost_64_16(expected); @@ -142,7 +142,7 @@ fn main() { false => {}, }; - match if_test_this_function(8, fn_idx) { + match is_selected(8, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u32 = jet::rightmost_64_32(expected); diff --git a/simf/tests/u64/math.simf b/simf/tests/u64/math.simf new file mode 100644 index 0000000..7071dc9 --- /dev/null +++ b/simf/tests/u64/math.simf @@ -0,0 +1,92 @@ +use crate::lib::u64::math::{ + checked_add_64, + safe_add_64, + checked_sub_64, + safe_sub_64, + checked_mul_64, + safe_mul_64, + checked_div_64, + safe_div_64, + gt_64, + ge_64 +}; +use crate::tests::support::expect::{assert_bool_by_opt_64, assert_eq_opt_64}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u64 = witness::FIRST_ARG; + let b: u64 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + // add + match is_selected(0, fn_idx) { + true => { + assert_eq_opt_64(checked_add_64(a, b), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert!(jet::eq_64(safe_add_64(a, b), unwrap(expected))); + }, + false => (), + }; + + // sub + match is_selected(2, fn_idx) { + true => { + assert_eq_opt_64(checked_sub_64(a, b), expected); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert!(jet::eq_64(safe_sub_64(a, b), unwrap(expected))); + }, + false => (), + }; + + // mul + match is_selected(4, fn_idx) { + true => { + assert_eq_opt_64(checked_mul_64(a, b), expected); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert!(jet::eq_64(safe_mul_64(a, b), unwrap(expected))); + }, + false => (), + }; + + // div + match is_selected(6, fn_idx) { + true => { + assert_eq_opt_64(checked_div_64(a, b), expected); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert!(jet::eq_64(safe_div_64(a, b), unwrap(expected))); + }, + false => (), + }; + + // gt, ge + match is_selected(8, fn_idx) { + true => { + assert_bool_by_opt_64(gt_64(a, b), expected); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_bool_by_opt_64(ge_64(a, b), expected); + }, + false => (), + }; +} diff --git a/simf/u64_mul_div_test.simf b/simf/tests/u64/mul_div.simf similarity index 83% rename from simf/u64_mul_div_test.simf rename to simf/tests/u64/mul_div.simf index fe99df2..ccd5654 100644 --- a/simf/u64_mul_div_test.simf +++ b/simf/tests/u64/mul_div.simf @@ -1,7 +1,7 @@ use crate::lib::u64::mul_div::mul_div_64; use crate::lib::asserts::assert_eq_64; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -12,7 +12,7 @@ fn main() { let expected: Option = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { assert_eq_64(mul_div_64(a, b, c), unwrap(expected)); }, diff --git a/simf/u8_convert_test.simf b/simf/tests/u8/convert.simf similarity index 87% rename from simf/u8_convert_test.simf rename to simf/tests/u8/convert.simf index 2256638..c038c00 100644 --- a/simf/u8_convert_test.simf +++ b/simf/tests/u8/convert.simf @@ -7,7 +7,6 @@ use crate::lib::u8::convert::{ split_u8_into_u1, safe_u8_to_u1 }; -use crate::lib::u128::bit::eq_128; use crate::lib::asserts::{ assert_eq_1, assert_eq_16, @@ -16,7 +15,7 @@ use crate::lib::asserts::{ assert_eq_128, assert_eq_256 }; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -25,7 +24,7 @@ fn main() { let expected: u256 = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); @@ -35,7 +34,7 @@ fn main() { false => (), }; - match if_test_this_function(1, fn_idx) { + match is_selected(1, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, expected): (u32, u32) = ::into(expected); @@ -45,7 +44,7 @@ fn main() { false => (), }; - match if_test_this_function(2, fn_idx) { + match is_selected(2, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); @@ -54,7 +53,7 @@ fn main() { false => (), }; - match if_test_this_function(3, fn_idx) { + match is_selected(3, fn_idx) { true => { let (_, expected): (u128, u128) = ::into(expected); @@ -63,14 +62,14 @@ fn main() { false => (), }; - match if_test_this_function(4, fn_idx) { + match is_selected(4, fn_idx) { true => { assert_eq_256(u8_to_u256(a), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { + match is_selected(5, fn_idx) { true => { let ( a7, @@ -108,7 +107,7 @@ fn main() { false => (), }; - match if_test_this_function(6, fn_idx) { + match is_selected(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let expected: u1 = jet::rightmost_64_1(expected); diff --git a/simf/tests/u8/math.simf b/simf/tests/u8/math.simf new file mode 100644 index 0000000..7f9c2eb --- /dev/null +++ b/simf/tests/u8/math.simf @@ -0,0 +1,92 @@ +use crate::lib::u8::math::{ + checked_add_8, + safe_add_8, + checked_sub_8, + safe_sub_8, + checked_mul_8, + safe_mul_8, + checked_div_8, + safe_div_8, + gt_8, + ge_8 +}; +use crate::tests::support::expect::{assert_bool_by_opt_8, assert_eq_opt_8}; +use crate::tests::support::dispatch::is_selected; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u8 = witness::FIRST_ARG; + let b: u8 = witness::SECOND_ARG; + let expected: Option = witness::EXPECTED; + + // add + match is_selected(0, fn_idx) { + true => { + assert_eq_opt_8(checked_add_8(a, b), expected); + }, + false => (), + }; + match is_selected(1, fn_idx) { + true => { + assert!(jet::eq_8(safe_add_8(a, b), unwrap(expected))); + }, + false => (), + }; + + // sub + match is_selected(2, fn_idx) { + true => { + assert_eq_opt_8(checked_sub_8(a, b), expected); + }, + false => (), + }; + match is_selected(3, fn_idx) { + true => { + assert!(jet::eq_8(safe_sub_8(a, b), unwrap(expected))); + }, + false => (), + }; + + // mul + match is_selected(4, fn_idx) { + true => { + assert_eq_opt_8(checked_mul_8(a, b), expected); + }, + false => (), + }; + match is_selected(5, fn_idx) { + true => { + assert!(jet::eq_8(safe_mul_8(a, b), unwrap(expected))); + }, + false => (), + }; + + // div + match is_selected(6, fn_idx) { + true => { + assert_eq_opt_8(checked_div_8(a, b), expected); + }, + false => (), + }; + match is_selected(7, fn_idx) { + true => { + assert!(jet::eq_8(safe_div_8(a, b), unwrap(expected))); + }, + false => (), + }; + + // gt, ge + match is_selected(8, fn_idx) { + true => { + assert_bool_by_opt_8(gt_8(a, b), expected); + }, + false => (), + }; + match is_selected(9, fn_idx) { + true => { + assert_bool_by_opt_8(ge_8(a, b), expected); + }, + false => (), + }; +} diff --git a/simf/u8_mul_div_test.simf b/simf/tests/u8/mul_div.simf similarity index 82% rename from simf/u8_mul_div_test.simf rename to simf/tests/u8/mul_div.simf index 0cb508d..65ab747 100644 --- a/simf/u8_mul_div_test.simf +++ b/simf/tests/u8/mul_div.simf @@ -1,7 +1,7 @@ use crate::lib::u8::mul_div::mul_div_8; use crate::lib::asserts::assert_eq_8; -use crate::helper::if_test_this_function; +use crate::tests::support::dispatch::is_selected; fn main() { let fn_idx: u8 = witness::FUNCTION_INDEX; @@ -12,7 +12,7 @@ fn main() { let expected: Option = witness::EXPECTED; - match if_test_this_function(0, fn_idx) { + match is_selected(0, fn_idx) { true => { assert_eq_8(mul_div_8(a, b, c), unwrap(expected)); }, diff --git a/simf/u128_math_test.simf b/simf/u128_math_test.simf deleted file mode 100644 index 1c73009..0000000 --- a/simf/u128_math_test.simf +++ /dev/null @@ -1,63 +0,0 @@ -use crate::lib::u128::math::{ - checked_add_128, - safe_add_128, - checked_sub_128, - safe_sub_128, - checked_mul_128, - safe_mul_128, - checked_div_128, - safe_div_128 -}; -use crate::lib::u128::comparison::{gt_128, ge_128}; -use crate::lib::asserts::{assert_none_128, assert_eq_128}; -use crate::lib::binary::not; -use crate::helper::if_test_this_function; - -/// Asserts a `checked_*` result equals the expected Option. -/// `None` encodes the overflow case, `Some(e)` the fitting case, so a single -/// witness value carries both, removing the need for a separate overflow flag. -fn assert_eq_opt(result: Option, expected: Option) { - match expected { - Some(e: u128) => assert_eq_128(unwrap(result), e), - None => assert_none_128(result), - } -} - -/// Asserts a result equals the expected bool value. -/// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { - match expected { - Some(_: u128) => assert!(result), - None => assert!(not(result)), - } -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u128 = witness::FIRST_ARG; - let b: u128 = witness::SECOND_ARG; - let expected: Option = witness::EXPECTED; - - /// Safe functions - - // add - match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_128(a, b), expected); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => {assert_eq_128(safe_add_128(a, b), unwrap(expected)); }, false => (), }; - - // sub - match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_128(a, b), expected); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => {assert_eq_128(safe_sub_128(a, b), unwrap(expected)); }, false => (), }; - - // mul - match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_128(a, b), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => {assert_eq_128(safe_mul_128(a, b), unwrap(expected)); }, false => (), }; - - // div - match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_128(a, b), expected); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => {assert_eq_128(safe_div_128(a, b), unwrap(expected)); }, false => (), }; - - // gt, ge - match if_test_this_function(8, fn_idx) { true => { assert_bool_by_opt(gt_128(a, b), expected); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_bool_by_opt(ge_128(a, b), expected); }, false => (), }; -} diff --git a/simf/u128_test_compare.simf b/simf/u128_test_compare.simf deleted file mode 100644 index e9badb1..0000000 --- a/simf/u128_test_compare.simf +++ /dev/null @@ -1,20 +0,0 @@ -use crate::lib::u128::comparison::{ - is_zero_128, - lt_128, - le_128, -}; -use crate::helper::{if_test_this_function, assert_bool}; - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u128 = witness::FIRST_ARG; - let b: u128 = witness::SECOND_ARG; - let expected_bool: bool = witness::EXPECTED_BOOL; - - /// Comparison operations - - match if_test_this_function(0, fn_idx) { true => { assert_bool(is_zero_128(a), expected_bool); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert_bool(lt_128(a, b), expected_bool); }, false => (), }; - match if_test_this_function(2, fn_idx) { true => { assert_bool(le_128(a, b), expected_bool); }, false => (), }; -} diff --git a/simf/u16_math_test.simf b/simf/u16_math_test.simf deleted file mode 100644 index bc7aece..0000000 --- a/simf/u16_math_test.simf +++ /dev/null @@ -1,51 +0,0 @@ -use crate::lib::u16::math::{checked_add_16, safe_add_16, checked_sub_16, safe_sub_16, checked_mul_16, safe_mul_16, checked_div_16, safe_div_16, gt_16, ge_16}; -use crate::lib::asserts::{assert_none_16, assert_eq_16}; -use crate::lib::binary::not; -use crate::helper::if_test_this_function; - -/// Asserts a `checked_*` result equals the expected Option. -/// `None` encodes the overflow case, `Some(e)` the fitting case, so a single -/// witness value carries both, removing the need for a separate overflow flag. -fn assert_eq_opt(result: Option, expected: Option) { - match expected { - None => assert_none_16(result), - Some(e: u16) => assert_eq_16(unwrap(result), e), - } -} - -/// Asserts a result equals the expected bool value. -/// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { - match expected { - Some(_: u16) => assert!(result), - None => assert!(not(result)), - } -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u16 = witness::FIRST_ARG; - let b: u16 = witness::SECOND_ARG; - let expected: Option = witness::EXPECTED; - - // add - match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_16(a, b), expected); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert!(jet::eq_16(safe_add_16(a, b), unwrap(expected))); }, false => (), }; - - // sub - match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_16(a, b), expected); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => { assert!(jet::eq_16(safe_sub_16(a, b), unwrap(expected))); }, false => (), }; - - // mul - match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_16(a, b), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert!(jet::eq_16(safe_mul_16(a, b), unwrap(expected))); }, false => (), }; - - // div - match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_16(a, b), expected); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert!(jet::eq_16(safe_div_16(a, b), unwrap(expected))); }, false => (), }; - - // gt, ge - match if_test_this_function(8, fn_idx) { true => { assert_bool_by_opt(gt_16(a, b), expected); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_bool_by_opt(ge_16(a, b), expected); }, false => (), }; -} diff --git a/simf/u256_math_test.simf b/simf/u256_math_test.simf deleted file mode 100644 index 9bc8930..0000000 --- a/simf/u256_math_test.simf +++ /dev/null @@ -1,63 +0,0 @@ -use crate::lib::u256::math::{ - checked_add_256, - safe_add_256, - checked_sub_256, - safe_sub_256, - checked_mul_256, - safe_mul_256, - checked_div_256, - safe_div_256 -}; -use crate::lib::u256::comparison::{gt_256, ge_256}; -use crate::lib::asserts::{assert_none_256, assert_eq_256}; -use crate::lib::binary::not; -use crate::helper::if_test_this_function; - -/// Asserts a `checked_*` result equals the expected Option. -/// `None` encodes the overflow case, `Some(e)` the fitting case, so a single -/// witness value carries both, removing the need for a separate overflow flag. -fn assert_eq_opt(result: Option, expected: Option) { - match expected { - Some(e: u256) => assert_eq_256(unwrap(result), e), - None => assert_none_256(result), - } -} - -/// Asserts a result equals the expected bool value. -/// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { - match expected { - Some(_: u256) => assert!(result), - None => assert!(not(result)), - } -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u256 = witness::FIRST_ARG; - let b: u256 = witness::SECOND_ARG; - let expected: Option = witness::EXPECTED; - - /// Safe functions - - // add - match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_256(a, b), expected); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => {assert_eq_256(safe_add_256(a, b), unwrap(expected)); }, false => (), }; - - // sub - match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_256(a, b), expected); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => {assert_eq_256(safe_sub_256(a, b), unwrap(expected)); }, false => (), }; - - // mul - match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_256(a, b), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => {assert_eq_256(safe_mul_256(a, b), unwrap(expected)); }, false => (), }; - - // div - match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_256(a, b), expected); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => {assert_eq_256(safe_div_256(a, b), unwrap(expected)); }, false => (), }; - - // gt, ge - match if_test_this_function(8, fn_idx) { true => { assert_bool_by_opt(gt_256(a, b), expected); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_bool_by_opt(ge_256(a, b), expected); }, false => (), }; -} diff --git a/simf/u256_test_add.simf b/simf/u256_test_add.simf deleted file mode 100644 index 5f210af..0000000 --- a/simf/u256_test_add.simf +++ /dev/null @@ -1,47 +0,0 @@ -use crate::lib::u256::math::{add_256, add_256_128, full_add_256}; -use crate::lib::asserts::assert_eq_256; -use crate::helper::{if_test_this_function, assert_bool}; - -/// Asserts a result equals expected u256 and bool values. -/// Used for functions that return carry or borrow bool value. -fn assert_eq_uint_bool(result: (bool, u256), expected: u256, expected_bool: bool) { - let (bool_res, uint_res): (bool, u256) = result; - - assert_bool(bool_res, expected_bool); - - assert_eq_256(uint_res, expected); -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u256 = witness::FIRST_ARG; - let b: u256 = witness::SECOND_ARG; - let carry_in: bool = witness::THIRD_ARG; - let expected: Option = witness::EXPECTED; - let expected_bool: bool = witness::EXPECTED_BOOL; - - /// Arithmetic - - match if_test_this_function(0, fn_idx) { - true => { - assert_eq_uint_bool(add_256(a, b), unwrap(expected), expected_bool); - }, - false => (), - }; - - match if_test_this_function(1, fn_idx) { - true => { - let (_, b): (u128, u128) = ::into(b); - assert_eq_uint_bool(add_256_128(a, b), unwrap(expected), expected_bool); - }, - false => (), - }; - - match if_test_this_function(2, fn_idx) { - true => { - assert_eq_uint_bool(full_add_256(carry_in, a, b), unwrap(expected), expected_bool); - }, - false => (), - }; -} diff --git a/simf/u256_test_compare.simf b/simf/u256_test_compare.simf deleted file mode 100644 index 5192369..0000000 --- a/simf/u256_test_compare.simf +++ /dev/null @@ -1,16 +0,0 @@ -use crate::lib::u256::comparison::{is_zero_256, lt_256, le_256}; -use crate::helper::{if_test_this_function, assert_bool}; - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u256 = witness::FIRST_ARG; - let b: u256 = witness::SECOND_ARG; - let expected_bool: bool = witness::EXPECTED_BOOL; - - /// Comparison operations - - match if_test_this_function(0, fn_idx) { true => { assert_bool(is_zero_256(a), expected_bool); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert_bool(lt_256(a, b), expected_bool); }, false => (), }; - match if_test_this_function(2, fn_idx) { true => { assert_bool(le_256(a, b), expected_bool); }, false => (), }; -} diff --git a/simf/u32_math_test.simf b/simf/u32_math_test.simf deleted file mode 100644 index 0d8274e..0000000 --- a/simf/u32_math_test.simf +++ /dev/null @@ -1,51 +0,0 @@ -use crate::lib::u32::math::{checked_add_32, safe_add_32, checked_sub_32, safe_sub_32, checked_mul_32, safe_mul_32, checked_div_32, safe_div_32, gt_32, ge_32}; -use crate::lib::asserts::{assert_none_32, assert_eq_32}; -use crate::lib::binary::not; -use crate::helper::if_test_this_function; - -/// Asserts a `checked_*` result equals the expected Option. -/// `None` encodes the overflow case, `Some(e)` the fitting case, so a single -/// witness value carries both, removing the need for a separate overflow flag. -fn assert_eq_opt(result: Option, expected: Option) { - match expected { - None => assert_none_32(result), - Some(e: u32) => assert_eq_32(unwrap(result), e), - } -} - -/// Asserts a result equals the expected bool value. -/// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { - match expected { - Some(_: u32) => assert!(result), - None => assert!(not(result)), - } -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u32 = witness::FIRST_ARG; - let b: u32 = witness::SECOND_ARG; - let expected: Option = witness::EXPECTED; - - // add - match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_32(a, b), expected); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert!(jet::eq_32(safe_add_32(a, b), unwrap(expected))); }, false => (), }; - - // sub - match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_32(a, b), expected); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => { assert!(jet::eq_32(safe_sub_32(a, b), unwrap(expected))); }, false => (), }; - - // mul - match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_32(a, b), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert!(jet::eq_32(safe_mul_32(a, b), unwrap(expected))); }, false => (), }; - - // div - match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_32(a, b), expected); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert!(jet::eq_32(safe_div_32(a, b), unwrap(expected))); }, false => (), }; - - // gt, ge - match if_test_this_function(8, fn_idx) { true => { assert_bool_by_opt(gt_32(a, b), expected); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_bool_by_opt(ge_32(a, b), expected); }, false => (), }; -} diff --git a/simf/u64_math_test.simf b/simf/u64_math_test.simf deleted file mode 100644 index 0866a57..0000000 --- a/simf/u64_math_test.simf +++ /dev/null @@ -1,62 +0,0 @@ -use crate::lib::u64::math::{ - checked_add_64, - safe_add_64, - checked_sub_64, - safe_sub_64, - checked_mul_64, - safe_mul_64, - checked_div_64, - safe_div_64, - gt_64, - ge_64 -}; -use crate::lib::asserts::{assert_none_64, assert_eq_64}; -use crate::lib::binary::not; -use crate::helper::if_test_this_function; - -/// Asserts a `checked_*` result equals the expected Option. -/// `None` encodes the overflow case, `Some(e)` the fitting case, so a single -/// witness value carries both, removing the need for a separate overflow flag. -fn assert_eq_opt(result: Option, expected: Option) { - match expected { - Some(e: u64) => assert_eq_64(unwrap(result), e), - None => assert_none_64(result), - } -} - -/// Asserts a result equals the expected bool value. -/// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { - match expected { - Some(_: u64) => assert!(result), - None => assert!(not(result)), - } -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u64 = witness::FIRST_ARG; - let b: u64 = witness::SECOND_ARG; - let expected: Option = witness::EXPECTED; - - // add - match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_64(a, b), expected); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert!(jet::eq_64(safe_add_64(a, b), unwrap(expected))); }, false => (), }; - - // sub - match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_64(a, b), expected); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => { assert!(jet::eq_64(safe_sub_64(a, b), unwrap(expected))); }, false => (), }; - - // mul - match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_64(a, b), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert!(jet::eq_64(safe_mul_64(a, b), unwrap(expected))); }, false => (), }; - - // div - match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_64(a, b), expected); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert!(jet::eq_64(safe_div_64(a, b), unwrap(expected))); }, false => (), }; - - // gt, ge - match if_test_this_function(8, fn_idx) { true => { assert_bool_by_opt(gt_64(a, b), expected); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_bool_by_opt(ge_64(a, b), expected); }, false => (), }; -} diff --git a/simf/u8_math_test.simf b/simf/u8_math_test.simf deleted file mode 100644 index d8c4f44..0000000 --- a/simf/u8_math_test.simf +++ /dev/null @@ -1,62 +0,0 @@ -use crate::lib::u8::math::{ - checked_add_8, - safe_add_8, - checked_sub_8, - safe_sub_8, - checked_mul_8, - safe_mul_8, - checked_div_8, - safe_div_8, - gt_8, - ge_8 -}; -use crate::lib::asserts::{assert_none_8, assert_eq_8}; -use crate::lib::binary::not; -use crate::helper::if_test_this_function; - -/// Asserts a `checked_*` result equals the expected Option. -/// `None` encodes the overflow case, `Some(e)` the fitting case, so a single -/// witness value carries both, removing the need for a separate overflow flag. -fn assert_eq_opt(result: Option, expected: Option) { - match expected { - Some(e: u8) => assert_eq_8(unwrap(result), e), - None => assert_none_8(result), - } -} - -/// Asserts a result equals the expected bool value. -/// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { - match expected { - Some(_: u8) => assert!(result), - None => assert!(not(result)), - } -} - -fn main() { - let fn_idx: u8 = witness::FUNCTION_INDEX; - - let a: u8 = witness::FIRST_ARG; - let b: u8 = witness::SECOND_ARG; - let expected: Option = witness::EXPECTED; - - // add - match if_test_this_function(0, fn_idx) { true => { assert_eq_opt(checked_add_8(a, b), expected); }, false => (), }; - match if_test_this_function(1, fn_idx) { true => { assert!(jet::eq_8(safe_add_8(a, b), unwrap(expected))); }, false => (), }; - - // sub - match if_test_this_function(2, fn_idx) { true => { assert_eq_opt(checked_sub_8(a, b), expected); }, false => (), }; - match if_test_this_function(3, fn_idx) { true => { assert!(jet::eq_8(safe_sub_8(a, b), unwrap(expected))); }, false => (), }; - - // mul - match if_test_this_function(4, fn_idx) { true => { assert_eq_opt(checked_mul_8(a, b), expected); }, false => (), }; - match if_test_this_function(5, fn_idx) { true => { assert!(jet::eq_8(safe_mul_8(a, b), unwrap(expected))); }, false => (), }; - - // div - match if_test_this_function(6, fn_idx) { true => { assert_eq_opt(checked_div_8(a, b), expected); }, false => (), }; - match if_test_this_function(7, fn_idx) { true => { assert!(jet::eq_8(safe_div_8(a, b), unwrap(expected))); }, false => (), }; - - // gt, ge - match if_test_this_function(8, fn_idx) { true => { assert_bool_by_opt(gt_8(a, b), expected); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_bool_by_opt(ge_8(a, b), expected); }, false => (), }; -} diff --git a/tests/asserts_test.rs b/tests/asserts_test.rs deleted file mode 100644 index 94fcee0..0000000 --- a/tests/asserts_test.rs +++ /dev/null @@ -1,499 +0,0 @@ -mod common; - -use rand::Rng; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::asserts_test::AssertsTestProgram; -use simplicityhl_std::artifacts::asserts_test::derived_asserts_test::{ - AssertsTestArguments, AssertsTestWitness, -}; - -// Dispatch indices — must match the `if_test_this_function(N, ..)` arms in -// simf/asserts_test.simf. -enum FunctionToTest { - AssertEq1, - AssertEq8, - AssertEq16, - AssertEq32, - AssertEq64, - AssertEq128, - AssertEq256, - AssertEqBool, - - AssertNone1, - AssertNone8, - AssertNone16, - AssertNone32, - AssertNone64, - AssertNone128, - AssertNone256, -} - -const DEFAULT_SOME_U8: Option = Some(0); -const DEFAULT_SOME_U16: Option = Some(0); -const DEFAULT_SOME_U32: Option = Some(0); -const DEFAULT_SOME_U64: Option = Some(0); -const DEFAULT_SOME_U128: Option = Some(0); -const DEFAULT_SOME_U256: Option<[u8; 32]> = Some([0; 32]); - -fn program() -> AssertsTestProgram { - AssertsTestProgram::new(&AssertsTestArguments {}) -} - -/// Returns two values in `[min, max]` that are equal when `same`, distinct otherwise. -pub fn generate_uints_in_one_range(same: bool, min_val: u128, max_val: u128) -> (u128, u128) { - let some_u = rand::thread_rng().gen_range(min_val..=max_val); - - if same { - return (some_u, some_u); - } - - assert!( - min_val != max_val, - "cannot generate distinct values in a single-value range" - ); - - let mut other_u = rand::thread_rng().gen_range(min_val..=max_val); - - while other_u == some_u { - other_u = rand::thread_rng().gen_range(min_val..=max_val); - } - - (some_u, other_u) -} - -/// Builds the witness for one assert call. `same` controls the two `assert_eq` -/// args; `none` makes the single `assert_none` arg `None`. -fn build_witness(function: FunctionToTest, same: bool, none: bool) -> AssertsTestWitness { - let mut witness = AssertsTestWitness { - function_index: 0, - first_arg_u1: DEFAULT_SOME_U8, // u1 in Simplicity is represented as u8 - second_arg_u1: DEFAULT_SOME_U8, - first_arg_u8: DEFAULT_SOME_U8, - second_arg_u8: DEFAULT_SOME_U8, - first_arg_u16: DEFAULT_SOME_U16, - second_arg_u16: DEFAULT_SOME_U16, - first_arg_u32: DEFAULT_SOME_U32, - second_arg_u32: DEFAULT_SOME_U32, - first_arg_u64: DEFAULT_SOME_U64, - second_arg_u64: DEFAULT_SOME_U64, - first_arg_u128: DEFAULT_SOME_U128, - second_arg_u128: DEFAULT_SOME_U128, - first_arg_u256: DEFAULT_SOME_U256, - second_arg_u256: DEFAULT_SOME_U256, - }; - - match function { - FunctionToTest::AssertEq1 => { - let (a, b) = generate_uints_in_one_range(same, 0, 1u128); - (witness.first_arg_u1, witness.second_arg_u1) = (Some(a as u8), Some(b as u8)); - } - FunctionToTest::AssertEq8 => { - let (a, b) = generate_uints_in_one_range(same, 0, u8::MAX as u128); - (witness.first_arg_u8, witness.second_arg_u8) = (Some(a as u8), Some(b as u8)); - } - FunctionToTest::AssertEq16 => { - let (a, b) = generate_uints_in_one_range(same, 0, u16::MAX as u128); - (witness.first_arg_u16, witness.second_arg_u16) = (Some(a as u16), Some(b as u16)); - } - FunctionToTest::AssertEq32 => { - let (a, b) = generate_uints_in_one_range(same, 0, u32::MAX as u128); - (witness.first_arg_u32, witness.second_arg_u32) = (Some(a as u32), Some(b as u32)); - } - FunctionToTest::AssertEq64 => { - let (a, b) = generate_uints_in_one_range(same, 0, u64::MAX as u128); - (witness.first_arg_u64, witness.second_arg_u64) = (Some(a as u64), Some(b as u64)); - } - FunctionToTest::AssertEq128 => { - let (a, b) = generate_uints_in_one_range(same, 0, u128::MAX); - (witness.first_arg_u128, witness.second_arg_u128) = (Some(a), Some(b)); - } - FunctionToTest::AssertEq256 => { - let (a, b) = generate_uints_in_one_range(same, 0, u8::MAX as u128); - (witness.first_arg_u256, witness.second_arg_u256) = - (Some([a as u8; 32]), Some([b as u8; 32])); - } - FunctionToTest::AssertEqBool => { - let (a, b) = generate_uints_in_one_range(same, 0, 1u128); - (witness.first_arg_u1, witness.second_arg_u1) = (Some(a as u8), Some(b as u8)); - } - FunctionToTest::AssertNone1 => { - if none { - witness.first_arg_u1 = None; - } - } - FunctionToTest::AssertNone8 => { - if none { - witness.first_arg_u8 = None; - } - } - FunctionToTest::AssertNone16 => { - if none { - witness.first_arg_u16 = None; - } - } - FunctionToTest::AssertNone32 => { - if none { - witness.first_arg_u32 = None; - } - } - FunctionToTest::AssertNone64 => { - if none { - witness.first_arg_u64 = None; - } - } - FunctionToTest::AssertNone128 => { - if none { - witness.first_arg_u128 = None; - } - } - FunctionToTest::AssertNone256 => { - if none { - witness.first_arg_u256 = None; - } - } - } - - witness.function_index = function as u8; - witness -} - -fn run_assert( - context: &simplex::TestContext, - function: FunctionToTest, - same: bool, - none: bool, - expect: Expect, -) -> anyhow::Result<()> { - run( - context, - program(), - build_witness(function, same, none), - expect, - ) -} - -mod asserts_test { - use super::*; - - // ---------- assert_eq: happy = equal args, unhappy = distinct args ---------- - #[simplex::test] - fn assert_eq_1_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert(&context, FunctionToTest::AssertEq1, true, false, Expect::Ok) - } - - #[simplex::test] - fn assert_eq_1_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq1, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_eq_8_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert(&context, FunctionToTest::AssertEq8, true, false, Expect::Ok) - } - - #[simplex::test] - fn assert_eq_8_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq8, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_eq_16_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq16, - true, - false, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_eq_16_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq16, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_eq_32_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq32, - true, - false, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_eq_32_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq32, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_eq_64_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq64, - true, - false, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_eq_64_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq64, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_eq_128_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq128, - true, - false, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_eq_128_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq128, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_eq_256_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq256, - true, - false, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_eq_256_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEq256, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_eq_bool_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEqBool, - true, - false, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_eq_bool_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertEqBool, - false, - false, - Expect::AssertFailed, - ) - } - - // ---------- assert_none: happy = None arg, unhappy = Some arg ---------- - #[simplex::test] - fn assert_none_1_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone1, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_1_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone1, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_none_8_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone8, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_8_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone8, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_none_16_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone16, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_16_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone16, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_none_32_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone32, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_32_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone32, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_none_64_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone64, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_64_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone64, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_none_128_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone128, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_128_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone128, - false, - false, - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn assert_none_256_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone256, - false, - true, - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_none_256_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { - run_assert( - &context, - FunctionToTest::AssertNone256, - false, - false, - Expect::AssertFailed, - ) - } -} diff --git a/tests/binary_test.rs b/tests/binary_test.rs deleted file mode 100644 index 2da001e..0000000 --- a/tests/binary_test.rs +++ /dev/null @@ -1,18 +0,0 @@ -mod common; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::binary_test::BinaryTestProgram; -use simplicityhl_std::artifacts::binary_test::derived_binary_test::{ - BinaryTestArguments, BinaryTestWitness, -}; - -mod binary_tests { - use super::*; - - #[simplex::test] - fn binary_test(context: simplex::TestContext) -> anyhow::Result<()> { - let program = BinaryTestProgram::new(&BinaryTestArguments {}); - run(&context, program, BinaryTestWitness {}, Expect::Ok) - } -} diff --git a/tests/helper_test.rs b/tests/helper_test.rs deleted file mode 100644 index 8843942..0000000 --- a/tests/helper_test.rs +++ /dev/null @@ -1,23 +0,0 @@ -mod common; - -use primitive_types::U256; - -use crate::common::helper::generate_u256; - -#[test] -fn generate_u256_respects_bounds() { - let cases = [ - (U256::zero(), U256::MAX), - (U256::one(), U256::from(u128::MAX)), - (U256::from(u128::MAX) + 1, U256::MAX), - (U256::from(u64::MAX) + 1, U256::from(u128::MAX)), - (U256::MAX, U256::MAX), - ]; - - for (lo, hi) in cases { - for _ in 0..10_000 { - let v = generate_u256(lo, hi); - assert!(lo <= v && v <= hi, "{v:#x} outside [{lo:#x}, {hi:#x}]"); - } - } -} diff --git a/tests/op_return_test.rs b/tests/op_return_test.rs deleted file mode 100644 index 4eb2fe1..0000000 --- a/tests/op_return_test.rs +++ /dev/null @@ -1,130 +0,0 @@ -mod common; - -use rand::Rng; - -use crate::common::core::{run, run_with_op_return}; -use crate::common::helper::DEFAULT_BOOL; -use common::core::Expect; - -use simplicityhl_std::artifacts::op_return_test::OpReturnTestProgram; -use simplicityhl_std::artifacts::op_return_test::derived_op_return_test::{ - OpReturnTestArguments, OpReturnTestWitness, -}; - -enum FunctionToTest { - IsOpReturn, - AssertOutputIsOpReturn, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -const DEFAULT_DATA: &[u8; 1] = &[1]; - -fn program() -> OpReturnTestProgram { - OpReturnTestProgram::new(&OpReturnTestArguments {}) -} - -fn build_witness(function: u8, index: u32, expected: bool) -> OpReturnTestWitness { - OpReturnTestWitness { - function_index: function, - index, - expected, - } -} - -mod op_return_tests { - use super::*; - - #[simplex::test] - fn is_output_op_return_true(context: simplex::TestContext) -> anyhow::Result<()> { - let index = 0; - - run_with_op_return( - &context, - program(), - build_witness(op(FunctionToTest::IsOpReturn), index, true), - Expect::Ok, - DEFAULT_DATA, - ) - } - - #[simplex::test] - fn is_output_op_return_empty_index_false(context: simplex::TestContext) -> anyhow::Result<()> { - let index = rand::thread_rng().gen_range(1..=u32::MAX); - - run_with_op_return( - &context, - program(), - build_witness(op(FunctionToTest::IsOpReturn), index, false), - Expect::Ok, - DEFAULT_DATA, - ) - } - - #[simplex::test] - fn is_output_op_return_false(context: simplex::TestContext) -> anyhow::Result<()> { - let index = 0; - - run( - &context, - program(), - build_witness(op(FunctionToTest::IsOpReturn), index, false), - Expect::Ok, - ) - } - - #[simplex::test] - fn assert_output_is_op_return_pass(context: simplex::TestContext) -> anyhow::Result<()> { - let index = 0; - - run_with_op_return( - &context, - program(), - build_witness( - op(FunctionToTest::AssertOutputIsOpReturn), - index, - DEFAULT_BOOL, - ), - Expect::Ok, - DEFAULT_DATA, - ) - } - - #[simplex::test] - fn assert_output_is_op_return_empty_index_fail( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let index = rand::thread_rng().gen_range(1..=u32::MAX); - - run_with_op_return( - &context, - program(), - build_witness( - op(FunctionToTest::AssertOutputIsOpReturn), - index, - DEFAULT_BOOL, - ), - Expect::AssertFailed, - DEFAULT_DATA, - ) - } - - #[simplex::test] - fn assert_output_is_op_return_fail(context: simplex::TestContext) -> anyhow::Result<()> { - let index = 0; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::AssertOutputIsOpReturn), - index, - DEFAULT_BOOL, - ), - Expect::AssertFailed, - ) - } -} diff --git a/tests/secp256k1_operations_test.rs b/tests/secp256k1_operations_test.rs deleted file mode 100644 index a834f63..0000000 --- a/tests/secp256k1_operations_test.rs +++ /dev/null @@ -1,569 +0,0 @@ -mod common; - -use num_bigint::BigUint; -use num_traits::Zero; -use rand::{RngCore, rngs::OsRng}; -use secp256k1_zkp::{PublicKey, Secp256k1, SecretKey, rand::rngs::OsRng as SecpOsRng}; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::secp256k1_operations_test::Secp256k1OperationsTestProgram; -use simplicityhl_std::artifacts::secp256k1_operations_test::derived_secp256k1_operations_test::{ - Secp256k1OperationsTestArguments, Secp256k1OperationsTestWitness, -}; - -enum FunctionToTest { - GeToPoint, - PointToGej, - FeSub, - ScalarSub, - GejSub, - FeEq, - ScalarEq, - GeEq, - GejPointEq, - SafeGejNormalize, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -const DEFAULT_UINT: [u8; 32] = [0u8; 32]; -const DEFAULT_GE: ([u8; 32], [u8; 32]) = ([0u8; 32], [0u8; 32]); -const DEFAULT_GEJ: (([u8; 32], [u8; 32]), [u8; 32]) = (([0u8; 32], [0u8; 32]), [0u8; 32]); -const DEFAULT_POINT: (u8, [u8; 32]) = (0, [0u8; 32]); - -// FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F -const SECP_P: [u8; 32] = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, -]; - -// FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 -const SECP_N: [u8; 32] = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41, -]; - -fn program() -> Secp256k1OperationsTestProgram { - Secp256k1OperationsTestProgram::new(&Secp256k1OperationsTestArguments {}) -} - -#[allow(clippy::too_many_arguments)] -fn build_witness( - function: u8, - first_uint: [u8; 32], - second_uint: [u8; 32], - first_ge: ([u8; 32], [u8; 32]), - second_ge: ([u8; 32], [u8; 32]), - first_gej: (([u8; 32], [u8; 32]), [u8; 32]), - second_gej: (([u8; 32], [u8; 32]), [u8; 32]), - first_point: (u8, [u8; 32]), - expected_uint: [u8; 32], - expected_ge: ([u8; 32], [u8; 32]), - expected_gej: (([u8; 32], [u8; 32]), [u8; 32]), - expected_point: (u8, [u8; 32]), -) -> Secp256k1OperationsTestWitness { - Secp256k1OperationsTestWitness { - function_index: function, - first_uint, - second_uint, - first_ge, - second_ge, - first_gej, - second_gej, - first_point, - expected_uint, - expected_ge, - expected_gej, - expected_point, - } -} - -fn secp_p() -> BigUint { - BigUint::from_bytes_be(&SECP_P) -} -fn secp_n() -> BigUint { - BigUint::from_bytes_be(&SECP_N) -} - -fn to_32_be(x: &BigUint) -> [u8; 32] { - let b = x.to_bytes_be(); - - let mut out = [0u8; 32]; - out[32 - b.len()..].copy_from_slice(&b); - - out -} - -fn mod_p(x: &BigUint) -> BigUint { - x % secp_p() -} -fn mod_n(x: &BigUint) -> BigUint { - x % secp_n() -} - -fn fe_sub_ref(a: [u8; 32], b: [u8; 32]) -> [u8; 32] { - let p = secp_p(); - let a = BigUint::from_bytes_be(&a) % &p; - let b = BigUint::from_bytes_be(&b) % &p; - - to_32_be(&((a + &p - b) % &p)) -} - -fn scalar_sub_ref(a: [u8; 32], b: [u8; 32]) -> [u8; 32] { - let n = secp_n(); - let a = BigUint::from_bytes_be(&a) % &n; - let b = BigUint::from_bytes_be(&b) % &n; - - to_32_be(&((a + &n - b) % &n)) -} - -fn fe_negate_ref(a: [u8; 32]) -> [u8; 32] { - let p = secp_p(); - let a = BigUint::from_bytes_be(&a) % &p; - - if a.is_zero() { - [0u8; 32] - } else { - to_32_be(&(&p - &a)) - } -} - -fn fe_mul_ref(a: [u8; 32], b: [u8; 32]) -> [u8; 32] { - let p = secp_p(); - let a = BigUint::from_bytes_be(&a); - let b = BigUint::from_bytes_be(&b); - - to_32_be(&((a * b) % &p)) -} - -// Randomness helpers -fn random_uint_bytes() -> [u8; 32] { - let mut b = [0u8; 32]; - OsRng.fill_bytes(&mut b); - - b -} - -fn random_fe_bytes() -> [u8; 32] { - to_32_be(&mod_p(&BigUint::from_bytes_be(&random_uint_bytes()))) -} - -fn random_scalar_bytes() -> [u8; 32] { - to_32_be(&mod_n(&BigUint::from_bytes_be(&random_uint_bytes()))) -} - -fn random_ge_bytes() -> ([u8; 32], [u8; 32]) { - let secp = Secp256k1::new(); - let sk = SecretKey::new(&mut SecpOsRng); - let pk = PublicKey::from_secret_key(&secp, &sk); - let ser = pk.serialize_uncompressed(); // 0x04 || x(32) || y(32) - - let mut x = [0u8; 32]; - x.copy_from_slice(&ser[1..33]); - - let mut y = [0u8; 32]; - y.copy_from_slice(&ser[33..65]); - - (x, y) -} - -fn ge_to_gej(ge: ([u8; 32], [u8; 32])) -> (([u8; 32], [u8; 32]), [u8; 32]) { - let mut one = [0u8; 32]; - one[31] = 1; - - (ge, one) -} - -fn compress(ge: ([u8; 32], [u8; 32])) -> (u8, [u8; 32]) { - (ge.1[31] & 1, ge.0) -} - -fn pk_to_gej(pk: &PublicKey) -> (([u8; 32], [u8; 32]), [u8; 32]) { - let ser = pk.serialize_uncompressed(); - - let mut x = [0u8; 32]; - x.copy_from_slice(&ser[1..33]); - - let mut y = [0u8; 32]; - y.copy_from_slice(&ser[33..65]); - - ge_to_gej((x, y)) -} - -mod secp256k1_operations_tests { - use super::*; - - // 0. ge_to_point - #[simplex::test] - fn ge_to_point_matches_parity(context: simplex::TestContext) -> anyhow::Result<()> { - // Sample one on-curve point; whatever parity it has, that's what we expect - // ge_to_point to produce. Covers both parities across repeated runs. - let ge = random_ge_bytes(); - let expected_parity = ge.1[31] & 1; // 0 (even y) or 1 (odd y) - - run( - &context, - program(), - build_witness( - op(FunctionToTest::GeToPoint), - DEFAULT_UINT, - DEFAULT_UINT, - ge, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_GEJ, - DEFAULT_POINT, - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GEJ, - (expected_parity, ge.0), - ), - Expect::Ok, - ) - } - - // 1. point_to_gej - #[simplex::test] - fn point_to_gej_roundtrip(context: simplex::TestContext) -> anyhow::Result<()> { - let ge = random_ge_bytes(); - let point = compress(ge); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::PointToGej), - DEFAULT_UINT, - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_GEJ, - point, - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GEJ, - point, - ), - Expect::Ok, - ) - } - - // 2. fe_sub - #[simplex::test] - fn fe_sub_self_is_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let a = random_fe_bytes(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FeSub), - a, - a, - DEFAULT_GE, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_GEJ, - DEFAULT_POINT, - [0u8; 32], - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_POINT, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn fe_sub_matches_reference(context: simplex::TestContext) -> anyhow::Result<()> { - let a = random_fe_bytes(); - let b = random_fe_bytes(); - let exp = fe_sub_ref(a, b); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FeSub), - a, - b, - DEFAULT_GE, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_GEJ, - DEFAULT_POINT, - exp, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_POINT, - ), - Expect::Ok, - ) - } - - // 3. scalar_sub - #[simplex::test] - fn scalar_sub_matches_reference(context: simplex::TestContext) -> anyhow::Result<()> { - let a = random_scalar_bytes(); - let b = random_scalar_bytes(); - let exp = scalar_sub_ref(a, b); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::ScalarSub), - a, - b, - DEFAULT_GE, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_GEJ, - DEFAULT_POINT, - exp, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_POINT, - ), - Expect::Ok, - ) - } - - // 4. gej_sub - #[simplex::test] - fn gej_sub_matches_reference(context: simplex::TestContext) -> anyhow::Result<()> { - let secp = Secp256k1::new(); - let sk_p = SecretKey::new(&mut SecpOsRng); - let sk_q = SecretKey::new(&mut SecpOsRng); - - let p = PublicKey::from_secret_key(&secp, &sk_p); - let q = PublicKey::from_secret_key(&secp, &sk_q); - let diff = p.combine(&q.negate(&secp)).expect("p - q non-infinity"); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::GejSub), - DEFAULT_UINT, - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GE, - pk_to_gej(&p), - pk_to_gej(&q), - DEFAULT_POINT, - DEFAULT_UINT, - DEFAULT_GE, - pk_to_gej(&diff), - DEFAULT_POINT, - ), - Expect::Ok, - ) - } - - // 5. fe_eq - #[simplex::test] - fn fe_eq_reflexive(context: simplex::TestContext) -> anyhow::Result<()> { - let a = random_fe_bytes(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FeEq), - a, - a, - DEFAULT_GE, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_GEJ, - DEFAULT_POINT, - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_POINT, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn fe_eq_zero_and_p_are_equal(context: simplex::TestContext) -> anyhow::Result<()> { - run( - &context, - program(), - build_witness( - op(FunctionToTest::FeEq), - [0u8; 32], - SECP_P, - DEFAULT_GE, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_GEJ, - DEFAULT_POINT, - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_POINT, - ), - Expect::Ok, - ) - } - - // 6. scalar_eq - #[simplex::test] - fn scalar_eq_s_and_s_plus_n_are_equal(context: simplex::TestContext) -> anyhow::Result<()> { - // s = 5. s + n has no carry past the low byte. - let mut s = [0u8; 32]; - s[31] = 5; - - let mut s_plus_n = SECP_N; - s_plus_n[31] = s_plus_n[31].wrapping_add(5); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::ScalarEq), - s, - s_plus_n, - DEFAULT_GE, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_GEJ, - DEFAULT_POINT, - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_POINT, - ), - Expect::Ok, - ) - } - - // 7. ge_eq - #[simplex::test] - fn ge_eq_rejects_negation(context: simplex::TestContext) -> anyhow::Result<()> { - let ge = random_ge_bytes(); - let neg_y = fe_negate_ref(ge.1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::GeEq), - DEFAULT_UINT, - DEFAULT_UINT, - ge, - (ge.0, neg_y), - DEFAULT_GEJ, - DEFAULT_GEJ, - DEFAULT_POINT, - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_POINT, - ), - Expect::AssertFailed, - ) - } - - // 8. gej_point_eq - #[simplex::test] - fn gej_point_eq_rescaled(context: simplex::TestContext) -> anyhow::Result<()> { - // (λ²X, λ³Y, λZ) is the same affine point as (X, Y, 1). - let ge = random_ge_bytes(); - let lambda = random_fe_bytes(); - let l2 = fe_mul_ref(lambda, lambda); - let l3 = fe_mul_ref(l2, lambda); - let g = ((fe_mul_ref(ge.0, l2), fe_mul_ref(ge.1, l3)), lambda); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::GejPointEq), - DEFAULT_UINT, - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GE, - g, - DEFAULT_GEJ, - compress(ge), - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_POINT, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn gej_point_eq_rejects_negation(context: simplex::TestContext) -> anyhow::Result<()> { - // Property under test: gej_point_eq(P, -P) == false. - // - // Construction: - // ge = random on-curve point P = (x, y) - // (parity, x) = compressed form of +P - // ge_to_gej(ge) = Gej encoding of +P - // (parity ^ 1, x) = compressed form of -P - // - // decompress((parity ^ 1, x)) inside gej_point_eq recovers (x, -y) = -P. - // Since P ≠ -P on secp256k1, the equivalence must return false. - // expected_bool = false locks that in. - let ge = random_ge_bytes(); - let (parity, x) = compress(ge); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::GejPointEq), - DEFAULT_UINT, - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GE, - ge_to_gej(ge), - DEFAULT_GEJ, - (parity ^ 1, x), - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GEJ, - DEFAULT_POINT, - ), - Expect::AssertFailed, - ) - } - - // 9. safe_gej_normalize - #[simplex::test] - fn safe_gej_normalize_roundtrip(context: simplex::TestContext) -> anyhow::Result<()> { - let ge = random_ge_bytes(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeGejNormalize), - DEFAULT_UINT, - DEFAULT_UINT, - DEFAULT_GE, - DEFAULT_GE, - ge_to_gej(ge), - DEFAULT_GEJ, - DEFAULT_POINT, - DEFAULT_UINT, - ge, - DEFAULT_GEJ, - DEFAULT_POINT, - ), - Expect::Ok, - ) - } -} diff --git a/tests/stdlib/asserts.rs b/tests/stdlib/asserts.rs new file mode 100644 index 0000000..b3ca487 --- /dev/null +++ b/tests/stdlib/asserts.rs @@ -0,0 +1,352 @@ +use rand::Rng; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::asserts::AssertsProgram as AssertsTestProgram; +use simplicityhl_std::artifacts::tests::asserts::derived_asserts::{ + AssertsArguments as AssertsTestArguments, AssertsWitness as AssertsTestWitness, +}; + +// Dispatch indices which must match the `is_selected(N, ..)` arms in +// simf/tests/asserts.simf. +use FunctionToTest::*; + +enum FunctionToTest { + AssertEq1, + AssertEq8, + AssertEq16, + AssertEq32, + AssertEq64, + AssertEq128, + AssertEq256, + AssertEqBool, + + AssertNone1, + AssertNone8, + AssertNone16, + AssertNone32, + AssertNone64, + AssertNone128, + AssertNone256, +} + +const DEFAULT_SOME_U8: Option = Some(0); +const DEFAULT_SOME_U16: Option = Some(0); +const DEFAULT_SOME_U32: Option = Some(0); +const DEFAULT_SOME_U64: Option = Some(0); +const DEFAULT_SOME_U128: Option = Some(0); +const DEFAULT_SOME_U256: Option<[u8; 32]> = Some([0; 32]); + +fn program() -> AssertsTestProgram { + AssertsTestProgram::new(&AssertsTestArguments {}) +} + +/// Returns two values in `[min, max]` that are equal when `same`, distinct otherwise. +pub fn generate_uints_in_one_range(same: bool, min_val: u128, max_val: u128) -> (u128, u128) { + let some_u = rand::thread_rng().gen_range(min_val..=max_val); + + if same { + return (some_u, some_u); + } + + assert!( + min_val != max_val, + "cannot generate distinct values in a single-value range" + ); + + let mut other_u = rand::thread_rng().gen_range(min_val..=max_val); + + while other_u == some_u { + other_u = rand::thread_rng().gen_range(min_val..=max_val); + } + + (some_u, other_u) +} + +/// Builds the witness for one assert call. `same` controls the two `assert_eq` +/// args; `none` makes the single `assert_none` arg `None`. +fn build_witness(function: FunctionToTest, same: bool, none: bool) -> AssertsTestWitness { + let mut witness = AssertsTestWitness { + function_index: 0, + first_arg_u1: DEFAULT_SOME_U8, // u1 in Simplicity is represented as u8 + second_arg_u1: DEFAULT_SOME_U8, + first_arg_u8: DEFAULT_SOME_U8, + second_arg_u8: DEFAULT_SOME_U8, + first_arg_u16: DEFAULT_SOME_U16, + second_arg_u16: DEFAULT_SOME_U16, + first_arg_u32: DEFAULT_SOME_U32, + second_arg_u32: DEFAULT_SOME_U32, + first_arg_u64: DEFAULT_SOME_U64, + second_arg_u64: DEFAULT_SOME_U64, + first_arg_u128: DEFAULT_SOME_U128, + second_arg_u128: DEFAULT_SOME_U128, + first_arg_u256: DEFAULT_SOME_U256, + second_arg_u256: DEFAULT_SOME_U256, + }; + + match function { + FunctionToTest::AssertEq1 => { + let (a, b) = generate_uints_in_one_range(same, 0, 1u128); + (witness.first_arg_u1, witness.second_arg_u1) = (Some(a as u8), Some(b as u8)); + } + FunctionToTest::AssertEq8 => { + let (a, b) = generate_uints_in_one_range(same, 0, u8::MAX as u128); + (witness.first_arg_u8, witness.second_arg_u8) = (Some(a as u8), Some(b as u8)); + } + FunctionToTest::AssertEq16 => { + let (a, b) = generate_uints_in_one_range(same, 0, u16::MAX as u128); + (witness.first_arg_u16, witness.second_arg_u16) = (Some(a as u16), Some(b as u16)); + } + FunctionToTest::AssertEq32 => { + let (a, b) = generate_uints_in_one_range(same, 0, u32::MAX as u128); + (witness.first_arg_u32, witness.second_arg_u32) = (Some(a as u32), Some(b as u32)); + } + FunctionToTest::AssertEq64 => { + let (a, b) = generate_uints_in_one_range(same, 0, u64::MAX as u128); + (witness.first_arg_u64, witness.second_arg_u64) = (Some(a as u64), Some(b as u64)); + } + FunctionToTest::AssertEq128 => { + let (a, b) = generate_uints_in_one_range(same, 0, u128::MAX); + (witness.first_arg_u128, witness.second_arg_u128) = (Some(a), Some(b)); + } + FunctionToTest::AssertEq256 => { + let (a, b) = generate_uints_in_one_range(same, 0, u8::MAX as u128); + (witness.first_arg_u256, witness.second_arg_u256) = + (Some([a as u8; 32]), Some([b as u8; 32])); + } + FunctionToTest::AssertEqBool => { + let (a, b) = generate_uints_in_one_range(same, 0, 1u128); + (witness.first_arg_u1, witness.second_arg_u1) = (Some(a as u8), Some(b as u8)); + } + FunctionToTest::AssertNone1 => { + if none { + witness.first_arg_u1 = None; + } + } + FunctionToTest::AssertNone8 => { + if none { + witness.first_arg_u8 = None; + } + } + FunctionToTest::AssertNone16 => { + if none { + witness.first_arg_u16 = None; + } + } + FunctionToTest::AssertNone32 => { + if none { + witness.first_arg_u32 = None; + } + } + FunctionToTest::AssertNone64 => { + if none { + witness.first_arg_u64 = None; + } + } + FunctionToTest::AssertNone128 => { + if none { + witness.first_arg_u128 = None; + } + } + FunctionToTest::AssertNone256 => { + if none { + witness.first_arg_u256 = None; + } + } + } + + witness.function_index = function as u8; + witness +} + +/// One assert call, described by what makes it pass. +struct Case { + function: FunctionToTest, + same: bool, + none: bool, +} + +fn case(function: FunctionToTest) -> Case { + Case { + function, + same: false, + none: false, + } +} + +impl Case { + /// Make the two `assert_eq` arguments equal. + fn equal(mut self) -> Self { + self.same = true; + self + } + + /// Make the `assert_none` argument `None`. + fn none(mut self) -> Self { + self.none = true; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + let witness = build_witness(self.function, self.same, self.none); + run(context, program(), witness, expect) + } +} + +// assert_eq: happy = equal args, unhappy = distinct args +#[simplex::test] +fn assert_eq_1_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq1).equal().run(&context) +} + +#[simplex::test] +fn assert_eq_1_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq1).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_eq_8_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq8).equal().run(&context) +} + +#[simplex::test] +fn assert_eq_8_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq8).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_eq_16_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq16).equal().run(&context) +} + +#[simplex::test] +fn assert_eq_16_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq16).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_eq_32_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq32).equal().run(&context) +} + +#[simplex::test] +fn assert_eq_32_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq32).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_eq_64_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq64).equal().run(&context) +} + +#[simplex::test] +fn assert_eq_64_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq64).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_eq_128_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq128).equal().run(&context) +} + +#[simplex::test] +fn assert_eq_128_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq128).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_eq_256_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq256).equal().run(&context) +} + +#[simplex::test] +fn assert_eq_256_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEq256).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_eq_bool_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEqBool).equal().run(&context) +} + +#[simplex::test] +fn assert_eq_bool_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertEqBool).expecting(&context, Expect::AssertFailed) +} + +// assert_none: happy = None arg, unhappy = Some arg +#[simplex::test] +fn assert_none_1_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone1).none().run(&context) +} + +#[simplex::test] +fn assert_none_1_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone1).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_none_8_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone8).none().run(&context) +} + +#[simplex::test] +fn assert_none_8_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone8).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_none_16_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone16).none().run(&context) +} + +#[simplex::test] +fn assert_none_16_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone16).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_none_32_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone32).none().run(&context) +} + +#[simplex::test] +fn assert_none_32_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone32).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_none_64_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone64).none().run(&context) +} + +#[simplex::test] +fn assert_none_64_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone64).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_none_128_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone128).none().run(&context) +} + +#[simplex::test] +fn assert_none_128_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone128).expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_none_256_happy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone256).none().run(&context) +} + +#[simplex::test] +fn assert_none_256_unhappy_path(context: simplex::TestContext) -> anyhow::Result<()> { + case(AssertNone256).expecting(&context, Expect::AssertFailed) +} diff --git a/tests/stdlib/binary.rs b/tests/stdlib/binary.rs new file mode 100644 index 0000000..ca00390 --- /dev/null +++ b/tests/stdlib/binary.rs @@ -0,0 +1,12 @@ +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::binary::BinaryProgram as BinaryTestProgram; +use simplicityhl_std::artifacts::tests::binary::derived_binary::{ + BinaryArguments as BinaryTestArguments, BinaryWitness as BinaryTestWitness, +}; + +#[simplex::test] +fn all_ops(context: simplex::TestContext) -> anyhow::Result<()> { + let program = BinaryTestProgram::new(&BinaryTestArguments {}); + run(&context, program, BinaryTestWitness {}, Expect::Ok) +} diff --git a/tests/common/core.rs b/tests/stdlib/common/core.rs similarity index 100% rename from tests/common/core.rs rename to tests/stdlib/common/core.rs diff --git a/tests/common/helper.rs b/tests/stdlib/common/helper.rs similarity index 50% rename from tests/common/helper.rs rename to tests/stdlib/common/helper.rs index 6b5a568..c161b6d 100644 --- a/tests/common/helper.rs +++ b/tests/stdlib/common/helper.rs @@ -7,16 +7,33 @@ use rand::Rng; use crate::common::u256_wrapper::U256Wrapper; -// Shared constants and helper functions used across integration tests - -pub const DEFAULT_BOOL: bool = false; +// Shared helper functions used across integration tests pub fn generate_u256(lower_bound: U256, upper_bound: U256) -> U256 { assert!( lower_bound <= upper_bound, "Error: lower bound is greater than upper bound" ); + rand::thread_rng() .gen_range(U256Wrapper(lower_bound)..=U256Wrapper(upper_bound)) .0 } + +#[test] +fn generate_u256_respects_bounds() { + let cases = [ + (U256::zero(), U256::MAX), + (U256::one(), U256::from(u128::MAX)), + (U256::from(u128::MAX) + 1, U256::MAX), + (U256::from(u64::MAX) + 1, U256::from(u128::MAX)), + (U256::MAX, U256::MAX), + ]; + + for (lo, hi) in cases { + for _ in 0..10_000 { + let v = generate_u256(lo, hi); + assert!(lo <= v && v <= hi, "{v:#x} outside [{lo:#x}, {hi:#x}]"); + } + } +} diff --git a/tests/common/mod.rs b/tests/stdlib/common/mod.rs similarity index 100% rename from tests/common/mod.rs rename to tests/stdlib/common/mod.rs diff --git a/tests/common/u256_wrapper.rs b/tests/stdlib/common/u256_wrapper.rs similarity index 98% rename from tests/common/u256_wrapper.rs rename to tests/stdlib/common/u256_wrapper.rs index 97b2679..79e91ac 100644 --- a/tests/common/u256_wrapper.rs +++ b/tests/stdlib/common/u256_wrapper.rs @@ -7,7 +7,7 @@ use std::ops::{Add, Deref, DerefMut, Div, Mul, Sub}; pub struct U256Wrapper(pub U256); impl U256Wrapper { - pub fn to_be_bytes(&self) -> [u8; 32] { + pub fn to_be_bytes(self) -> [u8; 32] { self.0.to_big_endian() } } diff --git a/tests/common/uint.rs b/tests/stdlib/common/uint.rs similarity index 99% rename from tests/common/uint.rs rename to tests/stdlib/common/uint.rs index b52149e..eeb5ff1 100644 --- a/tests/common/uint.rs +++ b/tests/stdlib/common/uint.rs @@ -12,8 +12,8 @@ use simplex::program::{Program, WitnessTrait}; use super::core::{Expect, run}; /// Dispatch indices for the operations that exist for every unsigned width. -/// These map 1:1 onto the `if_test_this_function(N, ..)` arms in each width's -/// `*_test.simf`. +/// These map 1:1 onto the `is_selected(N, ..)` arms in each width's math test +/// program under `simf/tests`. pub enum CommonOp { CheckedAdd, SafeAdd, diff --git a/tests/stdlib/main.rs b/tests/stdlib/main.rs new file mode 100644 index 0000000..8698e0e --- /dev/null +++ b/tests/stdlib/main.rs @@ -0,0 +1,13 @@ +mod common; + +mod asserts; +mod binary; +mod op_return; +mod secp256k1; +mod u1; +mod u128; +mod u16; +mod u256; +mod u32; +mod u64; +mod u8; diff --git a/tests/stdlib/op_return.rs b/tests/stdlib/op_return.rs new file mode 100644 index 0000000..2b83226 --- /dev/null +++ b/tests/stdlib/op_return.rs @@ -0,0 +1,131 @@ +use rand::Rng; + +use crate::common::core::{Expect, run, run_with_op_return}; + +use simplicityhl_std::artifacts::tests::op_return::OpReturnProgram as OpReturnTestProgram; +use simplicityhl_std::artifacts::tests::op_return::derived_op_return::{ + OpReturnArguments as OpReturnTestArguments, OpReturnWitness as OpReturnTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + IsOpReturn, + AssertOutputIsOpReturn, +} + +const DEFAULT_DATA: &[u8; 1] = &[1]; + +fn program() -> OpReturnTestProgram { + OpReturnTestProgram::new(&OpReturnTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads and whether the +/// spend carries an `OP_RETURN` output. +struct Case { + witness: OpReturnTestWitness, + data: Option<&'static [u8]>, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: OpReturnTestWitness { + function_index: function as u8, + index: 0, + expected: false, + }, + data: None, + } +} + +impl Case { + /// `index`: the output the arm inspects. + fn index(mut self, index: u32) -> Self { + self.witness.index = index; + self + } + + /// `expected`: the boolean the arm should report. + fn flag(mut self, flag: bool) -> Self { + self.witness.expected = flag; + self + } + + /// Add an `OP_RETURN` output carrying `data` to the spend. + fn op_return(mut self, data: &'static [u8]) -> Self { + self.data = Some(data); + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + match self.data { + Some(data) => run_with_op_return(context, program(), self.witness, expect, data), + None => run(context, program(), self.witness, expect), + } + } +} + +#[simplex::test] +fn is_output_op_return_true(context: simplex::TestContext) -> anyhow::Result<()> { + let index = 0; + + case(IsOpReturn) + .index(index) + .flag(true) + .op_return(DEFAULT_DATA) + .run(&context) +} + +#[simplex::test] +fn is_output_op_return_empty_index_false(context: simplex::TestContext) -> anyhow::Result<()> { + let index = rand::thread_rng().gen_range(1..=u32::MAX); + + case(IsOpReturn) + .index(index) + .op_return(DEFAULT_DATA) + .run(&context) +} + +#[simplex::test] +fn is_output_op_return_false(context: simplex::TestContext) -> anyhow::Result<()> { + let index = 0; + + case(IsOpReturn).index(index).run(&context) +} + +#[simplex::test] +fn assert_output_is_op_return_pass(context: simplex::TestContext) -> anyhow::Result<()> { + let index = 0; + + case(AssertOutputIsOpReturn) + .index(index) + .op_return(DEFAULT_DATA) + .run(&context) +} + +#[simplex::test] +fn assert_output_is_op_return_empty_index_fail( + context: simplex::TestContext, +) -> anyhow::Result<()> { + let index = rand::thread_rng().gen_range(1..=u32::MAX); + + case(AssertOutputIsOpReturn) + .index(index) + .op_return(DEFAULT_DATA) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn assert_output_is_op_return_fail(context: simplex::TestContext) -> anyhow::Result<()> { + let index = 0; + + case(AssertOutputIsOpReturn) + .index(index) + .expecting(&context, Expect::AssertFailed) +} diff --git a/tests/stdlib/secp256k1/mod.rs b/tests/stdlib/secp256k1/mod.rs new file mode 100644 index 0000000..9045df1 --- /dev/null +++ b/tests/stdlib/secp256k1/mod.rs @@ -0,0 +1 @@ +mod operations; diff --git a/tests/stdlib/secp256k1/operations.rs b/tests/stdlib/secp256k1/operations.rs new file mode 100644 index 0000000..673dedf --- /dev/null +++ b/tests/stdlib/secp256k1/operations.rs @@ -0,0 +1,411 @@ +use num_bigint::BigUint; +use num_traits::Zero; +use rand::{RngCore, rngs::OsRng}; +use secp256k1_zkp::{PublicKey, Secp256k1, SecretKey, rand::rngs::OsRng as SecpOsRng}; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::secp256k1::operations::OperationsProgram as Secp256k1OperationsTestProgram; +use simplicityhl_std::artifacts::tests::secp256k1::operations::derived_operations::{ + OperationsArguments as Secp256k1OperationsTestArguments, + OperationsWitness as Secp256k1OperationsTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + GeToPoint, + PointToGej, + FeSub, + ScalarSub, + GejSub, + FeEq, + ScalarEq, + GeEq, + GejPointEq, + SafeGejNormalize, +} + +// FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F +const SECP_P: [u8; 32] = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, +]; + +// FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 +const SECP_N: [u8; 32] = [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41, +]; + +fn program() -> Secp256k1OperationsTestProgram { + Secp256k1OperationsTestProgram::new(&Secp256k1OperationsTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: Secp256k1OperationsTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: Secp256k1OperationsTestWitness { + function_index: function as u8, + first_uint: [0; 32], + second_uint: [0; 32], + first_ge: ([0; 32], [0; 32]), + second_ge: ([0; 32], [0; 32]), + first_gej: (([0; 32], [0; 32]), [0; 32]), + second_gej: (([0; 32], [0; 32]), [0; 32]), + first_point: (0, [0; 32]), + expected_uint: [0; 32], + expected_ge: ([0; 32], [0; 32]), + expected_gej: (([0; 32], [0; 32]), [0; 32]), + expected_point: (0, [0; 32]), + }, + } +} + +impl Case { + /// The two field or scalar operands, `first_uint` and `second_uint`. + fn uints(mut self, first_uint: [u8; 32], second_uint: [u8; 32]) -> Self { + self.witness.first_uint = first_uint; + self.witness.second_uint = second_uint; + self + } + + /// Only `first_ge`. + fn ge(mut self, first_ge: ([u8; 32], [u8; 32])) -> Self { + self.witness.first_ge = first_ge; + self + } + + /// The two affine points, `first_ge` and `second_ge`. + fn ges(mut self, first_ge: ([u8; 32], [u8; 32]), second_ge: ([u8; 32], [u8; 32])) -> Self { + self.witness.first_ge = first_ge; + self.witness.second_ge = second_ge; + self + } + + /// Only `first_gej`. + fn gej(mut self, first_gej: (([u8; 32], [u8; 32]), [u8; 32])) -> Self { + self.witness.first_gej = first_gej; + self + } + + /// The two Jacobian points, `first_gej` and `second_gej`. + fn gejs( + mut self, + first_gej: (([u8; 32], [u8; 32]), [u8; 32]), + second_gej: (([u8; 32], [u8; 32]), [u8; 32]), + ) -> Self { + self.witness.first_gej = first_gej; + self.witness.second_gej = second_gej; + self + } + + /// `first_point`: a compressed point, parity byte and x coordinate. + fn point(mut self, first_point: (u8, [u8; 32])) -> Self { + self.witness.first_point = first_point; + self + } + + /// `expected_uint`: the field or scalar the arm should produce. + fn expect_uint(mut self, expected_uint: [u8; 32]) -> Self { + self.witness.expected_uint = expected_uint; + self + } + + /// `expected_ge`: the affine point the arm should produce. + fn expect_ge(mut self, expected_ge: ([u8; 32], [u8; 32])) -> Self { + self.witness.expected_ge = expected_ge; + self + } + + /// `expected_gej`: the Jacobian point the arm should produce. + fn expect_gej(mut self, expected_gej: (([u8; 32], [u8; 32]), [u8; 32])) -> Self { + self.witness.expected_gej = expected_gej; + self + } + + /// `expected_point`: the compressed point the arm should produce. + fn expect_point(mut self, expected_point: (u8, [u8; 32])) -> Self { + self.witness.expected_point = expected_point; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +fn secp_p() -> BigUint { + BigUint::from_bytes_be(&SECP_P) +} +fn secp_n() -> BigUint { + BigUint::from_bytes_be(&SECP_N) +} + +fn to_32_be(x: &BigUint) -> [u8; 32] { + let b = x.to_bytes_be(); + + let mut out = [0u8; 32]; + out[32 - b.len()..].copy_from_slice(&b); + + out +} + +fn mod_p(x: &BigUint) -> BigUint { + x % secp_p() +} +fn mod_n(x: &BigUint) -> BigUint { + x % secp_n() +} + +fn fe_sub_ref(a: [u8; 32], b: [u8; 32]) -> [u8; 32] { + let p = secp_p(); + let a = BigUint::from_bytes_be(&a) % &p; + let b = BigUint::from_bytes_be(&b) % &p; + + to_32_be(&((a + &p - b) % &p)) +} + +fn scalar_sub_ref(a: [u8; 32], b: [u8; 32]) -> [u8; 32] { + let n = secp_n(); + let a = BigUint::from_bytes_be(&a) % &n; + let b = BigUint::from_bytes_be(&b) % &n; + + to_32_be(&((a + &n - b) % &n)) +} + +fn fe_negate_ref(a: [u8; 32]) -> [u8; 32] { + let p = secp_p(); + let a = BigUint::from_bytes_be(&a) % &p; + + if a.is_zero() { + [0u8; 32] + } else { + to_32_be(&(&p - &a)) + } +} + +fn fe_mul_ref(a: [u8; 32], b: [u8; 32]) -> [u8; 32] { + let p = secp_p(); + let a = BigUint::from_bytes_be(&a); + let b = BigUint::from_bytes_be(&b); + + to_32_be(&((a * b) % &p)) +} + +// Randomness helpers +fn random_uint_bytes() -> [u8; 32] { + let mut b = [0u8; 32]; + OsRng.fill_bytes(&mut b); + + b +} + +fn random_fe_bytes() -> [u8; 32] { + to_32_be(&mod_p(&BigUint::from_bytes_be(&random_uint_bytes()))) +} + +fn random_scalar_bytes() -> [u8; 32] { + to_32_be(&mod_n(&BigUint::from_bytes_be(&random_uint_bytes()))) +} + +fn random_ge_bytes() -> ([u8; 32], [u8; 32]) { + let secp = Secp256k1::new(); + let sk = SecretKey::new(&mut SecpOsRng); + let pk = PublicKey::from_secret_key(&secp, &sk); + let ser = pk.serialize_uncompressed(); // 0x04 || x(32) || y(32) + + let mut x = [0u8; 32]; + x.copy_from_slice(&ser[1..33]); + + let mut y = [0u8; 32]; + y.copy_from_slice(&ser[33..65]); + + (x, y) +} + +fn ge_to_gej(ge: ([u8; 32], [u8; 32])) -> (([u8; 32], [u8; 32]), [u8; 32]) { + let mut one = [0u8; 32]; + one[31] = 1; + + (ge, one) +} + +fn compress(ge: ([u8; 32], [u8; 32])) -> (u8, [u8; 32]) { + (ge.1[31] & 1, ge.0) +} + +fn pk_to_gej(pk: &PublicKey) -> (([u8; 32], [u8; 32]), [u8; 32]) { + let ser = pk.serialize_uncompressed(); + + let mut x = [0u8; 32]; + x.copy_from_slice(&ser[1..33]); + + let mut y = [0u8; 32]; + y.copy_from_slice(&ser[33..65]); + + ge_to_gej((x, y)) +} + +// 0. ge_to_point +#[simplex::test] +fn ge_to_point_matches_parity(context: simplex::TestContext) -> anyhow::Result<()> { + // Sample one on-curve point; whatever parity it has, that's what we expect + // ge_to_point to produce. Covers both parities across repeated runs. + let ge = random_ge_bytes(); + let expected_parity = ge.1[31] & 1; // 0 (even y) or 1 (odd y) + + case(GeToPoint) + .ge(ge) + .expect_point((expected_parity, ge.0)) + .run(&context) +} + +// 1. point_to_gej +#[simplex::test] +fn point_to_gej_roundtrip(context: simplex::TestContext) -> anyhow::Result<()> { + let ge = random_ge_bytes(); + let point = compress(ge); + + case(PointToGej) + .point(point) + .expect_point(point) + .run(&context) +} + +// 2. fe_sub +#[simplex::test] +fn fe_sub_self_is_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let a = random_fe_bytes(); + + case(FeSub).uints(a, a).expect_uint([0u8; 32]).run(&context) +} + +#[simplex::test] +fn fe_sub_matches_reference(context: simplex::TestContext) -> anyhow::Result<()> { + let a = random_fe_bytes(); + let b = random_fe_bytes(); + let exp = fe_sub_ref(a, b); + + case(FeSub).uints(a, b).expect_uint(exp).run(&context) +} + +// 3. scalar_sub +#[simplex::test] +fn scalar_sub_matches_reference(context: simplex::TestContext) -> anyhow::Result<()> { + let a = random_scalar_bytes(); + let b = random_scalar_bytes(); + let exp = scalar_sub_ref(a, b); + + case(ScalarSub).uints(a, b).expect_uint(exp).run(&context) +} + +// 4. gej_sub +#[simplex::test] +fn gej_sub_matches_reference(context: simplex::TestContext) -> anyhow::Result<()> { + let secp = Secp256k1::new(); + let sk_p = SecretKey::new(&mut SecpOsRng); + let sk_q = SecretKey::new(&mut SecpOsRng); + + let p = PublicKey::from_secret_key(&secp, &sk_p); + let q = PublicKey::from_secret_key(&secp, &sk_q); + let diff = p.combine(&q.negate(&secp)).expect("p - q non-infinity"); + + case(GejSub) + .gejs(pk_to_gej(&p), pk_to_gej(&q)) + .expect_gej(pk_to_gej(&diff)) + .run(&context) +} + +// 5. fe_eq +#[simplex::test] +fn fe_eq_reflexive(context: simplex::TestContext) -> anyhow::Result<()> { + let a = random_fe_bytes(); + + case(FeEq).uints(a, a).run(&context) +} + +#[simplex::test] +fn fe_eq_zero_and_p_are_equal(context: simplex::TestContext) -> anyhow::Result<()> { + case(FeEq).uints([0u8; 32], SECP_P).run(&context) +} + +// 6. scalar_eq +#[simplex::test] +fn scalar_eq_s_and_s_plus_n_are_equal(context: simplex::TestContext) -> anyhow::Result<()> { + // s = 5. s + n has no carry past the low byte. + let mut s = [0u8; 32]; + s[31] = 5; + + let mut s_plus_n = SECP_N; + s_plus_n[31] = s_plus_n[31].wrapping_add(5); + + case(ScalarEq).uints(s, s_plus_n).run(&context) +} + +// 7. ge_eq +#[simplex::test] +fn ge_eq_rejects_negation(context: simplex::TestContext) -> anyhow::Result<()> { + let ge = random_ge_bytes(); + let neg_y = fe_negate_ref(ge.1); + + case(GeEq) + .ges(ge, (ge.0, neg_y)) + .expecting(&context, Expect::AssertFailed) +} + +// 8. gej_point_eq +#[simplex::test] +fn gej_point_eq_rescaled(context: simplex::TestContext) -> anyhow::Result<()> { + // (λ²X, λ³Y, λZ) is the same affine point as (X, Y, 1). + let ge = random_ge_bytes(); + let lambda = random_fe_bytes(); + let l2 = fe_mul_ref(lambda, lambda); + let l3 = fe_mul_ref(l2, lambda); + let g = ((fe_mul_ref(ge.0, l2), fe_mul_ref(ge.1, l3)), lambda); + + case(GejPointEq).gej(g).point(compress(ge)).run(&context) +} + +#[simplex::test] +fn gej_point_eq_rejects_negation(context: simplex::TestContext) -> anyhow::Result<()> { + // Property under test: gej_point_eq(P, -P) == false. + // + // Construction: + // ge = random on-curve point P = (x, y) + // (parity, x) = compressed form of +P + // ge_to_gej(ge) = Gej encoding of +P + // (parity ^ 1, x) = compressed form of -P + // + // decompress((parity ^ 1, x)) inside gej_point_eq recovers (x, -y) = -P. + // Since P ≠ -P on secp256k1, the equivalence must return false. + // expected_bool = false locks that in. + let ge = random_ge_bytes(); + let (parity, x) = compress(ge); + + case(GejPointEq) + .gej(ge_to_gej(ge)) + .point((parity ^ 1, x)) + .expecting(&context, Expect::AssertFailed) +} + +// 9. safe_gej_normalize +#[simplex::test] +fn safe_gej_normalize_roundtrip(context: simplex::TestContext) -> anyhow::Result<()> { + let ge = random_ge_bytes(); + + case(SafeGejNormalize) + .gej(ge_to_gej(ge)) + .expect_ge(ge) + .run(&context) +} diff --git a/tests/stdlib/u1/convert.rs b/tests/stdlib/u1/convert.rs new file mode 100644 index 0000000..69e84e4 --- /dev/null +++ b/tests/stdlib/u1/convert.rs @@ -0,0 +1,134 @@ +use primitive_types::U256; +use rand::Rng; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::u1::convert::ConvertProgram as U1ConvertTestProgram; +use simplicityhl_std::artifacts::tests::u1::convert::derived_convert::{ + ConvertArguments as U1ConvertTestArguments, ConvertWitness as U1ConvertTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + U1ToU8, + U1ToU16, + U1ToU32, + U1ToU64, + U1ToU128, + U1ToU256, + U1ToBool, +} + +fn program() -> U1ConvertTestProgram { + U1ConvertTestProgram::new(&U1ConvertTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U1ConvertTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U1ConvertTestWitness { + function_index: function as u8, + first_arg: 0, + expected: [0; 32], + }, + } +} + +impl Case { + /// The operand, `first_arg`. + fn arg(mut self, a: u8) -> Self { + self.witness.first_arg = a; + self + } + + /// `expected`: the value the arm should produce. + fn expect(mut self, expected: [u8; 32]) -> Self { + self.witness.expected = expected; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn u1_to_u8(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=1); + + case(U1ToU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u1_to_u16(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=1); + + case(U1ToU16) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u1_to_u32(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=1); + + case(U1ToU32) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u1_to_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=1); + + case(U1ToU64) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u1_to_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=1); + + case(U1ToU128) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u1_to_u256(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=1); + + case(U1ToU256) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn split_u1_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=1); + + case(U1ToBool) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} diff --git a/tests/stdlib/u1/mod.rs b/tests/stdlib/u1/mod.rs new file mode 100644 index 0000000..bb13da4 --- /dev/null +++ b/tests/stdlib/u1/mod.rs @@ -0,0 +1 @@ +mod convert; diff --git a/tests/stdlib/u128/bit.rs b/tests/stdlib/u128/bit.rs new file mode 100644 index 0000000..bba6b0b --- /dev/null +++ b/tests/stdlib/u128/bit.rs @@ -0,0 +1,168 @@ +use rand::Rng; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::u128::bit::BitProgram as U128TestBitsProgram; +use simplicityhl_std::artifacts::tests::u128::bit::derived_bit::{ + BitArguments as U128TestBitsArguments, BitWitness as U128TestBitsWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + And128, + Or128, + Eq128, + LeftShift128, + RightShift128, +} + +fn program() -> U128TestBitsProgram { + U128TestBitsProgram::new(&U128TestBitsArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U128TestBitsWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U128TestBitsWitness { + function_index: function as u8, + first_arg: 0, + second_arg: 0, + expected: None, + expected_bool: false, + }, + } +} + +impl Case { + /// The two operands, `first_arg` and `second_arg`. + fn args(mut self, a: u128, b: u128) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self + } + + /// The value the arm should return. `None`, the default, means the arm is + /// expected to produce nothing. + fn expect(mut self, expected: u128) -> Self { + self.witness.expected = Some(expected); + self + } + + /// `expected_bool`: the boolean the arm should report. + fn flag(mut self, expected_bool: bool) -> Self { + self.witness.expected_bool = expected_bool; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn and_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(0..=u128::MAX); + let result = a & b; + + case(And128).args(a, b).expect(result).run(&context) +} + +#[simplex::test] +fn or_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(0..=u128::MAX); + let result = a | b; + + case(Or128).args(a, b).expect(result).run(&context) +} + +#[simplex::test] +fn eq_128_true(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + + case(Eq128).args(a, a).expect(0).flag(true).run(&context) +} + +#[simplex::test] +fn eq_128_false(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u128::MAX); + let b = a - 1; + + case(Eq128).args(a, b).expect(0).run(&context) +} + +#[simplex::test] +fn left_shift_128(context: simplex::TestContext) -> anyhow::Result<()> { + let shift = rand::thread_rng().gen_range(1..=127_u128); + let val = rand::thread_rng().gen_range(0..=u128::MAX); + let result = val << shift; + + case(LeftShift128) + .args(shift, val) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn left_shift_128_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let shift = 0; + let val = rand::thread_rng().gen_range(0..=u128::MAX); + let result = val; + + case(LeftShift128) + .args(shift, val) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn left_shift_128_out_of_range(context: simplex::TestContext) -> anyhow::Result<()> { + let shift = rand::thread_rng().gen_range(128..=u8::MAX as u128); + let val = rand::thread_rng().gen_range(0..=u128::MAX); + + case(LeftShift128).args(shift, val).expect(0).run(&context) +} + +#[simplex::test] +fn right_shift_128(context: simplex::TestContext) -> anyhow::Result<()> { + let shift = rand::thread_rng().gen_range(1..=127_u128); + let val = rand::thread_rng().gen_range(0..=u128::MAX); + let result = val >> shift; + + case(RightShift128) + .args(shift, val) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn right_shift_128_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let shift = 0; + let val = rand::thread_rng().gen_range(0..=u128::MAX); + let result = val; + + case(RightShift128) + .args(shift, val) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn right_shift_128_out_of_range(context: simplex::TestContext) -> anyhow::Result<()> { + let shift = rand::thread_rng().gen_range(128..=u8::MAX as u128); + let val = rand::thread_rng().gen_range(0..=u128::MAX); + + case(RightShift128).args(shift, val).expect(0).run(&context) +} diff --git a/tests/stdlib/u128/comparison.rs b/tests/stdlib/u128/comparison.rs new file mode 100644 index 0000000..b97c596 --- /dev/null +++ b/tests/stdlib/u128/comparison.rs @@ -0,0 +1,129 @@ +use rand::Rng; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::u128::comparison::ComparisonProgram as U128TestCompareProgram; +use simplicityhl_std::artifacts::tests::u128::comparison::derived_comparison::{ + ComparisonArguments as U128TestCompareArguments, ComparisonWitness as U128TestCompareWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + IsZero128, + Lt128, + Le128, +} + +fn program() -> U128TestCompareProgram { + U128TestCompareProgram::new(&U128TestCompareArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U128TestCompareWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U128TestCompareWitness { + function_index: function as u8, + first_arg: 0, + second_arg: 0, + expected_bool: false, + }, + } +} + +impl Case { + /// Only `first_arg`, for the arms that ignore the second operand. + fn arg(mut self, a: u128) -> Self { + self.witness.first_arg = a; + self + } + + /// The two operands, `first_arg` and `second_arg`. + fn args(mut self, a: u128, b: u128) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self + } + + /// `expected_bool`: the boolean the arm should report. + fn flag(mut self, expected_bool: bool) -> Self { + self.witness.expected_bool = expected_bool; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn is_zero_128_true(context: simplex::TestContext) -> anyhow::Result<()> { + let a = 0; + + case(IsZero128).arg(a).flag(true).run(&context) +} + +#[simplex::test] +fn is_zero_128_false(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u128::MAX); + + case(IsZero128).arg(a).run(&context) +} + +#[simplex::test] +fn lt_128_less(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = a + 1; + + case(Lt128).args(a, b).flag(true).run(&context) +} + +#[simplex::test] +fn lt_128_eq(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = a; + + case(Lt128).args(a, b).run(&context) +} + +#[simplex::test] +fn lt_128_bigger(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u128::MAX); + let b = a - 1; + + case(Lt128).args(a, b).run(&context) +} + +#[simplex::test] +fn le_128_less(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = a + 1; + + case(Le128).args(a, b).flag(true).run(&context) +} + +#[simplex::test] +fn le_128_eq(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = a; + + case(Le128).args(a, b).flag(true).run(&context) +} + +#[simplex::test] +fn le_128_bigger(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u128::MAX); + let b = a - 1; + + case(Le128).args(a, b).run(&context) +} diff --git a/tests/stdlib/u128/convert.rs b/tests/stdlib/u128/convert.rs new file mode 100644 index 0000000..b1cf059 --- /dev/null +++ b/tests/stdlib/u128/convert.rs @@ -0,0 +1,217 @@ +use primitive_types::U256; +use rand::Rng; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::u128::convert::ConvertProgram as U128ConvertTestProgram; +use simplicityhl_std::artifacts::tests::u128::convert::derived_convert::{ + ConvertArguments as U128ConvertTestArguments, ConvertWitness as U128ConvertTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + U128ToU256, + SplitU128IntoU8, + SplitU128IntoU16, + SplitU128IntoU32, + SplitU128IntoU64, + SafeU128ToU1, + SafeU128ToU8, + SafeU128ToU16, + SafeU128ToU32, + SafeU128ToU64, +} + +fn program() -> U128ConvertTestProgram { + U128ConvertTestProgram::new(&U128ConvertTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U128ConvertTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U128ConvertTestWitness { + function_index: function as u8, + first_arg: 0, + expected: [0; 32], + }, + } +} + +impl Case { + /// The operand, `first_arg`. + fn arg(mut self, a: u128) -> Self { + self.witness.first_arg = a; + self + } + + /// `expected`: the value the arm should produce. + fn expect(mut self, expected: [u8; 32]) -> Self { + self.witness.expected = expected; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn u128_to_u256(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + + case(U128ToU256) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn split_u128_into_u8(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + + case(SplitU128IntoU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn split_u128_into_u16(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + + case(SplitU128IntoU16) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn split_u128_into_u32(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + + case(SplitU128IntoU32) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn split_u128_into_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + + case(SplitU128IntoU64) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u128_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=1); + + case(SafeU128ToU1) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u128_to_u1_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u128::MAX); + + case(SafeU128ToU1) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u128_to_u8(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u8::MAX as u128); + + case(SafeU128ToU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u128_to_u8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(u8::MAX as u128 + 1..=u128::MAX); + + case(SafeU128ToU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u128_to_u16(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u16::MAX as u128); + + case(SafeU128ToU16) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u128_to_u16_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(u16::MAX as u128 + 1..=u128::MAX); + + case(SafeU128ToU16) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u128_to_u32(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u32::MAX as u128); + + case(SafeU128ToU32) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u128_to_u32_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(u32::MAX as u128 + 1..=u128::MAX); + + case(SafeU128ToU32) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u128_to_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u64::MAX as u128); + + case(SafeU128ToU64) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u128_to_u64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(u64::MAX as u128 + 1..=u128::MAX); + + case(SafeU128ToU64) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} diff --git a/tests/u128_math_test.rs b/tests/stdlib/u128/math/api.rs similarity index 64% rename from tests/u128_math_test.rs rename to tests/stdlib/u128/math/api.rs index 06e2d98..c624b3f 100644 --- a/tests/u128_math_test.rs +++ b/tests/stdlib/u128/math/api.rs @@ -1,10 +1,8 @@ -mod common; +use crate::common::uint::TestUint; -use common::uint::TestUint; - -use simplicityhl_std::artifacts::u128_math_test::U128MathTestProgram; -use simplicityhl_std::artifacts::u128_math_test::derived_u128_math_test::{ - U128MathTestArguments, U128MathTestWitness, +use simplicityhl_std::artifacts::tests::u128::math::api::ApiProgram as U128MathTestProgram; +use simplicityhl_std::artifacts::tests::u128::math::api::derived_api::{ + ApiArguments as U128MathTestArguments, ApiWitness as U128MathTestWitness, }; // The only per-width code for the common operations. @@ -32,9 +30,5 @@ impl TestUint for u128 { } } -mod u128_math_tests { - use super::*; - - // Stamps the 22 `#[simplex::test]` entry points for u128. Logic lives in common::uint. - uint_tests!(u128); -} +// Stamps the 22 `#[simplex::test]` entry points for u128. Logic lives in common::uint. +crate::uint_tests!(u128); diff --git a/tests/stdlib/u128/math/mod.rs b/tests/stdlib/u128/math/mod.rs new file mode 100644 index 0000000..914dfcb --- /dev/null +++ b/tests/stdlib/u128/math/mod.rs @@ -0,0 +1,2 @@ +mod api; +mod primitives; diff --git a/tests/stdlib/u128/math/primitives.rs b/tests/stdlib/u128/math/primitives.rs new file mode 100644 index 0000000..367e41f --- /dev/null +++ b/tests/stdlib/u128/math/primitives.rs @@ -0,0 +1,645 @@ +use primitive_types::U256; +use rand::Rng; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::u128::math::primitives::PrimitivesProgram as U128BasicMathTestProgram; +use simplicityhl_std::artifacts::tests::u128::math::primitives::derived_primitives::{ + PrimitivesArguments as U128BasicMathTestArguments, + PrimitivesWitness as U128BasicMathTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + Add128, + Add128_64, + FullAdd128, + Sub128, + FullSub128, + Mul128, + Mul128_64, + CalculateNormalizerBase64, + EstimateQuotientDigitBase64, + DivMod128_64, + DivMod128, + Div128, +} + +fn program() -> U128BasicMathTestProgram { + U128BasicMathTestProgram::new(&U128BasicMathTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U128BasicMathTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U128BasicMathTestWitness { + function_index: function as u8, + first_arg: 0, + second_arg: 0, + expected: None, + expected_bool: false, + second_expected: 0, + }, + } +} + +impl Case { + /// The two operands, `first_arg` and `second_arg`. + fn args(mut self, a: u128, b: u128) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self + } + + /// The value the arm should return. `None`, the default, means the arm is + /// expected to produce nothing. + fn expect(mut self, expected: u128) -> Self { + self.witness.expected = Some(expected); + self + } + + /// `expected_bool`: the carry or borrow an arm reports beside its value. + fn flag(mut self, flag: bool) -> Self { + self.witness.expected_bool = flag; + self + } + + /// `second_expected`: the spare slot. A remainder, a low word, or a carry + /// fed back in, depending on the arm. + fn second(mut self, second: u128) -> Self { + self.witness.second_expected = second; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +fn split_helper(a: U256) -> (u128, u128) { + let a_high = (a >> 128).as_u128(); + let a_low = a.low_u128(); + + (a_high, a_low) +} + +#[simplex::test] +fn add_128_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX / 2); + let b = rand::thread_rng().gen_range(0..=u128::MAX / 2); + let result = a + b; + + case(Add128).args(a, b).expect(result).run(&context) +} + +#[simplex::test] +fn add_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = u128::MAX; + let b = rand::thread_rng().gen_range(1..=u128::MAX); + let result = b - 1; + + case(Add128) + .args(a, b) + .expect(result) + .flag(true) + .run(&context) +} + +#[simplex::test] +fn add_128_64_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX / 2); + let b = rand::thread_rng().gen_range(0..=u64::MAX) as u128; + let result = a + b; + + case(Add128_64).args(a, b).expect(result).run(&context) +} + +#[simplex::test] +fn add_128_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = u128::MAX; + let b = rand::thread_rng().gen_range(1..=u64::MAX) as u128; + let result = b - 1; + + case(Add128_64) + .args(a, b) + .expect(result) + .flag(true) + .run(&context) +} + +#[simplex::test] +fn full_add_128_not_overflow_carry_low_false(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX / 2); + let b = rand::thread_rng().gen_range(0..=u128::MAX / 2); + let result = a + b; + let result_carry = false; + let carry_low = 0_u128; + + case(FullAdd128) + .args(a, b) + .expect(result) + .flag(result_carry) + .second(carry_low) + .run(&context) +} + +#[simplex::test] +fn full_add_128_overflow_carry_low_false(context: simplex::TestContext) -> anyhow::Result<()> { + let a = u128::MAX; + let b = rand::thread_rng().gen_range(1..=u128::MAX); + let result = b - 1; + let result_carry = true; + let carry_low = 0_u128; + + case(FullAdd128) + .args(a, b) + .expect(result) + .flag(result_carry) + .second(carry_low) + .run(&context) +} + +#[simplex::test] +fn full_add_128_not_overflow_carry_low_true(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX / 2); + let b = rand::thread_rng().gen_range(0..=u128::MAX / 2); + let result = a + b + 1; + let result_carry = false; + let carry_low = 1_u128; + + case(FullAdd128) + .args(a, b) + .expect(result) + .flag(result_carry) + .second(carry_low) + .run(&context) +} + +#[simplex::test] +fn full_add_128_overflow_carry_low_true(context: simplex::TestContext) -> anyhow::Result<()> { + let a = u128::MAX; + let b = rand::thread_rng().gen_range(1..=u128::MAX); + let result = b; + let result_carry = true; + let carry_low = 1_u128; + + case(FullAdd128) + .args(a, b) + .expect(result) + .flag(result_carry) + .second(carry_low) + .run(&context) +} + +#[simplex::test] +fn sub_128_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(0..=a); + let result = a - b; + + case(Sub128).args(a, b).expect(result).run(&context) +} + +#[simplex::test] +fn sub_128_a_eq_b(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + + case(Sub128).args(a, a).expect(0).run(&context) +} + +#[simplex::test] +fn sub_128_a_low_eq_b_low(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b_high = rand::thread_rng().gen_range(0..=u64::MAX); + + let low: u64 = a as u64; + let b = ((b_high as u128) << 64) | (low as u128); + + let carry = a < b; + let result = a.wrapping_sub(b); + + case(Sub128) + .args(a, b) + .expect(result) + .flag(carry) + .run(&context) +} + +#[simplex::test] +fn sub_128_diff_is_u64_max(context: simplex::TestContext) -> anyhow::Result<()> { + let a_low: u64 = u64::MAX; + + let a_high = rand::thread_rng().gen_range(0..=u64::MAX); + let b_high = rand::thread_rng().gen_range(0..=u64::MAX); + + let a = ((a_high as u128) << 64) | (a_low as u128); + let b = (b_high as u128) << 64; // b_low is 0 + + let carry = a < b; + let result = a.wrapping_sub(b); + + case(Sub128) + .args(a, b) + .expect(result) + .flag(carry) + .run(&context) +} + +#[simplex::test] +fn sub_128_diff_is_u128_max(context: simplex::TestContext) -> anyhow::Result<()> { + let a = u128::MAX; + let b = 0; + + case(Sub128).args(a, b).expect(a).run(&context) +} + +#[simplex::test] +fn sub_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = u128::MAX; + let result = a + 1; + + case(Sub128) + .args(a, b) + .expect(result) + .flag(true) + .run(&context) +} + +#[simplex::test] +fn full_sub_128_borrow_low_false(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(0..=a); + let result = a - b; + let result_borrow = false; + let borrow_low = 0_u128; + + case(FullSub128) + .args(a, b) + .expect(result) + .flag(result_borrow) + .second(borrow_low) + .run(&context) +} + +#[simplex::test] +fn full_sub_128_overflow_borrow_low_false(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = u128::MAX; + let result = a + 1; + let result_borrow = true; + let borrow_low = 0_u128; + + case(FullSub128) + .args(a, b) + .expect(result) + .flag(result_borrow) + .second(borrow_low) + .run(&context) +} + +#[simplex::test] +fn full_sub_128_borrow_low_true(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(0..a); + let result = a - b - 1; + let result_borrow = false; + let borrow_low = 1_u128; + + case(FullSub128) + .args(a, b) + .expect(result) + .flag(result_borrow) + .second(borrow_low) + .run(&context) +} + +#[simplex::test] +fn full_sub_128_overflow_borrow_low_true(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = u128::MAX; + let (result, result_borrow) = a.overflowing_sub(b); + + let borrow_low = 1_u128; + + case(FullSub128) + .args(a, b) + .expect(result - 1) + .flag(result_borrow) + .second(borrow_low) + .run(&context) +} + +#[simplex::test] +fn mul_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = rand::thread_rng().gen_range(0..u128::MAX); + let result = U256::from(a) * U256::from(b); + + let (result_high, result_low) = split_helper(result); + + case(Mul128) + .args(a, b) + .expect(result_high) + .second(result_low) + .run(&context) +} + +#[simplex::test] +fn mul_128_64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = rand::thread_rng().gen_range(0..u64::MAX); + let result = U256::from(a) * U256::from(b); + + let (result_high, result_low) = split_helper(result); + + case(Mul128_64) + .args(a, b as u128) + .expect(result_high) + .second(result_low) + .run(&context) +} + +#[simplex::test] +fn calculate_normalizer_base_64_b_is_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let threshold = 1u128 << 63; + + let b = rand::thread_rng().gen_range(1..threshold); + + let norm: u128 = threshold.div_ceil(b); + + case(CalculateNormalizerBase64) + .args(0, b) + .expect(norm) + .run(&context) +} + +#[simplex::test] +fn calculate_normalizer_base_64_b_is_big_enough_not_normalize( + context: simplex::TestContext, +) -> anyhow::Result<()> { + let threshold = 1u128 << 63; + + let b = rand::thread_rng().gen_range(threshold..=u64::MAX as u128); + + case(CalculateNormalizerBase64) + .args(0, b) + .expect(1) + .run(&context) +} + +#[simplex::test] +fn calculate_normalizer_base_64_b_is_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let threshold = 1u128 << 63; + + let b = rand::thread_rng().gen_range((u64::MAX as u128) + 1..=u128::MAX); + let b_high = b >> 64; + + let norm: u128 = threshold.div_ceil(b_high); + + case(CalculateNormalizerBase64) + .args(0, b) + .expect(norm) + .flag(true) + .run(&context) +} + +#[simplex::test] +fn calculate_normalizer_base_64_b_is_u64_fail(context: simplex::TestContext) -> anyhow::Result<()> { + let b = rand::thread_rng().gen_range((u64::MAX as u128) + 1..=u128::MAX); + + case(CalculateNormalizerBase64) + .args(0, b) + .expect(0) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn calculate_normalizer_base_64_b_is_u128_fail( + context: simplex::TestContext, +) -> anyhow::Result<()> { + let b = rand::thread_rng().gen_range(1..=u64::MAX as u128); + + case(CalculateNormalizerBase64) + .args(0, b) + .expect(0) + .flag(true) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn calculate_normalizer_base_64_b_is_zero_fail( + context: simplex::TestContext, +) -> anyhow::Result<()> { + let b = 0; + + case(CalculateNormalizerBase64) + .args(0, b) + .expect(0) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn estimate_quotient_digit_base_64(context: simplex::TestContext) -> anyhow::Result<()> { + let threshold = 1u64 << 63; + + let b_high = rand::thread_rng().gen_range(threshold..=u64::MAX); + let b_low = rand::thread_rng().gen_range(0..=u64::MAX); + + let a_high = rand::thread_rng().gen_range(0..b_high); + let a_low = rand::thread_rng().gen_range(0..=u128::MAX); + + let a = ((U256::from(a_high)) << 128) | (U256::from(a_low)); + let b = ((b_high as u128) << 64) | (b_low as u128); + + let q = (a / b).as_u128(); + + case(EstimateQuotientDigitBase64) + .args(a_high as u128, a_low) + .expect(q) + .second(b) + .run(&context) +} + +#[simplex::test] +fn estimate_quotient_digit_base_64_fail(context: simplex::TestContext) -> anyhow::Result<()> { + // expected to fail because a is to big for q to fit unto u64 + let threshold = 1u64 << 63; + + let b_high = rand::thread_rng().gen_range(threshold..u64::MAX); + let b_low = rand::thread_rng().gen_range(0..=u64::MAX); + + let a_high = rand::thread_rng().gen_range(b_high + 1..=u64::MAX); + let a_low = rand::thread_rng().gen_range(0..=u128::MAX); + + let a = ((U256::from(a_high)) << 128) | (U256::from(a_low)); + let b = ((b_high as u128) << 64) | (b_low as u128); + + let q = (a / b).as_u128(); + + case(EstimateQuotientDigitBase64) + .args(a_high as u128, a_low) + .expect(q) + .second(b) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn div_mod_128_64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(1..=u64::MAX as u128); + + let q = a / b; + let r = a % b; + + case(DivMod128_64) + .args(a, b) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn div_mod_128_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = 0; + + case(DivMod128_64) + .args(a, b) + .expect(0) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn div_mod_128_a_less_than_b(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..u128::MAX); + let b = rand::thread_rng().gen_range(a + 1..=u128::MAX); + + let q = a / b; + let r = a % b; + + case(DivMod128).args(a, b).expect(q).second(r).run(&context) +} + +#[simplex::test] +fn div_mod_128_div_64(context: simplex::TestContext) -> anyhow::Result<()> { + let b = rand::thread_rng().gen_range(1..=u64::MAX); + let a = rand::thread_rng().gen_range(b..=u64::MAX) as u128; + + let q = a / b as u128; + let r = a % b as u128; + + case(DivMod128) + .args(a, b as u128) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn div_mod_128_q_is_1(context: simplex::TestContext) -> anyhow::Result<()> { + // case where a >= b and a_high = b_high != 0 + let b_low = rand::thread_rng().gen_range(0..=u64::MAX); + let a_low = rand::thread_rng().gen_range(b_low..=u64::MAX); + let high = rand::thread_rng().gen_range(1..u64::MAX); + + let a = ((high as u128) << 64) | (a_low as u128); + let b = ((high as u128) << 64) | (b_low as u128); + + let q = a / b; + let r = a % b; + + case(DivMod128).args(a, b).expect(q).second(r).run(&context) +} + +#[simplex::test] +fn div_mod_128_b_is_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let b = rand::thread_rng().gen_range(1..=u64::MAX as u128); + let a = rand::thread_rng().gen_range(u64::MAX as u128 + 1..=u128::MAX); + + let q = a / b; + let r = a % b; + + case(DivMod128).args(a, b).expect(q).second(r).run(&context) +} + +#[simplex::test] +fn div_mod_128_b_is_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let b_high = rand::thread_rng().gen_range(1..u64::MAX); + let a_high = rand::thread_rng().gen_range(b_high + 1..=u64::MAX); + + let a = ((a_high as u128) << 64) | (rand::thread_rng().gen_range(0..u64::MAX) as u128); + let b = ((b_high as u128) << 64) | (rand::thread_rng().gen_range(0..u64::MAX) as u128); + + let q = a / b; + let r = a % b; + + case(DivMod128).args(a, b).expect(q).second(r).run(&context) +} + +#[simplex::test] +fn div_mod_128_a_equal_b(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u128::MAX); + + case(DivMod128) + .args(a, a) + .expect(1u128) + .second(0u128) + .run(&context) +} + +#[simplex::test] +fn div_mod_128_equal_high_words_max_low_diff(context: simplex::TestContext) -> anyhow::Result<()> { + let high = rand::thread_rng().gen_range(1..=u64::MAX); + + let a = ((high as u128) << 64) | (u64::MAX as u128); + let b = (high as u128) << 64; + + case(DivMod128) + .args(a, b) + .expect(1u128) + .second(u64::MAX as u128) + .run(&context) +} + +#[simplex::test] +fn div_mod_128_eq_high_words_a_less_than_b(context: simplex::TestContext) -> anyhow::Result<()> { + let high = rand::thread_rng().gen_range(1..=u64::MAX); + + let a = (high as u128) << 64; + let b = ((high as u128) << 64) | (u64::MAX as u128); + + case(DivMod128) + .args(a, b) + .expect(0u128) + .second(a) + .run(&context) +} + +#[simplex::test] +fn div_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = rand::thread_rng().gen_range(1..=u128::MAX); + let result = a / b; + + case(Div128).args(a, b).expect(result).run(&context) +} + +#[simplex::test] +fn div_128_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u128::MAX); + let b = 0; + + case(Div128).args(a, b).expect(0).run(&context) +} diff --git a/tests/stdlib/u128/mod.rs b/tests/stdlib/u128/mod.rs new file mode 100644 index 0000000..5af8775 --- /dev/null +++ b/tests/stdlib/u128/mod.rs @@ -0,0 +1,5 @@ +mod bit; +mod comparison; +mod convert; +mod math; +mod mul_div; diff --git a/tests/stdlib/u128/mul_div.rs b/tests/stdlib/u128/mul_div.rs new file mode 100644 index 0000000..90f4315 --- /dev/null +++ b/tests/stdlib/u128/mul_div.rs @@ -0,0 +1,109 @@ +use primitive_types::U256; +use rand::Rng; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::u128::mul_div::MulDivProgram as U128MulDivTestProgram; +use simplicityhl_std::artifacts::tests::u128::mul_div::derived_mul_div::{ + MulDivArguments as U128MulDivTestArguments, MulDivWitness as U128MulDivTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + MulDiv, +} + +fn program() -> U128MulDivTestProgram { + U128MulDivTestProgram::new(&U128MulDivTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U128MulDivTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U128MulDivTestWitness { + function_index: function as u8, + first_arg: 0, + second_arg: 0, + third_arg: 0, + expected: None, + }, + } +} + +impl Case { + /// The three operands, `first_arg`, `second_arg` and `third_arg`. + fn args(mut self, a: u128, b: u128, c: u128) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self.witness.third_arg = c; + self + } + + /// The value the arm should return. `None`, the default, means the arm is + /// expected to produce nothing. + fn expect(mut self, expected: u128) -> Self { + self.witness.expected = Some(expected); + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn mul_div_128_product_is_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u64::MAX) as u128; + let b = rand::thread_rng().gen_range(0..=u64::MAX) as u128; + let c = rand::thread_rng().gen_range(1..=u128::MAX); + + let res = a * b / c; + + case(MulDiv).args(a, b, c).expect(res).run(&context) +} + +#[simplex::test] +fn mul_div_128_intermediate_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u128::MAX); + let b = u128::MAX; + let c = rand::thread_rng().gen_range(a..=u128::MAX); + + let res = U256::from(a) * U256::from(b) / U256::from(c); + + case(MulDiv) + .args(a, b, c) + .expect(res.low_u128()) + .run(&context) +} + +#[simplex::test] +fn mul_div_128_result_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u128::MAX); + let b = u128::MAX; + let c = rand::thread_rng().gen_range(1..a); + + case(MulDiv) + .args(a, b, c) + .expect(0) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn mul_div_128_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u128::MAX); + let b = rand::thread_rng().gen_range(1..=u128::MAX); + let c = 0; + + case(MulDiv).args(a, b, c).expect(0).run(&context) +} diff --git a/tests/stdlib/u16/convert.rs b/tests/stdlib/u16/convert.rs new file mode 100644 index 0000000..036a8a4 --- /dev/null +++ b/tests/stdlib/u16/convert.rs @@ -0,0 +1,154 @@ +use primitive_types::U256; +use rand::Rng; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::u16::convert::ConvertProgram as U16ConvertTestProgram; +use simplicityhl_std::artifacts::tests::u16::convert::derived_convert::{ + ConvertArguments as U16ConvertTestArguments, ConvertWitness as U16ConvertTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + U16ToU32, + U16ToU64, + U16ToU128, + U16ToU256, + SplitU16IntoU8, + SafeU16ToU1, + SafeU16ToU8, +} + +fn program() -> U16ConvertTestProgram { + U16ConvertTestProgram::new(&U16ConvertTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U16ConvertTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U16ConvertTestWitness { + function_index: function as u8, + first_arg: 0, + expected: [0; 32], + }, + } +} + +impl Case { + /// The operand, `first_arg`. + fn arg(mut self, a: u16) -> Self { + self.witness.first_arg = a; + self + } + + /// `expected`: the value the arm should produce. + fn expect(mut self, expected: [u8; 32]) -> Self { + self.witness.expected = expected; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn u16_to_u32(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u16::MAX); + + case(U16ToU32) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u16_to_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u16::MAX); + + case(U16ToU64) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u16_to_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u16::MAX); + + case(U16ToU128) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u16_to_u256(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u16::MAX); + + case(U16ToU256) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn split_u16_into_u8(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u16::MAX); + + case(SplitU16IntoU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u16_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=1); + + case(SafeU16ToU1) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u16_to_u1_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u16::MAX); + + case(SafeU16ToU1) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u16_to_u8(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u8::MAX as u16); + + case(SafeU16ToU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u16_to_u8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(u8::MAX as u16 + 1..=u16::MAX); + + case(SafeU16ToU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} diff --git a/tests/u16_math_test.rs b/tests/stdlib/u16/math.rs similarity index 63% rename from tests/u16_math_test.rs rename to tests/stdlib/u16/math.rs index 07b4c00..a343cfb 100644 --- a/tests/u16_math_test.rs +++ b/tests/stdlib/u16/math.rs @@ -1,10 +1,8 @@ -mod common; +use crate::common::uint::TestUint; -use common::uint::TestUint; - -use simplicityhl_std::artifacts::u16_math_test::U16MathTestProgram; -use simplicityhl_std::artifacts::u16_math_test::derived_u16_math_test::{ - U16MathTestArguments, U16MathTestWitness, +use simplicityhl_std::artifacts::tests::u16::math::MathProgram as U16MathTestProgram; +use simplicityhl_std::artifacts::tests::u16::math::derived_math::{ + MathArguments as U16MathTestArguments, MathWitness as U16MathTestWitness, }; // The only per-width code for the common operations. @@ -32,9 +30,5 @@ impl TestUint for u16 { } } -mod u16_math_tests { - use super::*; - - // Stamps the 22 `#[simplex::test]` entry points for u16. Logic lives in common::uint. - uint_tests!(u16); -} +// Stamps the 22 `#[simplex::test]` entry points for u16. Logic lives in common::uint. +crate::uint_tests!(u16); diff --git a/tests/stdlib/u16/mod.rs b/tests/stdlib/u16/mod.rs new file mode 100644 index 0000000..828ff4c --- /dev/null +++ b/tests/stdlib/u16/mod.rs @@ -0,0 +1,3 @@ +mod convert; +mod math; +mod mul_div; diff --git a/tests/stdlib/u16/mul_div.rs b/tests/stdlib/u16/mul_div.rs new file mode 100644 index 0000000..7fd260a --- /dev/null +++ b/tests/stdlib/u16/mul_div.rs @@ -0,0 +1,104 @@ +use crate::common::core::{Expect, run}; +use rand::Rng; + +use simplicityhl_std::artifacts::tests::u16::mul_div::MulDivProgram as U16MulDivTestProgram; +use simplicityhl_std::artifacts::tests::u16::mul_div::derived_mul_div::{ + MulDivArguments as U16MulDivTestArguments, MulDivWitness as U16MulDivTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + MulDiv, +} + +fn program() -> U16MulDivTestProgram { + U16MulDivTestProgram::new(&U16MulDivTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U16MulDivTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U16MulDivTestWitness { + function_index: function as u8, + first_arg: 0, + second_arg: 0, + third_arg: 0, + expected: None, + }, + } +} + +impl Case { + /// The three operands, `first_arg`, `second_arg` and `third_arg`. + fn args(mut self, a: u16, b: u16, c: u16) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self.witness.third_arg = c; + self + } + + /// The value the arm should return. `None`, the default, means the arm is + /// expected to produce nothing. + fn expect(mut self, expected: u16) -> Self { + self.witness.expected = Some(expected); + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn mul_div_16_product_is_u16(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u8::MAX) as u16; + let b = rand::thread_rng().gen_range(0..=u8::MAX) as u16; + let c = rand::thread_rng().gen_range(1..=u16::MAX); + + let res = a * b / c; + + case(MulDiv).args(a, b, c).expect(res).run(&context) +} + +#[simplex::test] +fn mul_div_16_intermediate_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u16::MAX); + let b = u16::MAX; + let c = rand::thread_rng().gen_range(a..=u16::MAX); + + let res = (a as u32) * (b as u32) / (c as u32); + + case(MulDiv).args(a, b, c).expect(res as u16).run(&context) +} + +#[simplex::test] +fn mul_div_16_result_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u16::MAX); + let b = u16::MAX; + let c = rand::thread_rng().gen_range(1..a); + + case(MulDiv) + .args(a, b, c) + .expect(0) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn mul_div_16_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u16::MAX); + let b = rand::thread_rng().gen_range(1..=u16::MAX); + let c = 0; + + case(MulDiv).args(a, b, c).expect(0).run(&context) +} diff --git a/tests/stdlib/u256/bit.rs b/tests/stdlib/u256/bit.rs new file mode 100644 index 0000000..0d0db36 --- /dev/null +++ b/tests/stdlib/u256/bit.rs @@ -0,0 +1,161 @@ +use primitive_types::U256; +use rand::Rng; + +use crate::common::core::{Expect, run}; +use crate::common::helper::generate_u256; + +use simplicityhl_std::artifacts::tests::u256::bit::BitProgram as U256TestBitsProgram; +use simplicityhl_std::artifacts::tests::u256::bit::derived_bit::{ + BitArguments as U256TestBitsArguments, BitWitness as U256TestBitsWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + And256, + Or256, + LeftShift256, + RightShift256, +} + +fn program() -> U256TestBitsProgram { + U256TestBitsProgram::new(&U256TestBitsArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U256TestBitsWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U256TestBitsWitness { + function_index: function as u8, + first_arg: [0; 32], + second_arg: [0; 32], + expected: None, + }, + } +} + +impl Case { + /// The two operands, `first_arg` and `second_arg`. + fn args(mut self, a: [u8; 32], b: [u8; 32]) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self + } + + /// The value the arm should return. `None`, the default, means the arm is + /// expected to produce nothing. + fn expect(mut self, expected: [u8; 32]) -> Self { + self.witness.expected = Some(expected); + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn and_256(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = generate_u256(U256::zero(), U256::MAX); + let result = (a & b).to_big_endian(); + + case(And256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn or_256(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = generate_u256(U256::zero(), U256::MAX); + let result = (a | b).to_big_endian(); + + case(Or256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn left_shift_256(context: simplex::TestContext) -> anyhow::Result<()> { + let shift = rand::thread_rng().gen_range(1..u8::MAX); + let val = generate_u256(U256::zero(), U256::MAX); + let result = (val << shift).to_big_endian(); + + case(LeftShift256) + .args(U256::from(shift).to_big_endian(), val.to_big_endian()) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn left_shift_256_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let shift = 0; + let val = generate_u256(U256::zero(), U256::MAX).to_big_endian(); + let result = val; + + case(LeftShift256) + .args(U256::from(shift).to_big_endian(), val) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn left_shift_256_max(context: simplex::TestContext) -> anyhow::Result<()> { + let shift = u8::MAX; + let val = generate_u256(U256::zero(), U256::MAX); + let result = (val << shift).to_big_endian(); + + case(LeftShift256) + .args(U256::from(shift).to_big_endian(), val.to_big_endian()) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn right_shift_256(context: simplex::TestContext) -> anyhow::Result<()> { + let shift = rand::thread_rng().gen_range(1..u8::MAX); + let val = generate_u256(U256::zero(), U256::MAX); + let result = (val >> shift).to_big_endian(); + + case(RightShift256) + .args(U256::from(shift).to_big_endian(), val.to_big_endian()) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn right_shift_256_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let shift = 0; + let val = generate_u256(U256::zero(), U256::MAX).to_big_endian(); + let result = val; + + case(RightShift256) + .args(U256::from(shift).to_big_endian(), val) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn right_shift_256_max(context: simplex::TestContext) -> anyhow::Result<()> { + let shift = u8::MAX; + let val = generate_u256(U256::zero(), U256::MAX); + let result = (val >> shift).to_big_endian(); + + case(RightShift256) + .args(U256::from(shift).to_big_endian(), val.to_big_endian()) + .expect(result) + .run(&context) +} diff --git a/tests/stdlib/u256/comparison.rs b/tests/stdlib/u256/comparison.rs new file mode 100644 index 0000000..27bdbb5 --- /dev/null +++ b/tests/stdlib/u256/comparison.rs @@ -0,0 +1,138 @@ +use primitive_types::U256; + +use crate::common::core::{Expect, run}; +use crate::common::helper::generate_u256; + +use simplicityhl_std::artifacts::tests::u256::comparison::ComparisonProgram as U256TestCompareProgram; +use simplicityhl_std::artifacts::tests::u256::comparison::derived_comparison::{ + ComparisonArguments as U256TestCompareArguments, ComparisonWitness as U256TestCompareWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + IsZero256, + Lt256, + Le256, +} + +fn program() -> U256TestCompareProgram { + U256TestCompareProgram::new(&U256TestCompareArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U256TestCompareWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U256TestCompareWitness { + function_index: function as u8, + first_arg: [0; 32], + second_arg: [0; 32], + expected_bool: false, + }, + } +} + +impl Case { + /// Only `first_arg`, for the arms that ignore the second operand. + fn arg(mut self, a: [u8; 32]) -> Self { + self.witness.first_arg = a; + self + } + + /// The two operands, `first_arg` and `second_arg`. + fn args(mut self, a: [u8; 32], b: [u8; 32]) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self + } + + /// `expected_bool`: the boolean the arm should report. + fn flag(mut self, expected_bool: bool) -> Self { + self.witness.expected_bool = expected_bool; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn is_zero_256_true(context: simplex::TestContext) -> anyhow::Result<()> { + let a = [0; 32]; + + case(IsZero256).arg(a).flag(true).run(&context) +} + +#[simplex::test] +fn is_zero_256_false(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::one(), U256::MAX).to_big_endian(); + + case(IsZero256).arg(a).run(&context) +} + +#[simplex::test] +fn lt_256_less(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX - 1); + let b = a + 1; + + case(Lt256) + .args(a.to_big_endian(), b.to_big_endian()) + .flag(true) + .run(&context) +} + +#[simplex::test] +fn lt_256_eq(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX).to_big_endian(); + + case(Lt256).args(a, a).run(&context) +} + +#[simplex::test] +fn lt_256_bigger(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::one(), U256::MAX); + let b = a - 1; + + case(Lt256) + .args(a.to_big_endian(), b.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn le_256_less(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX - 1); + let b = a + 1; + + case(Le256) + .args(a.to_big_endian(), b.to_big_endian()) + .flag(true) + .run(&context) +} + +#[simplex::test] +fn le_256_eq(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::one(), U256::MAX).to_big_endian(); + + case(Le256).args(a, a).flag(true).run(&context) +} + +#[simplex::test] +fn le_256_bigger(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::one(), U256::MAX); + let b = a - 1; + + case(Le256) + .args(a.to_big_endian(), b.to_big_endian()) + .run(&context) +} diff --git a/tests/stdlib/u256/convert.rs b/tests/stdlib/u256/convert.rs new file mode 100644 index 0000000..2bd68cb --- /dev/null +++ b/tests/stdlib/u256/convert.rs @@ -0,0 +1,239 @@ +use primitive_types::U256; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::u256::convert::ConvertProgram as U256ConvertTestProgram; +use simplicityhl_std::artifacts::tests::u256::convert::derived_convert::{ + ConvertArguments as U256ConvertTestArguments, ConvertWitness as U256ConvertTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + SplitU256IntoU8, + SplitU256IntoU16, + SplitU256IntoU32, + SplitU256IntoU64, + SplitU256IntoU128, + SafeU256ToU1, + SafeU256ToU8, + SafeU256ToU16, + SafeU256ToU32, + SafeU256ToU64, + SafeU256ToU128, +} + +fn program() -> U256ConvertTestProgram { + U256ConvertTestProgram::new(&U256ConvertTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U256ConvertTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U256ConvertTestWitness { + function_index: function as u8, + first_arg: [0; 32], + expected: [0; 32], + }, + } +} + +impl Case { + /// The operand, `first_arg`. + fn arg(mut self, a: [u8; 32]) -> Self { + self.witness.first_arg = a; + self + } + + /// `expected`: the value the arm should produce. + fn expect(mut self, expected: [u8; 32]) -> Self { + self.witness.expected = expected; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +use crate::common::helper::generate_u256; + +#[simplex::test] +fn u256_into_u8(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + + case(SplitU256IntoU8) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u256_into_u16(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + + case(SplitU256IntoU16) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u256_into_u32(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + + case(SplitU256IntoU32) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u256_into_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + + case(SplitU256IntoU64) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u256_into_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + + case(SplitU256IntoU128) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u256_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::one()); + + case(SafeU256ToU1) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u256_to_u1_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::from(2), U256::MAX); + + case(SafeU256ToU1) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u256_to_u8(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::from(u8::MAX)); + + case(SafeU256ToU8) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u256_to_u8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::from(u8::MAX) + 1, U256::MAX); + + case(SafeU256ToU8) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u256_to_u16(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::from(u16::MAX)); + + case(SafeU256ToU16) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u256_to_u16_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::from(u16::MAX) + 1, U256::MAX); + + case(SafeU256ToU16) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u256_to_u32(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::from(u32::MAX)); + + case(SafeU256ToU32) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u256_to_u32_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::from(u32::MAX) + 1, U256::MAX); + + case(SafeU256ToU32) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u256_to_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::from(u64::MAX)); + + case(SafeU256ToU64) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u256_to_u64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::from(u64::MAX) + 1, U256::MAX); + + case(SafeU256ToU64) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u256_to_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::from(u128::MAX)); + + case(SafeU256ToU128) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u256_to_u128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); + + case(SafeU256ToU128) + .arg(a.to_big_endian()) + .expect(a.to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} diff --git a/tests/stdlib/u256/math/add.rs b/tests/stdlib/u256/math/add.rs new file mode 100644 index 0000000..bbd813c --- /dev/null +++ b/tests/stdlib/u256/math/add.rs @@ -0,0 +1,195 @@ +use primitive_types::U256; + +use crate::common::core::{Expect, run}; +use crate::common::helper::generate_u256; + +use simplicityhl_std::artifacts::tests::u256::math::add::AddProgram as U256TestAddProgram; +use simplicityhl_std::artifacts::tests::u256::math::add::derived_add::{ + AddArguments as U256TestAddArguments, AddWitness as U256TestAddWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + Add256, + Add256_128, + FullAdd256, +} + +fn program() -> U256TestAddProgram { + U256TestAddProgram::new(&U256TestAddArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U256TestAddWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U256TestAddWitness { + function_index: function as u8, + first_arg: [0; 32], + second_arg: [0; 32], + third_arg: false, + expected: None, + expected_bool: false, + }, + } +} + +impl Case { + /// The two operands, `first_arg` and `second_arg`. + fn args(mut self, a: [u8; 32], b: [u8; 32]) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self + } + + /// `third_arg`: the extra operand only some arms take. + fn third_arg(mut self, c: bool) -> Self { + self.witness.third_arg = c; + self + } + + /// The value the arm should return. `None`, the default, means the arm is + /// expected to produce nothing. + fn expect(mut self, expected: [u8; 32]) -> Self { + self.witness.expected = Some(expected); + self + } + + /// `expected_bool`: the boolean the arm should report. + fn flag(mut self, expected_bool: bool) -> Self { + self.witness.expected_bool = expected_bool; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn add_256_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX / 2); + let b = generate_u256(U256::zero(), U256::MAX / 2); + let result = (a + b).to_big_endian(); + + case(Add256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn add_256_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = U256::MAX; + let b = generate_u256(U256::one(), U256::MAX); + let result = (b - 1).to_big_endian(); + + case(Add256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result) + .flag(true) + .run(&context) +} + +#[simplex::test] +fn add_256_128_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX / 2); + let b = generate_u256(U256::one(), U256::from(u128::MAX)); + let result = (a + b).to_big_endian(); + + case(Add256_128) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn add_256_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = U256::MAX; + let b = generate_u256(U256::one(), U256::from(u128::MAX)); + let result = (b - 1).to_big_endian(); + + case(Add256_128) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result) + .flag(true) + .run(&context) +} + +#[simplex::test] +fn full_add_256_not_overflow_carry_low_false(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX / 2); + let b = generate_u256(U256::zero(), U256::MAX / 2); + + let result = (a + b).to_big_endian(); + let result_carry = false; + let carry_low = false; + + case(FullAdd256) + .args(a.to_big_endian(), b.to_big_endian()) + .third_arg(carry_low) + .expect(result) + .flag(result_carry) + .run(&context) +} + +#[simplex::test] +fn full_add_256_overflow_carry_low_false(context: simplex::TestContext) -> anyhow::Result<()> { + let a = U256::MAX; + let b = generate_u256(U256::one(), U256::MAX); + + let result = (b - 1).to_big_endian(); + let result_carry = true; + let carry_low = false; + + case(FullAdd256) + .args(a.to_big_endian(), b.to_big_endian()) + .third_arg(carry_low) + .expect(result) + .flag(result_carry) + .run(&context) +} + +#[simplex::test] +fn full_add_256_not_overflow_carry_low_true(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX / 2); + let b = generate_u256(U256::zero(), U256::MAX / 2); + + let result = (a + b + 1).to_big_endian(); + let result_carry = false; + let carry_low = true; + + case(FullAdd256) + .args(a.to_big_endian(), b.to_big_endian()) + .third_arg(carry_low) + .expect(result) + .flag(result_carry) + .run(&context) +} + +#[simplex::test] +fn full_add_256_overflow_carry_low_true(context: simplex::TestContext) -> anyhow::Result<()> { + let a = U256::MAX; + let b = generate_u256(U256::one(), U256::MAX).to_big_endian(); + + let result = b; + let result_carry = true; + let carry_low = true; + + case(FullAdd256) + .args(a.to_big_endian(), b) + .third_arg(carry_low) + .expect(result) + .flag(result_carry) + .run(&context) +} diff --git a/tests/u256_math_test.rs b/tests/stdlib/u256/math/api.rs similarity index 69% rename from tests/u256_math_test.rs rename to tests/stdlib/u256/math/api.rs index 67ebc4a..3964165 100644 --- a/tests/u256_math_test.rs +++ b/tests/stdlib/u256/math/api.rs @@ -1,13 +1,11 @@ -mod common; - use primitive_types::U256; -use common::u256_wrapper::U256Wrapper; -use common::uint::TestUint; +use crate::common::u256_wrapper::U256Wrapper; +use crate::common::uint::TestUint; -use simplicityhl_std::artifacts::u256_math_test::U256MathTestProgram; -use simplicityhl_std::artifacts::u256_math_test::derived_u256_math_test::{ - U256MathTestArguments, U256MathTestWitness, +use simplicityhl_std::artifacts::tests::u256::math::api::ApiProgram as U256MathTestProgram; +use simplicityhl_std::artifacts::tests::u256::math::api::derived_api::{ + ApiArguments as U256MathTestArguments, ApiWitness as U256MathTestWitness, }; // The only per-width code for the common operations. @@ -40,9 +38,5 @@ impl TestUint for U256Wrapper { } } -mod u256_math_tests { - use super::*; - - // Stamps the 22 `#[simplex::test]` entry points for U256Wrapper. Logic lives in common::uint. - uint_tests!(U256Wrapper); -} +// Stamps the 22 `#[simplex::test]` entry points for U256Wrapper. Logic lives in common::uint. +crate::uint_tests!(U256Wrapper); diff --git a/tests/stdlib/u256/math/div.rs b/tests/stdlib/u256/math/div.rs new file mode 100644 index 0000000..8fb84db --- /dev/null +++ b/tests/stdlib/u256/math/div.rs @@ -0,0 +1,453 @@ +use primitive_types::U256; + +use crate::common::core::{Expect, run}; +use crate::common::helper::generate_u256; + +use simplicityhl_std::artifacts::tests::u256::math::div::DivProgram as U256TestDivProgram; +use simplicityhl_std::artifacts::tests::u256::math::div::derived_div::{ + DivArguments as U256TestDivArguments, DivWitness as U256TestDivWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + CalculateNormalizerBase128, + DivMod256_64, + AlgorithmD256_128, + DivMod256_128, + DivMod256, + Div256, +} + +fn program() -> U256TestDivProgram { + U256TestDivProgram::new(&U256TestDivArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U256TestDivWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U256TestDivWitness { + function_index: function as u8, + first_arg: [0; 32], + second_arg: [0; 32], + expected: None, + second_expected: [0; 32], + }, + } +} + +impl Case { + /// Only `first_arg`, for the arms that ignore the second operand. + fn arg(mut self, a: [u8; 32]) -> Self { + self.witness.first_arg = a; + self + } + + /// The two operands, `first_arg` and `second_arg`. + fn args(mut self, a: [u8; 32], b: [u8; 32]) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self + } + + /// The value the arm should return. `None`, the default, means the arm is + /// expected to produce nothing. + fn expect(mut self, expected: [u8; 32]) -> Self { + self.witness.expected = Some(expected); + self + } + + /// `second_expected`: the arm's second result. + fn second(mut self, second_expected: [u8; 32]) -> Self { + self.witness.second_expected = second_expected; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn calculate_normalizer_base_128(context: simplex::TestContext) -> anyhow::Result<()> { + let threshold = 1u128 << 127; + + let a = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); + let a_high = (a >> 128).as_u128(); + + let norm = threshold.div_ceil(a_high); + + case(CalculateNormalizerBase128) + .arg(a.to_big_endian()) + .expect(U256::from(norm).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn calculate_normalizer_base_128_norm_is_1(context: simplex::TestContext) -> anyhow::Result<()> { + let threshold = 1u128 << 127; + + // a >= 2^255 keeps a_high >= 2^127, so the divisor is already normalized + let a = generate_u256(U256::from(2).pow(U256::from(255)), U256::MAX); + let a_high = (a >> 128).as_u128(); + + let norm = threshold.div_ceil(a_high); + assert_eq!(norm, 1); + + case(CalculateNormalizerBase128) + .arg(a.to_big_endian()) + .expect(U256::from(norm).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn calculate_normalizer_base_128_norm_greater_than_1( + context: simplex::TestContext, +) -> anyhow::Result<()> { + let threshold = 1u128 << 127; + + // a < 2^255 keeps a_high < 2^127, so the divisor has to be scaled up + let a = generate_u256( + U256::from(u128::MAX) + 1, + U256::from(2).pow(U256::from(255)) - 1, + ); + let a_high = (a >> 128).as_u128(); + + let norm = threshold.div_ceil(a_high); + assert!(norm > 1); + + case(CalculateNormalizerBase128) + .arg(a.to_big_endian()) + .expect(U256::from(norm).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn calculate_normalizer_base_128_a_is_u128_fail( + context: simplex::TestContext, +) -> anyhow::Result<()> { + let threshold = 1u128 << 127; + + let a = generate_u256(U256::one(), U256::from(threshold) - 1); + + let norm: u128 = threshold.div_ceil(a.low_u128()); + + case(CalculateNormalizerBase128) + .arg(a.to_big_endian()) + .expect(U256::from(norm).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn calculate_normalizer_base_128_b_is_zero_fail( + context: simplex::TestContext, +) -> anyhow::Result<()> { + let a = [0; 32]; + + case(CalculateNormalizerBase128) + .arg(a) + .expect([0; 32]) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn div_mod_256_64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = generate_u256(U256::one(), U256::from(u64::MAX)); + + let q = (a / b).to_big_endian(); + let r = (a % b).to_big_endian(); + + case(DivMod256_64) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = [0; 32]; + + case(DivMod256_64) + .args(a.to_big_endian(), b) + .expect([0; 32]) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn algorithm_d_256_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = generate_u256(U256::from(u64::MAX) + 1, U256::from(u128::MAX)); + + let q = (a / b).to_big_endian(); + let r = (a % b).to_big_endian(); + + case(AlgorithmD256_128) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn algorithm_d_256_128_fail_b_fits_into_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = generate_u256(U256::one(), U256::from(u64::MAX)); + + let q = (a / b).to_big_endian(); + let r = (a % b).to_big_endian(); + + case(AlgorithmD256_128) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(q) + .second(r) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn algorithm_d_256_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = [0; 32]; + + case(AlgorithmD256_128) + .args(a.to_big_endian(), b) + .expect([0; 32]) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn algorithm_d_256_128_a_eq_b(context: simplex::TestContext) -> anyhow::Result<()> { + let a = (generate_u256(U256::one(), U256::from(u128::MAX))).to_big_endian(); + + let q = U256::one().to_big_endian(); + let r = U256::zero().to_big_endian(); + + case(AlgorithmD256_128) + .args(a, a) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = generate_u256(U256::from(u64::MAX) + 1, U256::from(u128::MAX)); + + let q = (a / b).to_big_endian(); + let r = (a % b).to_big_endian(); + + case(DivMod256_128) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_128_b_fits_into_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = generate_u256(U256::one(), U256::from(u64::MAX)); + + let q = (a / b).to_big_endian(); + let r = (a % b).to_big_endian(); + + case(DivMod256_128) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = [0; 32]; + + case(DivMod256_128) + .args(a.to_big_endian(), b) + .expect([0; 32]) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn div_mod_256_128_a_eq_b(context: simplex::TestContext) -> anyhow::Result<()> { + let a = (generate_u256(U256::one(), U256::from(u128::MAX))).to_big_endian(); + + let q = U256::one().to_big_endian(); + let r = U256::zero().to_big_endian(); + + case(DivMod256_128) + .args(a, a) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_a_less_than_b(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::one(), U256::MAX - 1); + let b = generate_u256(a + 1, U256::MAX); + + let q = (a / b).to_big_endian(); + let r = (a % b).to_big_endian(); + + case(DivMod256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_div_128(context: simplex::TestContext) -> anyhow::Result<()> { + let b = generate_u256(U256::one(), U256::from(u128::MAX)); + let a = generate_u256(b, U256::from(u128::MAX)); + + let q = (a / b).to_big_endian(); + let r = (a % b).to_big_endian(); + + case(DivMod256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_q_is_1(context: simplex::TestContext) -> anyhow::Result<()> { + // case where a >= b and a_high = b_high != 0 + let b_low = generate_u256(U256::zero(), U256::from(u128::MAX)); + let a_low = generate_u256(b_low, U256::from(u128::MAX)); + let high = generate_u256(U256::one(), U256::from(u128::MAX)); + + let a = (high << 128) | (a_low); + let b = (high << 128) | (b_low); + + let q = (a / b).to_big_endian(); + let r = (a % b).to_big_endian(); + + case(DivMod256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_b_fits_into_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let b = generate_u256(U256::one(), U256::from(u128::MAX)); + let a = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); + + let q = (a / b).to_big_endian(); + let r = (a % b).to_big_endian(); + + case(DivMod256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_b_is_u256(context: simplex::TestContext) -> anyhow::Result<()> { + let b = generate_u256(U256::one(), U256::MAX - 1); + let a = generate_u256(b + 1, U256::MAX); + + let q = (a / b).to_big_endian(); + let r = (a % b).to_big_endian(); + + case(DivMod256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(q) + .second(r) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_a_equal_b(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::one(), U256::MAX).to_big_endian(); + + case(DivMod256) + .args(a, a) + .expect(U256::one().to_big_endian()) + .second([0; 32]) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_equal_high_words_max_low_diff(context: simplex::TestContext) -> anyhow::Result<()> { + let high = generate_u256(U256::one(), U256::from(u128::MAX)); + + let a = ((high << 128) | (U256::from(u128::MAX))).to_big_endian(); + let b = (high << 128).to_big_endian(); + + case(DivMod256) + .args(a, b) + .expect(U256::one().to_big_endian()) + .second(U256::from(u128::MAX).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_eq_high_words_a_less_than_b(context: simplex::TestContext) -> anyhow::Result<()> { + let high = generate_u256(U256::one(), U256::from(u128::MAX)); + + let a = (high << 128).to_big_endian(); + let b = ((high << 128) | (U256::from(u128::MAX))).to_big_endian(); + + case(DivMod256) + .args(a, b) + .expect([0; 32]) + .second(a) + .run(&context) +} + +#[simplex::test] +fn div_mod_256_edge_case(context: simplex::TestContext) -> anyhow::Result<()> { + let a: U256 = U256::from(2).pow(U256::from(255)); + let b = U256::from(2).pow(U256::from(127)) + U256::from(2).pow(U256::from(64)) - 1; + + let (q, r) = a.div_mod(b); + + case(DivMod256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(q.to_big_endian()) + .second(r.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn div_256(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = generate_u256(U256::one(), U256::MAX); + let result = (a / b).to_big_endian(); + + case(Div256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn div_256_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = [0; 32]; + + case(Div256) + .args(a.to_big_endian(), b) + .expect([0; 32]) + .run(&context) +} diff --git a/tests/stdlib/u256/math/mod.rs b/tests/stdlib/u256/math/mod.rs new file mode 100644 index 0000000..297b0a0 --- /dev/null +++ b/tests/stdlib/u256/math/mod.rs @@ -0,0 +1,4 @@ +mod add; +mod api; +mod div; +mod sub_mul; diff --git a/tests/stdlib/u256/math/sub_mul.rs b/tests/stdlib/u256/math/sub_mul.rs new file mode 100644 index 0000000..2d5a64d --- /dev/null +++ b/tests/stdlib/u256/math/sub_mul.rs @@ -0,0 +1,276 @@ +use primitive_types::U256; +use primitive_types::U512; +use rand::Rng; + +use crate::common::core::{Expect, run}; +use crate::common::helper::generate_u256; + +use simplicityhl_std::artifacts::tests::u256::math::sub_mul::SubMulProgram as U256TestSubMulProgram; +use simplicityhl_std::artifacts::tests::u256::math::sub_mul::derived_sub_mul::{ + SubMulArguments as U256TestSubMulArguments, SubMulWitness as U256TestSubMulWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + Sub256, + Mul256, + Mul256_64, + Mul256_128, + Mul512_128, + SafeMul256_128, +} + +fn program() -> U256TestSubMulProgram { + U256TestSubMulProgram::new(&U256TestSubMulArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U256TestSubMulWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U256TestSubMulWitness { + function_index: function as u8, + first_arg: [0; 32], + second_arg: [0; 32], + third_arg: 0, + expected: None, + expected_bool: false, + second_expected: [0; 32], + third_expected: [0; 32], + }, + } +} + +impl Case { + /// The two operands, `first_arg` and `second_arg`. + fn args(mut self, a: [u8; 32], b: [u8; 32]) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self + } + + /// `third_arg`: the extra operand only some arms take. + fn third_arg(mut self, c: u128) -> Self { + self.witness.third_arg = c; + self + } + + /// The value the arm should return. `None`, the default, means the arm is + /// expected to produce nothing. + fn expect(mut self, expected: [u8; 32]) -> Self { + self.witness.expected = Some(expected); + self + } + + /// `expected_bool`: the boolean the arm should report. + fn flag(mut self, expected_bool: bool) -> Self { + self.witness.expected_bool = expected_bool; + self + } + + /// `second_expected`: the arm's second result. + fn second(mut self, second_expected: [u8; 32]) -> Self { + self.witness.second_expected = second_expected; + self + } + + /// `third_expected`: the arm's third result. + fn third(mut self, third_expected: [u8; 32]) -> Self { + self.witness.third_expected = third_expected; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +fn split_u512(a: [u8; 64]) -> ([u8; 32], [u8; 32]) { + let high = U256::from_big_endian(&a[0..32]); + let low = U256::from_big_endian(&a[32..64]); + + (high.to_big_endian(), low.to_big_endian()) +} + +#[simplex::test] +fn sub_256_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b = generate_u256(U256::zero(), a); + let result = (a - b).to_big_endian(); + + case(Sub256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result) + .run(&context) +} + +#[simplex::test] +fn sub_256_a_eq_b(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX).to_big_endian(); + + case(Sub256).args(a, a).expect([0; 32]).run(&context) +} + +#[simplex::test] +fn sub_256_a_low_eq_b_low(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::MAX); + let b_high = rand::thread_rng().gen_range(0..=u128::MAX); + + let low: u128 = a.low_u128(); + let b = (U256::from(b_high) << 128) | U256::from(low); + + let (result, carry) = a.overflowing_sub(b); + + case(Sub256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result.to_big_endian()) + .flag(carry) + .run(&context) +} + +#[simplex::test] +fn sub_256_diff_is_u128_max(context: simplex::TestContext) -> anyhow::Result<()> { + let a_low: u128 = u128::MAX; + + let a_high = rand::thread_rng().gen_range(0..=u128::MAX); + let b_high = rand::thread_rng().gen_range(0..=u128::MAX); + + let a = (U256::from(a_high) << 128) | U256::from(a_low); + let b = (U256::from(b_high)) << 128; // b_low is 0 + + let (result, carry) = a.overflowing_sub(b); + + case(Sub256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result.to_big_endian()) + .flag(carry) + .run(&context) +} + +#[simplex::test] +fn sub_256_diff_is_u256_max(context: simplex::TestContext) -> anyhow::Result<()> { + let a = U256::MAX.to_big_endian(); + let b = U256::zero(); + + case(Sub256) + .args(a, b.to_big_endian()) + .expect(a) + .run(&context) +} + +#[simplex::test] +fn sub_256_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::one(), U256::MAX - 1); + let b = U256::MAX; + let result = a + 1; + + case(Sub256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result.to_big_endian()) + .flag(true) + .run(&context) +} + +#[simplex::test] +fn mul_256(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::one(), U256::MAX); + let b = generate_u256(U256::one(), U256::MAX); + let result = a.full_mul(b).to_big_endian(); + + let (result_high, result_low) = split_u512(result); + + case(Mul256) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result_high) + .second(result_low) + .run(&context) +} + +#[simplex::test] +fn mul_256_64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::one(), U256::MAX); + let b = generate_u256(U256::one(), U256::from(u64::MAX)); + let result = a.full_mul(b).to_big_endian(); + + let (result_high, result_low) = split_u512(result); + + case(Mul256_64) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result_high) + .second(result_low) + .run(&context) +} + +#[simplex::test] +fn mul_256_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::one(), U256::MAX); + let b = generate_u256(U256::one(), U256::from(u128::MAX)); + let result = a.full_mul(b).to_big_endian(); + + let (result_high, result_low) = split_u512(result); + + case(Mul256_128) + .args(a.to_big_endian(), b.to_big_endian()) + .expect(result_high) + .second(result_low) + .run(&context) +} + +#[simplex::test] +fn mul_512_128(context: simplex::TestContext) -> anyhow::Result<()> { + let a_1 = generate_u256(U256::one(), U256::MAX); + let a_0 = generate_u256(U256::one(), U256::MAX); + let b = rand::thread_rng().gen_range(1..=u128::MAX); + + let result_low = U512::from(a_0) * U512::from(b); + let result_high = U512::from(a_1) * U512::from(b); + + let (res_1, res_0) = split_u512(result_low.to_big_endian()); + let (res_3, res_2) = split_u512(result_high.to_big_endian()); + + let res_2_1 = U512::from_big_endian(&res_1) + U512::from_big_endian(&res_2); + let (res_3_1, res_2_1) = split_u512(res_2_1.to_big_endian()); + + let res_3_final = + (U256::from_big_endian(&res_3_1) + U256::from_big_endian(&res_3)).to_big_endian(); + + case(Mul512_128) + .args(a_1.to_big_endian(), a_0.to_big_endian()) + .third_arg(b) + .expect(res_3_final) + .second(res_2_1) + .third(res_0) + .run(&context) +} + +#[simplex::test] +fn safe_mul_256_128_fitting(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::from(u128::MAX)); + let b = generate_u256(U256::zero(), U256::from(u128::MAX)); + + case(SafeMul256_128) + .args(a.to_big_endian(), b.to_big_endian()) + .expect((a * b).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_mul_256_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); + let b = U256::from(u128::MAX); + + case(SafeMul256_128) + .args(a.to_big_endian(), b.to_big_endian()) + .expect([0; 32]) + .expecting(&context, Expect::AssertFailed) +} diff --git a/tests/stdlib/u256/mod.rs b/tests/stdlib/u256/mod.rs new file mode 100644 index 0000000..5af8775 --- /dev/null +++ b/tests/stdlib/u256/mod.rs @@ -0,0 +1,5 @@ +mod bit; +mod comparison; +mod convert; +mod math; +mod mul_div; diff --git a/tests/stdlib/u256/mul_div.rs b/tests/stdlib/u256/mul_div.rs new file mode 100644 index 0000000..afd5123 --- /dev/null +++ b/tests/stdlib/u256/mul_div.rs @@ -0,0 +1,262 @@ +use primitive_types::U256; +use std::cmp::max; +use std::ops::Div; + +use crate::common::core::{Expect, run}; +use crate::common::helper::generate_u256; + +use simplicityhl_std::artifacts::tests::u256::mul_div::MulDivProgram as U256MulDivTestProgram; +use simplicityhl_std::artifacts::tests::u256::mul_div::derived_mul_div::{ + MulDivArguments as U256MulDivTestArguments, MulDivWitness as U256MulDivTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + MulDiv, +} + +fn program() -> U256MulDivTestProgram { + U256MulDivTestProgram::new(&U256MulDivTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U256MulDivTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U256MulDivTestWitness { + function_index: function as u8, + first_arg: [0; 32], + second_arg: [0; 32], + third_arg: [0; 32], + expected: None, + }, + } +} + +impl Case { + /// The three operands, `first_arg`, `second_arg` and `third_arg`. + fn args(mut self, a: [u8; 32], b: [u8; 32], c: [u8; 32]) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self.witness.third_arg = c; + self + } + + /// The value the arm should return. `None`, the default, means the arm is + /// expected to produce nothing. + fn expect(mut self, expected: [u8; 32]) -> Self { + self.witness.expected = Some(expected); + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +fn safe_u512_to_u256(a: [u8; 64]) -> [u8; 32] { + let high = U256::from_big_endian(&a[0..32]); + let low = U256::from_big_endian(&a[32..64]); + + assert!(high == U256::zero()); + + low.to_big_endian() +} + +#[simplex::test] +fn mul_div_256_product_fits_into_u256(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::zero(), U256::from(u128::MAX)); + let b = generate_u256(U256::zero(), U256::from(u128::MAX)); + let c = generate_u256(U256::one(), U256::MAX); + + let res = safe_u512_to_u256(a.full_mul(b).div(c).to_big_endian()); + + case(MulDiv) + .args(a.to_big_endian(), b.to_big_endian(), c.to_big_endian()) + .expect(res) + .run(&context) +} + +#[simplex::test] +fn mul_div_256_intermediate_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::from(2), U256::MAX); + let b = U256::MAX; + let c = generate_u256(a, U256::MAX); + + let res = safe_u512_to_u256(a.full_mul(b).div(c).to_big_endian()); + + case(MulDiv) + .args(a.to_big_endian(), b.to_big_endian(), c.to_big_endian()) + .expect(res) + .run(&context) +} + +#[simplex::test] +fn mul_div_256_result_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::from(2), U256::MAX); + let b = U256::MAX; + let c = generate_u256(U256::one(), a); + + case(MulDiv) + .args(a.to_big_endian(), b.to_big_endian(), c.to_big_endian()) + .expect([0; 32]) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn mul_div_256_remainder_is_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); + let b = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); + let c = a; + + case(MulDiv) + .args(a.to_big_endian(), b.to_big_endian(), c.to_big_endian()) + .expect(b.to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn mul_div_256_denominator_is_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::one(), U256::MAX); + let b = generate_u256(U256::one(), U256::from(u128::MAX)); + let c = generate_u256(b, U256::from(u128::MAX)); + + let res = safe_u512_to_u256(a.full_mul(b).div(c).to_big_endian()); + + case(MulDiv) + .args(a.to_big_endian(), b.to_big_endian(), c.to_big_endian()) + .expect(res) + .run(&context) +} + +#[simplex::test] +fn mul_div_256_min_denom_high(context: simplex::TestContext) -> anyhow::Result<()> { + let pow129: U256 = U256::from(2).pow(U256::from(129)); + + let a = generate_u256(U256::from(u128::MAX) + 1, pow129); + let b = generate_u256(U256::from(u128::MAX) + 1, pow129); + let c = generate_u256(U256::from(u128::MAX) + 1, pow129 - 1); + + let res = safe_u512_to_u256(a.full_mul(b).div(c).to_big_endian()); + + case(MulDiv) + .args(a.to_big_endian(), b.to_big_endian(), c.to_big_endian()) + .expect(res) + .run(&context) +} + +#[simplex::test] +fn mul_div_256_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let a = generate_u256(U256::one(), U256::MAX); + let b = generate_u256(U256::one(), U256::MAX); + let c = U256::zero(); + + case(MulDiv) + .args(a.to_big_endian(), b.to_big_endian(), c.to_big_endian()) + .expect([0; 32]) + .run(&context) +} + +#[simplex::test] +fn mul_div_256_algorithm_d_512_256_check(context: simplex::TestContext) -> anyhow::Result<()> { + let pow2_128: U256 = U256::from(u128::MAX) + 1; + + let a = generate_u256(pow2_128, U256::MAX); + let b = generate_u256(pow2_128, U256::MAX - pow2_128); + + let product = a.full_mul(b); + let result_high = U256::from_big_endian(&(safe_u512_to_u256((product >> 256).to_big_endian()))); + + let c = generate_u256(max(U256::from(u128::MAX) + 1, result_high + 1), U256::MAX); + + let res = safe_u512_to_u256(product.div(c).to_big_endian()); + + case(MulDiv) + .args(a.to_big_endian(), b.to_big_endian(), c.to_big_endian()) + .expect(res) + .run(&context) +} + +#[simplex::test] +fn mul_div_256_algorithm_d_512_256_c_is_res_high( + context: simplex::TestContext, +) -> anyhow::Result<()> { + let pow2_128: U256 = U256::from(u128::MAX) + 1; + + let a: U256 = generate_u256(pow2_128, U256::MAX); + let b = generate_u256(pow2_128, U256::MAX - pow2_128); + + let product = a.full_mul(b); + let result_high = U256::from_big_endian(&(safe_u512_to_u256((product >> 256).to_big_endian()))); + + let c = result_high + 1; + + let res = safe_u512_to_u256(product.div(c).to_big_endian()); + + case(MulDiv) + .args(a.to_big_endian(), b.to_big_endian(), c.to_big_endian()) + .expect(res) + .run(&context) +} + +#[simplex::test] +fn mul_div_256_normalize_to_threshold_512_127_norm_is_1( + context: simplex::TestContext, +) -> anyhow::Result<()> { + let pow2_128: U256 = U256::from(u128::MAX) + 1; + + let a: U256 = generate_u256(pow2_128, U256::MAX); + let b = generate_u256(pow2_128, U256::MAX - pow2_128); + + let product = a.full_mul(b); + let result_high = U256::from_big_endian(&(safe_u512_to_u256((product >> 256).to_big_endian()))); + + let c = generate_u256( + max(U256::from(2).pow(U256::from(255)), result_high + 1), + U256::MAX, + ); + + let res = safe_u512_to_u256(product.div(c).to_big_endian()); + + case(MulDiv) + .args(a.to_big_endian(), b.to_big_endian(), c.to_big_endian()) + .expect(res) + .run(&context) +} + +#[simplex::test] +fn mul_div_256_normalize_to_threshold_512_127_norm_greater_than_1( + context: simplex::TestContext, +) -> anyhow::Result<()> { + let a = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); + let b = generate_u256( + U256::from(u128::MAX) + 1, + U256::from(2).pow(U256::from(192)), + ); + + let product = a.full_mul(b); + let result_high = + U256::from_big_endian(&(safe_u512_to_u256((product >> 256).to_big_endian()))) + 1; + + let c = generate_u256( + max(U256::from(u128::MAX) + 1, result_high), + U256::from(2).pow(U256::from(255)) - 1, + ); + + let res = safe_u512_to_u256(product.div(c).to_big_endian()); + + case(MulDiv) + .args(a.to_big_endian(), b.to_big_endian(), c.to_big_endian()) + .expect(res) + .run(&context) +} diff --git a/tests/stdlib/u32/convert.rs b/tests/stdlib/u32/convert.rs new file mode 100644 index 0000000..ccf0cf9 --- /dev/null +++ b/tests/stdlib/u32/convert.rs @@ -0,0 +1,175 @@ +use primitive_types::U256; +use rand::Rng; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::u32::convert::ConvertProgram as U32ConvertTestProgram; +use simplicityhl_std::artifacts::tests::u32::convert::derived_convert::{ + ConvertArguments as U32ConvertTestArguments, ConvertWitness as U32ConvertTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + U32ToU64, + U32ToU128, + U32ToU256, + SplitU32IntoU8, + SplitU32IntoU16, + SafeU32ToU1, + SafeU32ToU8, + SafeU32ToU16, +} + +fn program() -> U32ConvertTestProgram { + U32ConvertTestProgram::new(&U32ConvertTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U32ConvertTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U32ConvertTestWitness { + function_index: function as u8, + first_arg: 0, + expected: [0; 32], + }, + } +} + +impl Case { + /// The operand, `first_arg`. + fn arg(mut self, a: u32) -> Self { + self.witness.first_arg = a; + self + } + + /// `expected`: the value the arm should produce. + fn expect(mut self, expected: [u8; 32]) -> Self { + self.witness.expected = expected; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn u32_to_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u32::MAX); + + case(U32ToU64) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u32_to_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u32::MAX); + + case(U32ToU128) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u32_to_u256(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u32::MAX); + + case(U32ToU256) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn split_u32_into_u8(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u32::MAX); + + case(SplitU32IntoU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn split_u32_into_u16(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u32::MAX); + + case(SplitU32IntoU16) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u32_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=1); + + case(SafeU32ToU1) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u32_to_u1_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u32::MAX); + + case(SafeU32ToU1) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u32_to_u8(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u8::MAX as u32); + + case(SafeU32ToU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u32_to_u8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(u8::MAX as u32 + 1..=u32::MAX); + + case(SafeU32ToU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u32_to_u16(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u16::MAX as u32); + + case(SafeU32ToU16) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u32_to_u16_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(u16::MAX as u32 + 1..=u32::MAX); + + case(SafeU32ToU16) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} diff --git a/tests/u32_math_test.rs b/tests/stdlib/u32/math.rs similarity index 63% rename from tests/u32_math_test.rs rename to tests/stdlib/u32/math.rs index 2db6eda..c25a816 100644 --- a/tests/u32_math_test.rs +++ b/tests/stdlib/u32/math.rs @@ -1,10 +1,8 @@ -mod common; +use crate::common::uint::TestUint; -use common::uint::TestUint; - -use simplicityhl_std::artifacts::u32_math_test::U32MathTestProgram; -use simplicityhl_std::artifacts::u32_math_test::derived_u32_math_test::{ - U32MathTestArguments, U32MathTestWitness, +use simplicityhl_std::artifacts::tests::u32::math::MathProgram as U32MathTestProgram; +use simplicityhl_std::artifacts::tests::u32::math::derived_math::{ + MathArguments as U32MathTestArguments, MathWitness as U32MathTestWitness, }; // The only per-width code for the common operations. @@ -32,9 +30,5 @@ impl TestUint for u32 { } } -mod u32_math_tests { - use super::*; - - // Stamps the 22 `#[simplex::test]` entry points for u32. Logic lives in common::uint. - uint_tests!(u32); -} +// Stamps the 22 `#[simplex::test]` entry points for u32. Logic lives in common::uint. +crate::uint_tests!(u32); diff --git a/tests/stdlib/u32/mod.rs b/tests/stdlib/u32/mod.rs new file mode 100644 index 0000000..828ff4c --- /dev/null +++ b/tests/stdlib/u32/mod.rs @@ -0,0 +1,3 @@ +mod convert; +mod math; +mod mul_div; diff --git a/tests/stdlib/u32/mul_div.rs b/tests/stdlib/u32/mul_div.rs new file mode 100644 index 0000000..1a45dca --- /dev/null +++ b/tests/stdlib/u32/mul_div.rs @@ -0,0 +1,107 @@ +use crate::common::core::{Expect, run}; +use rand::Rng; + +use simplicityhl_std::artifacts::tests::u32::mul_div::MulDivProgram as U32MulDivTestProgram; +use simplicityhl_std::artifacts::tests::u32::mul_div::derived_mul_div::{ + MulDivArguments as U32MulDivTestArguments, MulDivWitness as U32MulDivTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + MulDiv, +} + +fn program() -> U32MulDivTestProgram { + U32MulDivTestProgram::new(&U32MulDivTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +/// +/// Every field the chosen arm ignores keeps its default, so a test names only +/// the values it actually depends on. +struct Case { + witness: U32MulDivTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U32MulDivTestWitness { + function_index: function as u8, + first_arg: 0, + second_arg: 0, + third_arg: 0, + expected: None, + }, + } +} + +impl Case { + /// The three operands, `first_arg`, `second_arg` and `third_arg`. + fn args(mut self, a: u32, b: u32, c: u32) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self.witness.third_arg = c; + self + } + + /// The value the arm should return. `None`, the default, means the arm is + /// expected to produce nothing. + fn expect(mut self, expected: u32) -> Self { + self.witness.expected = Some(expected); + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn mul_div_32_product_is_u32(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u16::MAX) as u32; + let b = rand::thread_rng().gen_range(0..=u16::MAX) as u32; + let c = rand::thread_rng().gen_range(1..=u32::MAX); + + let res = a * b / c; + + case(MulDiv).args(a, b, c).expect(res).run(&context) +} + +#[simplex::test] +fn mul_div_32_intermediate_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u32::MAX); + let b = u32::MAX; + let c = rand::thread_rng().gen_range(a..=u32::MAX); + + let res = (a as u64) * (b as u64) / (c as u64); + + case(MulDiv).args(a, b, c).expect(res as u32).run(&context) +} + +#[simplex::test] +fn mul_div_32_result_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u32::MAX); + let b = u32::MAX; + let c = rand::thread_rng().gen_range(1..a); + + case(MulDiv) + .args(a, b, c) + .expect(0) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn mul_div_32_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u32::MAX); + let b = rand::thread_rng().gen_range(1..=u32::MAX); + let c = 0; + + case(MulDiv).args(a, b, c).expect(0).run(&context) +} diff --git a/tests/stdlib/u64/convert.rs b/tests/stdlib/u64/convert.rs new file mode 100644 index 0000000..78a6289 --- /dev/null +++ b/tests/stdlib/u64/convert.rs @@ -0,0 +1,196 @@ +use primitive_types::U256; +use rand::Rng; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::u64::convert::ConvertProgram as U64ConvertTestProgram; +use simplicityhl_std::artifacts::tests::u64::convert::derived_convert::{ + ConvertArguments as U64ConvertTestArguments, ConvertWitness as U64ConvertTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + U64ToU128, + U64ToU256, + SplitU64IntoU8, + SplitU64IntoU16, + SplitU64IntoU32, + SafeU64ToU1, + SafeU64ToU8, + SafeU64ToU16, + SafeU64ToU32, +} + +fn program() -> U64ConvertTestProgram { + U64ConvertTestProgram::new(&U64ConvertTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U64ConvertTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U64ConvertTestWitness { + function_index: function as u8, + first_arg: 0, + expected: [0; 32], + }, + } +} + +impl Case { + /// The operand, `first_arg`. + fn arg(mut self, a: u64) -> Self { + self.witness.first_arg = a; + self + } + + /// `expected`: the value the arm should produce. + fn expect(mut self, expected: [u8; 32]) -> Self { + self.witness.expected = expected; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn u64_to_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u64::MAX); + + case(U64ToU128) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u64_to_u256(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u64::MAX); + + case(U64ToU256) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn split_u64_into_u8(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u64::MAX); + + case(SplitU64IntoU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn split_u64_into_u16(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u64::MAX); + + case(SplitU64IntoU16) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn split_u64_into_u32(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u64::MAX); + + case(SplitU64IntoU32) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u64_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=1); + + case(SafeU64ToU1) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u64_to_u1_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u64::MAX); + + case(SafeU64ToU1) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u64_to_u8(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u8::MAX as u64); + + case(SafeU64ToU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u64_to_u8_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(u8::MAX as u64 + 1..=u64::MAX); + + case(SafeU64ToU8) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u64_to_u16(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u16::MAX as u64); + + case(SafeU64ToU16) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u64_to_u16_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(u16::MAX as u64 + 1..=u64::MAX); + + case(SafeU64ToU16) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn safe_u64_to_u32(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u32::MAX as u64); + + case(SafeU64ToU32) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u64_to_u32_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(u32::MAX as u64 + 1..=u64::MAX); + + case(SafeU64ToU32) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} diff --git a/tests/u64_math_test.rs b/tests/stdlib/u64/math.rs similarity index 63% rename from tests/u64_math_test.rs rename to tests/stdlib/u64/math.rs index 216b4bf..327894e 100644 --- a/tests/u64_math_test.rs +++ b/tests/stdlib/u64/math.rs @@ -1,10 +1,8 @@ -mod common; +use crate::common::uint::TestUint; -use common::uint::TestUint; - -use simplicityhl_std::artifacts::u64_math_test::U64MathTestProgram; -use simplicityhl_std::artifacts::u64_math_test::derived_u64_math_test::{ - U64MathTestArguments, U64MathTestWitness, +use simplicityhl_std::artifacts::tests::u64::math::MathProgram as U64MathTestProgram; +use simplicityhl_std::artifacts::tests::u64::math::derived_math::{ + MathArguments as U64MathTestArguments, MathWitness as U64MathTestWitness, }; // The only per-width code for the common operations. @@ -32,9 +30,5 @@ impl TestUint for u64 { } } -mod u64_math_tests { - use super::*; - - // Stamps the 22 `#[simplex::test]` entry points for u64. Logic lives in common::uint. - uint_tests!(u64); -} +// Stamps the 22 `#[simplex::test]` entry points for u64. Logic lives in common::uint. +crate::uint_tests!(u64); diff --git a/tests/stdlib/u64/mod.rs b/tests/stdlib/u64/mod.rs new file mode 100644 index 0000000..828ff4c --- /dev/null +++ b/tests/stdlib/u64/mod.rs @@ -0,0 +1,3 @@ +mod convert; +mod math; +mod mul_div; diff --git a/tests/stdlib/u64/mul_div.rs b/tests/stdlib/u64/mul_div.rs new file mode 100644 index 0000000..d460e28 --- /dev/null +++ b/tests/stdlib/u64/mul_div.rs @@ -0,0 +1,104 @@ +use crate::common::core::{Expect, run}; +use rand::Rng; + +use simplicityhl_std::artifacts::tests::u64::mul_div::MulDivProgram as U64MulDivTestProgram; +use simplicityhl_std::artifacts::tests::u64::mul_div::derived_mul_div::{ + MulDivArguments as U64MulDivTestArguments, MulDivWitness as U64MulDivTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + MulDiv, +} + +fn program() -> U64MulDivTestProgram { + U64MulDivTestProgram::new(&U64MulDivTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U64MulDivTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U64MulDivTestWitness { + function_index: function as u8, + first_arg: 0, + second_arg: 0, + third_arg: 0, + expected: None, + }, + } +} + +impl Case { + /// The three operands, `first_arg`, `second_arg` and `third_arg`. + fn args(mut self, a: u64, b: u64, c: u64) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self.witness.third_arg = c; + self + } + + /// The value the arm should return. `None`, the default, means the arm is + /// expected to produce nothing. + fn expect(mut self, expected: u64) -> Self { + self.witness.expected = Some(expected); + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn mul_div_64_product_is_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u32::MAX) as u64; + let b = rand::thread_rng().gen_range(0..=u32::MAX) as u64; + let c = rand::thread_rng().gen_range(1..=u64::MAX); + + let res = a * b / c; + + case(MulDiv).args(a, b, c).expect(res).run(&context) +} + +#[simplex::test] +fn mul_div_64_intermediate_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u64::MAX); + let b = u64::MAX; + let c = rand::thread_rng().gen_range(a..=u64::MAX); + + let res = (a as u128) * (b as u128) / (c as u128); + + case(MulDiv).args(a, b, c).expect(res as u64).run(&context) +} + +#[simplex::test] +fn mul_div_64_result_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u64::MAX); + let b = u64::MAX; + let c = rand::thread_rng().gen_range(1..a); + + case(MulDiv) + .args(a, b, c) + .expect(0) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn mul_div_64_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u64::MAX); + let b = rand::thread_rng().gen_range(1..=u64::MAX); + let c = 0; + + case(MulDiv).args(a, b, c).expect(0).run(&context) +} diff --git a/tests/stdlib/u8/convert.rs b/tests/stdlib/u8/convert.rs new file mode 100644 index 0000000..d536dd8 --- /dev/null +++ b/tests/stdlib/u8/convert.rs @@ -0,0 +1,144 @@ +use primitive_types::U256; +use rand::Rng; + +use crate::common::core::{Expect, run}; + +use simplicityhl_std::artifacts::tests::u8::convert::ConvertProgram as U8ConvertTestProgram; +use simplicityhl_std::artifacts::tests::u8::convert::derived_convert::{ + ConvertArguments as U8ConvertTestArguments, ConvertWitness as U8ConvertTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + U8ToU16, + U8ToU32, + U8ToU64, + U8ToU128, + U8ToU256, + SplitU8IntoU1, + SafeU8ToU1, +} + +fn program() -> U8ConvertTestProgram { + U8ConvertTestProgram::new(&U8ConvertTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U8ConvertTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U8ConvertTestWitness { + function_index: function as u8, + first_arg: 0, + expected: [0; 32], + }, + } +} + +impl Case { + /// The operand, `first_arg`. + fn arg(mut self, a: u8) -> Self { + self.witness.first_arg = a; + self + } + + /// `expected`: the value the arm should produce. + fn expect(mut self, expected: [u8; 32]) -> Self { + self.witness.expected = expected; + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn u8_to_u16(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u8::MAX); + + case(U8ToU16) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u8_to_u32(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u8::MAX); + + case(U8ToU32) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u8_to_u64(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u8::MAX); + + case(U8ToU64) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u8_to_u128(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u8::MAX); + + case(U8ToU128) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn u8_to_u256(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u8::MAX); + + case(U8ToU256) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn split_u8_into_u1(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u8::MAX); + + case(SplitU8IntoU1) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u8_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=1); + + case(SafeU8ToU1) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .run(&context) +} + +#[simplex::test] +fn safe_u8_to_u1_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u8::MAX); + + case(SafeU8ToU1) + .arg(a) + .expect(U256::from(a).to_big_endian()) + .expecting(&context, Expect::AssertFailed) +} diff --git a/tests/u8_math_test.rs b/tests/stdlib/u8/math.rs similarity index 63% rename from tests/u8_math_test.rs rename to tests/stdlib/u8/math.rs index 3ff3d7b..cefd1b8 100644 --- a/tests/u8_math_test.rs +++ b/tests/stdlib/u8/math.rs @@ -1,10 +1,8 @@ -mod common; +use crate::common::uint::TestUint; -use common::uint::TestUint; - -use simplicityhl_std::artifacts::u8_math_test::U8MathTestProgram; -use simplicityhl_std::artifacts::u8_math_test::derived_u8_math_test::{ - U8MathTestArguments, U8MathTestWitness, +use simplicityhl_std::artifacts::tests::u8::math::MathProgram as U8MathTestProgram; +use simplicityhl_std::artifacts::tests::u8::math::derived_math::{ + MathArguments as U8MathTestArguments, MathWitness as U8MathTestWitness, }; // The only per-width code for the common operations. @@ -32,9 +30,5 @@ impl TestUint for u8 { } } -mod u8_math_tests { - use super::*; - - // Stamps the 22 `#[simplex::test]` entry points for u8. Logic lives in common::uint. - uint_tests!(u8); -} +// Stamps the 22 `#[simplex::test]` entry points for u8. Logic lives in common::uint. +crate::uint_tests!(u8); diff --git a/tests/stdlib/u8/mod.rs b/tests/stdlib/u8/mod.rs new file mode 100644 index 0000000..828ff4c --- /dev/null +++ b/tests/stdlib/u8/mod.rs @@ -0,0 +1,3 @@ +mod convert; +mod math; +mod mul_div; diff --git a/tests/stdlib/u8/mul_div.rs b/tests/stdlib/u8/mul_div.rs new file mode 100644 index 0000000..eddc18b --- /dev/null +++ b/tests/stdlib/u8/mul_div.rs @@ -0,0 +1,104 @@ +use crate::common::core::{Expect, run}; +use rand::Rng; + +use simplicityhl_std::artifacts::tests::u8::mul_div::MulDivProgram as U8MulDivTestProgram; +use simplicityhl_std::artifacts::tests::u8::mul_div::derived_mul_div::{ + MulDivArguments as U8MulDivTestArguments, MulDivWitness as U8MulDivTestWitness, +}; + +use FunctionToTest::*; + +enum FunctionToTest { + MulDiv, +} + +fn program() -> U8MulDivTestProgram { + U8MulDivTestProgram::new(&U8MulDivTestArguments {}) +} + +/// One dispatch arm of the contract, plus the witness it reads. +struct Case { + witness: U8MulDivTestWitness, +} + +fn case(function: FunctionToTest) -> Case { + Case { + witness: U8MulDivTestWitness { + function_index: function as u8, + first_arg: 0, + second_arg: 0, + third_arg: 0, + expected: None, + }, + } +} + +impl Case { + /// The three operands, `first_arg`, `second_arg` and `third_arg`. + fn args(mut self, a: u8, b: u8, c: u8) -> Self { + self.witness.first_arg = a; + self.witness.second_arg = b; + self.witness.third_arg = c; + self + } + + /// The value the arm should return. `None`, the default, means the arm is + /// expected to produce nothing. + fn expect(mut self, expected: u8) -> Self { + self.witness.expected = Some(expected); + self + } + + /// Fund, spend, and expect the spend to succeed. + fn run(self, context: &simplex::TestContext) -> anyhow::Result<()> { + self.expecting(context, Expect::Ok) + } + + /// Fund, spend, and expect `expect`. + fn expecting(self, context: &simplex::TestContext, expect: Expect) -> anyhow::Result<()> { + run(context, program(), self.witness, expect) + } +} + +#[simplex::test] +fn mul_div_8_product_is_u8(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u8::MAX); + let b = u8::MAX / a; + let c = rand::thread_rng().gen_range(1..=u8::MAX); + + let res = a * b / c; + + case(MulDiv).args(a, b, c).expect(res).run(&context) +} + +#[simplex::test] +fn mul_div_8_intermediate_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u8::MAX); + let b = u8::MAX; + let c = rand::thread_rng().gen_range(a..=u8::MAX); + + let res = (a as u16) * (b as u16) / (c as u16); + + case(MulDiv).args(a, b, c).expect(res as u8).run(&context) +} + +#[simplex::test] +fn mul_div_8_result_overflow(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(2..=u8::MAX); + let b = u8::MAX; + let c = rand::thread_rng().gen_range(1..a); + + case(MulDiv) + .args(a, b, c) + .expect(0) + .expecting(&context, Expect::AssertFailed) +} + +#[simplex::test] +fn mul_div_8_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(1..=u8::MAX); + let b = rand::thread_rng().gen_range(1..=u8::MAX); + let c = 0; + + case(MulDiv).args(a, b, c).expect(0).run(&context) +} diff --git a/tests/u128_basic_math_test.rs b/tests/u128_basic_math_test.rs deleted file mode 100644 index 5d0b4ab..0000000 --- a/tests/u128_basic_math_test.rs +++ /dev/null @@ -1,1006 +0,0 @@ -mod common; - -use primitive_types::U256; -use rand::Rng; - -use crate::common::helper::DEFAULT_BOOL; -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u128_basic_math_test::U128BasicMathTestProgram; -use simplicityhl_std::artifacts::u128_basic_math_test::derived_u128_basic_math_test::{ - U128BasicMathTestArguments, U128BasicMathTestWitness, -}; - -enum FunctionToTest { - Add128, - Add128_64, - FullAdd128, - Sub128, - FullSub128, - Mul128, - Mul128_64, - CalculateNormalizerBase64, - EstimateQuotientDigitBase64, - DivMod128_64, - DivMod128, - Div128, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -const DEFAULT_EXPECTED: u128 = 0; - -fn program() -> U128BasicMathTestProgram { - U128BasicMathTestProgram::new(&U128BasicMathTestArguments {}) -} - -fn build_witness( - function: u8, - a: u128, - b: u128, - expected: Option, - expected_bool: bool, - second_expected: u128, -) -> U128BasicMathTestWitness { - U128BasicMathTestWitness { - function_index: function, - first_arg: a, - second_arg: b, - expected, - expected_bool, - second_expected, - } -} - -fn split_helper(a: U256) -> (u128, u128) { - let a_high = (a >> 128).as_u128(); - let a_low = a.low_u128(); - - (a_high, a_low) -} - -mod u128_tests_arithmetic { - use super::*; - - #[simplex::test] - fn u128_test_add_128_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX / 2); - let b = rand::thread_rng().gen_range(0..=u128::MAX / 2); - let result = a + b; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Add128), - a, - b, - Some(result), - false, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_add_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = u128::MAX; - let b = rand::thread_rng().gen_range(1..=u128::MAX); - let result = b - 1; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Add128), - a, - b, - Some(result), - true, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_add_128_64_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX / 2); - let b = rand::thread_rng().gen_range(0..=u64::MAX) as u128; - let result = a + b; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Add128_64), - a, - b, - Some(result), - false, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_add_128_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = u128::MAX; - let b = rand::thread_rng().gen_range(1..=u64::MAX) as u128; - let result = b - 1; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Add128_64), - a, - b, - Some(result), - true, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_full_add_128_not_overflow_carry_low_false( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX / 2); - let b = rand::thread_rng().gen_range(0..=u128::MAX / 2); - let result = a + b; - let result_carry = false; - let carry_low = 0_u128; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FullAdd128), - a, - b, - Some(result), - result_carry, - carry_low, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_full_add_128_overflow_carry_low_false( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = u128::MAX; - let b = rand::thread_rng().gen_range(1..=u128::MAX); - let result = b - 1; - let result_carry = true; - let carry_low = 0_u128; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FullAdd128), - a, - b, - Some(result), - result_carry, - carry_low, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_full_add_128_not_overflow_carry_low_true( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX / 2); - let b = rand::thread_rng().gen_range(0..=u128::MAX / 2); - let result = a + b + 1; - let result_carry = false; - let carry_low = 1_u128; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FullAdd128), - a, - b, - Some(result), - result_carry, - carry_low, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_full_add_128_overflow_carry_low_true( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = u128::MAX; - let b = rand::thread_rng().gen_range(1..=u128::MAX); - let result = b; - let result_carry = true; - let carry_low = 1_u128; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FullAdd128), - a, - b, - Some(result), - result_carry, - carry_low, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_sub_128_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - let b = rand::thread_rng().gen_range(0..=a); - let result = a - b; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Sub128), - a, - b, - Some(result), - false, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_sub_128_a_eq_b(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Sub128), - a, - a, - Some(0), - false, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_sub_128_a_low_eq_b_low(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - let b_high = rand::thread_rng().gen_range(0..=u64::MAX); - - let low: u64 = a as u64; - let b = ((b_high as u128) << 64) | (low as u128); - - let carry = a < b; - let result = a.wrapping_sub(b); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Sub128), - a, - b, - Some(result), - carry, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_sub_128_diff_is_u64_max(context: simplex::TestContext) -> anyhow::Result<()> { - let a_low: u64 = u64::MAX; - - let a_high = rand::thread_rng().gen_range(0..=u64::MAX); - let b_high = rand::thread_rng().gen_range(0..=u64::MAX); - - let a = ((a_high as u128) << 64) | (a_low as u128); - let b = (b_high as u128) << 64; // b_low is 0 - - let carry = a < b; - let result = a.wrapping_sub(b); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Sub128), - a, - b, - Some(result), - carry, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_sub_128_diff_is_u128_max(context: simplex::TestContext) -> anyhow::Result<()> { - let a = u128::MAX; - let b = 0; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Sub128), - a, - b, - Some(a), - false, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_sub_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..u128::MAX); - let b = u128::MAX; - let result = a + 1; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Sub128), - a, - b, - Some(result), - true, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_full_sub_128_borrow_low_false( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - let b = rand::thread_rng().gen_range(0..=a); - let result = a - b; - let result_borrow = false; - let borrow_low = 0_u128; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FullSub128), - a, - b, - Some(result), - result_borrow, - borrow_low, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_full_sub_128_overflow_borrow_low_false( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..u128::MAX); - let b = u128::MAX; - let result = a + 1; - let result_borrow = true; - let borrow_low = 0_u128; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FullSub128), - a, - b, - Some(result), - result_borrow, - borrow_low, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_full_sub_128_borrow_low_true(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - let b = rand::thread_rng().gen_range(0..a); - let result = a - b - 1; - let result_borrow = false; - let borrow_low = 1_u128; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FullSub128), - a, - b, - Some(result), - result_borrow, - borrow_low, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_full_sub_128_overflow_borrow_low_true( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..u128::MAX); - let b = u128::MAX; - let (result, result_borrow) = a.overflowing_sub(b); - - let borrow_low = 1_u128; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FullSub128), - a, - b, - Some(result - 1), - result_borrow, - borrow_low, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_mul_128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..u128::MAX); - let b = rand::thread_rng().gen_range(0..u128::MAX); - let result = U256::from(a) * U256::from(b); - - let (result_high, result_low) = split_helper(result); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Mul128), - a, - b, - Some(result_high), - DEFAULT_BOOL, - result_low, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_mul_128_64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..u128::MAX); - let b = rand::thread_rng().gen_range(0..u64::MAX); - let result = U256::from(a) * U256::from(b); - - let (result_high, result_low) = split_helper(result); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Mul128_64), - a, - b as u128, - Some(result_high), - DEFAULT_BOOL, - result_low, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_calculate_normalizer_base_64_b_is_u64( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let threshold = 1u128 << 63; - - let b = rand::thread_rng().gen_range(1..threshold); - - let norm: u128 = threshold.div_ceil(b); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::CalculateNormalizerBase64), - DEFAULT_EXPECTED, - b, - Some(norm), - false, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_calculate_normalizer_base_64_b_is_big_enough_not_normalize( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let threshold = 1u128 << 63; - - let b = rand::thread_rng().gen_range(threshold..=u64::MAX as u128); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::CalculateNormalizerBase64), - DEFAULT_EXPECTED, - b, - Some(1), - false, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_calculate_normalizer_base_64_b_is_u128( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let threshold = 1u128 << 63; - - let b = rand::thread_rng().gen_range((u64::MAX as u128) + 1..=u128::MAX); - let b_high = b >> 64; - - let norm: u128 = threshold.div_ceil(b_high); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::CalculateNormalizerBase64), - DEFAULT_EXPECTED, - b, - Some(norm), - true, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_calculate_normalizer_base_64_b_is_u64_fail( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let b = rand::thread_rng().gen_range((u64::MAX as u128) + 1..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::CalculateNormalizerBase64), - DEFAULT_EXPECTED, - b, - Some(DEFAULT_EXPECTED), - false, - DEFAULT_EXPECTED, - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u128_test_calculate_normalizer_base_64_b_is_u128_fail( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let b = rand::thread_rng().gen_range(1..=u64::MAX as u128); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::CalculateNormalizerBase64), - DEFAULT_EXPECTED, - b, - Some(DEFAULT_EXPECTED), - true, - DEFAULT_EXPECTED, - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u128_test_calculate_normalizer_base_64_b_is_zero_fail( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let b = 0; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::CalculateNormalizerBase64), - DEFAULT_EXPECTED, - b, - Some(DEFAULT_EXPECTED), - false, - DEFAULT_EXPECTED, - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u128_test_estimate_quotient_digit_base_64( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let threshold = 1u64 << 63; - - let b_high = rand::thread_rng().gen_range(threshold..=u64::MAX); - let b_low = rand::thread_rng().gen_range(0..=u64::MAX); - - let a_high = rand::thread_rng().gen_range(0..b_high); - let a_low = rand::thread_rng().gen_range(0..=u128::MAX); - - let a = ((U256::from(a_high)) << 128) | (U256::from(a_low)); - let b = ((b_high as u128) << 64) | (b_low as u128); - - let q = (a / b).as_u128(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::EstimateQuotientDigitBase64), - a_high as u128, - a_low, - Some(q), - DEFAULT_BOOL, - b, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_estimate_quotient_digit_base_64_fail( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - // expected to fail because a is to big for q to fit unto u64 - let threshold = 1u64 << 63; - - let b_high = rand::thread_rng().gen_range(threshold..u64::MAX); - let b_low = rand::thread_rng().gen_range(0..=u64::MAX); - - let a_high = rand::thread_rng().gen_range(b_high + 1..=u64::MAX); - let a_low = rand::thread_rng().gen_range(0..=u128::MAX); - - let a = ((U256::from(a_high)) << 128) | (U256::from(a_low)); - let b = ((b_high as u128) << 64) | (b_low as u128); - - let q = (a / b).as_u128(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::EstimateQuotientDigitBase64), - a_high as u128, - a_low, - Some(q), - DEFAULT_BOOL, - b, - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn test_div_mod_128_64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - let b = rand::thread_rng().gen_range(1..=u64::MAX as u128); - - let q = a / b; - let r = a % b; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod128_64), - a, - b, - Some(q), - DEFAULT_BOOL, - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn test_div_mod_128_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - let b = 0; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod128_64), - a, - b, - Some(DEFAULT_EXPECTED), - DEFAULT_BOOL, - DEFAULT_EXPECTED, - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u128_test_div_mod_128_a_less_than_b(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..u128::MAX); - let b = rand::thread_rng().gen_range(a + 1..=u128::MAX); - - let q = a / b; - let r = a % b; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod128), - a, - b, - Some(q), - DEFAULT_BOOL, - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_div_mod_128_div_64(context: simplex::TestContext) -> anyhow::Result<()> { - let b = rand::thread_rng().gen_range(1..=u64::MAX); - let a = rand::thread_rng().gen_range(b..=u64::MAX) as u128; - - let q = a / b as u128; - let r = a % b as u128; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod128), - a, - b as u128, - Some(q), - DEFAULT_BOOL, - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_div_mod_128_q_is_1(context: simplex::TestContext) -> anyhow::Result<()> { - // case where a >= b and a_high = b_high != 0 - let b_low = rand::thread_rng().gen_range(0..=u64::MAX); - let a_low = rand::thread_rng().gen_range(b_low..=u64::MAX); - let high = rand::thread_rng().gen_range(1..u64::MAX); - - let a = ((high as u128) << 64) | (a_low as u128); - let b = ((high as u128) << 64) | (b_low as u128); - - let q = a / b; - let r = a % b; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod128), - a, - b, - Some(q), - DEFAULT_BOOL, - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_div_mod_128_b_is_u64(context: simplex::TestContext) -> anyhow::Result<()> { - let b = rand::thread_rng().gen_range(1..=u64::MAX as u128); - let a = rand::thread_rng().gen_range(u64::MAX as u128 + 1..=u128::MAX); - - let q = a / b; - let r = a % b; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod128), - a, - b, - Some(q), - DEFAULT_BOOL, - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_div_mod_128_b_is_u128(context: simplex::TestContext) -> anyhow::Result<()> { - let b_high = rand::thread_rng().gen_range(1..u64::MAX); - let a_high = rand::thread_rng().gen_range(b_high + 1..=u64::MAX); - - let a = ((a_high as u128) << 64) | (rand::thread_rng().gen_range(0..u64::MAX) as u128); - let b = ((b_high as u128) << 64) | (rand::thread_rng().gen_range(0..u64::MAX) as u128); - - let q = a / b; - let r = a % b; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod128), - a, - b, - Some(q), - DEFAULT_BOOL, - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_div_mod_128_a_equal_b(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(1..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod128), - a, - a, - Some(1u128), - DEFAULT_BOOL, - 0u128, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_div_mod_128_equal_high_words_max_low_diff( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let high = rand::thread_rng().gen_range(1..=u64::MAX); - - let a = ((high as u128) << 64) | (u64::MAX as u128); - let b = (high as u128) << 64; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod128), - a, - b, - Some(1u128), - DEFAULT_BOOL, - u64::MAX as u128, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_div_mod_128_eq_high_words_a_less_than_b( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let high = rand::thread_rng().gen_range(1..=u64::MAX); - - let a = (high as u128) << 64; - let b = ((high as u128) << 64) | (u64::MAX as u128); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod128), - a, - b, - Some(0u128), - DEFAULT_BOOL, - a, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_div_128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - let b = rand::thread_rng().gen_range(1..=u128::MAX); - let result = a / b; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Div128), - a, - b, - Some(result), - DEFAULT_BOOL, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_div_128_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - let b = 0; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Div128), - a, - b, - Some(0), - DEFAULT_BOOL, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } -} diff --git a/tests/u128_convert_test.rs b/tests/u128_convert_test.rs deleted file mode 100644 index e2d0a22..0000000 --- a/tests/u128_convert_test.rs +++ /dev/null @@ -1,295 +0,0 @@ -mod common; - -use primitive_types::U256; -use rand::Rng; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u128_convert_test::U128ConvertTestProgram; -use simplicityhl_std::artifacts::u128_convert_test::derived_u128_convert_test::{ - U128ConvertTestArguments, U128ConvertTestWitness, -}; - -enum FunctionToTest { - U128ToU256, - SplitU128IntoU8, - SplitU128IntoU16, - SplitU128IntoU32, - SplitU128IntoU64, - SafeU128ToU1, - SafeU128ToU8, - SafeU128ToU16, - SafeU128ToU32, - SafeU128ToU64, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U128ConvertTestProgram { - U128ConvertTestProgram::new(&U128ConvertTestArguments {}) -} - -fn build_witness(function: u8, a: u128, expected: [u8; 32]) -> U128ConvertTestWitness { - U128ConvertTestWitness { - function_index: function, - first_arg: a, - expected, - } -} - -mod u128_convert_test { - use super::*; - - #[simplex::test] - fn u128_convert_test_u128_to_u256(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U128ToU256), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_convert_test_split_u128_into_u8(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU128IntoU8), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_convert_test_split_u128_into_u16(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU128IntoU16), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_convert_test_split_u128_into_u32(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU128IntoU32), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_convert_test_split_u128_into_u64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU128IntoU64), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_convert_test_safe_u128_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU128ToU1), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_convert_test_safe_u128_to_u1_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU128ToU1), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u128_convert_test_safe_u128_to_u8(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u8::MAX as u128); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU128ToU8), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_convert_test_safe_u128_to_u8_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(u8::MAX as u128 + 1..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU128ToU8), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u128_convert_test_safe_u128_to_u16(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u16::MAX as u128); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU128ToU16), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_convert_test_safe_u128_to_u16_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(u16::MAX as u128 + 1..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU128ToU16), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u128_convert_test_safe_u128_to_u32(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u32::MAX as u128); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU128ToU32), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_convert_test_safe_u128_to_u32_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(u32::MAX as u128 + 1..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU128ToU32), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u128_convert_test_safe_u128_to_u64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u64::MAX as u128); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU128ToU64), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_convert_test_safe_u128_to_u64_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(u64::MAX as u128 + 1..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU128ToU64), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } -} diff --git a/tests/u128_mul_div_test.rs b/tests/u128_mul_div_test.rs deleted file mode 100644 index 5abd937..0000000 --- a/tests/u128_mul_div_test.rs +++ /dev/null @@ -1,108 +0,0 @@ -mod common; - -use primitive_types::U256; -use rand::Rng; - -use crate::common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u128_mul_div_test::U128MulDivTestProgram; -use simplicityhl_std::artifacts::u128_mul_div_test::derived_u128_mul_div_test::{ - U128MulDivTestArguments, U128MulDivTestWitness, -}; - -const DEFAULT_EXPECTED: u128 = 0; - -enum FunctionToTest { - MulDiv, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U128MulDivTestProgram { - U128MulDivTestProgram::new(&U128MulDivTestArguments {}) -} - -fn build_witness( - op: u8, - a: u128, - b: u128, - c: u128, - expected: Option, -) -> U128MulDivTestWitness { - U128MulDivTestWitness { - function_index: op, - first_arg: a, - second_arg: b, - third_arg: c, - expected, - } -} - -mod u128_mul_div_test { - use super::*; - - #[simplex::test] - fn u128_test_mul_div_128_product_is_u128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u64::MAX) as u128; - let b = rand::thread_rng().gen_range(0..=u64::MAX) as u128; - let c = rand::thread_rng().gen_range(1..=u128::MAX); - - let res = a * b / c; - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(res)), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_mul_div_128_intermediate_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u128::MAX); - let b = u128::MAX; - let c = rand::thread_rng().gen_range(a..=u128::MAX); - - let res = U256::from(a) * U256::from(b) / U256::from(c); - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(res.low_u128())), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_mul_div_128_result_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u128::MAX); - let b = u128::MAX; - let c = rand::thread_rng().gen_range(1..a); - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(DEFAULT_EXPECTED)), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u128_test_mul_div_128_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(1..=u128::MAX); - let b = rand::thread_rng().gen_range(1..=u128::MAX); - let c = 0; - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(0)), - Expect::Ok, - ) - } -} diff --git a/tests/u128_test_bits.rs b/tests/u128_test_bits.rs deleted file mode 100644 index 508d5f7..0000000 --- a/tests/u128_test_bits.rs +++ /dev/null @@ -1,233 +0,0 @@ -mod common; - -use rand::Rng; - -use crate::common::helper::DEFAULT_BOOL; -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u128_test_bits::U128TestBitsProgram; -use simplicityhl_std::artifacts::u128_test_bits::derived_u128_test_bits::{ - U128TestBitsArguments, U128TestBitsWitness, -}; - -enum FunctionToTest { - And128, - Or128, - Eq128, - LeftShift128, - RightShift128, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -const DEFAULT_EXPECTED: u128 = 0; - -fn program() -> U128TestBitsProgram { - U128TestBitsProgram::new(&U128TestBitsArguments {}) -} - -fn build_witness( - function: u8, - a: u128, - b: u128, - expected: Option, - expected_bool: bool, -) -> U128TestBitsWitness { - U128TestBitsWitness { - function_index: function, - first_arg: a, - second_arg: b, - expected, - expected_bool, - } -} - -mod u128_tests_bits { - use super::*; - - #[simplex::test] - fn u128_test_and_128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - let b = rand::thread_rng().gen_range(0..=u128::MAX); - let result = a & b; - - run( - &context, - program(), - build_witness(op(FunctionToTest::And128), a, b, Some(result), DEFAULT_BOOL), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_or_128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - let b = rand::thread_rng().gen_range(0..=u128::MAX); - let result = a | b; - - run( - &context, - program(), - build_witness(op(FunctionToTest::Or128), a, b, Some(result), DEFAULT_BOOL), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_eq_128_true(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Eq128), - a, - a, - Some(DEFAULT_EXPECTED), - true, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_eq_128_false(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(1..=u128::MAX); - let b = a - 1; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Eq128), - a, - b, - Some(DEFAULT_EXPECTED), - false, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_left_shift_128(context: simplex::TestContext) -> anyhow::Result<()> { - let shift = rand::thread_rng().gen_range(1..=127_u128); - let val = rand::thread_rng().gen_range(0..=u128::MAX); - let result = val << shift; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::LeftShift128), - shift, - val, - Some(result), - DEFAULT_BOOL, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_left_shift_128_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let shift = 0; - let val = rand::thread_rng().gen_range(0..=u128::MAX); - let result = val; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::LeftShift128), - shift, - val, - Some(result), - DEFAULT_BOOL, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_left_shift_128_out_of_range(context: simplex::TestContext) -> anyhow::Result<()> { - let shift = rand::thread_rng().gen_range(128..=u8::MAX as u128); - let val = rand::thread_rng().gen_range(0..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::LeftShift128), - shift, - val, - Some(0), - DEFAULT_BOOL, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_right_shift_128(context: simplex::TestContext) -> anyhow::Result<()> { - let shift = rand::thread_rng().gen_range(1..=127_u128); - let val = rand::thread_rng().gen_range(0..=u128::MAX); - let result = val >> shift; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::RightShift128), - shift, - val, - Some(result), - DEFAULT_BOOL, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_right_shift_128_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let shift = 0; - let val = rand::thread_rng().gen_range(0..=u128::MAX); - let result = val; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::RightShift128), - shift, - val, - Some(result), - DEFAULT_BOOL, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_right_shift_128_out_of_range(context: simplex::TestContext) -> anyhow::Result<()> { - let shift = rand::thread_rng().gen_range(128..=u8::MAX as u128); - let val = rand::thread_rng().gen_range(0..=u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::RightShift128), - shift, - val, - Some(0), - DEFAULT_BOOL, - ), - Expect::Ok, - ) - } -} diff --git a/tests/u128_test_compare.rs b/tests/u128_test_compare.rs deleted file mode 100644 index 1c7a01e..0000000 --- a/tests/u128_test_compare.rs +++ /dev/null @@ -1,142 +0,0 @@ -mod common; - -use rand::Rng; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u128_test_compare::U128TestCompareProgram; -use simplicityhl_std::artifacts::u128_test_compare::derived_u128_test_compare::{ - U128TestCompareArguments, U128TestCompareWitness, -}; - -enum FunctionToTest { - IsZero128, - Lt128, - Le128, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -const DEFAULT_EXPECTED: u128 = 0; - -fn program() -> U128TestCompareProgram { - U128TestCompareProgram::new(&U128TestCompareArguments {}) -} - -fn build_witness(function: u8, a: u128, b: u128, expected_bool: bool) -> U128TestCompareWitness { - U128TestCompareWitness { - function_index: function, - first_arg: a, - second_arg: b, - expected_bool, - } -} - -mod u128_tests_arithmetic { - use super::*; - - #[simplex::test] - fn u128_test_is_zero_128_true(context: simplex::TestContext) -> anyhow::Result<()> { - let a = 0; - - run( - &context, - program(), - build_witness(op(FunctionToTest::IsZero128), a, DEFAULT_EXPECTED, true), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_is_zero_128_false(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(1..=u128::MAX); - - run( - &context, - program(), - build_witness(op(FunctionToTest::IsZero128), a, DEFAULT_EXPECTED, false), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_lt_128_less(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..u128::MAX); - let b = a + 1; - - run( - &context, - program(), - build_witness(op(FunctionToTest::Lt128), a, b, true), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_lt_128_eq(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..u128::MAX); - let b = a; - - run( - &context, - program(), - build_witness(op(FunctionToTest::Lt128), a, b, false), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_lt_128_bigger(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(1..=u128::MAX); - let b = a - 1; - - run( - &context, - program(), - build_witness(op(FunctionToTest::Lt128), a, b, false), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_le_128_less(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..u128::MAX); - let b = a + 1; - - run( - &context, - program(), - build_witness(op(FunctionToTest::Le128), a, b, true), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_le_128_eq(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..u128::MAX); - let b = a; - - run( - &context, - program(), - build_witness(op(FunctionToTest::Le128), a, b, true), - Expect::Ok, - ) - } - - #[simplex::test] - fn u128_test_le_128_bigger(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(1..=u128::MAX); - let b = a - 1; - - run( - &context, - program(), - build_witness(op(FunctionToTest::Le128), a, b, false), - Expect::Ok, - ) - } -} diff --git a/tests/u16_convert_test.rs b/tests/u16_convert_test.rs deleted file mode 100644 index 65df71a..0000000 --- a/tests/u16_convert_test.rs +++ /dev/null @@ -1,190 +0,0 @@ -mod common; - -use primitive_types::U256; -use rand::Rng; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u16_convert_test::U16ConvertTestProgram; -use simplicityhl_std::artifacts::u16_convert_test::derived_u16_convert_test::{ - U16ConvertTestArguments, U16ConvertTestWitness, -}; - -enum FunctionToTest { - U16ToU32, - U16ToU64, - U16ToU128, - U16ToU256, - SplitU16IntoU8, - SafeU16ToU1, - SafeU16ToU8, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U16ConvertTestProgram { - U16ConvertTestProgram::new(&U16ConvertTestArguments {}) -} - -fn build_witness(function: u8, a: u16, expected: [u8; 32]) -> U16ConvertTestWitness { - U16ConvertTestWitness { - function_index: function, - first_arg: a, - expected, - } -} - -mod u16_convert_test { - use super::*; - - #[simplex::test] - fn u16_convert_test_u16_to_u32(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u16::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U16ToU32), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u16_convert_test_u16_to_u64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u16::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U16ToU64), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u16_convert_test_u16_to_u128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u16::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U16ToU128), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u16_convert_test_u16_to_u256(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u16::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U16ToU256), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u16_convert_test_split_u16_into_u8(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u16::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU16IntoU8), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u16_convert_test_safe_u16_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU16ToU1), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u16_convert_test_safe_u16_to_u1_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u16::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU16ToU1), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u16_convert_test_safe_u16_to_u8(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u8::MAX as u16); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU16ToU8), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u16_convert_test_safe_u16_to_u8_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(u8::MAX as u16 + 1..=u16::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU16ToU8), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } -} diff --git a/tests/u16_mul_div_test.rs b/tests/u16_mul_div_test.rs deleted file mode 100644 index eb18073..0000000 --- a/tests/u16_mul_div_test.rs +++ /dev/null @@ -1,100 +0,0 @@ -mod common; - -use crate::common::core::{Expect, run}; -use rand::Rng; - -use simplicityhl_std::artifacts::u16_mul_div_test::U16MulDivTestProgram; -use simplicityhl_std::artifacts::u16_mul_div_test::derived_u16_mul_div_test::{ - U16MulDivTestArguments, U16MulDivTestWitness, -}; - -const DEFAULT_EXPECTED: u16 = 0; - -enum FunctionToTest { - MulDiv, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U16MulDivTestProgram { - U16MulDivTestProgram::new(&U16MulDivTestArguments {}) -} - -fn build_witness(op: u8, a: u16, b: u16, c: u16, expected: Option) -> U16MulDivTestWitness { - U16MulDivTestWitness { - function_index: op, - first_arg: a, - second_arg: b, - third_arg: c, - expected, - } -} - -mod u16_mul_div_test { - use super::*; - - #[simplex::test] - fn u16_test_mul_div_16_product_is_u16(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u8::MAX) as u16; - let b = rand::thread_rng().gen_range(0..=u8::MAX) as u16; - let c = rand::thread_rng().gen_range(1..=u16::MAX); - - let res = a * b / c; - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(res)), - Expect::Ok, - ) - } - - #[simplex::test] - fn u16_test_mul_div_16_intermediate_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u16::MAX); - let b = u16::MAX; - let c = rand::thread_rng().gen_range(a..=u16::MAX); - - let res = (a as u32) * (b as u32) / (c as u32); - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(res as u16)), - Expect::Ok, - ) - } - - #[simplex::test] - fn u16_test_mul_div_16_result_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u16::MAX); - let b = u16::MAX; - let c = rand::thread_rng().gen_range(1..a); - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(DEFAULT_EXPECTED)), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u16_test_mul_div_16_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(1..=u16::MAX); - let b = rand::thread_rng().gen_range(1..=u16::MAX); - let c = 0; - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(0)), - Expect::Ok, - ) - } -} diff --git a/tests/u1_convert_test.rs b/tests/u1_convert_test.rs deleted file mode 100644 index 26c743c..0000000 --- a/tests/u1_convert_test.rs +++ /dev/null @@ -1,150 +0,0 @@ -mod common; - -use primitive_types::U256; -use rand::Rng; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u1_convert_test::U1ConvertTestProgram; -use simplicityhl_std::artifacts::u1_convert_test::derived_u1_convert_test::{ - U1ConvertTestArguments, U1ConvertTestWitness, -}; - -enum FunctionToTest { - U1ToU8, - U1ToU16, - U1ToU32, - U1ToU64, - U1ToU128, - U1ToU256, - U1ToBool, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U1ConvertTestProgram { - U1ConvertTestProgram::new(&U1ConvertTestArguments {}) -} - -fn build_witness(function: u8, a: u8, expected: [u8; 32]) -> U1ConvertTestWitness { - U1ConvertTestWitness { - function_index: function, - first_arg: a, - expected, - } -} - -mod u1_convert_test { - use super::*; - - #[simplex::test] - fn u1_convert_test_u1_to_u8(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=1); - - run( - &context, - program(), - build_witness(op(FunctionToTest::U1ToU8), a, U256::from(a).to_big_endian()), - Expect::Ok, - ) - } - - #[simplex::test] - fn u1_convert_test_u1_to_u16(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U1ToU16), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u1_convert_test_u1_to_u32(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U1ToU32), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u1_convert_test_u1_to_u64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U1ToU64), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u1_convert_test_u1_to_u128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U1ToU128), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u1_convert_test_u1_to_u256(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U1ToU256), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u1_convert_test_split_u1_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U1ToBool), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } -} diff --git a/tests/u256_convert_test.rs b/tests/u256_convert_test.rs deleted file mode 100644 index 923c40a..0000000 --- a/tests/u256_convert_test.rs +++ /dev/null @@ -1,331 +0,0 @@ -mod common; - -use primitive_types::U256; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u256_convert_test::U256ConvertTestProgram; -use simplicityhl_std::artifacts::u256_convert_test::derived_u256_convert_test::{ - U256ConvertTestArguments, U256ConvertTestWitness, -}; - -enum FunctionToTest { - SplitU256IntoU8, - SplitU256IntoU16, - SplitU256IntoU32, - SplitU256IntoU64, - SplitU256IntoU128, - SafeU256ToU1, - SafeU256ToU8, - SafeU256ToU16, - SafeU256ToU32, - SafeU256ToU64, - SafeU256ToU128, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U256ConvertTestProgram { - U256ConvertTestProgram::new(&U256ConvertTestArguments {}) -} - -fn build_witness(function: u8, a: [u8; 32], expected: [u8; 32]) -> U256ConvertTestWitness { - U256ConvertTestWitness { - function_index: function, - first_arg: a, - expected, - } -} - -mod u256_convert_test { - use crate::common::helper::generate_u256; - - use super::*; - - #[simplex::test] - fn u256_convert_test_u256_into_u8(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU256IntoU8), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_convert_test_u256_into_u16(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU256IntoU16), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_convert_test_u256_into_u32(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU256IntoU32), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_convert_test_u256_into_u64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU256IntoU64), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_convert_test_u256_into_u128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU256IntoU128), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_convert_test_safe_u256_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::one()); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU256ToU1), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_convert_test_safe_u256_to_u1_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::from(2), U256::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU256ToU1), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u256_convert_test_safe_u256_to_u8(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::from(u8::MAX)); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU256ToU8), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_convert_test_safe_u256_to_u8_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::from(u8::MAX) + 1, U256::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU256ToU8), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u256_convert_test_safe_u256_to_u16(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::from(u16::MAX)); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU256ToU16), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_convert_test_safe_u256_to_u16_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::from(u16::MAX) + 1, U256::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU256ToU16), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u256_convert_test_safe_u256_to_u32(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::from(u32::MAX)); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU256ToU32), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_convert_test_safe_u256_to_u32_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::from(u32::MAX) + 1, U256::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU256ToU32), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u256_convert_test_safe_u256_to_u64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::from(u64::MAX)); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU256ToU64), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_convert_test_safe_u256_to_u64_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::from(u64::MAX) + 1, U256::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU256ToU64), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u256_convert_test_safe_u256_to_u128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::from(u128::MAX)); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU256ToU128), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_convert_test_safe_u256_to_u128_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU256ToU128), - a.to_big_endian(), - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } -} diff --git a/tests/u256_mul_div_test.rs b/tests/u256_mul_div_test.rs deleted file mode 100644 index 5723c8a..0000000 --- a/tests/u256_mul_div_test.rs +++ /dev/null @@ -1,346 +0,0 @@ -mod common; - -use primitive_types::U256; -use std::cmp::max; -use std::ops::Div; - -use crate::common::core::{Expect, run}; -use crate::common::helper::generate_u256; - -use simplicityhl_std::artifacts::u256_mul_div_test::U256MulDivTestProgram; -use simplicityhl_std::artifacts::u256_mul_div_test::derived_u256_mul_div_test::{ - U256MulDivTestArguments, U256MulDivTestWitness, -}; - -const DEFAULT_EXPECTED: [u8; 32] = [0; 32]; - -enum FunctionToTest { - MulDiv, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U256MulDivTestProgram { - U256MulDivTestProgram::new(&U256MulDivTestArguments {}) -} - -fn build_witness( - op: u8, - a: [u8; 32], - b: [u8; 32], - c: [u8; 32], - expected: Option<[u8; 32]>, -) -> U256MulDivTestWitness { - U256MulDivTestWitness { - function_index: op, - first_arg: a, - second_arg: b, - third_arg: c, - expected, - } -} - -fn safe_u512_to_u256(a: [u8; 64]) -> [u8; 32] { - let high = U256::from_big_endian(&a[0..32]); - let low = U256::from_big_endian(&a[32..64]); - - assert!(high == U256::zero()); - - low.to_big_endian() -} - -mod u256_mul_div_test { - use super::*; - - #[simplex::test] - fn u256_test_mul_div_256_product_fits_into_u256( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::from(u128::MAX)); - let b = generate_u256(U256::zero(), U256::from(u128::MAX)); - let c = generate_u256(U256::one(), U256::MAX); - - let res = safe_u512_to_u256(a.full_mul(b).div(c).to_big_endian()); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::MulDiv), - a.to_big_endian(), - b.to_big_endian(), - c.to_big_endian(), - Some(res), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_div_256_intermediate_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::from(2), U256::MAX); - let b = U256::MAX; - let c = generate_u256(a, U256::MAX); - - let res = safe_u512_to_u256(a.full_mul(b).div(c).to_big_endian()); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::MulDiv), - a.to_big_endian(), - b.to_big_endian(), - c.to_big_endian(), - Some(res), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_div_256_result_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::from(2), U256::MAX); - let b = U256::MAX; - let c = generate_u256(U256::one(), a); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::MulDiv), - a.to_big_endian(), - b.to_big_endian(), - c.to_big_endian(), - Some(DEFAULT_EXPECTED), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u256_test_mul_div_256_remainder_is_zero( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); - let b = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); - let c = a; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::MulDiv), - a.to_big_endian(), - b.to_big_endian(), - c.to_big_endian(), - Some(b.to_big_endian()), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_div_256_denominator_is_u128( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::one(), U256::MAX); - let b = generate_u256(U256::one(), U256::from(u128::MAX)); - let c = generate_u256(b, U256::from(u128::MAX)); - - let res = safe_u512_to_u256(a.full_mul(b).div(c).to_big_endian()); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::MulDiv), - a.to_big_endian(), - b.to_big_endian(), - c.to_big_endian(), - Some(res), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_div_256_min_denom_high(context: simplex::TestContext) -> anyhow::Result<()> { - let pow129: U256 = U256::from(2).pow(U256::from(129)); - - let a = generate_u256(U256::from(u128::MAX) + 1, pow129); - let b = generate_u256(U256::from(u128::MAX) + 1, pow129); - let c = generate_u256(U256::from(u128::MAX) + 1, pow129 - 1); - - let res = safe_u512_to_u256(a.full_mul(b).div(c).to_big_endian()); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::MulDiv), - a.to_big_endian(), - b.to_big_endian(), - c.to_big_endian(), - Some(res), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_div_256_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::one(), U256::MAX); - let b = generate_u256(U256::one(), U256::MAX); - let c = U256::zero(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::MulDiv), - a.to_big_endian(), - b.to_big_endian(), - c.to_big_endian(), - Some([0; 32]), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_div_256_algorithm_d_512_256_check( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let pow2_128: U256 = U256::from(u128::MAX) + 1; - - let a = generate_u256(pow2_128, U256::MAX); - let b = generate_u256(pow2_128, U256::MAX - pow2_128); - - let product = a.full_mul(b); - let result_high = - U256::from_big_endian(&(safe_u512_to_u256((product >> 256).to_big_endian()))); - - let c = generate_u256(max(U256::from(u128::MAX) + 1, result_high + 1), U256::MAX); - - let res = safe_u512_to_u256(product.div(c).to_big_endian()); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::MulDiv), - a.to_big_endian(), - b.to_big_endian(), - c.to_big_endian(), - Some(res), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_div_256_algorithm_d_512_256_c_is_res_high( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let pow2_128: U256 = U256::from(u128::MAX) + 1; - - let a: U256 = generate_u256(pow2_128, U256::MAX); - let b = generate_u256(pow2_128, U256::MAX - pow2_128); - - let product = a.full_mul(b); - let result_high = - U256::from_big_endian(&(safe_u512_to_u256((product >> 256).to_big_endian()))); - - let c = result_high + 1; - - let res = safe_u512_to_u256(product.div(c).to_big_endian()); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::MulDiv), - a.to_big_endian(), - b.to_big_endian(), - c.to_big_endian(), - Some(res), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_div_256_normalize_to_threshold_512_127_norm_is_1( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let pow2_128: U256 = U256::from(u128::MAX) + 1; - - let a: U256 = generate_u256(pow2_128, U256::MAX); - let b = generate_u256(pow2_128, U256::MAX - pow2_128); - - let product = a.full_mul(b); - let result_high = - U256::from_big_endian(&(safe_u512_to_u256((product >> 256).to_big_endian()))); - - let c = generate_u256( - max(U256::from(2).pow(U256::from(255)), result_high + 1), - U256::MAX, - ); - - let res = safe_u512_to_u256(product.div(c).to_big_endian()); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::MulDiv), - a.to_big_endian(), - b.to_big_endian(), - c.to_big_endian(), - Some(res), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_div_256_normalize_to_threshold_512_127_norm_greater_than_1( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); - let b = generate_u256( - U256::from(u128::MAX) + 1, - U256::from(2).pow(U256::from(192)), - ); - - let product = a.full_mul(b); - let result_high = - U256::from_big_endian(&(safe_u512_to_u256((product >> 256).to_big_endian()))) + 1; - - let c = generate_u256( - max(U256::from(u128::MAX) + 1, result_high), - U256::from(2).pow(U256::from(255)) - 1, - ); - - let res = safe_u512_to_u256(product.div(c).to_big_endian()); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::MulDiv), - a.to_big_endian(), - b.to_big_endian(), - c.to_big_endian(), - Some(res), - ), - Expect::Ok, - ) - } -} diff --git a/tests/u256_test_add.rs b/tests/u256_test_add.rs deleted file mode 100644 index bdda2ef..0000000 --- a/tests/u256_test_add.rs +++ /dev/null @@ -1,236 +0,0 @@ -mod common; - -use primitive_types::U256; - -use crate::common::helper::{DEFAULT_BOOL, generate_u256}; -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u256_test_add::U256TestAddProgram; -use simplicityhl_std::artifacts::u256_test_add::derived_u256_test_add::{ - U256TestAddArguments, U256TestAddWitness, -}; - -enum FunctionToTest { - Add256, - Add256_128, - FullAdd256, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U256TestAddProgram { - U256TestAddProgram::new(&U256TestAddArguments {}) -} - -fn build_witness( - function: u8, - a: [u8; 32], - b: [u8; 32], - c: bool, - expected: Option<[u8; 32]>, - expected_bool: bool, -) -> U256TestAddWitness { - U256TestAddWitness { - function_index: function, - first_arg: a, - second_arg: b, - third_arg: c, - expected, - expected_bool, - } -} - -mod u256_tests_arithmetic { - use super::*; - - #[simplex::test] - fn u256_test_add_256_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX / 2); - let b = generate_u256(U256::zero(), U256::MAX / 2); - let result = (a + b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Add256), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_BOOL, - Some(result), - false, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_add_256_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = U256::MAX; - let b = generate_u256(U256::one(), U256::MAX); - let result = (b - 1).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Add256), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_BOOL, - Some(result), - true, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_add_256_128_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX / 2); - let b = generate_u256(U256::one(), U256::from(u128::MAX)); - let result = (a + b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Add256_128), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_BOOL, - Some(result), - false, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_add_256_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = U256::MAX; - let b = generate_u256(U256::one(), U256::from(u128::MAX)); - let result = (b - 1).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Add256_128), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_BOOL, - Some(result), - true, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_full_add_256_not_overflow_carry_low_false( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX / 2); - let b = generate_u256(U256::zero(), U256::MAX / 2); - - let result = (a + b).to_big_endian(); - let result_carry = false; - let carry_low = false; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FullAdd256), - a.to_big_endian(), - b.to_big_endian(), - carry_low, - Some(result), - result_carry, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_full_add_256_overflow_carry_low_false( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = U256::MAX; - let b = generate_u256(U256::one(), U256::MAX); - - let result = (b - 1).to_big_endian(); - let result_carry = true; - let carry_low = false; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FullAdd256), - a.to_big_endian(), - b.to_big_endian(), - carry_low, - Some(result), - result_carry, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_full_add_256_not_overflow_carry_low_true( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX / 2); - let b = generate_u256(U256::zero(), U256::MAX / 2); - - let result = (a + b + 1).to_big_endian(); - let result_carry = false; - let carry_low = true; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FullAdd256), - a.to_big_endian(), - b.to_big_endian(), - carry_low, - Some(result), - result_carry, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_full_add_256_overflow_carry_low_true( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = U256::MAX; - let b = generate_u256(U256::one(), U256::MAX).to_big_endian(); - - let result = b; - let result_carry = true; - let carry_low = true; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::FullAdd256), - a.to_big_endian(), - b, - carry_low, - Some(result), - result_carry, - ), - Expect::Ok, - ) - } -} diff --git a/tests/u256_test_bits.rs b/tests/u256_test_bits.rs deleted file mode 100644 index c0c78e6..0000000 --- a/tests/u256_test_bits.rs +++ /dev/null @@ -1,198 +0,0 @@ -mod common; - -use primitive_types::U256; -use rand::Rng; - -use crate::common::helper::generate_u256; -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u256_test_bits::U256TestBitsProgram; -use simplicityhl_std::artifacts::u256_test_bits::derived_u256_test_bits::{ - U256TestBitsArguments, U256TestBitsWitness, -}; - -enum FunctionToTest { - And256, - Or256, - LeftShift256, - RightShift256, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U256TestBitsProgram { - U256TestBitsProgram::new(&U256TestBitsArguments {}) -} - -fn build_witness( - function: u8, - a: [u8; 32], - b: [u8; 32], - expected: Option<[u8; 32]>, -) -> U256TestBitsWitness { - U256TestBitsWitness { - function_index: function, - first_arg: a, - second_arg: b, - expected, - } -} - -mod u256_tests_bits { - use super::*; - - #[simplex::test] - fn u256_test_and_256(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = generate_u256(U256::zero(), U256::MAX); - let result = (a & b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::And256), - a.to_big_endian(), - b.to_big_endian(), - Some(result), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_or_256(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = generate_u256(U256::zero(), U256::MAX); - let result = (a | b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Or256), - a.to_big_endian(), - b.to_big_endian(), - Some(result), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_left_shift_256(context: simplex::TestContext) -> anyhow::Result<()> { - let shift = rand::thread_rng().gen_range(1..u8::MAX); - let val = generate_u256(U256::zero(), U256::MAX); - let result = (val << shift).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::LeftShift256), - U256::from(shift).to_big_endian(), - val.to_big_endian(), - Some(result), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_left_shift_256_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let shift = 0; - let val = generate_u256(U256::zero(), U256::MAX).to_big_endian(); - let result = val; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::LeftShift256), - U256::from(shift).to_big_endian(), - val, - Some(result), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_left_shift_256_max(context: simplex::TestContext) -> anyhow::Result<()> { - let shift = u8::MAX; - let val = generate_u256(U256::zero(), U256::MAX); - let result = (val << shift).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::LeftShift256), - U256::from(shift).to_big_endian(), - val.to_big_endian(), - Some(result), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_right_shift_256(context: simplex::TestContext) -> anyhow::Result<()> { - let shift = rand::thread_rng().gen_range(1..u8::MAX); - let val = generate_u256(U256::zero(), U256::MAX); - let result = (val >> shift).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::RightShift256), - U256::from(shift).to_big_endian(), - val.to_big_endian(), - Some(result), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_right_shift_256_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let shift = 0; - let val = generate_u256(U256::zero(), U256::MAX).to_big_endian(); - let result = val; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::RightShift256), - U256::from(shift).to_big_endian(), - val, - Some(result), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_right_shift_256_max(context: simplex::TestContext) -> anyhow::Result<()> { - let shift = u8::MAX; - let val = generate_u256(U256::zero(), U256::MAX); - let result = (val >> shift).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::RightShift256), - U256::from(shift).to_big_endian(), - val.to_big_endian(), - Some(result), - ), - Expect::Ok, - ) - } -} diff --git a/tests/u256_test_compare.rs b/tests/u256_test_compare.rs deleted file mode 100644 index 560e113..0000000 --- a/tests/u256_test_compare.rs +++ /dev/null @@ -1,166 +0,0 @@ -mod common; - -use primitive_types::U256; - -use crate::common::helper::generate_u256; -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u256_test_compare::U256TestCompareProgram; -use simplicityhl_std::artifacts::u256_test_compare::derived_u256_test_compare::{ - U256TestCompareArguments, U256TestCompareWitness, -}; - -enum FunctionToTest { - IsZero256, - Lt256, - Le256, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -const DEFAULT_EXPECTED: [u8; 32] = [0; 32]; - -fn program() -> U256TestCompareProgram { - U256TestCompareProgram::new(&U256TestCompareArguments {}) -} - -fn build_witness( - function: u8, - a: [u8; 32], - b: [u8; 32], - expected_bool: bool, -) -> U256TestCompareWitness { - U256TestCompareWitness { - function_index: function, - first_arg: a, - second_arg: b, - expected_bool, - } -} - -mod u256_tests_compare { - use super::*; - - #[simplex::test] - fn u256_test_is_zero_256_true(context: simplex::TestContext) -> anyhow::Result<()> { - let a = [0; 32]; - - run( - &context, - program(), - build_witness(op(FunctionToTest::IsZero256), a, DEFAULT_EXPECTED, true), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_is_zero_256_false(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::one(), U256::MAX).to_big_endian(); - - run( - &context, - program(), - build_witness(op(FunctionToTest::IsZero256), a, DEFAULT_EXPECTED, false), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_lt_256_less(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX - 1); - let b = a + 1; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Lt256), - a.to_big_endian(), - b.to_big_endian(), - true, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_lt_256_eq(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX).to_big_endian(); - - run( - &context, - program(), - build_witness(op(FunctionToTest::Lt256), a, a, false), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_lt_256_bigger(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::one(), U256::MAX); - let b = a - 1; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Lt256), - a.to_big_endian(), - b.to_big_endian(), - false, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_le_256_less(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX - 1); - let b = a + 1; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Le256), - a.to_big_endian(), - b.to_big_endian(), - true, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_le_256_eq(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::one(), U256::MAX).to_big_endian(); - - run( - &context, - program(), - build_witness(op(FunctionToTest::Le256), a, a, true), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_le_256_bigger(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::one(), U256::MAX); - let b = a - 1; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Le256), - a.to_big_endian(), - b.to_big_endian(), - false, - ), - Expect::Ok, - ) - } -} diff --git a/tests/u256_test_div.rs b/tests/u256_test_div.rs deleted file mode 100644 index d74a0ba..0000000 --- a/tests/u256_test_div.rs +++ /dev/null @@ -1,609 +0,0 @@ -mod common; - -use primitive_types::U256; - -use crate::common::helper::generate_u256; -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u256_test_div::U256TestDivProgram; -use simplicityhl_std::artifacts::u256_test_div::derived_u256_test_div::{ - U256TestDivArguments, U256TestDivWitness, -}; - -enum FunctionToTest { - CalculateNormalizerBase128, - DivMod256_64, - AlgorithmD256_128, - DivMod256_128, - DivMod256, - Div256, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -const DEFAULT_EXPECTED: [u8; 32] = [0; 32]; - -fn program() -> U256TestDivProgram { - U256TestDivProgram::new(&U256TestDivArguments {}) -} - -fn build_witness( - function: u8, - a: [u8; 32], - b: [u8; 32], - expected: Option<[u8; 32]>, - second_expected: [u8; 32], -) -> U256TestDivWitness { - U256TestDivWitness { - function_index: function, - first_arg: a, - second_arg: b, - expected, - second_expected, - } -} - -mod u256_tests_arithmetic { - use super::*; - - #[simplex::test] - fn u256_test_calculate_normalizer_base_128( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let threshold = 1u128 << 127; - - let a = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); - let a_high = (a >> 128).as_u128(); - - let norm = threshold.div_ceil(a_high); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::CalculateNormalizerBase128), - a.to_big_endian(), - DEFAULT_EXPECTED, - Some(U256::from(norm).to_big_endian()), - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_calculate_normalizer_base_128_norm_is_1( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let threshold = 1u128 << 127; - - // a >= 2^255 keeps a_high >= 2^127, so the divisor is already normalized - let a = generate_u256(U256::from(2).pow(U256::from(255)), U256::MAX); - let a_high = (a >> 128).as_u128(); - - let norm = threshold.div_ceil(a_high); - assert_eq!(norm, 1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::CalculateNormalizerBase128), - a.to_big_endian(), - DEFAULT_EXPECTED, - Some(U256::from(norm).to_big_endian()), - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_calculate_normalizer_base_128_norm_greater_than_1( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let threshold = 1u128 << 127; - - // a < 2^255 keeps a_high < 2^127, so the divisor has to be scaled up - let a = generate_u256( - U256::from(u128::MAX) + 1, - U256::from(2).pow(U256::from(255)) - 1, - ); - let a_high = (a >> 128).as_u128(); - - let norm = threshold.div_ceil(a_high); - assert!(norm > 1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::CalculateNormalizerBase128), - a.to_big_endian(), - DEFAULT_EXPECTED, - Some(U256::from(norm).to_big_endian()), - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_calculate_normalizer_base_128_a_is_u128_fail( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let threshold = 1u128 << 127; - - let a = generate_u256(U256::one(), U256::from(threshold) - 1); - - let norm: u128 = threshold.div_ceil(a.low_u128()); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::CalculateNormalizerBase128), - a.to_big_endian(), - DEFAULT_EXPECTED, - Some(U256::from(norm).to_big_endian()), - DEFAULT_EXPECTED, - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u256_test_calculate_normalizer_base_128_b_is_zero_fail( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = [0; 32]; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::CalculateNormalizerBase128), - a, - DEFAULT_EXPECTED, - Some(DEFAULT_EXPECTED), - DEFAULT_EXPECTED, - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn test_div_mod_256_64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = generate_u256(U256::one(), U256::from(u64::MAX)); - - let q = (a / b).to_big_endian(); - let r = (a % b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256_64), - a.to_big_endian(), - b.to_big_endian(), - Some(q), - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn test_div_mod_256_64_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = [0; 32]; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256_64), - a.to_big_endian(), - b, - Some(DEFAULT_EXPECTED), - DEFAULT_EXPECTED, - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn test_algorithm_d_256_128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = generate_u256(U256::from(u64::MAX) + 1, U256::from(u128::MAX)); - - let q = (a / b).to_big_endian(); - let r = (a % b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::AlgorithmD256_128), - a.to_big_endian(), - b.to_big_endian(), - Some(q), - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn test_algorithm_d_256_128_fail_b_fits_into_u64( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = generate_u256(U256::one(), U256::from(u64::MAX)); - - let q = (a / b).to_big_endian(); - let r = (a % b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::AlgorithmD256_128), - a.to_big_endian(), - b.to_big_endian(), - Some(q), - r, - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn test_algorithm_d_256_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = [0; 32]; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::AlgorithmD256_128), - a.to_big_endian(), - b, - Some(DEFAULT_EXPECTED), - DEFAULT_EXPECTED, - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn test_algorithm_d_256_128_a_eq_b(context: simplex::TestContext) -> anyhow::Result<()> { - let a = (generate_u256(U256::one(), U256::from(u128::MAX))).to_big_endian(); - - let q = U256::one().to_big_endian(); - let r = U256::zero().to_big_endian(); - - run( - &context, - program(), - build_witness(op(FunctionToTest::AlgorithmD256_128), a, a, Some(q), r), - Expect::Ok, - ) - } - - #[simplex::test] - fn test_div_mod_256_128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = generate_u256(U256::from(u64::MAX) + 1, U256::from(u128::MAX)); - - let q = (a / b).to_big_endian(); - let r = (a % b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256_128), - a.to_big_endian(), - b.to_big_endian(), - Some(q), - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn test_div_mod_256_128_b_fits_into_u64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = generate_u256(U256::one(), U256::from(u64::MAX)); - - let q = (a / b).to_big_endian(); - let r = (a % b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256_128), - a.to_big_endian(), - b.to_big_endian(), - Some(q), - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn test_div_mod_256_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = [0; 32]; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256_128), - a.to_big_endian(), - b, - Some(DEFAULT_EXPECTED), - DEFAULT_EXPECTED, - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn test_div_mod_256_128_a_eq_b(context: simplex::TestContext) -> anyhow::Result<()> { - let a = (generate_u256(U256::one(), U256::from(u128::MAX))).to_big_endian(); - - let q = U256::one().to_big_endian(); - let r = U256::zero().to_big_endian(); - - run( - &context, - program(), - build_witness(op(FunctionToTest::DivMod256_128), a, a, Some(q), r), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_div_mod_256_a_less_than_b(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::one(), U256::MAX - 1); - let b = generate_u256(a + 1, U256::MAX); - - let q = (a / b).to_big_endian(); - let r = (a % b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256), - a.to_big_endian(), - b.to_big_endian(), - Some(q), - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_div_mod_256_div_128(context: simplex::TestContext) -> anyhow::Result<()> { - let b = generate_u256(U256::one(), U256::from(u128::MAX)); - let a = generate_u256(b, U256::from(u128::MAX)); - - let q = (a / b).to_big_endian(); - let r = (a % b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256), - a.to_big_endian(), - b.to_big_endian(), - Some(q), - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_div_mod_256_q_is_1(context: simplex::TestContext) -> anyhow::Result<()> { - // case where a >= b and a_high = b_high != 0 - let b_low = generate_u256(U256::zero(), U256::from(u128::MAX)); - let a_low = generate_u256(b_low, U256::from(u128::MAX)); - let high = generate_u256(U256::one(), U256::from(u128::MAX)); - - let a = (high << 128) | (a_low); - let b = (high << 128) | (b_low); - - let q = (a / b).to_big_endian(); - let r = (a % b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256), - a.to_big_endian(), - b.to_big_endian(), - Some(q), - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_div_mod_256_b_fits_into_u128(context: simplex::TestContext) -> anyhow::Result<()> { - let b = generate_u256(U256::one(), U256::from(u128::MAX)); - let a = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); - - let q = (a / b).to_big_endian(); - let r = (a % b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256), - a.to_big_endian(), - b.to_big_endian(), - Some(q), - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_div_mod_256_b_is_u256(context: simplex::TestContext) -> anyhow::Result<()> { - let b = generate_u256(U256::one(), U256::MAX - 1); - let a = generate_u256(b + 1, U256::MAX); - - let q = (a / b).to_big_endian(); - let r = (a % b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256), - a.to_big_endian(), - b.to_big_endian(), - Some(q), - r, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_div_mod_256_a_equal_b(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::one(), U256::MAX).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256), - a, - a, - Some(U256::one().to_big_endian()), - [0; 32], - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_div_mod_256_equal_high_words_max_low_diff( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let high = generate_u256(U256::one(), U256::from(u128::MAX)); - - let a = ((high << 128) | (U256::from(u128::MAX))).to_big_endian(); - let b = (high << 128).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256), - a, - b, - Some(U256::one().to_big_endian()), - U256::from(u128::MAX).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_div_mod_256_eq_high_words_a_less_than_b( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let high = generate_u256(U256::one(), U256::from(u128::MAX)); - - let a = (high << 128).to_big_endian(); - let b = ((high << 128) | (U256::from(u128::MAX))).to_big_endian(); - - run( - &context, - program(), - build_witness(op(FunctionToTest::DivMod256), a, b, Some([0; 32]), a), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_div_mod_256_edge_case(context: simplex::TestContext) -> anyhow::Result<()> { - let a: U256 = U256::from(2).pow(U256::from(255)); - let b = U256::from(2).pow(U256::from(127)) + U256::from(2).pow(U256::from(64)) - 1; - - let (q, r) = a.div_mod(b); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::DivMod256), - a.to_big_endian(), - b.to_big_endian(), - Some(q.to_big_endian()), - r.to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_div_256(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = generate_u256(U256::one(), U256::MAX); - let result = (a / b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Div256), - a.to_big_endian(), - b.to_big_endian(), - Some(result), - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_div_256_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = [0; 32]; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Div256), - a.to_big_endian(), - b, - Some([0; 32]), - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } -} diff --git a/tests/u256_test_sub_mul.rs b/tests/u256_test_sub_mul.rs deleted file mode 100644 index ccb3963..0000000 --- a/tests/u256_test_sub_mul.rs +++ /dev/null @@ -1,366 +0,0 @@ -mod common; - -use primitive_types::U256; -use primitive_types::U512; -use rand::Rng; - -use crate::common::helper::{DEFAULT_BOOL, generate_u256}; -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u256_test_sub_mul::U256TestSubMulProgram; -use simplicityhl_std::artifacts::u256_test_sub_mul::derived_u256_test_sub_mul::{ - U256TestSubMulArguments, U256TestSubMulWitness, -}; - -enum FunctionToTest { - Sub256, - Mul256, - Mul256_64, - Mul256_128, - Mul512_128, - SafeMul256_128, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -const DEFAULT_EXPECTED: [u8; 32] = [0; 32]; -const DEFAULT_U128: u128 = 0; - -fn program() -> U256TestSubMulProgram { - U256TestSubMulProgram::new(&U256TestSubMulArguments {}) -} - -fn build_witness( - function: u8, - a: [u8; 32], - b: [u8; 32], - c: u128, - expected: Option<[u8; 32]>, - expected_bool: bool, - second_expected: [u8; 32], - third_expected: [u8; 32], -) -> U256TestSubMulWitness { - U256TestSubMulWitness { - function_index: function, - first_arg: a, - second_arg: b, - third_arg: c, - expected, - expected_bool, - second_expected, - third_expected, - } -} - -fn split_u512(a: [u8; 64]) -> ([u8; 32], [u8; 32]) { - let high = U256::from_big_endian(&a[0..32]); - let low = U256::from_big_endian(&a[32..64]); - - (high.to_big_endian(), low.to_big_endian()) -} - -mod u256_tests_arithmetic { - use super::*; - - #[simplex::test] - fn u256_test_sub_256_not_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b = generate_u256(U256::zero(), a); - let result = (a - b).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Sub256), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_U128, - Some(result), - false, - DEFAULT_EXPECTED, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_sub_256_a_eq_b(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Sub256), - a, - a, - DEFAULT_U128, - Some([0; 32]), - false, - DEFAULT_EXPECTED, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_sub_256_a_low_eq_b_low(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::MAX); - let b_high = rand::thread_rng().gen_range(0..=u128::MAX); - - let low: u128 = a.low_u128(); - let b = (U256::from(b_high) << 128) | U256::from(low); - - let (result, carry) = a.overflowing_sub(b); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Sub256), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_U128, - Some(result.to_big_endian()), - carry, - DEFAULT_EXPECTED, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_sub_256_diff_is_u128_max(context: simplex::TestContext) -> anyhow::Result<()> { - let a_low: u128 = u128::MAX; - - let a_high = rand::thread_rng().gen_range(0..=u128::MAX); - let b_high = rand::thread_rng().gen_range(0..=u128::MAX); - - let a = (U256::from(a_high) << 128) | U256::from(a_low); - let b = (U256::from(b_high)) << 128; // b_low is 0 - - let (result, carry) = a.overflowing_sub(b); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Sub256), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_U128, - Some(result.to_big_endian()), - carry, - DEFAULT_EXPECTED, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_sub_256_diff_is_u256_max(context: simplex::TestContext) -> anyhow::Result<()> { - let a = U256::MAX.to_big_endian(); - let b = U256::zero(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Sub256), - a, - b.to_big_endian(), - DEFAULT_U128, - Some(a), - false, - DEFAULT_EXPECTED, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_sub_256_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::one(), U256::MAX - 1); - let b = U256::MAX; - let result = a + 1; - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Sub256), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_U128, - Some(result.to_big_endian()), - true, - DEFAULT_EXPECTED, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_256(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::one(), U256::MAX); - let b = generate_u256(U256::one(), U256::MAX); - let result = a.full_mul(b).to_big_endian(); - - let (result_high, result_low) = split_u512(result); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Mul256), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_U128, - Some(result_high), - DEFAULT_BOOL, - result_low, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_256_64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::one(), U256::MAX); - let b = generate_u256(U256::one(), U256::from(u64::MAX)); - let result = a.full_mul(b).to_big_endian(); - - let (result_high, result_low) = split_u512(result); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Mul256_64), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_U128, - Some(result_high), - DEFAULT_BOOL, - result_low, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_256_128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::one(), U256::MAX); - let b = generate_u256(U256::one(), U256::from(u128::MAX)); - let result = a.full_mul(b).to_big_endian(); - - let (result_high, result_low) = split_u512(result); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Mul256_128), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_U128, - Some(result_high), - DEFAULT_BOOL, - result_low, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_mul_512_128(context: simplex::TestContext) -> anyhow::Result<()> { - let a_1 = generate_u256(U256::one(), U256::MAX); - let a_0 = generate_u256(U256::one(), U256::MAX); - let b = rand::thread_rng().gen_range(1..=u128::MAX); - - let result_low = U512::from(a_0) * U512::from(b); - let result_high = U512::from(a_1) * U512::from(b); - - let (res_1, res_0) = split_u512(result_low.to_big_endian()); - let (res_3, res_2) = split_u512(result_high.to_big_endian()); - - let res_2_1 = U512::from_big_endian(&res_1) + U512::from_big_endian(&res_2); - let (res_3_1, res_2_1) = split_u512(res_2_1.to_big_endian()); - - let res_3_final = - (U256::from_big_endian(&res_3_1) + U256::from_big_endian(&res_3)).to_big_endian(); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::Mul512_128), - a_1.to_big_endian(), - a_0.to_big_endian(), - b, - Some(res_3_final), - DEFAULT_BOOL, - res_2_1, - res_0, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_safe_mul_256_128_fitting(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::zero(), U256::from(u128::MAX)); - let b = generate_u256(U256::zero(), U256::from(u128::MAX)); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeMul256_128), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_U128, - Some((a * b).to_big_endian()), - DEFAULT_BOOL, - DEFAULT_EXPECTED, - DEFAULT_EXPECTED, - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u256_test_safe_mul_256_128_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = generate_u256(U256::from(u128::MAX) + 1, U256::MAX); - let b = U256::from(u128::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeMul256_128), - a.to_big_endian(), - b.to_big_endian(), - DEFAULT_U128, - Some(DEFAULT_EXPECTED), - DEFAULT_BOOL, - DEFAULT_EXPECTED, - DEFAULT_EXPECTED, - ), - Expect::AssertFailed, - ) - } -} diff --git a/tests/u32_convert_test.rs b/tests/u32_convert_test.rs deleted file mode 100644 index e7874f0..0000000 --- a/tests/u32_convert_test.rs +++ /dev/null @@ -1,225 +0,0 @@ -mod common; - -use primitive_types::U256; -use rand::Rng; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u32_convert_test::U32ConvertTestProgram; -use simplicityhl_std::artifacts::u32_convert_test::derived_u32_convert_test::{ - U32ConvertTestArguments, U32ConvertTestWitness, -}; - -enum FunctionToTest { - U32ToU64, - U32ToU128, - U32ToU256, - SplitU32IntoU8, - SplitU32IntoU16, - SafeU32ToU1, - SafeU32ToU8, - SafeU32ToU16, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U32ConvertTestProgram { - U32ConvertTestProgram::new(&U32ConvertTestArguments {}) -} - -fn build_witness(function: u8, a: u32, expected: [u8; 32]) -> U32ConvertTestWitness { - U32ConvertTestWitness { - function_index: function, - first_arg: a, - expected, - } -} - -mod u32_convert_test { - use super::*; - - #[simplex::test] - fn u32_convert_test_u32_to_u64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u32::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U32ToU64), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u32_convert_test_u32_to_u128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u32::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U32ToU128), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u32_convert_test_u32_to_u256(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u32::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U32ToU256), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u32_convert_test_split_u32_into_u8(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u32::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU32IntoU8), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u32_convert_test_split_u32_into_u16(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u32::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU32IntoU16), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u32_convert_test_safe_u32_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU32ToU1), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u32_convert_test_safe_u32_to_u1_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u32::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU32ToU1), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u32_convert_test_safe_u32_to_u8(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u8::MAX as u32); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU32ToU8), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u32_convert_test_safe_u32_to_u8_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(u8::MAX as u32 + 1..=u32::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU32ToU8), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u32_convert_test_safe_u32_to_u16(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u16::MAX as u32); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU32ToU16), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u32_convert_test_safe_u32_to_u16_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(u16::MAX as u32 + 1..=u32::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU32ToU16), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } -} diff --git a/tests/u32_mul_div_test.rs b/tests/u32_mul_div_test.rs deleted file mode 100644 index 2487f08..0000000 --- a/tests/u32_mul_div_test.rs +++ /dev/null @@ -1,100 +0,0 @@ -mod common; - -use crate::common::core::{Expect, run}; -use rand::Rng; - -use simplicityhl_std::artifacts::u32_mul_div_test::U32MulDivTestProgram; -use simplicityhl_std::artifacts::u32_mul_div_test::derived_u32_mul_div_test::{ - U32MulDivTestArguments, U32MulDivTestWitness, -}; - -const DEFAULT_EXPECTED: u32 = 0; - -enum FunctionToTest { - MulDiv, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U32MulDivTestProgram { - U32MulDivTestProgram::new(&U32MulDivTestArguments {}) -} - -fn build_witness(op: u8, a: u32, b: u32, c: u32, expected: Option) -> U32MulDivTestWitness { - U32MulDivTestWitness { - function_index: op, - first_arg: a, - second_arg: b, - third_arg: c, - expected, - } -} - -mod u32_mul_div_test { - use super::*; - - #[simplex::test] - fn u32_test_mul_div_32_product_is_u32(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u16::MAX) as u32; - let b = rand::thread_rng().gen_range(0..=u16::MAX) as u32; - let c = rand::thread_rng().gen_range(1..=u32::MAX); - - let res = a * b / c; - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(res)), - Expect::Ok, - ) - } - - #[simplex::test] - fn u32_test_mul_div_32_intermediate_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u32::MAX); - let b = u32::MAX; - let c = rand::thread_rng().gen_range(a..=u32::MAX); - - let res = (a as u64) * (b as u64) / (c as u64); - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(res as u32)), - Expect::Ok, - ) - } - - #[simplex::test] - fn u32_test_mul_div_32_result_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u32::MAX); - let b = u32::MAX; - let c = rand::thread_rng().gen_range(1..a); - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(DEFAULT_EXPECTED)), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u32_test_mul_div_32_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(1..=u32::MAX); - let b = rand::thread_rng().gen_range(1..=u32::MAX); - let c = 0; - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(0)), - Expect::Ok, - ) - } -} diff --git a/tests/u64_convert_test.rs b/tests/u64_convert_test.rs deleted file mode 100644 index 050faaa..0000000 --- a/tests/u64_convert_test.rs +++ /dev/null @@ -1,260 +0,0 @@ -mod common; - -use primitive_types::U256; -use rand::Rng; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u64_convert_test::U64ConvertTestProgram; -use simplicityhl_std::artifacts::u64_convert_test::derived_u64_convert_test::{ - U64ConvertTestArguments, U64ConvertTestWitness, -}; - -enum FunctionToTest { - U64ToU128, - U64ToU256, - SplitU64IntoU8, - SplitU64IntoU16, - SplitU64IntoU32, - SafeU64ToU1, - SafeU64ToU8, - SafeU64ToU16, - SafeU64ToU32, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U64ConvertTestProgram { - U64ConvertTestProgram::new(&U64ConvertTestArguments {}) -} - -fn build_witness(function: u8, a: u64, expected: [u8; 32]) -> U64ConvertTestWitness { - U64ConvertTestWitness { - function_index: function, - first_arg: a, - expected, - } -} - -mod u64_convert_test { - use super::*; - - #[simplex::test] - fn u64_convert_test_u64_to_u128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u64::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U64ToU128), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u64_convert_test_u64_to_u256(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u64::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U64ToU256), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u64_convert_test_split_u64_into_u8(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u64::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU64IntoU8), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u64_convert_test_split_u64_into_u16(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u64::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU64IntoU16), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u64_convert_test_split_u64_into_u32(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u64::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU64IntoU32), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u64_convert_test_safe_u64_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU64ToU1), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u64_convert_test_safe_u64_to_u1_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u64::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU64ToU1), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u64_convert_test_safe_u64_to_u8(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u8::MAX as u64); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU64ToU8), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u64_convert_test_safe_u64_to_u8_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(u8::MAX as u64 + 1..=u64::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU64ToU8), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u64_convert_test_safe_u64_to_u16(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u16::MAX as u64); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU64ToU16), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u64_convert_test_safe_u64_to_u16_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(u16::MAX as u64 + 1..=u64::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU64ToU16), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u64_convert_test_safe_u64_to_u32(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u32::MAX as u64); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU64ToU32), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u64_convert_test_safe_u64_to_u32_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(u32::MAX as u64 + 1..=u64::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU64ToU32), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } -} diff --git a/tests/u64_mul_div_test.rs b/tests/u64_mul_div_test.rs deleted file mode 100644 index bbd17d3..0000000 --- a/tests/u64_mul_div_test.rs +++ /dev/null @@ -1,100 +0,0 @@ -mod common; - -use crate::common::core::{Expect, run}; -use rand::Rng; - -use simplicityhl_std::artifacts::u64_mul_div_test::U64MulDivTestProgram; -use simplicityhl_std::artifacts::u64_mul_div_test::derived_u64_mul_div_test::{ - U64MulDivTestArguments, U64MulDivTestWitness, -}; - -const DEFAULT_EXPECTED: u64 = 0; - -enum FunctionToTest { - MulDiv, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U64MulDivTestProgram { - U64MulDivTestProgram::new(&U64MulDivTestArguments {}) -} - -fn build_witness(op: u8, a: u64, b: u64, c: u64, expected: Option) -> U64MulDivTestWitness { - U64MulDivTestWitness { - function_index: op, - first_arg: a, - second_arg: b, - third_arg: c, - expected, - } -} - -mod u64_mul_div_test { - use super::*; - - #[simplex::test] - fn u64_test_mul_div_64_product_is_u64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u32::MAX) as u64; - let b = rand::thread_rng().gen_range(0..=u32::MAX) as u64; - let c = rand::thread_rng().gen_range(1..=u64::MAX); - - let res = a * b / c; - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(res)), - Expect::Ok, - ) - } - - #[simplex::test] - fn u64_test_mul_div_64_intermediate_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u64::MAX); - let b = u64::MAX; - let c = rand::thread_rng().gen_range(a..=u64::MAX); - - let res = (a as u128) * (b as u128) / (c as u128); - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(res as u64)), - Expect::Ok, - ) - } - - #[simplex::test] - fn u64_test_mul_div_64_result_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u64::MAX); - let b = u64::MAX; - let c = rand::thread_rng().gen_range(1..a); - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(DEFAULT_EXPECTED)), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u64_test_mul_div_64_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(1..=u64::MAX); - let b = rand::thread_rng().gen_range(1..=u64::MAX); - let c = 0; - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(0)), - Expect::Ok, - ) - } -} diff --git a/tests/u8_convert_test.rs b/tests/u8_convert_test.rs deleted file mode 100644 index c44ecd0..0000000 --- a/tests/u8_convert_test.rs +++ /dev/null @@ -1,170 +0,0 @@ -mod common; - -use primitive_types::U256; -use rand::Rng; - -use common::core::{Expect, run}; - -use simplicityhl_std::artifacts::u8_convert_test::U8ConvertTestProgram; -use simplicityhl_std::artifacts::u8_convert_test::derived_u8_convert_test::{ - U8ConvertTestArguments, U8ConvertTestWitness, -}; - -enum FunctionToTest { - U8ToU16, - U8ToU32, - U8ToU64, - U8ToU128, - U8ToU256, - SplitU8IntoU1, - SafeU8ToU1, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U8ConvertTestProgram { - U8ConvertTestProgram::new(&U8ConvertTestArguments {}) -} - -fn build_witness(function: u8, a: u8, expected: [u8; 32]) -> U8ConvertTestWitness { - U8ConvertTestWitness { - function_index: function, - first_arg: a, - expected, - } -} - -mod u8_convert_test { - use super::*; - - #[simplex::test] - fn u8_convert_test_u8_to_u16(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u8::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U8ToU16), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u8_convert_test_u8_to_u32(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u8::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U8ToU32), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u8_convert_test_u8_to_u64(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u8::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U8ToU64), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u8_convert_test_u8_to_u128(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u8::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U8ToU128), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u8_convert_test_u8_to_u256(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u8::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::U8ToU256), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u8_convert_test_split_u8_into_u1(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=u8::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SplitU8IntoU1), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u8_convert_test_safe_u8_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(0..=1); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU8ToU1), - a, - U256::from(a).to_big_endian(), - ), - Expect::Ok, - ) - } - - #[simplex::test] - fn u8_convert_test_safe_u8_to_u1_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u8::MAX); - - run( - &context, - program(), - build_witness( - op(FunctionToTest::SafeU8ToU1), - a, - U256::from(a).to_big_endian(), - ), - Expect::AssertFailed, - ) - } -} diff --git a/tests/u8_mul_div_test.rs b/tests/u8_mul_div_test.rs deleted file mode 100644 index f18e46a..0000000 --- a/tests/u8_mul_div_test.rs +++ /dev/null @@ -1,100 +0,0 @@ -mod common; - -use crate::common::core::{Expect, run}; -use rand::Rng; - -use simplicityhl_std::artifacts::u8_mul_div_test::U8MulDivTestProgram; -use simplicityhl_std::artifacts::u8_mul_div_test::derived_u8_mul_div_test::{ - U8MulDivTestArguments, U8MulDivTestWitness, -}; - -const DEFAULT_EXPECTED: u8 = 0; - -enum FunctionToTest { - MulDiv, -} - -#[inline] -fn op(o: FunctionToTest) -> u8 { - o as u8 -} - -fn program() -> U8MulDivTestProgram { - U8MulDivTestProgram::new(&U8MulDivTestArguments {}) -} - -fn build_witness(op: u8, a: u8, b: u8, c: u8, expected: Option) -> U8MulDivTestWitness { - U8MulDivTestWitness { - function_index: op, - first_arg: a, - second_arg: b, - third_arg: c, - expected, - } -} - -mod u8_mul_div_test { - use super::*; - - #[simplex::test] - fn u8_test_mul_div_8_product_is_u8(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(1..=u8::MAX); - let b = u8::MAX / a; - let c = rand::thread_rng().gen_range(1..=u8::MAX); - - let res = a * b / c; - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(res)), - Expect::Ok, - ) - } - - #[simplex::test] - fn u8_test_mul_div_8_intermediate_overflow( - context: simplex::TestContext, - ) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u8::MAX); - let b = u8::MAX; - let c = rand::thread_rng().gen_range(a..=u8::MAX); - - let res = (a as u16) * (b as u16) / (c as u16); - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(res as u8)), - Expect::Ok, - ) - } - - #[simplex::test] - fn u8_test_mul_div_8_result_overflow(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(2..=u8::MAX); - let b = u8::MAX; - let c = rand::thread_rng().gen_range(1..a); - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(DEFAULT_EXPECTED)), - Expect::AssertFailed, - ) - } - - #[simplex::test] - fn u8_test_mul_div_8_div_by_zero(context: simplex::TestContext) -> anyhow::Result<()> { - let a = rand::thread_rng().gen_range(1..=u8::MAX); - let b = rand::thread_rng().gen_range(1..=u8::MAX); - let c = 0; - - run( - &context, - program(), - build_witness(op(FunctionToTest::MulDiv), a, b, c, Some(0)), - Expect::Ok, - ) - } -}