Skip to main content

origin_crypto_sdk/primitives/
tier.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Memory tier configuration for Argon2id KDF.
4//!
5//! Three tiers prove viability across the device spectrum:
6//! - **Nano**: IoT / edge / RPi Zero (8 MB, 2 iter, 1 thread)
7//! - **Standard**: Mid-tier laptop (64 MB, 3 iter, 2 threads)
8//! - **Sovereign**: Datacenter / high-security (256 MB, 5 iter, 4 threads)
9//!
10//! The quantum pipeline (SHAKE-256 + KMAC-256 + hybrid keys) is identical
11//! across all tiers. Only the Argon2id password-to-seed cost changes.
12
13use argon2::Params;
14
15/// Device memory tier — gates only the Argon2id KDF cost.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
17pub enum MemoryTier {
18    /// IoT / Edge / RPi Zero: 8 MB, 2 iterations, 1 lane.
19    Nano,
20    /// Mid-tier laptop / server: 64 MB, 3 iterations, 2 lanes.
21    #[default]
22    Standard,
23    /// Datacenter / high-security: 256 MB, 5 iterations, 4 lanes.
24    Sovereign,
25}
26
27impl MemoryTier {
28    /// Return Argon2id parameters for this tier.
29    pub fn argon2_params(self, output_len: usize) -> Params {
30        let (m_cost, t_cost, p_cost) = match self {
31            MemoryTier::Nano => (8 * 1024, 2, 1),        // 8 MB
32            MemoryTier::Standard => (64 * 1024, 3, 2),   // 64 MB
33            MemoryTier::Sovereign => (256 * 1024, 5, 4), // 256 MB
34        };
35        Params::new(m_cost, t_cost, p_cost, Some(output_len)).expect("valid Argon2 params")
36    }
37
38    /// Human-readable label.
39    pub fn label(self) -> &'static str {
40        match self {
41            MemoryTier::Nano => "nano",
42            MemoryTier::Standard => "standard",
43            MemoryTier::Sovereign => "sovereign",
44        }
45    }
46
47    /// Get the recommended buffer size for this tier
48    pub fn buffer_size(&self) -> usize {
49        match self {
50            MemoryTier::Nano => 1024,
51            MemoryTier::Standard => 4096,
52            MemoryTier::Sovereign => 4096,
53        }
54    }
55
56    /// Whether memory should be locked (mlock)
57    pub fn should_lock(&self) -> bool {
58        matches!(self, MemoryTier::Sovereign)
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn nano_params_valid() {
68        let p = MemoryTier::Nano.argon2_params(32);
69        assert_eq!(p.m_cost(), 8 * 1024);
70        assert_eq!(p.t_cost(), 2);
71        assert_eq!(p.p_cost(), 1);
72    }
73
74    #[test]
75    fn standard_params_valid() {
76        let p = MemoryTier::Standard.argon2_params(32);
77        assert_eq!(p.m_cost(), 64 * 1024);
78    }
79
80    #[test]
81    fn sovereign_params_valid() {
82        let p = MemoryTier::Sovereign.argon2_params(32);
83        assert_eq!(p.m_cost(), 256 * 1024);
84        assert_eq!(p.t_cost(), 5);
85        assert_eq!(p.p_cost(), 4);
86    }
87}