use alloc::vec::Vec;
use crate::TeeParamError;
pub const HEADER_LEN: usize = 4;
pub const fn capacity(max: usize) -> usize {
HEADER_LEN + max
}
pub fn write(buf: &mut [u8], payload: &[u8]) -> Result<usize, TeeParamError> {
let len = u32::try_from(payload.len()).map_err(|_| TeeParamError::EncodeFailed)?;
let total = HEADER_LEN + payload.len();
if total > buf.len() {
consortium_log::trace!(
"tee inout frame needs {} bytes but buffer is {}",
total,
buf.len()
);
return Err(TeeParamError::EncodeFailed);
}
buf[..HEADER_LEN].copy_from_slice(&len.to_le_bytes());
buf[HEADER_LEN..total].copy_from_slice(payload);
Ok(total)
}
pub fn to_vec(payload: &[u8]) -> Result<Vec<u8>, TeeParamError> {
let mut buf = alloc::vec![0; HEADER_LEN + payload.len()];
write(&mut buf, payload)?;
Ok(buf)
}
pub fn read(buf: &[u8], max: usize) -> Result<&[u8], TeeParamError> {
let Some((header, rest)) = buf.split_first_chunk::<HEADER_LEN>() else {
consortium_log::trace!("tee inout frame truncated: {} bytes", buf.len());
return Err(TeeParamError::DecodeFailed);
};
let len = u32::from_le_bytes(*header) as usize;
if len > max || len > rest.len() {
consortium_log::trace!(
"tee inout frame declares {} bytes, max {}, present {}",
len,
max,
rest.len()
);
return Err(TeeParamError::DecodeFailed);
}
Ok(&rest[..len])
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trips_through_a_padded_buffer() {
let mut buf = [0xAAu8; capacity(8)];
assert_eq!(write(&mut buf, &[1, 2, 3]), Ok(HEADER_LEN + 3));
assert_eq!(read(&buf, 8), Ok(&[1u8, 2, 3][..]));
assert_eq!(to_vec(&[1, 2, 3]).as_deref(), Ok(&buf[..HEADER_LEN + 3]));
}
#[test]
fn empty_payload_is_a_valid_frame() {
let frame = to_vec(&[]).unwrap();
assert_eq!(frame, [0, 0, 0, 0]);
assert_eq!(read(&frame, 0), Ok(&[][..]));
}
#[test]
fn write_rejects_a_buffer_without_room() {
let mut buf = [0u8; capacity(2)];
assert_eq!(
write(&mut buf, &[1, 2, 3]),
Err(TeeParamError::EncodeFailed)
);
}
#[test]
fn read_rejects_truncated_oversized_and_overlong_frames() {
assert_eq!(read(&[3, 0], 8), Err(TeeParamError::DecodeFailed));
assert_eq!(
read(&[9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 8),
Err(TeeParamError::DecodeFailed)
);
assert_eq!(
read(&[4, 0, 0, 0, 1, 2], 8),
Err(TeeParamError::DecodeFailed)
);
}
}