use crate::errors::ArrkeyError;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Params {
pub m_cost: u32,
pub t_cost: u32,
pub p_cost: u32,
pub constraint: u8,
pub context: Option<String>,
}
const SYNC_POINTS: usize = 4;
impl Params {
pub const DEFAULT_M: u32 = 12288;
const MIN_M: u32 = 2 * SYNC_POINTS as u32;
pub const DEFAULT_T: u32 = 3;
const MIN_T: u32 = 1;
pub const DEFAULT_P: u32 = 1;
const MIN_P: u32 = 1;
const MAX_P: u32 = 0xFFFFFF;
pub const DEFAULT_CONSTRAINT: u8 = 16;
const MIN_CONSTRAINT: u8 = 1;
pub const DEFAULT: Self = Params {
m_cost: Self::DEFAULT_M,
t_cost: Self::DEFAULT_T,
p_cost: Self::DEFAULT_P,
constraint: Self::DEFAULT_CONSTRAINT,
context: None,
};
pub fn new(
m_cost: u32,
t_cost: u32,
p_cost: u32,
constraint: u8,
context: Option<&str>,
) -> Result<Self, ArrkeyError> {
if m_cost < Self::MIN_M {
return Err(ArrkeyError::MemoryTooSmall);
}
if m_cost < p_cost * 8 {
return Err(ArrkeyError::MemoryTooSmall);
}
if t_cost < Self::MIN_T {
return Err(ArrkeyError::TimeTooSmall);
}
if p_cost < Self::MIN_P {
return Err(ArrkeyError::ThreadsTooFew);
}
if p_cost > Self::MAX_P {
return Err(ArrkeyError::ThreadsTooMany);
}
if constraint < Self::MIN_CONSTRAINT {
return Err(ArrkeyError::ConstraintTooSmall);
}
Ok(Self {
m_cost,
t_cost,
p_cost,
constraint,
context: context.map(|s| s.to_string()),
})
}
}
impl Default for Params {
fn default() -> Self {
Params::DEFAULT
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default() {
let params = Params::default();
assert_eq!(params.m_cost, Params::DEFAULT_M);
assert_eq!(params.t_cost, Params::DEFAULT_T);
assert_eq!(params.p_cost, Params::DEFAULT_P);
assert_eq!(params.constraint, Params::DEFAULT_CONSTRAINT);
assert_eq!(params.context, None);
let params = Params::DEFAULT;
assert_eq!(params.m_cost, Params::DEFAULT_M);
assert_eq!(params.t_cost, Params::DEFAULT_T);
assert_eq!(params.p_cost, Params::DEFAULT_P);
assert_eq!(params.constraint, Params::DEFAULT_CONSTRAINT);
assert_eq!(params.context, None);
}
#[test]
fn new_valid_params() {
let result = Params::new(12288, 3, 1, 16, None);
assert!(result.is_ok());
let params = result.unwrap();
assert_eq!(params.m_cost, 12288);
assert_eq!(params.t_cost, 3);
assert_eq!(params.p_cost, 1);
assert_eq!(params.constraint, 16);
assert_eq!(params.context, None);
}
#[test]
fn new_with_context() {
let result = Params::new(12288, 3, 1, 16, Some("EOTWS_Variation1"));
assert!(result.is_ok());
let params = result.unwrap();
assert_eq!(params.context, Some("EOTWS_Variation1".to_string()));
}
#[test]
fn m_cost_too_small() {
let result = Params::new(1, 3, 1, 16, None);
assert_eq!(result.unwrap_err(), ArrkeyError::MemoryTooSmall);
}
#[test]
fn m_cost_too_small_p_cost() {
let result = Params::new(15, 3, 2, 16, None);
assert_eq!(result.unwrap_err(), ArrkeyError::MemoryTooSmall);
}
#[test]
fn t_cost_too_small() {
let result = Params::new(12288, 0, 1, 16, None);
assert_eq!(result.unwrap_err(), ArrkeyError::TimeTooSmall);
}
#[test]
fn p_cost_min_p() {
let result = Params::new(12288, 3, 0, 16, None);
assert_eq!(result.unwrap_err(), ArrkeyError::ThreadsTooFew);
}
#[test]
fn p_cost_max_p() {
let result = Params::new(0x1000000 * 8, 3, 0x1000000, 16, None);
assert_eq!(result.unwrap_err(), ArrkeyError::ThreadsTooMany);
}
#[test]
fn min_constraint() {
let result = Params::new(12288, 3, 1, 0, None);
assert_eq!(result.unwrap_err(), ArrkeyError::ConstraintTooSmall);
}
}