Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions yescrypt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ yescrypt is a variant of the [scrypt] password-based key derivation function and
[Password Hashing Competition]. It has been adopted by several Linux distributions for the system
password hashing function, including Fedora, Debian, Ubuntu, and Arch.

The algorithm is described in [yescrypt - a Password Hashing Competition submission][paper].

## ⚠️ Security Warning

The implementation contained in this crate has never been independently audited!
Expand Down Expand Up @@ -64,3 +66,4 @@ dual licensed as above, without any additional terms or conditions.
[yescrypt]: https://www.openwall.com/yescrypt/
[scrypt]: https://en.wikipedia.org/wiki/Scrypt
[Password Hashing Competition]: https://www.password-hashing.net/
[paper]: https://www.password-hashing.net/submissions/specs/yescrypt-v2.pdf
6 changes: 6 additions & 0 deletions yescrypt/src/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ const MODE_MASK: u32 = 0x3;
const RW_FLAVOR_MASK: u32 = 0x3fc;

/// Flags for selecting the "flavor" of `yescrypt`.
///
/// A bitmask allowing to enable the individual extra features of yescrypt, e.g:
///
/// - [`Flags::RW`]: yescrypt’s native mode. Call [`Flags::default`] to fully configure this.
/// - [`Flags::WORM`]: conservative enhancement of classic scrypt. Mutually exclusive with `RW`.
/// - [`Flags::EMPTY`]: requests classic scrypt.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Flags(pub(crate) u32);

Expand Down
11 changes: 9 additions & 2 deletions yescrypt/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ pub struct Params {
pub(crate) flags: Flags,

/// `N`: CPU/memory cost (like `scrypt`).
///
/// yescrypt, including in scrypt compatibility mode, is defined only for values of N that are
/// powers of 2 (and larger than 1, which matches scrypt’s requirements).
pub(crate) n: u64,

/// `r`: block size (like `scrypt`).
Expand All @@ -28,10 +31,14 @@ pub struct Params {
/// `p`: parallelism (like `scrypt`).
pub(crate) p: u32,

/// special to yescrypt.
/// Controls yescrypt’s computation time while keeping its peak memory usage the same.
///
/// `t = 0` is optimal for achieving the highest normalized area-time cost for ASIC attackers.
pub(crate) t: u32,

/// special to yescrypt.
/// The number of cost upgrades performed to the hash so far.
///
/// `0` means no upgrades yet, and is currently the only allowed value.
pub(crate) g: u32,

/// special to yescrypt.
Expand Down
28 changes: 23 additions & 5 deletions yescrypt/src/pwxform.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
//! pwxform: parallel wide transformation
//! pwxform stands for "parallel wide transformation", although it can as well be tuned to be as
//! narrow as one 64-bit lane.
//!
//! It operates on 64-bit lanes which are designed to be grouped into wider "simple SIMD" lanes,
//! which are in turn possibly grouped into an even wider "gather SIMD" vector.

use crate::{
salsa20,
util::{slice_as_chunks_mut, xor},
};

// These are tunable, but they must meet certain constraints.
/// Number of 64-bit lanes per "simple SIMD" lane (requiring only arithmetic and bitwise operations
/// on its 64-bit elements). Must be a power of 2.
const PWXSIMPLE: usize = 2;

/// Number of parallel "simple SIMD" lanes per "gather SIMD" vector (requiring "S-box lookups" of
/// values as wide as a "simple SIMD" lane from PWXgather typically non-contiguous memory
/// locations). Must be a power of 2.
const PWXGATHER: usize = 4;

/// Number of sequential rounds of pwxform’s basic transformation. Must be a power of 2, plus 2
/// (e.g. 3, 4, 6, 10).
const PWXROUNDS: usize = 6;

/// Number of S-box index bits, thereby controlling the size of each of pwxform’s two S-boxes
/// (in "simple SIMD" wide elements).
const SWIDTH: usize = 8;

// Derived values. Not tunable on their own.
const PWXBYTES: usize = PWXGATHER * PWXSIMPLE * 8;
const PWXWORDS: usize = PWXBYTES / size_of::<u32>();
const SMASK: usize = ((1 << SWIDTH) - 1) * PWXSIMPLE * 8;
Expand All @@ -28,9 +42,13 @@ pub(crate) struct PwxformCtx<'a> {
}

impl PwxformCtx<'_> {
/// Compute `B = BlockMix_pwxform{salsa20/2, ctx, r}(B)`.
/// Compute `B = BlockMix_pwxform{salsa20/2, ctx, r}(B)`. Input `B` must be 128 bytes in length.
///
/// The input `B` must be 128r bytes in length.
/// `BlockMix_pwxform` differs from scrypt’s `BlockMix` in that it doesn’t shuffle output
/// sub-blocks, uses pwxform in place of Salsa20/8 for as long as sub-blocks processed with
/// pwxform fit in the provided block B, and finally uses Salsa20/2 (that is, Salsa20 with only
/// one double-round) to post-process the last sub-block output by pwxform (thereby finally
/// mixing pwxform’s parallel lanes).
pub(crate) fn blockmix_pwxform(&mut self, b: &mut [u32], r: usize) {
// Convert 128-byte blocks to PWXbytes blocks
// TODO(tarcieri): use upstream `[T]::as_chunks_mut` when MSRV is 1.88
Expand Down