From a28947d142b48a3f5a54395428c5690f954594d3 Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Wed, 22 Oct 2025 22:11:41 -0700 Subject: [PATCH] Parallelize scrypt with rayon --- Cargo.lock | 1 + scrypt/Cargo.toml | 4 +++- scrypt/benches/lib.rs | 14 +++++++++++++- scrypt/src/lib.rs | 27 +++++++++++++++++++++++---- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7102251a..544f2a2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -419,6 +419,7 @@ version = "0.12.0-rc.2" dependencies = [ "password-hash", "pbkdf2", + "rayon", "salsa20", "sha2", ] diff --git a/scrypt/Cargo.toml b/scrypt/Cargo.toml index 7622727c..295fe4d9 100644 --- a/scrypt/Cargo.toml +++ b/scrypt/Cargo.toml @@ -17,6 +17,7 @@ rust-version = "1.85" pbkdf2 = { version = "0.13.0-rc.1", path = "../pbkdf2" } salsa20 = { version = "0.11.0-rc.1", default-features = false } sha2 = { version = "0.11.0-rc.2", default-features = false } +rayon = { version = "1.11", optional = true } # optional dependencies password-hash = { version = "0.6.0-rc.1", default-features = false, features = ["rand_core"], optional = true } @@ -25,8 +26,9 @@ password-hash = { version = "0.6.0-rc.1", default-features = false, features = [ password-hash = { version = "0.6.0-rc.1", features = ["rand_core"] } [features] -default = ["simple"] +default = ["simple", "rayon"] simple = ["password-hash"] +rayon = ["dep:rayon"] [package.metadata.docs.rs] all-features = true diff --git a/scrypt/benches/lib.rs b/scrypt/benches/lib.rs index 4e400153..423c6248 100644 --- a/scrypt/benches/lib.rs +++ b/scrypt/benches/lib.rs @@ -6,7 +6,7 @@ extern crate test; use test::Bencher; #[bench] -pub fn scrypt_15_8_1(bh: &mut Bencher) { +pub fn scrypt_17_8_1(bh: &mut Bencher) { let password = b"my secure password"; let salt = b"salty salt"; let mut buf = [0u8; 32]; @@ -16,3 +16,15 @@ pub fn scrypt_15_8_1(bh: &mut Bencher) { test::black_box(&buf); }); } + +#[bench] +pub fn scrypt_17_2_4(bh: &mut Bencher) { + let password = b"my secure password"; + let salt = b"salty salt"; + let mut buf = [0u8; 32]; + let params = scrypt::Params::new(17, 2, 4).unwrap(); + bh.iter(|| { + scrypt::scrypt(password, salt, ¶ms, &mut buf).unwrap(); + test::black_box(&buf); + }); +} diff --git a/scrypt/src/lib.rs b/scrypt/src/lib.rs index 03bca3fa..57976860 100644 --- a/scrypt/src/lib.rs +++ b/scrypt/src/lib.rs @@ -112,13 +112,32 @@ pub fn scrypt( let mut b = vec![0u8; pr128]; pbkdf2_hmac::(password, salt, 1, &mut b); + #[cfg(not(feature = "rayon"))] + romix_sequential(nr128, r128, n, &mut b); + #[cfg(feature = "rayon")] + romix_parallel(nr128, r128, n, &mut b); + + pbkdf2_hmac::(password, &b, 1, output); + Ok(()) +} + +#[cfg(not(feature = "rayon"))] +fn romix_sequential(nr128: usize, r128: usize, n: usize, b: &mut [u8]) { let mut v = vec![0u8; nr128]; let mut t = vec![0u8; r128]; - for chunk in &mut b.chunks_mut(r128) { + b.chunks_mut(r128).for_each(|chunk| { romix::scrypt_ro_mix(chunk, &mut v, &mut t, n); - } + }); +} - pbkdf2_hmac::(password, &b, 1, output); - Ok(()) +#[cfg(feature = "rayon")] +fn romix_parallel(nr128: usize, r128: usize, n: usize, b: &mut [u8]) { + use rayon::{iter::ParallelIterator as _, slice::ParallelSliceMut as _}; + + b.par_chunks_mut(r128).for_each(|chunk| { + let mut v = vec![0u8; nr128]; + let mut t = vec![0u8; r128]; + romix::scrypt_ro_mix(chunk, &mut v, &mut t, n); + }); }