PBKDF: implement argon2id

This commit is contained in:
sam.hadow committed 2026-10-01 18:28:40 +02:00
1 parent 1fcf38db41
commit b30b5d0add
13 files changed
+1291 -148

No files matched your search

+134
View File
@@ -0,0 +1,134 @@
/// 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);
}