use steel::*;
use crate::consts::*;
use crate::error::*;
use crate::types::*;
use brine_tree::{MerkleTree, Leaf};
pub fn check_condition<E>(condition: bool, err: E) -> ProgramResult
where
E: Into<ProgramError>,
{
if !condition {
return Err(err.into());
}
Ok(())
}
pub fn padded_array<const N: usize>(input: &[u8]) -> [u8; N] {
assert!(input.len() <= N, "input too long");
let mut out = [0u8; N];
out[..input.len()].copy_from_slice(input);
out
}
pub fn to_name(val: &str) -> [u8; MAX_NAME_LEN] {
assert!(val.len() <= MAX_NAME_LEN, "name too long");
padded_array::<MAX_NAME_LEN>(val.as_bytes())
}
pub fn from_name(val: &[u8; MAX_NAME_LEN]) -> String {
let mut name_bytes = val.to_vec();
name_bytes.retain(|&x| x != 0);
String::from_utf8(name_bytes).unwrap()
}
#[inline(always)]
pub fn compute_leaf(
segment_id: u64,
chunk_id: u64,
chunk: &Chunk
) -> Leaf {
let segment_id = segment_id.to_le_bytes();
let chunk_id = chunk_id.to_le_bytes();
Leaf::new(&[
segment_id.as_ref(), chunk_id.as_ref(), chunk.as_bytes(),
])
}
#[inline(always)]
pub fn write_chunks(
tree: &mut MerkleTree<{TREE_HEIGHT}>,
segment_id: u64,
segment: &Segment,
) -> ProgramResult {
let chunks = segment.chunks();
for (chunk_id, chunk) in chunks.enumerate() {
let leaf = compute_leaf(
segment_id,
chunk_id as u64,
&chunk);
check_condition(
tree.try_add_leaf(leaf).is_ok(),
TapeError::WriteFailed,
)?;
}
Ok(())
}
#[inline(always)]
pub fn compute_recall_tape(
challenge: &[u8; 32],
total_tapes: u64,
) -> u64 {
if total_tapes == 0 {
return 1;
}
(u64::from_le_bytes(challenge[0..8].try_into().unwrap()) % total_tapes)
.max(1)
}
#[inline(always)]
pub fn compute_recall_segment(
challenge: &[u8; 32],
total_segments: u64,
) -> u64 {
if total_segments == 0 {
return 0;
}
u64::from_le_bytes(challenge[8..16].try_into().unwrap()) % total_segments
}
#[inline(always)]
pub fn compute_recall_chunk(
challenge: &[u8; 32],
) -> u64 {
u64::from_le_bytes(challenge[16..24].try_into().unwrap()) % MAGIC_NUMBER as u64
}