scrypt function

Uint8List scrypt(
  1. List<int> password,
  2. List<int> salt, {
  3. required int n,
  4. required int r,
  5. required int p,
  6. required int dkLen,
})

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;
}