Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions simf/lib/u16/convert.simf
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/// Widening uint conversions

/// Converts u16 to u32
pub fn u16_to_u32(a: u16) -> u32 {
jet::left_pad_low_16_32(a)
}

/// Converts u16 to u64
pub fn u16_to_u64(a: u16) -> u64 {
jet::left_pad_low_16_64(a)
}

/// Converts u16 to u128
pub fn u16_to_u128(a: u16) -> u128 {
let a_u64: u64 = u16_to_u64(a);

<(u64, u64)>::into((0, a_u64))
}

/// Converts u16 to u256
pub fn u16_to_u256(a: u16) -> u256 {
let a_u128: u128 = u16_to_u128(a);

<(u128, u128)>::into((0, a_u128))
}

/// Splitting uint conversions

/// Splits u16 into two u8
pub fn split_u16_to_u8(a: u16) -> (u8, u8) {
<u16>::into(a)
}

/// Narrowing uint conversions

/// Converts u16 into u1.
/// Panics if the value does not fit in u1
pub fn safe_u16_to_u1(a: u16) -> u1 {
let u1_max: u16 = jet::left_pad_low_1_16(jet::high_1());

assert!(jet::le_16(a, u1_max));

jet::rightmost_16_1(a)
}

/// Converts u16 into u8.
/// Panics if the value does not fit in u8
pub fn safe_u16_to_u8(a: u16) -> u8 {
let u8_max: u16 = jet::left_pad_low_8_16(jet::high_8());

assert!(jet::le_16(a, u8_max));

jet::rightmost_16_8(a)
}
File renamed without changes.
89 changes: 89 additions & 0 deletions simf/u16_convert_test.simf
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use crate::lib::u16::convert::{
u16_to_u32,
u16_to_u64,
u16_to_u128,
u16_to_u256,
split_u16_to_u8,
safe_u16_to_u1,
safe_u16_to_u8
};
use crate::lib::u128::eq_128;
use crate::lib::asserts::{assert_eq_1, assert_eq_8};
use crate::helper::if_test_this_function;

fn main() {
let fn_idx: u8 = witness::FUNCTION_INDEX;

let a: u16 = witness::FIRST_ARG;

let expected: u256 = witness::EXPECTED;

match if_test_this_function(0, fn_idx) {
true => {
let (_, _, _, expected): (u64, u64, u64, u64) = <u256>::into(expected);
let (_, expected): (u32, u32) = <u64>::into(expected);

assert!(jet::eq_32(u16_to_u32(a), expected));
},
false => {},
};

match if_test_this_function(1, fn_idx) {
true => {
let (_, _, _, expected): (u64, u64, u64, u64) = <u256>::into(expected);

assert!(jet::eq_64(u16_to_u64(a), expected));
},
false => {},
};

match if_test_this_function(2, fn_idx) {
true => {
let (_, expected): (u128, u128) = <u256>::into(expected);

assert!(eq_128(u16_to_u128(a), expected));
},
false => {},
};

match if_test_this_function(3, fn_idx) {
true => {
assert!(jet::eq_256(u16_to_u256(a), expected));
},
false => {},
};

match if_test_this_function(4, fn_idx) {
true => {
let (a1, a0): (u8, u8) = split_u16_to_u8(a);

let (_, _, _, expected): (u64, u64, u64, u64) = <u256>::into(expected);
let expected: u16 = jet::rightmost_64_16(expected);
let (expected1, expected0): (u8, u8) = <u16>::into(expected);

assert_eq_8(a1, expected1);
assert_eq_8(a0, expected0);
},
false => {},
};

match if_test_this_function(5, fn_idx) {
true => {
let (_, _, _, expected): (u64, u64, u64, u64) = <u256>::into(expected);
let expected: u1 = jet::rightmost_64_1(expected);

assert_eq_1(safe_u16_to_u1(a), expected);
},
false => {},
};

match if_test_this_function(6, fn_idx) {
true => {
let (_, _, _, expected): (u64, u64, u64, u64) = <u256>::into(expected);
let expected: u8 = jet::rightmost_64_8(expected);

assert_eq_8(safe_u16_to_u8(a), expected);
},
false => {},
};
}
2 changes: 1 addition & 1 deletion simf/u16_test.simf → simf/u16_math_test.simf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::lib::u16::{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::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;
Expand Down
190 changes: 190 additions & 0 deletions tests/u16_convert_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
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,
SplitU16ToU8,
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_to_u8(context: simplex::TestContext) -> anyhow::Result<()> {
let a = rand::thread_rng().gen_range(0..=u16::MAX);

run(
&context,
program(),
build_witness(
op(FunctionToTest::SplitU16ToU8),
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,
)
}
}
20 changes: 11 additions & 9 deletions tests/u16_test.rs → tests/u16_math_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,28 @@ mod common;

use common::uint::TestUint;

use simplicityhl_std::artifacts::u16_test::U16TestProgram;
use simplicityhl_std::artifacts::u16_test::derived_u16_test::{U16TestArguments, U16TestWitness};
use simplicityhl_std::artifacts::u16_math_test::U16MathTestProgram;
use simplicityhl_std::artifacts::u16_math_test::derived_u16_math_test::{
U16MathTestArguments, U16MathTestWitness,
};

// The only per-width code for the common operations.
impl TestUint for u16 {
type Program = U16TestProgram;
type Witness = U16TestWitness;
type Program = U16MathTestProgram;
type Witness = U16MathTestWitness;

const ZERO: u16 = 0;
const ONE: u16 = 1;
const MAX: u16 = u16::MAX;
const HALF_MAX: u16 = u16::MAX / 2;
const MUL_BOUND: u16 = 1 << 8; // 2^(16/2)

fn program() -> U16TestProgram {
U16TestProgram::new(U16TestArguments {})
fn program() -> U16MathTestProgram {
U16MathTestProgram::new(U16MathTestArguments {})
}

fn witness(op: u8, a: u16, b: u16, expected: Option<u16>) -> U16TestWitness {
U16TestWitness {
fn witness(op: u8, a: u16, b: u16, expected: Option<u16>) -> U16MathTestWitness {
U16MathTestWitness {
function_index: op,
first_arg: a,
second_arg: b,
Expand All @@ -30,7 +32,7 @@ impl TestUint for u16 {
}
}

mod u16_tests {
mod u16_math_tests {
use super::*;

// Stamps the 16 `#[simplex::test]` entry points for u16. Logic lives in common::uint.
Expand Down