Skip to content

Commit 199d08a

Browse files
committed
Add new way of calling function, supporting "p"
1 parent 23e1542 commit 199d08a

File tree

6 files changed

+219
-62
lines changed

6 files changed

+219
-62
lines changed

Diff for: LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2013-2014 Dmitry Chestnykh. All rights reserved.
1+
Copyright (c) 2013-2016 Dmitry Chestnykh. All rights reserved.
22

33
Redistribution and use in source and binary forms, with or without
44
modification, are permitted provided that the following conditions are

Diff for: README.md

+46-13
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ such as <https://github.com/YuzuJS/setImmediate>.
3535
Usage
3636
-----
3737

38-
### scrypt(password, salt, logN, r, dkLen, [interruptStep], callback, [encoding])
38+
### Modern API
39+
40+
#### scrypt(password, salt, options, callback)
3941

4042
Derives a key from password and salt and calls callback
4143
with derived key as the only argument.
@@ -47,22 +49,53 @@ after the calculation, avoiding setImmediate.
4749

4850
#### Arguments:
4951

50-
* *password* - password (string or array of bytes)
51-
* *salt* - salt (string or array of bytes)
52-
* *logN* - CPU/memory cost parameter (1 to 31)
53-
* *r* - block size parameter
54-
* *dkLen* - length of derived key
55-
* *interruptStep* - (optional) steps to split calculation with timeouts (defaults to 1000)
56-
* *callback* - callback function (`function (array|string)`)
57-
* *encoding* - (optional) result encoding (`"base64"`, `"hex"`, or `null`/`undefined`).
52+
* *password* — password (`string` or `Array` of bytes or `Uint8Array`)
53+
* *salt* — salt (`string` or `Array` of bytes or `Uint8Array`)
54+
* *options* — object with key derivation options
55+
* *callback* — callback function receiving result (`function (Array|string)`)
5856

59-
When encoding is not set, the result is an `Array` of bytes.
57+
##### Options:
58+
59+
* `N` — CPU/memory cost parameter (must be power of two;
60+
alternatively, you can specify `logN` where *N = 2^logN*).
61+
* `r` — block size parameter
62+
* `p` — parallelization parameter (default is 1)
63+
* `dkLen` — derived key length (default is 32)
64+
* `interruptStep` — (optional) steps to split calculation with timeouts (defaults to 1000)
65+
* `encoding` — (optional) result encoding `'base64'` or `'hex'` (result with be a `string`), or undefined (result will be an `Array` of bytes).
66+
67+
#### Example:
68+
69+
```javascript
70+
scrypt('mypassword', 'saltysalt', {
71+
N: 16384,
72+
r: 8,
73+
p: 1,
74+
dkLen: 16,
75+
encoding: 'hex'
76+
}, function(derivedKey) {
77+
console.log(derivedKey); // "5012b74fca8ec8a4a0a62ffdeeee959d"
78+
});
79+
```
6080

81+
### Legacy API (deprecated)
6182

62-
Limitation
63-
----------
83+
#### scrypt(password, salt, logN, r, dkLen, [interruptStep], callback, [encoding])
6484

65-
Doesn't support parallelization parameter greater than 1.
85+
Legacy API doesn't support parallelization parameter greater than 1.
86+
87+
##### Arguments:
88+
89+
* *password* — password (string or array of bytes)
90+
* *salt* — salt (string or array of bytes)
91+
* *logN* — CPU/memory cost parameter (1 to 31)
92+
* *r* — block size parameter
93+
* *dkLen* — length of derived key
94+
* *interruptStep* — (optional) steps to split calculation with timeouts (defaults to 1000)
95+
* *callback* — callback function receiving result (`function (Array|string)`)
96+
* *encoding* — (optional) result encoding (`'base64'`, `'hex'`, or undefined).
97+
98+
When encoding is not set, the result is an `Array` of bytes.
6699

67100

68101
License

Diff for: scrypt-async.js

