Skip to main content

argon2/
block.rs

1//! Argon2 memory block functions
2
3use core::{
4    convert::{AsMut, AsRef},
5    num::Wrapping,
6    ops::{BitXor, BitXorAssign},
7    slice,
8};
9
10#[cfg(feature = "zeroize")]
11use zeroize::Zeroize;
12
13const TRUNC: u64 = u32::MAX as u64;
14
15#[rustfmt::skip]
16macro_rules! permute_step {
17    ($a:expr, $b:expr, $c:expr, $d:expr) => {
18        $a = (Wrapping($a) + Wrapping($b) + (Wrapping(2) * Wrapping(($a & TRUNC) * ($b & TRUNC)))).0;
19        $d = ($d ^ $a).rotate_right(32);
20        $c = (Wrapping($c) + Wrapping($d) + (Wrapping(2) * Wrapping(($c & TRUNC) * ($d & TRUNC)))).0;
21        $b = ($b ^ $c).rotate_right(24);
22
23        $a = (Wrapping($a) + Wrapping($b) + (Wrapping(2) * Wrapping(($a & TRUNC) * ($b & TRUNC)))).0;
24        $d = ($d ^ $a).rotate_right(16);
25        $c = (Wrapping($c) + Wrapping($d) + (Wrapping(2) * Wrapping(($c & TRUNC) * ($d & TRUNC)))).0;
26        $b = ($b ^ $c).rotate_right(63);
27    };
28}
29
30macro_rules! permute {
31    (
32        $v0:expr, $v1:expr, $v2:expr, $v3:expr,
33        $v4:expr, $v5:expr, $v6:expr, $v7:expr,
34        $v8:expr, $v9:expr, $v10:expr, $v11:expr,
35        $v12:expr, $v13:expr, $v14:expr, $v15:expr,
36    ) => {
37        permute_step!($v0, $v4, $v8, $v12);
38        permute_step!($v1, $v5, $v9, $v13);
39        permute_step!($v2, $v6, $v10, $v14);
40        permute_step!($v3, $v7, $v11, $v15);
41        permute_step!($v0, $v5, $v10, $v15);
42        permute_step!($v1, $v6, $v11, $v12);
43        permute_step!($v2, $v7, $v8, $v13);
44        permute_step!($v3, $v4, $v9, $v14);
45    };
46}
47
48/// Structure for the (1 KiB) memory block implemented as 128 64-bit words.
49#[derive(Copy, Clone, Debug)]
50#[repr(align(64))]
51pub struct Block([u64; Self::SIZE / 8]);
52
53impl Block {
54    /// Memory block size in bytes
55    pub const SIZE: usize = 1024;
56
57    /// Returns a Block initialized with zeros.
58    #[must_use]
59    pub const fn new() -> Self {
60        Self([0u64; Self::SIZE / 8])
61    }
62
63    /// Load a block from a block-sized byte slice
64    #[inline(always)]
65    pub(crate) fn load(&mut self, input: &[u8; Block::SIZE]) {
66        for (i, chunk) in input.chunks(8).enumerate() {
67            self.0[i] = u64::from_le_bytes(chunk.try_into().expect("should be 8 bytes"));
68        }
69    }
70
71    /// Iterate over the `u64` values contained in this block
72    #[inline(always)]
73    pub(crate) fn iter(&self) -> slice::Iter<'_, u64> {
74        self.0.iter()
75    }
76
77    /// NOTE: do not call this directly. It should only be called via
78    /// `Argon2::compress`.
79    #[inline(always)]
80    pub(crate) fn compress(rhs: &Self, lhs: &Self) -> Self {
81        let r = *rhs ^ lhs;
82
83        // Apply permutations rowwise
84        let mut q = r;
85        for chunk in q.0.chunks_exact_mut(16) {
86            #[rustfmt::skip]
87            permute!(
88                chunk[0], chunk[1], chunk[2], chunk[3],
89                chunk[4], chunk[5], chunk[6], chunk[7],
90                chunk[8], chunk[9], chunk[10], chunk[11],
91                chunk[12], chunk[13], chunk[14], chunk[15],
92            );
93        }
94
95        // Apply permutations columnwise
96        for i in 0..8 {
97            let b = i * 2;
98
99            #[rustfmt::skip]
100            permute!(
101                q.0[b], q.0[b + 1],
102                q.0[b + 16], q.0[b + 17],
103                q.0[b + 32], q.0[b + 33],
104                q.0[b + 48], q.0[b + 49],
105                q.0[b + 64], q.0[b + 65],
106                q.0[b + 80], q.0[b + 81],
107                q.0[b + 96], q.0[b + 97],
108                q.0[b + 112], q.0[b + 113],
109            );
110        }
111
112        q ^= &r;
113        q
114    }
115}
116
117impl Default for Block {
118    fn default() -> Self {
119        Self([0u64; Self::SIZE / 8])
120    }
121}
122
123impl AsRef<[u64]> for Block {
124    fn as_ref(&self) -> &[u64] {
125        &self.0
126    }
127}
128
129impl AsMut<[u64]> for Block {
130    fn as_mut(&mut self) -> &mut [u64] {
131        &mut self.0
132    }
133}
134
135impl BitXor<&Block> for Block {
136    type Output = Block;
137
138    fn bitxor(mut self, rhs: &Block) -> Self::Output {
139        self ^= rhs;
140        self
141    }
142}
143
144impl BitXorAssign<&Block> for Block {
145    fn bitxor_assign(&mut self, rhs: &Block) {
146        for (dst, src) in self.0.iter_mut().zip(rhs.0.iter()) {
147            *dst ^= src;
148        }
149    }
150}
151
152#[cfg(feature = "zeroize")]
153impl Zeroize for Block {
154    fn zeroize(&mut self) {
155        self.0.zeroize();
156    }
157}
158
159/// Custom implementation of `Box<[Block]>` until `Box::try_new_zeroed_slice` is stabilized.
160#[cfg(feature = "alloc")]
161pub(crate) struct Blocks {
162    p: core::ptr::NonNull<Block>,
163    len: usize,
164}
165
166#[cfg(feature = "alloc")]
167impl Blocks {
168    pub fn new(len: usize) -> Option<Self> {
169        use alloc::alloc::{Layout, alloc_zeroed};
170        use core::ptr::NonNull;
171
172        if len == 0 {
173            return None;
174        }
175
176        let layout = Layout::array::<Block>(len).ok()?;
177        // SAFETY: `alloc_zeroed` is used correctly with non-zero layout
178        let p = unsafe { alloc_zeroed(layout) };
179
180        let p = NonNull::new(p.cast())?;
181        Some(Self { p, len })
182    }
183
184    pub fn as_slice(&mut self) -> &mut [Block] {
185        // SAFETY: `self.p` is a valid non-zero pointer that points to memory of the necessary size
186        unsafe { slice::from_raw_parts_mut(self.p.as_ptr(), self.len) }
187    }
188}
189
190#[cfg(feature = "alloc")]
191impl Drop for Blocks {
192    fn drop(&mut self) {
193        use alloc::alloc::{Layout, dealloc};
194        // SAFETY: layout was checked during construction
195        let layout = unsafe { Layout::array::<Block>(self.len).unwrap_unchecked() };
196        // SAFETY: we use `dealloc` correctly with the previously allocated pointer
197        unsafe {
198            dealloc(self.p.as_ptr().cast(), layout);
199        }
200    }
201}