Files
filecrypt-rs/src/kdf/compress.rs
T
2026-10-01 18:28:40 +02:00

135 lines
3.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// One Argon2 memory block is 1024 bytes = 128 × u64.
pub(super) const BLOCK_WORDS: usize = 128;
/// One Argon2 memory block is 1024 bytes.
pub(super) const BLOCK_SIZE: usize = 1024;
/// A single 1024-byte Argon2 memory block.
#[derive(Clone, Copy)]
pub(super) struct Block(pub(super) [u64; BLOCK_WORDS]);
impl Block {
pub(super) const ZERO: Self = Self([0u64; BLOCK_WORDS]);
}
/// Argon2 compression function G.
///
/// R = X XOR Y
/// Z = P(R)
/// output = Z XOR R
///
/// On passes after the first, the old contents of the destination block are also XORed into the result.
pub(super) fn compress_block(previous: &Block, reference: &Block, old: Option<&Block>) -> Block {
let mut r = [0u64; BLOCK_WORDS];
for (dst, (&a, &b)) in r.iter_mut().zip(previous.0.iter().zip(reference.0.iter())) {
*dst = a ^ b;
}
/*
* P(R), first over rows and then over columns.
*/
let mut z = r;
/*
* Row-wise permutation.
*/
for row in 0..8 {
let start = row * 16;
let mut words = [0u64; 16];
words.copy_from_slice(&z[start..start + 16]);
round(&mut words);
z[start..start + 16].copy_from_slice(&words);
}
/*
* Column-wise permutation.
*
* Each permutation operates on two adjacent 64-bit
* columns from each of the eight rows.
*/
for column_pair in 0..8 {
let mut words = [0u64; 16];
for row in 0..8 {
let source = row * 16 + column_pair * 2;
words[row * 2] = z[source];
words[row * 2 + 1] = z[source + 1];
}
round(&mut words);
for row in 0..8 {
let destination = row * 16 + column_pair * 2;
z[destination] = words[row * 2];
z[destination + 1] = words[row * 2 + 1];
}
}
let mut output = [0u64; BLOCK_WORDS];
for i in 0..BLOCK_WORDS {
output[i] = z[i] ^ r[i] ^ old.map_or(0, |block| block.0[i]);
}
Block(output)
}
/// The Argon2/BLAKE2b quarter-round.
///
/// This is the BlaMka operation used by Argon2.
#[inline(always)]
fn g(v: &mut [u64; 16], a: usize, b: usize, c: usize, d: usize) {
v[a] = blamka(v[a], v[b]);
v[d] = (v[d] ^ v[a]).rotate_right(32);
v[c] = blamka(v[c], v[d]);
v[b] = (v[b] ^ v[c]).rotate_right(24);
v[a] = blamka(v[a], v[b]);
v[d] = (v[d] ^ v[a]).rotate_right(16);
v[c] = blamka(v[c], v[d]);
v[b] = (v[b] ^ v[c]).rotate_right(63);
}
/// BlaMka addition:
///
/// a + b + 2 * low32(a) * low32(b) mod 2^64.
#[inline(always)]
fn blamka(a: u64, b: u64) -> u64 {
let product = 2u64
.wrapping_mul(a & 0xffff_ffff)
.wrapping_mul(b & 0xffff_ffff);
a.wrapping_add(b).wrapping_add(product)
}
/// One BLAKE2b style 16 word round used by Argon2.
#[inline(always)]
fn round(v: &mut [u64; 16]) {
// Column step.
g(v, 0, 4, 8, 12);
g(v, 1, 5, 9, 13);
g(v, 2, 6, 10, 14);
g(v, 3, 7, 11, 15);
// Diagonal step.
g(v, 0, 5, 10, 15);
g(v, 1, 6, 11, 12);
g(v, 2, 7, 8, 13);
g(v, 3, 4, 9, 14);
}