use alloc::{vec, vec::Vec};
use miden_core::Felt;
use miden_processor::{
ProcessorState,
advice::AdviceMutation,
event::{EventError, EventName},
};
pub const U128_DIV_EVENT_NAME: EventName = EventName::new("miden::core::math::u128::u128_div");
pub fn handle_u128_div(process: &ProcessorState) -> Result<Vec<AdviceMutation>, EventError> {
let divisor = read_u128_from_stack(process, 1, "divisor")?;
if divisor == 0 {
return Err(U128DivError::DivideByZero.into());
}
let dividend = read_u128_from_stack(process, 5, "dividend")?;
let quotient = dividend / divisor;
let remainder = dividend - quotient * divisor;
let (q0, q1, q2, q3) = u128_to_u32_felts(quotient);
let (r0, r1, r2, r3) = u128_to_u32_felts(remainder);
let mutation = AdviceMutation::extend_stack([r0, r1, r2, r3, q0, q1, q2, q3]);
Ok(vec![mutation])
}
fn read_u128_from_stack(
process: &ProcessorState,
start: usize,
name: &'static str,
) -> Result<u128, EventError> {
let mut value: u128 = 0;
for i in (0..4).rev() {
let limb = process.get_stack_item(start + i).as_canonical_u64();
if limb > u32::MAX as u64 {
return Err(U128DivError::NotU32Value {
value: limb,
position: name,
limb_index: i,
}
.into());
}
value = (value << 32) | limb as u128;
}
Ok(value)
}
fn u128_to_u32_felts(value: u128) -> (Felt, Felt, Felt, Felt) {
let limb0 = Felt::from_u32(value as u32);
let limb1 = Felt::from_u32((value >> 32) as u32);
let limb2 = Felt::from_u32((value >> 64) as u32);
let limb3 = Felt::from_u32((value >> 96) as u32);
(limb0, limb1, limb2, limb3)
}
#[derive(Debug, thiserror::Error)]
pub enum U128DivError {
#[error("division by zero")]
DivideByZero,
#[error("value {value} at {position} limb {limb_index} is not a valid u32")]
NotU32Value {
value: u64,
position: &'static str,
limb_index: usize,
},
}