diff --git a/simf/asserts_test.simf b/simf/asserts_test.simf index fafd2f1..36e1708 100644 --- a/simf/asserts_test.simf +++ b/simf/asserts_test.simf @@ -1,6 +1,19 @@ 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_none_1, assert_none_8, assert_none_16, assert_none_32, assert_none_64, assert_none_128, assert_none_256 + 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; @@ -36,13 +49,14 @@ fn main() { 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(7, fn_idx) { true => { assert_none_1(a_u1); }, false => (), }; - match if_test_this_function(8, fn_idx) { true => { assert_none_8(a_u8); }, false => (), }; - match if_test_this_function(9, fn_idx) { true => { assert_none_16(a_u16); }, false => (), }; - match if_test_this_function(10, fn_idx) { true => { assert_none_32(a_u32); }, false => (), }; - match if_test_this_function(11, fn_idx) { true => { assert_none_64(a_u64); }, false => (), }; - match if_test_this_function(12, fn_idx) { true => { assert_none_128(a_u128); }, false => (), }; - match if_test_this_function(13, fn_idx) { true => { assert_none_256(a_u256); }, false => (), }; + 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/ct_compile_check.simf b/simf/ct_compile_check.simf new file mode 100644 index 0000000..7de723b --- /dev/null +++ b/simf/ct_compile_check.simf @@ -0,0 +1,38 @@ +use crate::lib::ct::relations::{ + zero, add, sub, add_scaled, sub_scaled, is_balanced, assert_balanced, + is_scaled_eq, assert_scaled_eq, is_value_eq, assert_value_eq, + assert_ratio_eq, assert_sum_eq +}; +use crate::lib::ct::commitment::{ + asset_generator, value_commitment, + assert_asset_generator, assert_value_commitment, assert_opens_to +}; +use crate::lib::secp256k1::operations::point_to_ge; + +fn main() { + let p: Point = witness::P; + let q: Point = witness::Q; + let s: Scalar = witness::S; + let id: u256 = witness::ID; + let asset: Asset1 = witness::ASSET; + let amount: Amount1 = witness::AMOUNT; + + let acc: Gej = sub_scaled(add_scaled(sub(add(zero(), p), q), 2, p), 3, q); + assert!(is_balanced(acc, s)); + assert_balanced(acc, s); + + assert!(is_scaled_eq(q, 2, p, s)); + assert_scaled_eq(q, 2, p, s); + assert!(is_value_eq(p, q, s)); + assert_value_eq(p, q, s); + assert_ratio_eq(3, p, 5, q, s); + assert_sum_eq(p, q, p, s); + + let h: Gej = asset_generator(id, s); + let c: Gej = value_commitment(7, h, s); + assert!(jet::gej_is_on_curve(c)); + + assert_asset_generator(point_to_ge(p), id, s); + assert_value_commitment(point_to_ge(p), 7, point_to_ge(q), s); + assert_opens_to(asset, amount, id, 7, s, s); +} diff --git a/simf/lib/asserts.simf b/simf/lib/asserts.simf index 60c577c..63c4a9a 100644 --- a/simf/lib/asserts.simf +++ b/simf/lib/asserts.simf @@ -35,6 +35,11 @@ pub fn assert_eq_256(a: u256, b: u256) { assert!(jet::eq_256(a, b)); } +/// Asserts that two bool values are equal +pub fn assert_eq_bool(a: bool, b: bool) { + assert_eq_1(::into(a), ::into(b)); +} + /// Asserts that provided `Option` value is a `None` pub fn assert_none_1(val: Option) { assert!(is_none::(val)); diff --git a/simf/lib/ct/commitment.simf b/simf/lib/ct/commitment.simf new file mode 100644 index 0000000..9a099c9 --- /dev/null +++ b/simf/lib/ct/commitment.simf @@ -0,0 +1,73 @@ +/* + * Confidential Transactions: commitment builders and openings. + * + * H_a = hash_to_curve(asset_id) + abf*G (asset generator) + * C = v*H_a + vbf*G (value commitment) + * + * Every assert in this module takes blinding factors, which means the value or + * asset id it checks becomes PUBLIC to anyone reading the witness. + * For checks that constrain commitments while keeping the values sealed, use + * `crate::lib::ct::relations`. + */ + +use crate::lib::asserts::{assert_eq_64, assert_eq_256}; +use crate::lib::secp256k1::operations::point_to_ge; +use crate::lib::u64::u64_into_u256; + +/// Builds the asset generator `H_a = hash_to_curve(asset_id) + abf*G`. +pub fn asset_generator(asset_id: u256, abf: Scalar) -> Gej { + jet::gej_ge_add(jet::generate(abf), jet::hash_to_curve(asset_id)) +} + +/// Builds the value commitment `C = v*asset_gen + vbf*G`. +pub fn value_commitment(v: u64, asset_gen: Gej, vbf: Scalar) -> Gej { + jet::linear_combination_1((u64_into_u256(v), asset_gen), vbf) +} + +/// Asserts that `h == hash_to_curve(asset_id) + abf*G`. +pub fn assert_asset_generator(h: Ge, asset_id: u256, abf: Scalar) { + jet::linear_verify_1(((1, jet::hash_to_curve(asset_id)), abf), h); +} + +/// Asserts that `c == v*h + vbf*G`, where `h` is the asset generator that `c` +/// commits against. +pub fn assert_value_commitment(c: Ge, v: u64, h: Ge, vbf: Scalar) { + jet::linear_verify_1(((u64_into_u256(v), h), vbf), c); +} + +/// Asserts that an `(asset, amount)` pair opens to `expected_asset_id` and +/// `expected_amount`. +pub fn assert_opens_to( + asset: Asset1, + amount: Amount1, + expected_asset_id: u256, + expected_amount: u64, + abf: Scalar, + vbf: Scalar, +) { + match asset { + Left(conf_asset: Point) => { + let h: Ge = point_to_ge(conf_asset); + assert_asset_generator(h, expected_asset_id, abf); + + match amount { + Left(conf_amount: Point) => { + assert_value_commitment(point_to_ge(conf_amount), expected_amount, h, vbf); + }, + Right(explicit_amount: u64) => assert_eq_64(explicit_amount, expected_amount), + }; + }, + Right(explicit_asset: u256) => { + assert_eq_256(explicit_asset, expected_asset_id); + + match amount { + // An explicit asset commits against the unblinded generator. + Left(conf_amount: Point) => { + let h: Ge = jet::hash_to_curve(expected_asset_id); + assert_value_commitment(point_to_ge(conf_amount), expected_amount, h, vbf); + }, + Right(explicit_amount: u64) => assert_eq_64(explicit_amount, expected_amount), + }; + }, + }; +} diff --git a/simf/lib/ct/relations.simf b/simf/lib/ct/relations.simf new file mode 100644 index 0000000..dde3981 --- /dev/null +++ b/simf/lib/ct/relations.simf @@ -0,0 +1,79 @@ +/* + * Confidential Transactions: relations between commitments. + * + * Nothing here takes a blinding factor, so nothing here discloses a committed + * value. For checks that do reveal a value or an asset id, see + * `crate::lib::ct::commitment`. + * + * A value commitment expands to + * + * C = v*H_a + vbf*G = v*H_0 + (v*abf + vbf)*G + * + */ + +use crate::lib::secp256k1::operations::{point_to_ge, point_to_gej}; + +/// The empty accumulator (the point at infinity). +pub fn zero() -> Gej { + jet::gej_infinity() +} + +/// `acc + c` +pub fn add(acc: Gej, c: Point) -> Gej { + jet::gej_ge_add(acc, point_to_ge(c)) +} + +/// `acc - c` +pub fn sub(acc: Gej, c: Point) -> Gej { + jet::gej_ge_add(acc, jet::ge_negate(point_to_ge(c))) +} + +/// `acc + k*c` +pub fn add_scaled(acc: Gej, k: Scalar, c: Point) -> Gej { + jet::gej_add(acc, jet::scale(k, point_to_gej(c))) +} + +/// `acc - k*c` +pub fn sub_scaled(acc: Gej, k: Scalar, c: Point) -> Gej { + add_scaled(acc, jet::scalar_negate(k), c) +} + +/// Returns true iff `acc == s*G`. +pub fn is_balanced(acc: Gej, s: Scalar) -> bool { + jet::gej_equiv(acc, jet::generate(s)) +} + +/// Asserts that `acc == s*G`. +pub fn assert_balanced(acc: Gej, s: Scalar) { + assert!(is_balanced(acc, s)); +} + +/// Returns true iff `q == k*p + s*G`. +pub fn is_scaled_eq(q: Point, k: Scalar, p: Point, s: Scalar) -> bool { + jet::gej_ge_equiv(jet::linear_combination_1((k, point_to_gej(p)), s), point_to_ge(q)) +} + +/// Asserts that `q == k*p + s*G`. +pub fn assert_scaled_eq(q: Point, k: Scalar, p: Point, s: Scalar,) { + jet::point_verify_1(((k, p), s), q); +} + +/// Returns true iff `p == q + s*G`. +pub fn is_value_eq(p: Point, q: Point, s: Scalar) -> bool { + is_scaled_eq(q, 1, p, s) +} + +/// Asserts that `p == q + s*G`, i.e. that two commitments hold the same value. +pub fn assert_value_eq(p: Point, q: Point, s: Scalar) { + assert_scaled_eq(q, 1, p, s); +} + +/// Asserts that `a*x == b*y + s*G`. +pub fn assert_ratio_eq(a: Scalar, x: Point, b: Scalar, y: Point, s: Scalar) { + assert_balanced(sub_scaled(add_scaled(zero(), a, x), b, y), s); +} + +/// Asserts that `c1 + c2 == c_sum + s*G`. +pub fn assert_sum_eq(c1: Point, c2: Point, c_sum: Point, s: Scalar) { + assert_balanced(sub(add(add(zero(), c1), c2), c_sum), s); +} diff --git a/simf/lib/secp256k1/operations.simf b/simf/lib/secp256k1/operations.simf index 0cfabbe..8c9d095 100644 --- a/simf/lib/secp256k1/operations.simf +++ b/simf/lib/secp256k1/operations.simf @@ -11,9 +11,16 @@ pub fn ge_to_point(p: Ge) -> Point { } } +/// Decompress a `Point` into affine coordinates. +/// Panics if `jet::decompress(p)` returns `None`. +pub fn point_to_ge(p: Point) -> Ge { + unwrap(jet::decompress(p)) +} + /// Decompress a `Point` into a Jacobian point with `z = 1`. +/// Panics if `jet::decompress(p)` returns `None`. pub fn point_to_gej(p: Point) -> Gej { - (unwrap(jet::decompress(p)), 1) + (point_to_ge(p), 1) } /// Convert the point into affine coordinates. diff --git a/simf/lib/u1/convert.simf b/simf/lib/u1/convert.simf new file mode 100644 index 0000000..f01b02e --- /dev/null +++ b/simf/lib/u1/convert.simf @@ -0,0 +1,42 @@ +/// Widening uint conversions + +/// Converts u1 to u8 +pub fn u1_to_u8(a: u1) -> u8 { + jet::left_pad_low_1_8(a) +} + +/// Converts u1 to u16 +pub fn u1_to_u16(a: u1) -> u16 { + jet::left_pad_low_1_16(a) +} + +/// Converts u1 to u32 +pub fn u1_to_u32(a: u1) -> u32 { + jet::left_pad_low_1_32(a) +} + +/// Converts u1 to u64 +pub fn u1_to_u64(a: u1) -> u64 { + jet::left_pad_low_1_64(a) +} + +/// Converts u1 to u128 +pub fn u1_to_u128(a: u1) -> u128 { + let a_u64: u64 = u1_to_u64(a); + + <(u64, u64)>::into((0, a_u64)) +} + +/// Converts u1 to u256 +pub fn u1_to_u256(a: u1) -> u256 { + let a_u128: u128 = u1_to_u128(a); + + <(u128, u128)>::into((0, a_u128)) +} + +/// Type conversions + +/// Converts u1 to bool +pub fn u1_to_bool(a: u1) -> bool { + ::into(a) +} diff --git a/simf/lib/u8/convert.simf b/simf/lib/u8/convert.simf new file mode 100644 index 0000000..fee231c --- /dev/null +++ b/simf/lib/u8/convert.simf @@ -0,0 +1,49 @@ +/// Widening uint conversions + +/// Converts u8 to u16 +pub fn u8_to_u16(a: u8) -> u16 { + jet::left_pad_low_8_16(a) +} + +/// Converts u8 to u32 +pub fn u8_to_u32(a: u8) -> u32 { + jet::left_pad_low_8_32(a) +} + +/// Converts u8 to u64 +pub fn u8_to_u64(a: u8) -> u64 { + jet::left_pad_low_8_64(a) +} + +/// Converts u8 to u128 +pub fn u8_to_u128(a: u8) -> u128 { + 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 { + let a_u128: u128 = u8_to_u128(a); + + <(u128, u128)>::into((0, a_u128)) +} + +/// 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 u1_max: u8 = jet::left_pad_low_1_8(jet::high_1()); + + assert!(jet::le_8(a, u1_max)); + + jet::rightmost_8_1(a) +} diff --git a/simf/lib/u8.simf b/simf/lib/u8/math.simf similarity index 100% rename from simf/lib/u8.simf rename to simf/lib/u8/math.simf diff --git a/simf/u1_convert_test.simf b/simf/u1_convert_test.simf new file mode 100644 index 0000000..a432dd9 --- /dev/null +++ b/simf/u1_convert_test.simf @@ -0,0 +1,84 @@ +use crate::lib::u1::convert::{ + u1_to_u8, + u1_to_u16, + u1_to_u32, + u1_to_u64, + u1_to_u128, + u1_to_u256, + u1_to_bool +}; +use crate::lib::u128::eq_128; +use crate::lib::asserts::assert_eq_bool; +use crate::helper::if_test_this_function; + +fn main() { + let fn_idx: u8 = witness::FUNCTION_INDEX; + + let a: u1 = witness::FIRST_ARG; + + let expected: u256 = witness::EXPECTED; + + match if_test_this_function(0, 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); + + assert!(jet::eq_8(u1_to_u8(a), expected)); + }, + false => {}, + }; + + match if_test_this_function(1, fn_idx) { + true => { + let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); + let (_, _, _, expected): (u16, u16, u16, u16) = ::into(expected); + + assert!(jet::eq_16(u1_to_u16(a), expected)); + }, + false => {}, + }; + + match if_test_this_function(2, fn_idx) { + true => { + let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); + let (_, expected): (u32, u32) = ::into(expected); + + assert!(jet::eq_32(u1_to_u32(a), expected)); + }, + false => {}, + }; + + match if_test_this_function(3, fn_idx) { + true => { + let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); + + assert!(jet::eq_64(u1_to_u64(a), expected)); + }, + false => {}, + }; + + match if_test_this_function(4, fn_idx) { + true => { + let (_, expected): (u128, u128) = ::into(expected); + + assert!(eq_128(u1_to_u128(a), expected)); + }, + false => {}, + }; + + match if_test_this_function(5, fn_idx) { + true => { + assert!(jet::eq_256(u1_to_u256(a), expected)); + }, + false => {}, + }; + + match if_test_this_function(6, fn_idx) { + true => { + let expected_bool: bool = jet::eq_256(expected, 1); + assert_eq_bool(u1_to_bool(a), expected_bool); + }, + false => {}, + }; +} diff --git a/simf/u8_convert_test.simf b/simf/u8_convert_test.simf new file mode 100644 index 0000000..7589160 --- /dev/null +++ b/simf/u8_convert_test.simf @@ -0,0 +1,114 @@ +use crate::lib::u8::convert::{ + u8_to_u16, + u8_to_u32, + u8_to_u64, + u8_to_u128, + u8_to_u256, + split_u8_to_u1, + safe_u8_to_u1 +}; +// 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() { + 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) { + 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) { + 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) { + 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) { + true => { + let (_, expected): (u128, u128) = ::into(expected); + + assert!(eq_128(u8_to_u128(a), expected)); + }, + false => {}, + }; + + match if_test_this_function(4, fn_idx) { + true => { + assert!(jet::eq_256(u8_to_u256(a), expected)); + }, + false => {}, + }; + + match if_test_this_function(5, fn_idx) { + 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: u8 = jet::rightmost_64_8(expected); + let ( + expected7, + expected6, + expected5, + expected4, + expected3, + expected2, + expected1, + expected0 + ): (u1, u1, u1, u1, u1, u1, u1, u1) = ::into(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); + }, + false => {}, + }; + + match if_test_this_function(6, fn_idx) { + true => { + let (_, _, _, expected): (u64, u64, u64, u64) = ::into(expected); + let expected: u1 = jet::rightmost_64_1(expected); + + assert_eq_1(safe_u8_to_u1(a), expected); + }, + false => {}, + }; +} diff --git a/simf/u8_test.simf b/simf/u8_math_test.simf similarity index 68% rename from simf/u8_test.simf rename to simf/u8_math_test.simf index 37e8d32..3bd2eef 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; @@ -8,8 +19,8 @@ use crate::helper::if_test_this_function; /// 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_8(result), Some(e: u8) => assert_eq_8(unwrap(result), e), + None => assert_none_8(result), } } @@ -30,22 +41,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/asserts_test.rs b/tests/asserts_test.rs index fad2ee3..e128ce9 100644 --- a/tests/asserts_test.rs +++ b/tests/asserts_test.rs @@ -19,6 +19,7 @@ enum FunctionToTest { AssertEq64, AssertEq128, AssertEq256, + AssertEqBool, AssertNone1, AssertNone8, @@ -113,6 +114,10 @@ fn build_witness(function: FunctionToTest, same: bool, none: bool) -> AssertsTes (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; @@ -315,6 +320,28 @@ mod asserts_test { ) } + #[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<()> { diff --git a/tests/u1_convert_test.rs b/tests/u1_convert_test.rs new file mode 100644 index 0000000..230acbf --- /dev/null +++ b/tests/u1_convert_test.rs @@ -0,0 +1,150 @@ +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/u8_convert_test.rs b/tests/u8_convert_test.rs new file mode 100644 index 0000000..6331249 --- /dev/null +++ b/tests/u8_convert_test.rs @@ -0,0 +1,170 @@ +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, + SplitU8ToU1, + 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_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, + ) + } +} 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.