use crate::pow::error::Error;
use crate::pow::siphash::siphash24;
use blake2::blake2b::blake2b;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use num::{PrimInt, ToPrimitive};
use std::fmt;
use std::hash::Hash;
use std::io::Cursor;
use std::ops::{BitOrAssign, Mul};
pub trait EdgeType: PrimInt + ToPrimitive + Mul + BitOrAssign + Hash {}
impl EdgeType for u32 {}
impl EdgeType for u64 {}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct Edge {
pub u: u64,
pub v: u64,
}
impl fmt::Display for Edge {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(u: {}, v: {})", self.u, self.v)
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Link {
pub next: u64,
pub to: u64,
}
impl fmt::Display for Link {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(next: {}, to: {})", self.next, self.to)
}
}
pub fn set_header_nonce(header: &[u8], nonce: Option<u32>) -> Result<[u64; 4], Error> {
if let Some(n) = nonce {
let len = header.len();
let mut header = header.to_owned();
header.truncate(len - 4); header.write_u32::<LittleEndian>(n)?;
create_siphash_keys(&header)
} else {
create_siphash_keys(&header)
}
}
pub fn create_siphash_keys(header: &[u8]) -> Result<[u64; 4], Error> {
let h = blake2b(32, &[], &header);
let hb = h.as_bytes();
let mut rdr = Cursor::new(hb);
Ok([
rdr.read_u64::<LittleEndian>()?,
rdr.read_u64::<LittleEndian>()?,
rdr.read_u64::<LittleEndian>()?,
rdr.read_u64::<LittleEndian>()?,
])
}
pub struct CuckooParams {
pub proof_size: usize,
pub num_edges: u64,
pub siphash_keys: [u64; 4],
pub edge_mask: u64,
pub node_mask: u64,
}
impl CuckooParams {
pub fn new(edge_bits: u8, node_bits: u8, proof_size: usize) -> Result<CuckooParams, Error> {
let num_edges = 1u64 << edge_bits;
let edge_mask = num_edges - 1;
let num_nodes = 1u64 << node_bits;
let node_mask = num_nodes - 1;
Ok(CuckooParams {
proof_size,
num_edges,
siphash_keys: [0; 4],
edge_mask,
node_mask,
})
}
pub fn reset_header_nonce(&mut self, header: Vec<u8>, nonce: Option<u32>) -> Result<(), Error> {
self.siphash_keys = set_header_nonce(&header, nonce)?;
Ok(())
}
pub fn sipnode(&self, edge: u64, uorv: u64) -> Result<u64, Error> {
let hash_u64 = siphash24(&self.siphash_keys, 2 * edge + uorv);
let node = hash_u64 & self.node_mask;
Ok(node)
}
}