scrypt function
scrypt (RFC 7914) on 32-bit words. pointycastle's byte-oriented version is too slow once compiled to JavaScript.
Implementation
Uint8List scrypt(
List<int> password,
List<int> salt, {
required int n,
required int r,
required int p,
required int dkLen,
}) {
if (n < 2 || n & (n - 1) != 0) {
throw ArgumentError.value(n, 'n', 'must be a power of 2 greater than 1');
}
final blockWords = 32 * r;
final initial = _pbkdf2(password, salt, 128 * r * p);
final b = _bytesToWords(initial);
initial.fillRange(0, initial.length, 0);
final v = Uint32List(blockWords * n);
final x = Uint32List(blockWords);
final y = Uint32List(blockWords);
final t = Uint32List(16);
for (var i = 0; i < p; i++) {
final offset = i * blockWords;
x.setRange(0, blockWords, b, offset);
for (var j = 0; j < n; j++) {
v.setRange(j * blockWords, (j + 1) * blockWords, x);
_blockMix(x, y, t, r);
}
for (var j = 0; j < n; j++) {
final vOffset = (x[blockWords - 16] & (n - 1)) * blockWords;
for (var k = 0; k < blockWords; k++) {
x[k] ^= v[vOffset + k];
}
_blockMix(x, y, t, r);
}
b.setRange(offset, offset + blockWords, x);
}
final mixed = _wordsToBytes(b);
for (final words in [b, v, x, y, t]) {
words.fillRange(0, words.length, 0);
}
final key = _pbkdf2(password, mixed, dkLen);
mixed.fillRange(0, mixed.length, 0);
return key;
}