use core::assert_matches;
#[cfg(feature = "arbitrary")]
use core::cmp;
use miden_core_lib::handlers::u64_div::{U64_DIV_EVENT_NAME, U64DivError};
use miden_processor::{ExecutionError, operation::OperationError};
#[cfg(feature = "arbitrary")]
use miden_utils_testing::proptest::prelude::*;
use miden_utils_testing::{
Felt, PrimeField64, U32_BOUND, expect_exec_error_matches, rand::rand_value, stack,
};
#[test]
fn wrapping_add() {
let a: u64 = rand_value();
let b: u64 = rand_value();
let c = a.wrapping_add(b);
let source = "
use miden::core::math::u64
begin
exec.u64::wrapping_add
end";
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1]);
}
#[test]
fn wrapping_add_le() {
let a: u64 = 0x0000_0002_0000_0005; let b: u64 = 0x0000_0001_0000_0003; let c = a.wrapping_add(b);
let source = "
use miden::core::math::u64
begin
exec.u64::wrapping_add
end";
let (a1, a0) = split_u64(a); let (b1, b0) = split_u64(b); let (c1, c0) = split_u64(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1]);
}
#[test]
fn overflowing_add() {
let source = "
use miden::core::math::u64
begin
exec.u64::overflowing_add
end";
let a = rand_value::<u64>() as u32 as u64;
let b = rand_value::<u64>() as u32 as u64;
let (c, _) = a.overflowing_add(b);
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[0, c0, c1]);
let a = u64::MAX;
let b = rand_value::<u64>();
let (c, _) = a.overflowing_add(b);
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[1, c0, c1]);
}
#[test]
fn widening_add() {
let source = "
use miden::core::math::u64
begin
exec.u64::widening_add
end";
let a = rand_value::<u64>() as u32 as u64;
let b = rand_value::<u64>() as u32 as u64;
let (c, overflow) = a.overflowing_add(b);
let carry = if overflow { 1 } else { 0 };
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1, carry]);
let a = u64::MAX;
let b = rand_value::<u64>();
let (c, overflow) = a.overflowing_add(b);
let carry = if overflow { 1 } else { 0 };
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1, carry]);
}
#[test]
fn wrapping_sub() {
let a: u64 = rand_value();
let b: u64 = rand_value();
let c = a.wrapping_sub(b);
let source = "
use miden::core::math::u64
begin
exec.u64::wrapping_sub
end";
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![b0, b1, a0, a1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1]);
}
#[test]
fn overflowing_sub() {
let a: u64 = rand_value();
let b: u64 = rand_value();
let (c, flag) = a.overflowing_sub(b);
let source = "
use miden::core::math::u64
begin
exec.u64::overflowing_sub
end";
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![b0, b1, a0, a1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[flag as u64, c0, c1]);
let base = rand_value::<u64>() as u32 as u64;
let diff = rand_value::<u64>() as u32 as u64;
let a = base;
let b = base + diff;
let (c, _) = a.overflowing_sub(b);
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![b0, b1, a0, a1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[1, c0, c1]);
let base = rand_value::<u64>() as u32 as u64;
let diff = rand_value::<u64>() as u32 as u64;
let a = base + diff;
let b = base;
let (c, _) = a.overflowing_sub(b);
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![b0, b1, a0, a1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[0, c0, c1]);
}
#[test]
fn wrapping_mul() {
let a: u64 = rand_value();
let b: u64 = rand_value();
let c = a.wrapping_mul(b);
let source = "
use miden::core::math::u64
begin
exec.u64::wrapping_mul
end";
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1]);
}
#[test]
fn widening_mul() {
let source = "
use miden::core::math::u64
begin
exec.u64::widening_mul
end";
let a = u64::MAX as u128;
let b = u64::MAX as u128;
let c = a.wrapping_mul(b);
let a = u64::MAX;
let b = u64::MAX;
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c3, c2, c1, c0) = split_u128(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1, c2, c3]);
let a = rand_value::<u64>() as u128;
let b = rand_value::<u64>() as u128;
let c = a.wrapping_mul(b);
let a = a as u64;
let b = b as u64;
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c3, c2, c1, c0) = split_u128(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1, c2, c3]);
}
#[test]
fn widening_mul_edge_cases() {
let source = "
use miden::core::math::u64
begin
exec.u64::widening_mul
end";
let cases: &[(u64, u64)] = &[
(0, 0),
(0, 1),
(1, 0),
(0, u64::MAX),
(u64::MAX, 0),
(1, 1),
(1, u64::MAX),
(u64::MAX, 1),
(0xffffffff, 0xffffffff),
(1u64 << 32, 1u64 << 32),
(1u64 << 32, (1u64 << 32) - 1),
((1u64 << 32) - 1, 1u64 << 32),
(0xffffffff, 0xffffffff_00000000),
(0xffffffff_00000000, 0xffffffff),
(0xffffffff_00000000, 0xffffffff_00000000),
(u64::MAX, u64::MAX),
(0xffffffff_00000000, 0x00000000_ffffffff),
(0x00000000_ffffffff, 0xffffffff_00000000),
(0xdeadbeef_cafebabe, 0x0123456789abcdef),
];
for &(a, b) in cases {
let c = (a as u128) * (b as u128);
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c3, c2, c1, c0) = split_u128(c);
let input_stack = stack![b0, b1, a0, a1, 777];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1, c2, c3, 777]);
}
}
#[test]
fn overflowing_mul() {
let source = "
use miden::core::math::u64
begin
exec.u64::overflowing_mul
end";
let cases: &[(u64, u64)] = &[
(0, 0),
(1, 1),
(1, u64::MAX),
(u64::MAX, 1),
(u32::MAX as u64, u32::MAX as u64), (1u64 << 32, 1u64 << 32), (u64::MAX, u64::MAX),
(rand_value(), rand_value()),
];
for &(a, b) in cases {
let (c, overflow) = a.overflowing_mul(b);
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[overflow as u64, c0, c1]);
}
}
#[test]
fn checked_not() {
let cases: &[u64] = &[0, 1, u64::MAX, u32::MAX as u64, 1u64 << 32, rand_value()];
let source = "
use miden::core::math::u64
begin
exec.u64::not
end";
for &a in cases {
let c = !a;
let (a1, a0) = split_u64(a);
let (c1, c0) = split_u64(c);
let input_stack = stack![a0, a1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1]);
}
}
#[test]
fn unchecked_lt() {
let source = "
use miden::core::math::u64
begin
exec.u64::lt
end";
build_test!(source, &stack![0, 0, 0, 0]).expect_stack(&[0]);
build_test!(source, &stack![1, 0, 0, 0]).expect_stack(&[1]);
build_test!(source, &stack![0, 0, 1, 0]).expect_stack(&[0]);
}
#[test]
fn unchecked_lte() {
let source = "
use miden::core::math::u64
begin
exec.u64::lte
end";
build_test!(source, &stack![0, 0, 0, 0]).expect_stack(&[1]);
build_test!(source, &stack![1, 0, 0, 0]).expect_stack(&[1]);
build_test!(source, &stack![0, 0, 1, 0]).expect_stack(&[0]);
let a: u64 = rand_value();
let b: u64 = rand_value();
let c = (a <= b) as u64;
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
build_test!(source, &stack![b0, b1, a0, a1]).expect_stack(&[c]);
}
#[test]
fn unchecked_gt() {
let source = "
use miden::core::math::u64
begin
exec.u64::gt
end";
build_test!(source, &stack![0, 0, 0, 0]).expect_stack(&[0]);
build_test!(source, &stack![1, 0, 0, 0]).expect_stack(&[0]);
build_test!(source, &stack![0, 0, 1, 0]).expect_stack(&[1]);
}
#[test]
fn unchecked_gte() {
let source = "
use miden::core::math::u64
begin
exec.u64::gte
end";
build_test!(source, &stack![0, 0, 0, 0]).expect_stack(&[1]);
build_test!(source, &stack![1, 0, 0, 0]).expect_stack(&[0]);
build_test!(source, &stack![0, 0, 1, 0]).expect_stack(&[1]);
let a: u64 = rand_value();
let b: u64 = rand_value();
let c = (a >= b) as u64;
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
build_test!(source, &stack![b0, b1, a0, a1]).expect_stack(&[c]);
}
#[test]
fn unchecked_min() {
let source = "
use miden::core::math::u64
begin
exec.u64::min
end";
build_test!(source, &stack![0, 0, 0, 0]).expect_stack(&[0, 0]);
build_test!(source, &stack![1, 0, 2, 0]).expect_stack(&[1, 0]);
build_test!(source, &stack![3, 0, 2, 0]).expect_stack(&[2, 0]);
}
#[test]
fn unchecked_max() {
let source = "
use miden::core::math::u64
begin
exec.u64::max
end";
build_test!(source, &stack![0, 0, 0, 0]).expect_stack(&[0, 0]);
build_test!(source, &stack![1, 0, 2, 0]).expect_stack(&[2, 0]);
build_test!(source, &stack![3, 0, 2, 0]).expect_stack(&[3, 0]);
}
#[test]
fn unchecked_eq() {
let source = "
use miden::core::math::u64
begin
exec.u64::eq
end";
build_test!(source, &stack![0, 0, 0, 0]).expect_stack(&[1]);
build_test!(source, &stack![0, 0, 1, 0]).expect_stack(&[0]);
build_test!(source, &stack![1, 0, 0, 0]).expect_stack(&[0]);
let a: u64 = rand_value();
let b: u64 = rand_value();
let c = (a == b) as u64;
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
build_test!(source, &stack![a0, a1, b0, b1]).expect_stack(&[c]);
}
#[test]
fn unchecked_neq() {
let source = "
use miden::core::math::u64
begin
exec.u64::neq
end";
build_test!(source, &stack![0, 0, 0, 0]).expect_stack(&[0]);
build_test!(source, &stack![0, 0, 1, 0]).expect_stack(&[1]);
build_test!(source, &stack![1, 0, 0, 0]).expect_stack(&[1]);
let a: u64 = rand_value();
let b: u64 = rand_value();
let c = (a != b) as u64;
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
build_test!(source, &stack![a0, a1, b0, b1]).expect_stack(&[c]);
}
#[test]
fn unchecked_eqz() {
let source = "
use miden::core::math::u64
begin
exec.u64::eqz
end";
build_test!(source, &stack![0, 0]).expect_stack(&[1]);
build_test!(source, &stack![1, 0]).expect_stack(&[0]);
let a: u64 = rand_value();
let c = (a == 0) as u64;
let (a1, a0) = split_u64(a);
build_test!(source, &stack![a0, a1]).expect_stack(&[c]);
}
#[test]
fn advice_push_u64div() {
let source = format!(
"begin emit.event(\"{U64_DIV_EVENT_NAME}\") adv_push adv_push adv_push adv_push movupw.2 dropw end"
);
let a = rand_value::<u64>();
let a_hi = a >> 32;
let a_lo = a as u32 as u64;
let b = rand_value::<u64>();
let b_hi = b >> 32;
let b_lo = b as u32 as u64;
let q = a / b;
let q_hi = q >> 32;
let q_lo = q as u32 as u64;
let r = a % b;
let r_hi = r >> 32;
let r_lo = r as u32 as u64;
let input_stack = stack![b_lo, b_hi, a_lo, a_hi];
let test = build_test!(source, &input_stack);
let expected = [r_lo, r_hi, q_lo, q_hi, b_lo, b_hi, a_lo, a_hi];
test.expect_stack(&expected);
}
#[test]
fn advice_push_u64div_two_pushes() {
let source = format!(
"begin
emit.event(\"{U64_DIV_EVENT_NAME}\")
adv_push adv_push # first push: quotient [q_lo, q_hi]
adv_push adv_push # second push: remainder [r_lo, r_hi]
# Stack: [r_lo, r_hi, q_lo, q_hi, b_lo, b_hi, a_lo, a_hi]
# Drop input: positions 4-7
movup.7 drop # a_hi
movup.6 drop # a_lo
movup.5 drop # b_hi
movup.4 drop # b_lo
end"
);
let input_stack = stack![10u64, 0, 123, 0];
let test = build_test!(source, &input_stack);
test.expect_stack(&[3, 0, 12, 0]);
}
#[test]
fn advice_push_u64div_local_procedure() {
let source = format!(
"
proc foo
emit.event(\"{U64_DIV_EVENT_NAME}\")
adv_push adv_push # quotient
adv_push adv_push # remainder
end
begin
exec.foo
movupw.2 dropw
end"
);
let a = rand_value::<u64>();
let a_hi = a >> 32;
let a_lo = a as u32 as u64;
let b = rand_value::<u64>();
let b_hi = b >> 32;
let b_lo = b as u32 as u64;
let q = a / b;
let q_hi = q >> 32;
let q_lo = q as u32 as u64;
let r = a % b;
let r_hi = r >> 32;
let r_lo = r as u32 as u64;
let input_stack = stack![b_lo, b_hi, a_lo, a_hi];
let test = build_test!(source, &input_stack);
let expected = [r_lo, r_hi, q_lo, q_hi, b_lo, b_hi, a_lo, a_hi];
test.expect_stack(&expected);
}
#[test]
fn advice_push_u64div_conditional_execution() {
let source = format!(
"
begin
eq
if.true
emit.event(\"{U64_DIV_EVENT_NAME}\")
adv_push adv_push # quotient
adv_push adv_push # remainder
else
padw
end
movupw.2 dropw
end"
);
let test = build_test!(&source, &[1, 1, 4, 0, 8, 0]);
test.expect_stack(&[0, 0, 2, 0, 4, 0, 8, 0]);
let test = build_test!(&source, &[0, 1, 4, 0, 8, 0]);
test.expect_stack(&[0, 0, 0, 0, 4, 0, 8, 0]);
}
#[test]
fn unchecked_div() {
let a: u64 = rand_value();
let b: u64 = rand_value();
let c = a / b;
let source = "
use miden::core::math::u64
begin
exec.u64::div
end";
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![b0, b1, a0, a1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1]);
let d = a / b0;
let (d1, d0) = split_u64(d);
let input_stack = stack![b0, 0, a0, a1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[d0, d1]);
}
#[test]
fn ensure_div_doesnt_crash() {
let source = "
use miden::core::math::u64
begin
exec.u64::div
end";
let (dividend_hi, dividend_lo) = (0, 1);
let (divisor_hi, divisor_lo) = (u32::MAX as u64, u32::MAX as u64 + 1);
let input_stack = stack![divisor_lo, divisor_hi, dividend_lo, dividend_hi];
let test = build_test!(source, &input_stack);
let err = test.execute();
match err {
Ok(_) => panic!("expected an error"),
Err(ExecutionError::EventError { error, .. }) => {
let u64_div_error = error.downcast_ref::<U64DivError>().expect("Expected U64DivError");
assert_matches!(
u64_div_error,
U64DivError::NotU32Value {
value: 4294967296,
position: "divisor_lo"
}
);
},
Err(err) => panic!("Unexpected error type: {err:?}"),
}
let (dividend_hi, dividend_lo) = (u32::MAX as u64, u32::MAX as u64 + 1);
let (divisor_hi, divisor_lo) = (0, 1);
let input_stack = stack![divisor_lo, divisor_hi, dividend_lo, dividend_hi];
let test = build_test!(source, &input_stack);
let err = test.execute();
match err {
Ok(_) => panic!("expected an error"),
Err(ExecutionError::EventError { error, .. }) => {
let u64_div_error = error.downcast_ref::<U64DivError>().expect("Expected U64DivError");
assert_matches!(
u64_div_error,
U64DivError::NotU32Value {
value: 4294967296,
position: "dividend_lo"
}
);
},
Err(err) => panic!("Unexpected error type: {err:?}"),
}
}
#[test]
fn unchecked_mod() {
let a: u64 = rand_value();
let b: u64 = rand_value();
let c = a % b;
let source = "
use miden::core::math::u64
begin
exec.u64::mod
end";
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![b0, b1, a0, a1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1]);
let d = a % b0;
let (d1, d0) = split_u64(d);
let input_stack = stack![b0, 0, a0, a1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[d0, d1]);
}
#[test]
fn unchecked_divmod() {
let a: u64 = rand_value();
let b: u64 = rand_value();
let q = a / b;
let r = a % b;
let source = "
use miden::core::math::u64
begin
exec.u64::divmod
end";
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (q1, q0) = split_u64(q);
let (r1, r0) = split_u64(r);
let input_stack = stack![b0, b1, a0, a1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[r0, r1, q0, q1]);
}
#[test]
fn checked_and() {
let a: u64 = rand_value();
let b: u64 = rand_value();
let c = a & b;
let source = "
use miden::core::math::u64
begin
exec.u64::and
end";
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1]);
}
#[test]
fn checked_and_fail() {
let a0: u64 = rand_value();
let b0: u64 = rand_value();
let a1: u64 = U32_BOUND;
let b1: u64 = U32_BOUND;
let source = "
use miden::core::math::u64
begin
exec.u64::and
end";
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
expect_exec_error_matches!(
test,
ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if
values.len() == 2 &&
values.contains(&Felt::new_unchecked(a0)) &&
values.contains(&Felt::new_unchecked(b0))
);
}
#[test]
fn checked_or() {
let a: u64 = rand_value();
let b: u64 = rand_value();
let c = a | b;
let source = "
use miden::core::math::u64
begin
exec.u64::or
end";
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1]);
}
#[test]
fn checked_or_fail() {
let a0: u64 = rand_value();
let b0: u64 = rand_value();
let a1: u64 = U32_BOUND;
let b1: u64 = U32_BOUND;
let source = "
use miden::core::math::u64
begin
exec.u64::or
end";
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
expect_exec_error_matches!(
test,
ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if
values.len() == 2 &&
values.contains(&Felt::new_unchecked(a0)) &&
values.contains(&Felt::new_unchecked(b0))
);
}
#[test]
fn checked_xor() {
let a: u64 = rand_value();
let b: u64 = rand_value();
let c = a ^ b;
let source = "
use miden::core::math::u64
begin
exec.u64::xor
end";
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
test.expect_stack(&[c0, c1]);
}
#[test]
fn checked_xor_fail() {
let a0: u64 = rand_value();
let b0: u64 = rand_value();
let a1: u64 = U32_BOUND;
let b1: u64 = U32_BOUND;
let source = "
use miden::core::math::u64
begin
exec.u64::xor
end";
let input_stack = stack![a0, a1, b0, b1];
let test = build_test!(source, &input_stack);
expect_exec_error_matches!(
test,
ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if
values.len() == 2 &&
values.contains(&Felt::new_unchecked(a0)) &&
values.contains(&Felt::new_unchecked(b0))
);
}
#[test]
fn unchecked_shl() {
let source = "
use miden::core::math::u64
begin
exec.u64::shl
end";
let a: u64 = rand_value();
let (a1, a0) = split_u64(a);
let b: u32 = 0;
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[a0, a1, 777]);
let b: u32 = 31;
let c = a.wrapping_shl(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
let a = 1_u64;
let (a1, a0) = split_u64(a);
let b: u32 = 32;
let c = a.wrapping_shl(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
let a = 1_u64;
let (a1, a0) = split_u64(a);
let b: u32 = 33;
let c = a.wrapping_shl(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
let a = 64_u64;
let (a1, a0) = split_u64(a);
let b: u32 = 58;
let c = a.wrapping_shl(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
}
#[test]
fn unchecked_shr() {
let source = "
use miden::core::math::u64
begin
exec.u64::shr
end";
let a: u64 = rand_value();
let (a1, a0) = split_u64(a);
let b: u32 = 0;
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[a0, a1, 777]);
build_test!(source, &stack![1, 1, 1, 777]).expect_stack(&[2_u64.pow(31), 0, 777]);
build_test!(source, &stack![1, 3, 3, 777]).expect_stack(&[2_u64.pow(31) + 1, 1, 777]);
let b: u32 = 31;
let c = a.wrapping_shr(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
let a = 1_u64;
let (a1, a0) = split_u64(a);
let b: u32 = 32;
let c = a.wrapping_shr(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
let a = 1_u64;
let (a1, a0) = split_u64(a);
let b: u32 = 33;
let c = a.wrapping_shr(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
let a = 4294967296;
let (a1, a0) = split_u64(a);
let b: u32 = 2;
let c = a.wrapping_shr(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
}
#[test]
fn shr_bug_shift_eq32_with_lo_all_ones() {
let source = "
use miden::core::math::u64
begin
exec.u64::shr
end";
let a: u64 = 0x0000_0005_ffff_ffff;
let (a1, a0) = split_u64(a);
let expected = a >> 32;
let (e1, e0) = split_u64(expected);
build_test!(source, &stack![32_u64, a0, a1, 99]).expect_stack(&[e0, e1, 99]);
}
#[test]
fn shr_bug_shift_gt32_with_lo_all_ones() {
let source = "
use miden::core::math::u64
begin
exec.u64::shr
end";
let a: u64 = 0x0000_0007_ffff_ffff;
let (a1, a0) = split_u64(a);
let expected = a >> 33;
let (e1, e0) = split_u64(expected);
build_test!(source, &stack![33_u64, a0, a1, 99]).expect_stack(&[e0, e1, 99]);
}
#[test]
fn shr_bug_shift_ge32_with_lo_all_ones_boundary_sweep() {
let source = "
use miden::core::math::u64
begin
exec.u64::shr
end";
let shifts = [32_u32, 33_u32, 47_u32, 63_u32];
let hi_values = [1_u32, 5_u32, u32::MAX];
for shift in shifts {
for hi in hi_values {
let a = ((hi as u64) << 32) | (u32::MAX as u64);
let (a1, a0) = split_u64(a);
let expected = a >> shift;
let (e1, e0) = split_u64(expected);
build_test!(source, &stack![shift as u64, a0, a1, 99]).expect_stack(&[e0, e1, 99]);
}
}
}
#[test]
fn unchecked_rotl() {
let source = "
use miden::core::math::u64
begin
exec.u64::rotl
end";
let a: u64 = rand_value();
let (a1, a0) = split_u64(a);
let b: u32 = 0;
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[a0, a1, 777]);
let b: u32 = 31;
let c = a.rotate_left(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
let a = 1_u64;
let (a1, a0) = split_u64(a);
let b: u32 = 32;
let c = a.rotate_left(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
let a = 1_u64;
let (a1, a0) = split_u64(a);
let b: u32 = 33;
let c = a.rotate_left(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
let a = 64_u64;
let (a1, a0) = split_u64(a);
let b: u32 = 58;
let c = a.rotate_left(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
}
#[test]
fn unchecked_rotr() {
let source = "
use miden::core::math::u64
begin
exec.u64::rotr
end";
let a: u64 = rand_value();
let (a1, a0) = split_u64(a);
let b: u32 = 0;
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[a0, a1, 777]);
let b: u32 = 31;
let c = a.rotate_right(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
let a = 1_u64;
let (a1, a0) = split_u64(a);
let b: u32 = 32;
let c = a.rotate_right(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
let a = 1_u64;
let (a1, a0) = split_u64(a);
let b: u32 = 33;
let c = a.rotate_right(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
let a = 64_u64;
let (a1, a0) = split_u64(a);
let b: u32 = 58;
let c = a.rotate_right(b);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
}
#[test]
fn unchecked_rotr_large_value_by_0() {
let source = "
use miden::core::math::u64
begin
exec.u64::rotr
end";
let a = Felt::ORDER_U64 + 1;
let (a1, a0) = split_u64(a);
build_test!(source, &stack![0_u64, a0, a1, 777]).expect_stack(&[a0, a1, 777]);
}
#[test]
fn unchecked_rotr_large_value_by_32() {
let source = "
use miden::core::math::u64
begin
exec.u64::rotr
end";
let a = Felt::ORDER_U64 + 1;
let (a1, a0) = split_u64(a);
let c = a.rotate_right(32);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![32_u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
}
#[test]
fn unchecked_rotl_large_value_by_0() {
let source = "
use miden::core::math::u64
begin
exec.u64::rotl
end";
let a = Felt::ORDER_U64 + 1;
let (a1, a0) = split_u64(a);
build_test!(source, &stack![0_u64, a0, a1, 777]).expect_stack(&[a0, a1, 777]);
}
#[test]
fn unchecked_rotl_large_value_by_32() {
let source = "
use miden::core::math::u64
begin
exec.u64::rotl
end";
let a = Felt::ORDER_U64 + 1;
let (a1, a0) = split_u64(a);
let c = a.rotate_left(32);
let (c1, c0) = split_u64(c);
build_test!(source, &stack![32_u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]);
}
#[test]
fn clz() {
let source = "
use miden::core::math::u64
begin
exec.u64::clz
end";
build_test!(source, &stack![0, 0]).expect_stack(&[64]);
build_test!(source, &stack![492665065, 0]).expect_stack(&[35]);
build_test!(source, &stack![3941320520, 0]).expect_stack(&[32]);
build_test!(source, &stack![3941320520, 492665065]).expect_stack(&[3]);
build_test!(source, &stack![492665065, 492665065]).expect_stack(&[3]);
}
#[test]
fn u32clz_zero_boundary_regression() {
let source = "begin u32clz end";
build_test!(source, &stack![0], &[31]).expect_stack(&[32]);
}
#[test]
fn u32clz_nonzero_boundary_regression() {
let source = "begin u32clz end";
build_test!(source, &stack![1], &[32]).expect_stack(&[31]);
}
#[cfg(feature = "arbitrary")]
proptest! {
#[test]
fn u32clz_matches_rust_leading_zeros(n in any::<u32>()) {
let source = "begin u32clz end";
build_test!(source, &stack![n as u64]).expect_stack(&[n.leading_zeros() as u64]);
}
}
#[test]
fn ctz() {
let source = "
use miden::core::math::u64
begin
exec.u64::ctz
end";
build_test!(source, &stack![0, 0]).expect_stack(&[64]);
build_test!(source, &stack![0, 3668265216]).expect_stack(&[40]);
build_test!(source, &stack![0, 3668265217]).expect_stack(&[32]);
build_test!(source, &stack![3668265216, 3668265217]).expect_stack(&[8]);
build_test!(source, &stack![3668265216, 3668265216]).expect_stack(&[8]);
}
#[test]
fn clo() {
let source = "
use miden::core::math::u64
begin
exec.u64::clo
end";
build_test!(source, &stack![4294967295, 4294967295]).expect_stack(&[64]);
build_test!(source, &stack![4278190080, 4294967295]).expect_stack(&[40]);
build_test!(source, &stack![0, 4294967295]).expect_stack(&[32]);
build_test!(source, &stack![0, 4278190080]).expect_stack(&[8]);
build_test!(source, &stack![4278190080, 4278190080]).expect_stack(&[8]);
}
#[test]
fn cto() {
let source = "
use miden::core::math::u64
begin
exec.u64::cto
end";
build_test!(source, &stack![4294967295, 4294967295]).expect_stack(&[64]);
build_test!(source, &stack![4294967295, 255]).expect_stack(&[40]);
build_test!(source, &stack![4294967295, 0]).expect_stack(&[32]);
build_test!(source, &stack![255, 0]).expect_stack(&[8]);
build_test!(source, &stack![255, 255]).expect_stack(&[8]);
}
#[cfg(feature = "arbitrary")]
proptest! {
#[test]
fn unchecked_lt_proptest(a in any::<u64>(), b in any::<u64>()) {
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let c = (a < b) as u64;
let source = "
use miden::core::math::u64
begin
exec.u64::lt
end";
build_test!(source, &stack![b0, b1, a0, a1]).prop_expect_stack(&[c])?;
}
#[test]
fn unchecked_gt_proptest(a in any::<u64>(), b in any::<u64>()) {
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let c = (a > b) as u64;
let source = "
use miden::core::math::u64
begin
exec.u64::gt
end";
build_test!(source, &stack![b0, b1, a0, a1]).prop_expect_stack(&[c])?;
}
#[test]
fn unchecked_min_proptest(a in any::<u64>(), b in any::<u64>()) {
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let c = cmp::min(a, b);
let (c1, c0) = split_u64(c);
let source = "
use miden::core::math::u64
begin
exec.u64::min
end";
build_test!(source, &stack![a0, a1, b0, b1]).prop_expect_stack(&[c0, c1])?;
}
#[test]
fn unchecked_max_proptest(a in any::<u64>(), b in any::<u64>()) {
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let c = cmp::max(a, b);
let (c1, c0) = split_u64(c);
let source = "
use miden::core::math::u64
begin
exec.u64::max
end";
build_test!(source, &stack![a0, a1, b0, b1]).prop_expect_stack(&[c0, c1])?;
}
#[test]
fn unchecked_div_proptest(a in any::<u64>(), b in any::<u64>()) {
let c = a / b;
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let source = "
use miden::core::math::u64
begin
exec.u64::div
end";
build_test!(source, &stack![b0, b1, a0, a1]).prop_expect_stack(&[c0, c1])?;
}
#[test]
fn unchecked_mod_proptest(a in any::<u64>(), b in any::<u64>()) {
let c = a % b;
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c1, c0) = split_u64(c);
let source = "
use miden::core::math::u64
begin
exec.u64::mod
end";
build_test!(source, &stack![b0, b1, a0, a1]).prop_expect_stack(&[c0, c1])?;
}
#[test]
fn widening_mul_proptest(a in boundary_biased_u64(), b in boundary_biased_u64()) {
let c = (a as u128) * (b as u128);
let (a1, a0) = split_u64(a);
let (b1, b0) = split_u64(b);
let (c3, c2, c1, c0) = split_u128(c);
let source = "
use miden::core::math::u64
begin
exec.u64::widening_mul
end";
build_test!(source, &stack![b0, b1, a0, a1, 777]).prop_expect_stack(&[c0, c1, c2, c3, 777])?;
}
#[test]
fn shl_proptest(a in any::<u64>(), b in 0_u32..64) {
let c = a.wrapping_shl(b);
let (a1, a0) = split_u64(a);
let (c1, c0) = split_u64(c);
let source = "
use miden::core::math::u64
begin
exec.u64::shl
end";
build_test!(source, &stack![b as u64, a0, a1, 777]).prop_expect_stack(&[c0, c1, 777])?;
}
#[test]
fn shr_proptest(a in boundary_biased_u64(), b in boundary_biased_shift()) {
let c = a.wrapping_shr(b);
let (a1, a0) = split_u64(a);
let (c1, c0) = split_u64(c);
let source = "
use miden::core::math::u64
begin
exec.u64::shr
end";
build_test!(source, &stack![b as u64, a0, a1, 777]).prop_expect_stack(&[c0, c1, 777])?;
}
#[test]
fn rotl_proptest(a in boundary_biased_u64(), b in boundary_biased_shift()) {
let c = a.rotate_left(b);
let (a1, a0) = split_u64(a);
let (c1, c0) = split_u64(c);
let source = "
use miden::core::math::u64
begin
exec.u64::rotl
end";
build_test!(source, &stack![b as u64, a0, a1, 777]).prop_expect_stack(&[c0, c1, 777])?;
}
#[test]
fn rotr_proptest(a in boundary_biased_u64(), b in boundary_biased_shift()) {
let c = a.rotate_right(b);
let (a1, a0) = split_u64(a);
let (c1, c0) = split_u64(c);
let source = "
use miden::core::math::u64
begin
exec.u64::rotr
end";
build_test!(source, &stack![b as u64, a0, a1, 777]).prop_expect_stack(&[c0, c1, 777])?;
}
#[test]
fn clz_proptest(a in any::<u64>()) {
let (a1, a0) = split_u64(a);
let c = a.leading_zeros() as u64;
let source = "
use miden::core::math::u64
begin
exec.u64::clz
end";
build_test!(source, &stack![a0, a1]).prop_expect_stack(&[c])?;
}
#[test]
fn ctz_proptest(a in any::<u64>()) {
let (a1, a0) = split_u64(a);
let c = a.trailing_zeros() as u64;
let source = "
use miden::core::math::u64
begin
exec.u64::ctz
end";
build_test!(source, &stack![a0, a1]).prop_expect_stack(&[c])?;
}
#[test]
fn clo_proptest(a in any::<u64>()) {
let (a1, a0) = split_u64(a);
let c = a.leading_ones() as u64;
let source = "
use miden::core::math::u64
begin
exec.u64::clo
end";
build_test!(source, &stack![a0, a1]).prop_expect_stack(&[c])?;
}
#[test]
fn cto_proptest(a in any::<u64>()) {
let (a1, a0) = split_u64(a);
let c = a.trailing_ones() as u64;
let source = "
use miden::core::math::u64
begin
exec.u64::cto
end";
build_test!(source, &stack![a0, a1]).prop_expect_stack(&[c])?;
}
}
#[cfg(feature = "arbitrary")]
fn boundary_biased_u64() -> impl Strategy<Value = u64> {
prop_oneof![
Just(0u64),
Just(1u64),
Just(u32::MAX as u64),
Just(1u64 << 32),
Just((1u64 << 32) - 1),
Just((1u64 << 32) + 1),
Just(u64::MAX),
Just(u64::MAX - 1),
Just(u64::MAX << 32),
Just((u64::MAX << 32) | 1),
any::<u64>(),
]
}
#[cfg(feature = "arbitrary")]
fn boundary_biased_shift() -> impl Strategy<Value = u32> {
prop_oneof![
Just(0u32),
Just(1u32),
Just(31u32),
Just(32u32),
Just(33u32),
Just(63u32),
0_u32..64,
]
}
fn split_u64(value: u64) -> (u64, u64) {
(value >> 32, value as u32 as u64)
}
fn split_u128(value: u128) -> (u64, u64, u64, u64) {
(
(value >> 96) as u64,
(value >> 64) as u32 as u64,
(value >> 32) as u32 as u64,
value as u32 as u64,
)
}