use crate::Result;
use amadeus_utils::blake3;
use amadeus_utils::{Hash, PublicKey, Signature};
use std::convert::TryInto;
pub const PREAMBLE_SIZE: usize = 240;
pub const MATRIX_SIZE: usize = 1024;
pub const SOL_SIZE: usize = PREAMBLE_SIZE + MATRIX_SIZE;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Sol {
pub epoch: u64,
pub segment_vr_hash: Hash,
pub pk: PublicKey,
pub pop: Signature,
pub computor: PublicKey,
pub nonce: [u8; 12],
pub tensor_c: [u8; 1024],
}
pub fn unpack(sol: &[u8; SOL_SIZE]) -> Result<Sol> {
let epoch = u32::from_le_bytes(sol[0..4].try_into().map_err(|_| "sol_unpack_failed")?) as u64;
let segment_vr_hash = Hash::new(sol[4..36].try_into().map_err(|_| "sol_unpack_failed")?);
let pk = PublicKey::new(sol[36..84].try_into().map_err(|_| "sol_unpack_failed")?);
let pop = Signature::new(sol[84..180].try_into().map_err(|_| "sol_unpack_failed")?);
let computor = PublicKey::new(sol[180..228].try_into().map_err(|_| "sol_unpack_failed")?);
let nonce: [u8; 12] = sol[228..240].try_into().map_err(|_| "sol_unpack_failed")?;
let tensor_c: [u8; 1024] = sol[240..(240 + 1024)].try_into().map_err(|_| "sol_unpack_failed")?;
Ok(Sol { epoch, segment_vr_hash, pk, pop, computor, nonce, tensor_c })
}
pub fn verify_hash_diff(_epoch: u64, hash: &[u8], diff_bits: u64) -> bool {
if diff_bits > 256 {
return false;
}
let (full, rem) = ((diff_bits / 8) as usize, (diff_bits % 8) as u8);
hash[..full].iter().all(|&b| b == 0) && (rem == 0 || (hash[full] & (0xFF << (8 - rem))) == 0)
}
pub fn verify(
sol: &[u8; SOL_SIZE],
solhash: &[u8],
segment_vr_hash: &[u8],
vr_b3: &[u8],
diff_bits: u64,
) -> Result<bool> {
let usol = unpack(sol)?;
if segment_vr_hash != &*usol.segment_vr_hash {
return Err("segment_vr_hash");
}
if sol.len() != SOL_SIZE {
return Err("invalid_sol_seed_size");
}
Ok(verify_hash_diff(usol.epoch, solhash, diff_bits) && blake3::freivalds_e260(sol, vr_b3))
}