Skip to content

Commit

Permalink
Increase pickParams() timing loop (fixes #18)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisveness committed Oct 21, 2024
1 parent 961b547 commit f70e8e3
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 5 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Changed

- Increase pickParams() timing loop

## [3.0.0] - 2024-10-18

### Changed
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ API

`Scrypt.pickParams(maxtime, maxmem, maxmemfrac)` – return scrypt parameters for given operational parameters.

Percival’s calculation for optimal parameters can be used to verify Valsorda’s / Percival’s [recommendation of 15](https://words.filippo.io/the-scrypt-parameters) for logN; though in empirical tests (in 2024) it appears to underestimate logN by one or two – timing tests are the most reliable way to validate optimal parameters.

- `maxtime` is the maximum time in seconds scrypt will spend computing the derived encryption key from the password (0.1 seconds is recommended for interactive logins).
- `maxmem` (optional) is the maximum RAM scrypt will use when computing the derived encryption key, in bytes (default maximum available physical memory).
- `maxmemfrac` (optional) is the maximum fraction of available RAM scrypt will use for computing the derived encryption key (default 0.5); if not within the range 0 < maxmemfrac <= 0.5, this will be set to 0.5.
Expand Down
19 changes: 14 additions & 5 deletions scrypt.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class Scrypt {
/**
* Produce derived key using scrypt as a key derivation function.
*
* Recommended parameter values (2017) are logN:15, r:8, p:1; words.filippo.io/the-scrypt-parameters.
*
* @param {string|Uint8Array|Buffer} passphrase - Secret value such as a password from which key is to be derived.
* @param {Object} params - Scrypt parameters.
* @param {number} params.logN - CPU/memory cost parameter.
Expand Down Expand Up @@ -225,7 +227,13 @@ class Scrypt {
/**
* Calculate scrypt parameters from maxtime, maxmem, maxmemfrac values.
*
* Adapted from Colin Percival's code: see github.com/Tarsnap/scrypt/tree/master/lib.
* Adapted from Colin Percival's code: see github.com/Tarsnap/scrypt/tree/master/lib/scryptenc.
* Percival recommended an interactive login delay of "up to 100ms".
*
* NOTE: empirical tests in 2024 suggest this approach underestimates logN by one or two, and
* confirm Filippo Valsorda's recommendation for logN=15; ("the biggest power of two that
* will run in less than 100ms") - timing tests are the most reliable way to validate
* optimal parameters.
*
* Returned parameters may vary depending on computer specs & current loading.
*
Expand All @@ -247,12 +255,13 @@ class Scrypt {

// Colin Percival measures how many scrypts can be done in one clock tick using C/POSIX
// clock_getres() / CLOCKS_PER_SEC (usually just one?); we will use performance.now() to get
// a DOMHighResTimeStamp. (Following meltdown/spectre timing attacks Chrome reduced the high
// res timestamp resolution to 100µs, so we'll be conservative and do a 1ms run - typically
// 1..10 minimal scrypts).
// a DOMHighResTimeStamp. (Following meltdown/spectre timing attacks high-res timestamp
// resolution has been 'coarsened' to 100µs, so we'll be conservative and do a 100ms run -
// typically 100..1000 minimal scrypts, noting greater timing variability in JavaScript than
// in C).
let i = 0;
const start = performance.now();
while (performance.now()-start < 1) {
while (performance.now()-start < 100) { // 100ms run
opensslScryptSync('', '', 64, { N: 128, r: 1, p: 1 });
i += 512; // we invoked the salsa20/8 core 512 times
}
Expand Down

0 comments on commit f70e8e3

Please sign in to comment.