use alloc::vec::Vec;
use core::mem::size_of;
use miden_core::{Felt, WORD_SIZE};
use miden_processor::ProcessState;
pub(crate) const BYTES_PER_U32: usize = size_of::<u32>();
pub mod ecdsa;
pub mod falcon_div;
pub mod keccak256;
pub mod smt_peek;
pub mod sorted_array;
pub mod u64_div;
fn u64_to_u32_elements(value: u64) -> (Felt, Felt) {
let hi = Felt::from((value >> 32) as u32);
let lo = Felt::from(value as u32);
(hi, lo)
}
pub(crate) fn read_memory_packed_u32(
process: &ProcessState,
start: u64,
len_bytes: usize,
) -> Result<Vec<u8>, MemoryReadError> {
if !start.is_multiple_of(WORD_SIZE as u64) {
return Err(MemoryReadError::UnalignedAddress { address: start });
}
let len_felt = len_bytes.div_ceil(BYTES_PER_U32);
let end = start
.checked_add(len_felt as u64)
.ok_or(MemoryReadError::AddressOverflow { start, len_bytes })?;
let start_u32 = start
.try_into()
.map_err(|_| MemoryReadError::AddressOverflow { start, len_bytes })?;
let end_u32 = end
.try_into()
.map_err(|_| MemoryReadError::AddressOverflow { start, len_bytes })?;
let len_padded = len_bytes
.checked_next_multiple_of(BYTES_PER_U32)
.ok_or(MemoryReadError::AddressOverflow { start, len_bytes })?;
let mut out = Vec::with_capacity(len_padded);
let ctx = process.ctx();
for address in start_u32..end_u32 {
let felt = process
.get_mem_value(ctx, address)
.ok_or(MemoryReadError::MemoryAccessFailed { address })?;
let value = felt.as_int();
let packed: u32 =
value.try_into().map_err(|_| MemoryReadError::InvalidValue { value, address })?;
out.extend(packed.to_le_bytes());
}
for (offset, &byte) in out[len_bytes..].iter().enumerate() {
if byte != 0 {
return Err(MemoryReadError::InvalidPadding {
value: byte,
position: len_bytes + offset,
});
}
}
out.truncate(len_bytes);
Ok(out)
}
pub fn bytes_to_packed_u32_felts(bytes: &[u8]) -> Vec<Felt> {
bytes
.chunks(BYTES_PER_U32)
.map(|chunk| {
let mut packed = [0u8; BYTES_PER_U32];
packed[..chunk.len()].copy_from_slice(chunk);
Felt::from(u32::from_le_bytes(packed))
})
.collect()
}
#[derive(Debug, thiserror::Error)]
pub(crate) enum MemoryReadError {
#[error("address overflow: start={start}, len_bytes={len_bytes}")]
AddressOverflow { start: u64, len_bytes: usize },
#[error("address {address} is not word-aligned (must be divisible by 4)")]
UnalignedAddress { address: u64 },
#[error("failed to read memory at address {address}")]
MemoryAccessFailed { address: u32 },
#[error("field element value {value} at address {address} exceeds u32::MAX")]
InvalidValue { value: u64, address: u32 },
#[error("non-zero padding byte {value:#x} at byte position {position}")]
InvalidPadding { value: u8, position: usize },
}