use alloc::vec::Vec;
use core::num::NonZeroU32;
use miden_core::deferred::{DataChunk, Node, PrecompileError};
pub const BYTES_PER_CHUNK: u32 = Node::PACKED_BYTES_PER_CHUNK as u32;
pub fn n_chunks(n_bytes: u32) -> NonZeroU32 {
NonZeroU32::new(n_bytes.div_ceil(BYTES_PER_CHUNK).max(1)).expect("clamped to at least 1")
}
pub fn chunks_to_bytes(chunks: &[DataChunk], n_bytes: usize) -> Result<Vec<u8>, PrecompileError> {
let chunk_bytes = BYTES_PER_CHUNK as usize;
if n_bytes > chunks.len() * chunk_bytes {
return Err(PrecompileError::InvalidNode);
}
let mut bytes = Vec::with_capacity(chunks.len() * chunk_bytes);
for chunk in chunks {
for felt in chunk {
let limb =
u32::try_from(felt.as_canonical_u64()).map_err(|_| PrecompileError::InvalidNode)?;
bytes.extend_from_slice(&limb.to_le_bytes());
}
}
if bytes[n_bytes..].iter().any(|&b| b != 0) {
return Err(PrecompileError::InvalidNode);
}
bytes.truncate(n_bytes);
Ok(bytes)
}
pub fn chunks_to_bytes_exact(
chunks: &[DataChunk],
expected_chunks: usize,
n_bytes: usize,
) -> Result<Vec<u8>, PrecompileError> {
if chunks.len() != expected_chunks {
return Err(PrecompileError::InvalidNode);
}
chunks_to_bytes(chunks, n_bytes)
}