From 8393f304fd8b5c2b93c7dbd97e80d089265e8110 Mon Sep 17 00:00:00 2001 From: aritkulova Date: Mon, 3 Aug 2026 20:22:10 +0300 Subject: [PATCH 1/8] added convert functions for u8 --- simf/lib/u8/convert.simf | 63 ++++++++++++ simf/lib/{u8.simf => u8/math.simf} | 77 +++++++++++---- simf/u8_convert_test.simf | 57 +++++++++++ simf/{u8_test.simf => u8_math_test.simf} | 43 +++++--- tests/u8_convert_test.rs | 120 +++++++++++++++++++++++ tests/{u8_test.rs => u8_math_tests.rs} | 20 ++-- 6 files changed, 341 insertions(+), 39 deletions(-) create mode 100644 simf/lib/u8/convert.simf rename simf/lib/{u8.simf => u8/math.simf} (60%) create mode 100644 simf/u8_convert_test.simf rename simf/{u8_test.simf => u8_math_test.simf} (63%) create mode 100644 tests/u8_convert_test.rs rename tests/{u8_test.rs => u8_math_tests.rs} (59%) diff --git a/simf/lib/u8/convert.simf b/simf/lib/u8/convert.simf new file mode 100644 index 0000000..6530b65 --- /dev/null +++ b/simf/lib/u8/convert.simf @@ -0,0 +1,63 @@ +/// Widening uint conversions + +/// Converts u8 to u16 +pub fn u8_to_u16(a: u8) -> u16 { + <(u8, u8)>::into((0, a)) +} + +/// Converts u8 to u32 +pub fn u8_to_u32(a: u8) -> u32 { + <(u8, u8, u8, u8)>::into((0, 0, 0, a)) +} + +/// Converts u8 to u64 +pub fn u8_to_u64(a: u8) -> u64 { + <(u8, u8, u8, u8, u8, u8, u8, u8)>::into((0, 0, 0, 0, 0, 0, 0, a)) +} + +/// Converts u8 to u128 +pub fn u8_to_u128(a: u8) -> u128 { + <(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8)>::into( + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a) + ) +} + +/// Converts u8 to u256 +pub fn u8_to_u256(a: u8) -> u256 { + <(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8)>::into( + ( + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + a + ) + ) +} diff --git a/simf/lib/u8.simf b/simf/lib/u8/math.simf similarity index 60% rename from simf/lib/u8.simf rename to simf/lib/u8/math.simf index 9d50464..67de3f8 100644 --- a/simf/lib/u8.simf +++ b/simf/lib/u8/math.simf @@ -1,60 +1,100 @@ /// Returns the sum of two u8 values wrapped in Some, or None if the result overflows u8 -pub fn checked_add_8(a: u8, b: u8) -> Option { +pub fn checked_add_8( + a: u8, + b: u8 +) -> Option { let (carry, sum): (bool, u8) = jet::add_8(a, b); match carry { - true => None, - false => Some(sum), + false => { + Some(sum) + }, + true => { + None + } } } /// Returns the sum of two u8 values, panics if the result overflows u8 -pub fn safe_add_8(a: u8, b: u8) -> u8 { +pub fn safe_add_8( + a: u8, + b: u8 +) -> u8 { unwrap(checked_add_8(a, b)) } /// Returns the difference of two u8 values wrapped in Some, or None if the result overflows u8 -pub fn checked_sub_8(a: u8, b: u8) -> Option { +pub fn checked_sub_8( + a: u8, + b: u8 +) -> Option { let (borrow, diff): (bool, u8) = jet::subtract_8(a, b); match borrow { - true => None, - false => Some(diff), + false => { + Some(diff) + }, + true => { + None + } } } /// Returns the difference of two u8 values, panics if the result overflows u8 -pub fn safe_sub_8(a: u8, b: u8) -> u8 { +pub fn safe_sub_8( + a: u8, + b: u8 +) -> u8 { unwrap(checked_sub_8(a, b)) } /// Returns the product of two u8 values wrapped in Some, or None if the result overflows u8 -pub fn checked_mul_8(a: u8, b: u8) -> Option { +pub fn checked_mul_8( + a: u8, + b: u8 +) -> Option { let result: u16 = jet::multiply_8(a, b); let (high, low): (u8, u8) = ::into(result); match jet::is_zero_8(high) { - true => Some(low), - false => None, + false => { + None + }, + true => { + Some(low) + } } } /// Returns the product of two u8 values, panics if the result overflows u8 -pub fn safe_mul_8(a: u8, b: u8) -> u8 { +pub fn safe_mul_8( + a: u8, + b: u8 +) -> u8 { unwrap(checked_mul_8(a, b)) } /// Returns the quotient of two u8 values wrapped in Some, or None if the result overflows u8 -pub fn checked_div_8(a: u8, b: u8) -> Option { +pub fn checked_div_8( + a: u8, + b: u8 +) -> Option { match jet::is_zero_8(b) { - true => None, - false => Some(jet::divide_8(a, b)), + false => { + Some(jet::divide_8(a, b)) + }, + true => { + None + } } } /// Returns the quotient of two u8 values, panics if the result overflows u8 -pub fn safe_div_8(a: u8, b: u8) -> u8 { +pub fn safe_div_8( + a: u8, + b: u8 +) -> u8 { unwrap(checked_div_8(a, b)) } @@ -64,6 +104,9 @@ pub fn gt_8(a: u8, b: u8) -> bool { } /// Check if an integer is greater than or equal to another integer -pub fn ge_8(a: u8, b: u8) -> bool { +pub fn ge_8( + a: u8, + b: u8 +) -> bool { jet::le_8(b, a) } diff --git a/simf/u8_convert_test.simf b/simf/u8_convert_test.simf new file mode 100644 index 0000000..8107d32 --- /dev/null +++ b/simf/u8_convert_test.simf @@ -0,0 +1,57 @@ +use crate::lib::u8::convert::{u8_to_u16, u8_to_u32, u8_to_u64, u8_to_u128, u8_to_u256}; +use crate::lib::u256::{split_256_into_64, eq_256}; +use crate::lib::u128::eq_128; +use crate::helper::if_test_this_function; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u8 = witness::FIRST_ARG; + + let expected: u256 = witness::EXPECTED; + + match if_test_this_function(0, fn_idx) { + false => {}, + true => { + let (_, _, _, expected): (u64, u64, u64, u64) = split_256_into_64(expected); + let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); + + assert!(jet::eq_16(u8_to_u16(a), expected)); + } + }; + + match if_test_this_function(1, fn_idx) { + false => {}, + true => { + let (_, _, _, expected): (u64, u64, u64, u64) = split_256_into_64(expected); + let (_, expected): (u32, u32) = ::into(expected); + + assert!(jet::eq_32(u8_to_u32(a), expected)); + } + }; + + match if_test_this_function(2, fn_idx) { + false => {}, + true => { + let (_, _, _, expected): (u64, u64, u64, u64) = split_256_into_64(expected); + + assert!(jet::eq_64(u8_to_u64(a), expected)); + } + }; + + match if_test_this_function(3, fn_idx) { + false => {}, + true => { + let (_, expected): (u128, u128) = ::into(expected); + + assert!(eq_128(u8_to_u128(a), expected)); + } + }; + + match if_test_this_function(4, fn_idx) { + false => {}, + true => { + assert!(eq_256(u8_to_u256(a), expected)); + } + }; +} diff --git a/simf/u8_test.simf b/simf/u8_math_test.simf similarity index 63% rename from simf/u8_test.simf rename to simf/u8_math_test.simf index 37e8d32..02ee705 100644 --- a/simf/u8_test.simf +++ b/simf/u8_math_test.simf @@ -1,4 +1,15 @@ -use crate::lib::u8::{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::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; @@ -6,7 +17,10 @@ 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) { +fn assert_eq_opt( + result: Option, + expected: Option +) { match expected { None => assert_none_8(result), Some(e: u8) => assert_eq_8(unwrap(result), e), @@ -15,7 +29,10 @@ fn assert_eq_opt(result: Option, expected: Option) { /// Asserts a result equals the expected bool value. /// `None` encodes `false`, and `Some(_)` encodes `true`. -fn assert_bool_by_opt(result: bool, expected: Option) { +fn assert_bool_by_opt( + result: bool, + expected: Option +) { match expected { Some(_: u8) => assert!(result), None => assert!(not(result)), @@ -30,22 +47,22 @@ fn main() { 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 => (), }; + 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 => (), }; + 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 => (), }; + 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 => (), }; + 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 => (), }; + 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/u8_convert_test.rs b/tests/u8_convert_test.rs new file mode 100644 index 0000000..78e1763 --- /dev/null +++ b/tests/u8_convert_test.rs @@ -0,0 +1,120 @@ +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, +} + +#[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, + ) + } +} diff --git a/tests/u8_test.rs b/tests/u8_math_tests.rs similarity index 59% rename from tests/u8_test.rs rename to tests/u8_math_tests.rs index 90bfaff..2d5c120 100644 --- a/tests/u8_test.rs +++ b/tests/u8_math_tests.rs @@ -2,13 +2,15 @@ mod common; use common::uint::TestUint; -use simplicityhl_std::artifacts::u8_test::U8TestProgram; -use simplicityhl_std::artifacts::u8_test::derived_u8_test::{U8TestArguments, U8TestWitness}; +use simplicityhl_std::artifacts::u8_math_test::U8MathTestProgram; +use simplicityhl_std::artifacts::u8_math_test::derived_u8_math_test::{ + U8MathTestArguments, U8MathTestWitness, +}; // The only per-width code for the common operations. impl TestUint for u8 { - type Program = U8TestProgram; - type Witness = U8TestWitness; + type Program = U8MathTestProgram; + type Witness = U8MathTestWitness; const ZERO: u8 = 0; const ONE: u8 = 1; @@ -16,12 +18,12 @@ impl TestUint for u8 { const HALF_MAX: u8 = u8::MAX / 2; const MUL_BOUND: u8 = 1 << 4; // 2^(8/2) - fn program() -> U8TestProgram { - U8TestProgram::new(U8TestArguments {}) + fn program() -> U8MathTestProgram { + U8MathTestProgram::new(U8MathTestArguments {}) } - fn witness(op: u8, a: u8, b: u8, expected: Option) -> U8TestWitness { - U8TestWitness { + fn witness(op: u8, a: u8, b: u8, expected: Option) -> U8MathTestWitness { + U8MathTestWitness { function_index: op, first_arg: a, second_arg: b, @@ -30,7 +32,7 @@ impl TestUint for u8 { } } -mod u8_tests { +mod u8_math_tests { use super::*; // Stamps the 16 `#[simplex::test]` entry points for u8. Logic lives in common::uint. From 730f6f67e7ca5b088ce4ac14d2b40272d0da0b71 Mon Sep 17 00:00:00 2001 From: aritkulova Date: Mon, 3 Aug 2026 21:57:05 +0300 Subject: [PATCH 2/8] commented out eq_256 (will be available with pr#30) --- simf/u8_convert_test.simf | 30 +++++++++++++++++++----------- tests/u8_convert_test.rs | 34 ++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/simf/u8_convert_test.simf b/simf/u8_convert_test.simf index 8107d32..6fa1d22 100644 --- a/simf/u8_convert_test.simf +++ b/simf/u8_convert_test.simf @@ -1,5 +1,11 @@ -use crate::lib::u8::convert::{u8_to_u16, u8_to_u32, u8_to_u64, u8_to_u128, u8_to_u256}; -use crate::lib::u256::{split_256_into_64, eq_256}; +use crate::lib::u8::convert::{ + u8_to_u16, + u8_to_u32, + u8_to_u64, + u8_to_u128, + u8_to_u256 +}; +// use crate::lib::u256::{split_256_into_64, eq_256}; TODO: uncomment when u256 functions are merged use crate::lib::u128::eq_128; use crate::helper::if_test_this_function; @@ -13,7 +19,7 @@ fn main() { match if_test_this_function(0, fn_idx) { false => {}, true => { - let (_, _, _, expected): (u64, u64, u64, u64) = split_256_into_64(expected); + let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); assert!(jet::eq_16(u8_to_u16(a), expected)); @@ -23,7 +29,7 @@ fn main() { match if_test_this_function(1, fn_idx) { false => {}, true => { - let (_, _, _, expected): (u64, u64, u64, u64) = split_256_into_64(expected); + let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, expected): (u32, u32) = ::into(expected); assert!(jet::eq_32(u8_to_u32(a), expected)); @@ -33,7 +39,7 @@ fn main() { match if_test_this_function(2, fn_idx) { false => {}, true => { - let (_, _, _, expected): (u64, u64, u64, u64) = split_256_into_64(expected); + let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); assert!(jet::eq_64(u8_to_u64(a), expected)); } @@ -48,10 +54,12 @@ fn main() { } }; - match if_test_this_function(4, fn_idx) { - false => {}, - true => { - assert!(eq_256(u8_to_u256(a), expected)); - } - }; + // TODO: uncomment when u256 functions are merged + + // match if_test_this_function(4, fn_idx) { + // false => {}, + // true => { + // assert!(eq_256(u8_to_u256(a), expected)); + // } + // }; } diff --git a/tests/u8_convert_test.rs b/tests/u8_convert_test.rs index 78e1763..89a2af0 100644 --- a/tests/u8_convert_test.rs +++ b/tests/u8_convert_test.rs @@ -15,7 +15,7 @@ enum FunctionToTest { U8ToU32, U8ToU64, U8ToU128, - U8ToU256, + // U8ToU256, TODO: uncomment when u256 functions are merged } #[inline] @@ -102,19 +102,21 @@ mod u8_convert_test { ) } - #[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, - ) - } + // TODO: uncomment when u256 functions are merged + + // #[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, + // ) + // } } From 2d432baa6edffc8ca72eda1d1485a82dcbf0c223 Mon Sep 17 00:00:00 2001 From: aritkulova Date: Tue, 4 Aug 2026 16:50:11 +0300 Subject: [PATCH 3/8] added split and safe_convert functions --- simf/lib/u8/convert.simf | 31 ++++++++++++++- simf/u8_convert_test.simf | 79 +++++++++++++++++++++++++++++++----- tests/u8_convert_test.rs | 84 ++++++++++++++++++++++++++++++--------- 3 files changed, 166 insertions(+), 28 deletions(-) diff --git a/simf/lib/u8/convert.simf b/simf/lib/u8/convert.simf index 6530b65..f7f3b3c 100644 --- a/simf/lib/u8/convert.simf +++ b/simf/lib/u8/convert.simf @@ -1,7 +1,11 @@ +use crate::lib::asserts::assert_eq_8; + /// Widening uint conversions /// Converts u8 to u16 -pub fn u8_to_u16(a: u8) -> u16 { +pub fn u8_to_u16( + a: u8 +) -> u16 { <(u8, u8)>::into((0, a)) } @@ -61,3 +65,28 @@ pub fn u8_to_u256(a: u8) -> u256 { ) ) } + +/// Splitting uint conversions + +/// Splits u8 into eight u1 +pub fn split_u8_to_u1( + a: u8 +) -> (u1, u1, u1, u1, u1, u1, u1, u1) { + ::into(a) +} + +/// Narrowing uint conversions + +/// Converts u8 into u1. +/// Panics if the value does not fit in u1 +pub fn safe_u8_to_u1( + a: u8 +) -> u1 { + let (_, _, _, _, _, _, _, a_u1): (u1, u1, u1, u1, u1, u1, u1, u1) = split_u8_to_u1(a); + + let a_recovered: u8 = <(u1, u1, u1, u1, u1, u1, u1, u1)>::into((0, 0, 0, 0, 0, 0, 0, a_u1)); + + assert_eq_8(a, a_recovered); + + a_u1 +} diff --git a/simf/u8_convert_test.simf b/simf/u8_convert_test.simf index 6fa1d22..ae85425 100644 --- a/simf/u8_convert_test.simf +++ b/simf/u8_convert_test.simf @@ -3,10 +3,13 @@ use crate::lib::u8::convert::{ u8_to_u32, u8_to_u64, u8_to_u128, - u8_to_u256 + u8_to_u256, + split_u8_to_u1, + safe_u8_to_u1 }; -// use crate::lib::u256::{split_256_into_64, eq_256}; TODO: uncomment when u256 functions are merged +// use crate::lib::u256::{split_256_into_64}; TODO: uncomment when u256 functions are merged use crate::lib::u128::eq_128; +use crate::lib::asserts::assert_eq_1; use crate::helper::if_test_this_function; fn main() { @@ -54,12 +57,70 @@ fn main() { } }; - // TODO: uncomment when u256 functions are merged + match if_test_this_function(4, fn_idx) { + false => {}, + true => { + assert!(jet::eq_256(u8_to_u256(a), expected)); + } + }; + + match if_test_this_function(5, fn_idx) { + false => {}, + true => { + let ( + a7, + a6, + a5, + a4, + a3, + a2, + a1, + a0 + ): (u1, u1, u1, u1, u1, u1, u1, u1) = split_u8_to_u1(a); + + let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); + let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); + let (_, expected): (u8, u8) = ::into(expected); + let ( + expected7, + expected6, + expected5, + expected4, + expected3, + expected2, + expected1, + expected0 + ): (u1, u1, u1, u1, u1, u1, u1, u1) = ::into(a); - // match if_test_this_function(4, fn_idx) { - // false => {}, - // true => { - // assert!(eq_256(u8_to_u256(a), expected)); - // } - // }; + assert_eq_1(a7, expected7); + assert_eq_1(a6, expected6); + assert_eq_1(a5, expected5); + assert_eq_1(a4, expected4); + assert_eq_1(a3, expected3); + assert_eq_1(a2, expected2); + assert_eq_1(a1, expected1); + assert_eq_1(a0, expected0); + } + }; + + match if_test_this_function(6, fn_idx) { + false => {}, + true => { + let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); + let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); + let (_, expected): (u8, u8) = ::into(expected); + let ( + _, + _, + _, + _, + _, + _, + _, + expected + ): (u1, u1, u1, u1, u1, u1, u1, u1) = ::into(expected); + + assert_eq_1(safe_u8_to_u1(a), expected); + } + }; } diff --git a/tests/u8_convert_test.rs b/tests/u8_convert_test.rs index 89a2af0..6331249 100644 --- a/tests/u8_convert_test.rs +++ b/tests/u8_convert_test.rs @@ -15,7 +15,9 @@ enum FunctionToTest { U8ToU32, U8ToU64, U8ToU128, - // U8ToU256, TODO: uncomment when u256 functions are merged + U8ToU256, + SplitU8ToU1, + SafeU8ToU1, } #[inline] @@ -102,21 +104,67 @@ mod u8_convert_test { ) } - // TODO: uncomment when u256 functions are merged - - // #[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_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_to_u1(context: simplex::TestContext) -> anyhow::Result<()> { + let a = rand::thread_rng().gen_range(0..=u8::MAX); + + run( + &context, + program(), + build_witness( + op(FunctionToTest::SplitU8ToU1), + 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, + ) + } } From f3ba777996c9e9b702ee397b6e3387d94baf65dd Mon Sep 17 00:00:00 2001 From: aritkulova Date: Wed, 5 Aug 2026 15:02:34 +0300 Subject: [PATCH 4/8] refactored widening functions --- simf/lib/u8/convert.simf | 53 +++++++++------------------------------- 1 file changed, 12 insertions(+), 41 deletions(-) diff --git a/simf/lib/u8/convert.simf b/simf/lib/u8/convert.simf index f7f3b3c..348adad 100644 --- a/simf/lib/u8/convert.simf +++ b/simf/lib/u8/convert.simf @@ -11,59 +11,30 @@ pub fn u8_to_u16( /// Converts u8 to u32 pub fn u8_to_u32(a: u8) -> u32 { - <(u8, u8, u8, u8)>::into((0, 0, 0, a)) + let a_u16: u16 = u8_to_u16(a); + + <(u16, u16)>::into((0, a_u16)) } /// Converts u8 to u64 pub fn u8_to_u64(a: u8) -> u64 { - <(u8, u8, u8, u8, u8, u8, u8, u8)>::into((0, 0, 0, 0, 0, 0, 0, a)) + let a_u32: u32 = u8_to_u32(a); + + <(u32, u32)>::into((0, a_u32)) } /// Converts u8 to u128 pub fn u8_to_u128(a: u8) -> u128 { - <(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8)>::into( - (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a) - ) + let a_u64: u64 = u8_to_u64(a); + + <(u64, u64)>::into((0, a_u64)) } /// Converts u8 to u256 pub fn u8_to_u256(a: u8) -> u256 { - <(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8)>::into( - ( - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - a - ) - ) + let a_u128: u128 = u8_to_u128(a); + + <(u128, u128)>::into((0, a_u128)) } /// Splitting uint conversions From 9b3e739bc64a83e664237f6788d585b386f947a7 Mon Sep 17 00:00:00 2001 From: aritkulova Date: Wed, 5 Aug 2026 19:39:22 +0300 Subject: [PATCH 5/8] linting --- simf/lib/u8/convert.simf | 12 ++---- simf/lib/u8/math.simf | 77 +++++++++------------------------------ simf/u8_convert_test.simf | 28 +++++++------- simf/u8_math_test.simf | 12 ++---- 4 files changed, 37 insertions(+), 92 deletions(-) diff --git a/simf/lib/u8/convert.simf b/simf/lib/u8/convert.simf index 348adad..3a05ea9 100644 --- a/simf/lib/u8/convert.simf +++ b/simf/lib/u8/convert.simf @@ -3,9 +3,7 @@ use crate::lib::asserts::assert_eq_8; /// Widening uint conversions /// Converts u8 to u16 -pub fn u8_to_u16( - a: u8 -) -> u16 { +pub fn u8_to_u16(a: u8) -> u16 { <(u8, u8)>::into((0, a)) } @@ -40,9 +38,7 @@ pub fn u8_to_u256(a: u8) -> u256 { /// Splitting uint conversions /// Splits u8 into eight u1 -pub fn split_u8_to_u1( - a: u8 -) -> (u1, u1, u1, u1, u1, u1, u1, u1) { +pub fn split_u8_to_u1(a: u8) -> (u1, u1, u1, u1, u1, u1, u1, u1) { ::into(a) } @@ -50,9 +46,7 @@ pub fn split_u8_to_u1( /// Converts u8 into u1. /// Panics if the value does not fit in u1 -pub fn safe_u8_to_u1( - a: u8 -) -> u1 { +pub fn safe_u8_to_u1(a: u8) -> u1 { let (_, _, _, _, _, _, _, a_u1): (u1, u1, u1, u1, u1, u1, u1, u1) = split_u8_to_u1(a); let a_recovered: u8 = <(u1, u1, u1, u1, u1, u1, u1, u1)>::into((0, 0, 0, 0, 0, 0, 0, a_u1)); diff --git a/simf/lib/u8/math.simf b/simf/lib/u8/math.simf index 67de3f8..9d50464 100644 --- a/simf/lib/u8/math.simf +++ b/simf/lib/u8/math.simf @@ -1,100 +1,60 @@ /// Returns the sum of two u8 values wrapped in Some, or None if the result overflows u8 -pub fn checked_add_8( - a: u8, - b: u8 -) -> Option { +pub fn checked_add_8(a: u8, b: u8) -> Option { let (carry, sum): (bool, u8) = jet::add_8(a, b); match carry { - false => { - Some(sum) - }, - true => { - None - } + true => None, + false => Some(sum), } } /// Returns the sum of two u8 values, panics if the result overflows u8 -pub fn safe_add_8( - a: u8, - b: u8 -) -> u8 { +pub fn safe_add_8(a: u8, b: u8) -> u8 { unwrap(checked_add_8(a, b)) } /// Returns the difference of two u8 values wrapped in Some, or None if the result overflows u8 -pub fn checked_sub_8( - a: u8, - b: u8 -) -> Option { +pub fn checked_sub_8(a: u8, b: u8) -> Option { let (borrow, diff): (bool, u8) = jet::subtract_8(a, b); match borrow { - false => { - Some(diff) - }, - true => { - None - } + true => None, + false => Some(diff), } } /// Returns the difference of two u8 values, panics if the result overflows u8 -pub fn safe_sub_8( - a: u8, - b: u8 -) -> u8 { +pub fn safe_sub_8(a: u8, b: u8) -> u8 { unwrap(checked_sub_8(a, b)) } /// Returns the product of two u8 values wrapped in Some, or None if the result overflows u8 -pub fn checked_mul_8( - a: u8, - b: u8 -) -> Option { +pub fn checked_mul_8(a: u8, b: u8) -> Option { let result: u16 = jet::multiply_8(a, b); let (high, low): (u8, u8) = ::into(result); match jet::is_zero_8(high) { - false => { - None - }, - true => { - Some(low) - } + true => Some(low), + false => None, } } /// Returns the product of two u8 values, panics if the result overflows u8 -pub fn safe_mul_8( - a: u8, - b: u8 -) -> u8 { +pub fn safe_mul_8(a: u8, b: u8) -> u8 { unwrap(checked_mul_8(a, b)) } /// Returns the quotient of two u8 values wrapped in Some, or None if the result overflows u8 -pub fn checked_div_8( - a: u8, - b: u8 -) -> Option { +pub fn checked_div_8(a: u8, b: u8) -> Option { match jet::is_zero_8(b) { - false => { - Some(jet::divide_8(a, b)) - }, - true => { - None - } + true => None, + false => Some(jet::divide_8(a, b)), } } /// Returns the quotient of two u8 values, panics if the result overflows u8 -pub fn safe_div_8( - a: u8, - b: u8 -) -> u8 { +pub fn safe_div_8(a: u8, b: u8) -> u8 { unwrap(checked_div_8(a, b)) } @@ -104,9 +64,6 @@ pub fn gt_8(a: u8, b: u8) -> bool { } /// Check if an integer is greater than or equal to another integer -pub fn ge_8( - a: u8, - b: u8 -) -> bool { +pub fn ge_8(a: u8, b: u8) -> bool { jet::le_8(b, a) } diff --git a/simf/u8_convert_test.simf b/simf/u8_convert_test.simf index ae85425..31a111d 100644 --- a/simf/u8_convert_test.simf +++ b/simf/u8_convert_test.simf @@ -20,52 +20,51 @@ fn main() { let expected: u256 = witness::EXPECTED; match if_test_this_function(0, fn_idx) { - false => {}, true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); assert!(jet::eq_16(u8_to_u16(a), expected)); - } + }, + false => {}, }; match if_test_this_function(1, fn_idx) { - false => {}, true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, expected): (u32, u32) = ::into(expected); assert!(jet::eq_32(u8_to_u32(a), expected)); - } + }, + false => {}, }; match if_test_this_function(2, fn_idx) { - false => {}, true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); assert!(jet::eq_64(u8_to_u64(a), expected)); - } + }, + false => {}, }; match if_test_this_function(3, fn_idx) { - false => {}, true => { let (_, expected): (u128, u128) = ::into(expected); assert!(eq_128(u8_to_u128(a), expected)); - } + }, + false => {}, }; match if_test_this_function(4, fn_idx) { - false => {}, true => { assert!(jet::eq_256(u8_to_u256(a), expected)); - } + }, + false => {}, }; match if_test_this_function(5, fn_idx) { - false => {}, true => { let ( a7, @@ -100,11 +99,11 @@ fn main() { assert_eq_1(a2, expected2); assert_eq_1(a1, expected1); assert_eq_1(a0, expected0); - } + }, + false => {}, }; match if_test_this_function(6, fn_idx) { - false => {}, true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); @@ -121,6 +120,7 @@ fn main() { ): (u1, u1, u1, u1, u1, u1, u1, u1) = ::into(expected); assert_eq_1(safe_u8_to_u1(a), expected); - } + }, + false => {}, }; } diff --git a/simf/u8_math_test.simf b/simf/u8_math_test.simf index 02ee705..3bd2eef 100644 --- a/simf/u8_math_test.simf +++ b/simf/u8_math_test.simf @@ -17,22 +17,16 @@ 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 -) { +fn assert_eq_opt(result: Option, expected: Option) { match expected { - None => assert_none_8(result), 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 -) { +fn assert_bool_by_opt(result: bool, expected: Option) { match expected { Some(_: u8) => assert!(result), None => assert!(not(result)), From 1e6d96b020adb62493c26408809e4f9047a5a4b1 Mon Sep 17 00:00:00 2001 From: aritkulova Date: Thu, 6 Aug 2026 11:35:10 +0300 Subject: [PATCH 6/8] refactored u8 functions --- simf/lib/u8/convert.simf | 18 ++++++------------ simf/u8_convert_test.simf | 16 ++-------------- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/simf/lib/u8/convert.simf b/simf/lib/u8/convert.simf index 3a05ea9..c67de4f 100644 --- a/simf/lib/u8/convert.simf +++ b/simf/lib/u8/convert.simf @@ -4,21 +4,17 @@ use crate::lib::asserts::assert_eq_8; /// Converts u8 to u16 pub fn u8_to_u16(a: u8) -> u16 { - <(u8, u8)>::into((0, a)) + jet::left_pad_low_8_16(a) } /// Converts u8 to u32 pub fn u8_to_u32(a: u8) -> u32 { - let a_u16: u16 = u8_to_u16(a); - - <(u16, u16)>::into((0, a_u16)) + jet::left_pad_low_8_32(a) } /// Converts u8 to u64 pub fn u8_to_u64(a: u8) -> u64 { - let a_u32: u32 = u8_to_u32(a); - - <(u32, u32)>::into((0, a_u32)) + jet::left_pad_low_8_64(a) } /// Converts u8 to u128 @@ -47,11 +43,9 @@ pub fn split_u8_to_u1(a: u8) -> (u1, u1, u1, u1, u1, u1, u1, u1) { /// Converts u8 into u1. /// Panics if the value does not fit in u1 pub fn safe_u8_to_u1(a: u8) -> u1 { - let (_, _, _, _, _, _, _, a_u1): (u1, u1, u1, u1, u1, u1, u1, u1) = split_u8_to_u1(a); - - let a_recovered: u8 = <(u1, u1, u1, u1, u1, u1, u1, u1)>::into((0, 0, 0, 0, 0, 0, 0, a_u1)); + let u1_max: u8 = jet::left_pad_low_1_8(jet::high_1()); - assert_eq_8(a, a_recovered); + assert!(jet::le_8(a, u1_max)); - a_u1 + jet::rightmost_8_1(a) } diff --git a/simf/u8_convert_test.simf b/simf/u8_convert_test.simf index 31a111d..af6a349 100644 --- a/simf/u8_convert_test.simf +++ b/simf/u8_convert_test.simf @@ -78,8 +78,7 @@ fn main() { ): (u1, u1, u1, u1, u1, u1, u1, u1) = split_u8_to_u1(a); let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); - let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); - let (_, expected): (u8, u8) = ::into(expected); + let expected: u8 = jet::rightmost_64_8(expected); let ( expected7, expected6, @@ -106,18 +105,7 @@ fn main() { match if_test_this_function(6, fn_idx) { true => { let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); - let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); - let (_, expected): (u8, u8) = ::into(expected); - let ( - _, - _, - _, - _, - _, - _, - _, - expected - ): (u1, u1, u1, u1, u1, u1, u1, u1) = ::into(expected); + let expected: u1 = jet::rightmost_64_1(expected); assert_eq_1(safe_u8_to_u1(a), expected); }, From 33947c6111bb31a7c4b18b79fd1fbd5fe7e5d9b5 Mon Sep 17 00:00:00 2001 From: aritkulova Date: Thu, 6 Aug 2026 12:40:18 +0300 Subject: [PATCH 7/8] typo --- simf/u8_convert_test.simf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simf/u8_convert_test.simf b/simf/u8_convert_test.simf index af6a349..7589160 100644 --- a/simf/u8_convert_test.simf +++ b/simf/u8_convert_test.simf @@ -88,7 +88,7 @@ fn main() { expected2, expected1, expected0 - ): (u1, u1, u1, u1, u1, u1, u1, u1) = ::into(a); + ): (u1, u1, u1, u1, u1, u1, u1, u1) = ::into(expected); assert_eq_1(a7, expected7); assert_eq_1(a6, expected6); From 908c182ff77b75ba1b9c4c380cc6fe6ad56bc6e6 Mon Sep 17 00:00:00 2001 From: aritkulova Date: Thu, 6 Aug 2026 15:22:39 +0300 Subject: [PATCH 8/8] removed unused import --- simf/lib/u8/convert.simf | 2 -- 1 file changed, 2 deletions(-) diff --git a/simf/lib/u8/convert.simf b/simf/lib/u8/convert.simf index c67de4f..fee231c 100644 --- a/simf/lib/u8/convert.simf +++ b/simf/lib/u8/convert.simf @@ -1,5 +1,3 @@ -use crate::lib::asserts::assert_eq_8; - /// Widening uint conversions /// Converts u8 to u16