use alloc::{boxed::Box, string::String, vec::Vec};
use core::{
fmt::{self, Write},
mem::{ManuallyDrop, MaybeUninit},
};
#[cfg(feature = "std")]
pub use miden_serde_utils::ReadAdapter;
pub use miden_serde_utils::{
BudgetedReader, ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
SliceReader,
};
use p3_maybe_rayon::prelude::*;
use crate::{Felt, Word, field::QuotientMap};
const BINARY_CHUNK_SIZE: usize = 7;
pub use k256::elliptic_curve::zeroize;
pub fn word_to_hex(w: &Word) -> Result<String, fmt::Error> {
let mut s = String::new();
for byte in w.iter().flat_map(|&e| e.to_bytes()) {
write!(s, "{byte:02x}")?;
}
Ok(s)
}
pub use miden_field::utils::{HexParseError, bytes_to_hex_string, hex_to_bytes};
pub fn bytes_to_elements_with_padding(bytes: &[u8]) -> Vec<Felt> {
if bytes.is_empty() {
return vec![];
}
let num_field_elem = bytes.len().div_ceil(BINARY_CHUNK_SIZE);
let mut buf = [0_u8; 8];
let last_chunk_idx = num_field_elem - 1;
bytes
.chunks(BINARY_CHUNK_SIZE)
.enumerate()
.map(|(current_chunk_idx, chunk)| {
if current_chunk_idx != last_chunk_idx {
buf[..BINARY_CHUNK_SIZE].copy_from_slice(chunk);
} else {
buf.fill(0);
buf[..chunk.len()].copy_from_slice(chunk);
buf[chunk.len()] = 1;
}
Felt::new_unchecked(u64::from_le_bytes(buf))
})
.collect()
}
pub fn padded_elements_to_bytes(felts: &[Felt]) -> Option<Vec<u8>> {
let number_felts = felts.len();
if number_felts == 0 {
return Some(vec![]);
}
let mut result = Vec::with_capacity(number_felts * BINARY_CHUNK_SIZE);
for felt in felts.iter().take(number_felts - 1) {
let felt_bytes = felt.as_canonical_u64().to_le_bytes();
result.extend_from_slice(&felt_bytes[..BINARY_CHUNK_SIZE]);
}
let felt_bytes = felts[number_felts - 1].as_canonical_u64().to_le_bytes();
let pos = felt_bytes.iter().rposition(|entry| *entry == 1_u8)?;
result.extend_from_slice(&felt_bytes[..pos]);
Some(result)
}
pub fn elements_to_bytes(felts: &[Felt]) -> Vec<u8> {
let number_felts = felts.len();
let mut result = Vec::with_capacity(number_felts * Felt::NUM_BYTES);
for felt in felts.iter().take(number_felts) {
let felt_bytes = felt.as_canonical_u64().to_le_bytes();
result.extend_from_slice(&felt_bytes);
}
result
}
pub fn bytes_to_elements_exact(bytes: &[u8]) -> Option<Vec<Felt>> {
if !bytes.len().is_multiple_of(Felt::NUM_BYTES) {
return None;
}
let mut result = Vec::with_capacity(bytes.len() / Felt::NUM_BYTES);
for chunk in bytes.chunks_exact(Felt::NUM_BYTES) {
let chunk_array: [u8; Felt::NUM_BYTES] =
chunk.try_into().expect("should succeed given the length check above");
let value = u64::from_le_bytes(chunk_array);
let felt = Felt::from_canonical_checked(value)?;
result.push(felt);
}
Some(result)
}
pub fn bytes_to_packed_u32_elements(bytes: &[u8]) -> Vec<Felt> {
const BYTES_PER_U32: usize = size_of::<u32>();
bytes
.chunks(BYTES_PER_U32)
.map(|chunk| {
let mut packed = [0u8; BYTES_PER_U32];
packed[..chunk.len()].copy_from_slice(chunk);
Felt::from_u32(u32::from_le_bytes(packed))
})
.collect()
}
pub fn uninit_vector<T>(length: usize) -> Vec<MaybeUninit<T>> {
Vec::from(Box::new_uninit_slice(length))
}
pub unsafe fn assume_init_vec<T>(v: Vec<MaybeUninit<T>>) -> Vec<T> {
let mut v = ManuallyDrop::new(v);
let ptr = v.as_mut_ptr();
let len = v.len();
let cap = v.capacity();
unsafe { Vec::from_raw_parts(ptr.cast::<T>(), len, cap) }
}
pub fn group_slice_elements<T, const N: usize>(source: &[T]) -> &[[T; N]] {
let (chunks, remainder) = source.as_chunks::<N>();
assert!(remainder.is_empty(), "source length must be divisible by {N}");
chunks
}
pub fn flatten_slice_elements<T, const N: usize>(source: &[[T; N]]) -> &[T] {
unsafe { p3_util::as_base_slice(source) }
}
pub fn flatten_vector_elements<T, const N: usize>(source: Vec<[T; N]>) -> Vec<T> {
unsafe { p3_util::flatten_to_base(source) }
}
pub fn transpose_slice<T: Copy + Send + Sync, const N: usize>(source: &[T]) -> Vec<[T; N]> {
let row_count = source.len() / N;
assert_eq!(
row_count * N,
source.len(),
"source length must be divisible by {}, but was {}",
N,
source.len()
);
let mut result = uninit_vector::<[T; N]>(row_count);
result.par_iter_mut().enumerate().for_each(|(i, slot)| {
let row = core::array::from_fn(|j| source[i + j * row_count]);
slot.write(row);
});
unsafe { assume_init_vec(result) }
}