+96-45
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
11
/*!
22
* Fast "async" scrypt implementation in JavaScript.
3-
* Copyright (c) 2013-2015 Dmitry Chestnykh | BSD License
3+
* Copyright (c) 2013-2016 Dmitry Chestnykh | BSD License
44
* https://github.com/dchest/scrypt-async-js
55
*/
66

7-
/*
8-
* Limitation: doesn't support parallelization parameter greater than 1.
9-
*/
10-
117
/**
12-
* scrypt(password, salt, logN, r, dkLen, [interruptStep], callback, [encoding])
8+
* scrypt(password, salt, options, callback)
9+
*
10+
* where
11+
*
12+
* password and salt are strings or arrays of bytes (Array of Uint8Array)
13+
* options is
14+
*
15+
* {
16+
* N: // CPU/memory cost parameter, must be power of two
17+
* // (alternatively, you can specify logN)
18+
* r: // block size
19+
* p: // parallelization parameter
20+
* dkLen: // length of derived key, default = 32
21+
* encoding: // optional encoding:
22+
* "base64" - standard Base64 encoding
23+
* "hex" — hex encoding,
24+
* undefined/null - Array of bytes
25+
* interruptStep: // optional, steps to split calculations (default is 0)
26+
* }
1327
*
1428
* Derives a key from password and salt and calls callback
1529
* with derived key as the only argument.
@@ -19,14 +33,9 @@
1933
* given, it defaults to 1000. If it's zero, the callback is called immediately
2034
* after the calculation, avoiding setImmediate.
2135
*
22-
* @param {string|Array.<number>} password Password.
23-
* @param {string|Array.<number>} salt Salt.
24-
* @param {number} logN CPU/memory cost parameter (1 to 31).
25-
* @param {number} r Block size parameter.
26-
* @param {number} dkLen Length of derived key.
27-
* @param {number?} interruptStep (optional) Steps to split calculation with timeouts (default 1000).
28-
* @param {function(string|Array.<number>)} callback Callback function.
29-
* @param {string?} encoding (optional) Result encoding ("base64", "hex", or null).
36+
* Legacy way (only supports p = 1) to call this function is:
37+
*
38+
* scrypt(password, salt, logN, r, dkLen, [interruptStep], callback, [encoding])
3039
*
3140
*/
3241
function scrypt(password, salt, logN, r, dkLen, interruptStep, callback, encoding) {
@@ -347,20 +356,53 @@ function scrypt(password, salt, logN, r, dkLen, interruptStep, callback, encodin
347356

348357
// Generate key.
349358

350-
// Set parallelization parameter to 1.
351-
var p = 1;
359+
var MAX_UINT = (-1)>>>0,
360+
p = 1;
361+
362+
if (typeof logN === "object") {
363+
// Called as: scrypt(password, salt, opts, callback)
364+
if (arguments.count > 4) {
365+
throw new Error('scrypt: incorrect number of arguments');
366+
}
367+
368+
var opts = logN;
369+
370+
callback = r;
371+
logN = opts.logN;
372+
if (typeof logN === 'undefined') {
373+
if (typeof opts.N !== 'undefined') {
374+
if (opts.N < 0 || opts.N > MAX_UINT)
375+
throw new Error('scrypt: N is out of range');
376+
377+
if (opts.N & (opts.N - 1) !== 0)
378+
throw new Error('scrypt: N is not a power of 2');
379+
380+
logN = Math.log(opts.N) / Math.LN2;
381+
} else {
382+
throw new Error('scrypt: missing N parameter');
383+
}
384+
}
385+
p = opts.p || 1;
386+
r = opts.r;
387+
dkLen = opts.dkLen || 32;
388+
interruptStep = opts.interruptStep || 0;
389+
encoding = opts.encoding;
390+
}
391+
392+
if (p < 1)
393+
throw new Error('scrypt: invalid p');
352394

353395
if (r <= 0)
354396
throw new Error('scrypt: invalid r');
355397

356398
if (logN < 1 || logN > 31)
357399
throw new Error('scrypt: logN not be between 1 and 31');
358400

359-
var MAX_INT = (1<<31)>>>0,
360-
N = (1<<logN)>>>0,
401+
402+
var N = (1<<logN)>>>0,
361403
XY, V, B, tmp;
362404

363-
if (r*p >= 1<<30 || r > MAX_INT/128/p || r > MAX_INT/256 || N > MAX_INT/128/r)
405+
if (r*p >= 1<<30 || r > MAX_UINT/128/p || r > MAX_UINT/256 || N > MAX_UINT/128/r)
364406
throw new Error('scrypt: parameters are too large');
365407

366408
// Decode strings.
@@ -383,9 +425,9 @@ function scrypt(password, salt, logN, r, dkLen, interruptStep, callback, encodin
383425

384426
var xi = 0, yi = 32 * r;
385427

386-
function smixStart() {
428+
function smixStart(pos) {
387429
for (var i = 0; i < 32*r; i++) {
388-
var j = i*4;
430+
var j = pos + i*4;
389431
XY[xi+i] = ((B[j+3] & 0xff)<<24) | ((B[j+2] & 0xff)<<16) |
390432
((B[j+1] & 0xff)<<8) | ((B[j+0] & 0xff)<<0);
391433
}
@@ -413,13 +455,13 @@ function scrypt(password, salt, logN, r, dkLen, interruptStep, callback, encodin
413455
}
414456
}
415457

416-
function smixFinish() {
458+
function smixFinish(pos) {
417459
for (var i = 0; i < 32*r; i++) {
418460
var j = XY[xi+i];
419-
B[i*4+0] = (j>>>0) & 0xff;
420-
B[i*4+1] = (j>>>8) & 0xff;
421-
B[i*4+2] = (j>>>16) & 0xff;
422-
B[i*4+3] = (j>>>24) & 0xff;
461+
B[pos + i*4 + 0] = (j>>>0) & 0xff;
462+
B[pos + i*4 + 1] = (j>>>8) & 0xff;
463+
B[pos + i*4 + 2] = (j>>>16) & 0xff;
464+
B[pos + i*4 + 3] = (j>>>24) & 0xff;
423465
}
424466
}
425467

@@ -448,6 +490,32 @@ function scrypt(password, salt, logN, r, dkLen, interruptStep, callback, encodin
448490
return result;
449491
}
450492

493+
// Blocking variant.
494+
function calculateSync() {
495+
for (var i = 0; i < p; i++) {
496+
smixStart(i*128*r);
497+
smixStep1(0, N);
498+
smixStep2(0, N);
499+
smixFinish(i*128*r);
500+
}
501+
callback(getResult(encoding));
502+
}
503+
504+
// Async variant.
505+
function calculateAsync(i) {
506+
smixStart(i*128*r);
507+
interruptedFor(0, N, interruptStep*2, smixStep1, function() {
508+
interruptedFor(0, N, interruptStep*2, smixStep2, function () {
509+
smixFinish(i*128*r);
510+
if (i + 1 < p) {
511+
nextTick(function() { calculateAsync(i + 1); });
512+
} else {
513+
callback(getResult(encoding));
514+
}
515+
});
516+
});
517+
}
518+
451519
if (typeof interruptStep === 'function') {
452520
// Called as: scrypt(..., callback, [encoding])
453521
// shifting: scrypt(..., interruptStep, callback, [encoding])
@@ -457,26 +525,9 @@ function scrypt(password, salt, logN, r, dkLen, interruptStep, callback, encodin
457525
}
458526

459527
if (interruptStep <= 0) {
460-
//
461-
// Blocking async variant, calls callback.
462-
//
463-
smixStart();
464-
smixStep1(0, N);
465-
smixStep2(0, N);
466-
smixFinish();
467-
callback(getResult(encoding));
468-
528+
calculateSync();
469529
} else {
470-
//
471-
// Async variant with interruptions, calls callback.
472-
//
473-
smixStart();
474-
interruptedFor(0, N, interruptStep*2, smixStep1, function() {
475-
interruptedFor(0, N, interruptStep*2, smixStep2, function () {
476-
smixFinish();
477-
callback(getResult(encoding));
478-
});
479-
});
530+
calculateAsync(0);
480531
}
481532
}
482533

0 commit comments

Comments
 (0)