use std::time::Duration;
use argon2::Algorithm;
use sysinfo::{System, SystemExt};
use crate::config::SystemDefault;
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct ArgonConfiguration {
pub hashers: u32,
pub algorithm: Algorithm,
pub params: ArgonParams,
}
impl SystemDefault for ArgonConfiguration {
fn default_for(system: &System) -> Self {
let cpu_count = u32::try_from(
system
.physical_core_count()
.unwrap_or_else(|| system.cpus().len()),
)
.expect("cpu count returned unexpectedly large value");
let mut hashers = (cpu_count + 3) / 4;
let max_hashers = u32::try_from(
system.total_memory() / u64::from(TimedArgonParams::MINIMUM_RAM_PER_HASHER),
)
.unwrap_or(u32::MAX);
if max_hashers > 0 && hashers > max_hashers {
hashers = max_hashers;
}
ArgonConfiguration {
hashers,
algorithm: Algorithm::Argon2id,
params: ArgonParams::default_for(system, hashers),
}
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
#[must_use]
pub enum ArgonParams {
Params(argon2::ParamsBuilder),
Timed(TimedArgonParams),
}
impl ArgonParams {
pub fn default_for(system: &System, hashers: u32) -> Self {
ArgonParams::Timed(TimedArgonParams::default_for(system, hashers))
}
}
#[derive(Debug, Clone)]
#[must_use]
pub struct TimedArgonParams {
pub lanes: u32,
pub ram_per_hasher: u32,
pub minimum_duration: Duration,
}
impl Default for TimedArgonParams {
fn default() -> Self {
Self {
lanes: 1,
ram_per_hasher: Self::MINIMUM_RAM_PER_HASHER,
minimum_duration: Duration::from_secs(1),
}
}
}
impl TimedArgonParams {
pub const MINIMUM_RAM_PER_HASHER: u32 = 19 * 1024 * 1024;
pub fn default_for(system: &System, hashers: u32) -> Self {
let total_memory = u32::try_from(system.total_memory()).unwrap_or(u32::MAX);
let max_memory = total_memory / 32;
let ram_per_hasher = if cfg!(debug_assertions) {
Self::MINIMUM_RAM_PER_HASHER
} else {
(max_memory / hashers).max(Self::MINIMUM_RAM_PER_HASHER)
};
Self {
lanes: 4,
ram_per_hasher,
minimum_duration: Duration::from_secs(1),
}
}
}