convert method

  1. @override
HashDigest convert(
  1. List<int> password
)
override

Generate a derived key using the scrypt algorithm.

Implementation

@override
HashDigest convert(List<int> password) {
  int N = cost;
  int midRO = (blockSize << 4);
  int roLength = (blockSize << 7);
  int roLength32 = (roLength >>> 2);
  int innerKeyLength = parallelism * roLength;
  int innerKeyLength32 = parallelism * roLength32;
  Uint32List inp = Uint32List(roLength32);
  Uint32List out = Uint32List(roLength32);
  Uint32List t = Uint32List(16);
  Uint32List v;

  // Initialize the memory
  List<Uint32List> acc = List.filled(N, Uint32List(roLength32));
  for (int i = 1; i < N; ++i) {
    acc[i] = Uint32List(roLength32);
  }

  // Derive the inner blocks
  var inner = pbkdf2(password, salt, 1, innerKeyLength).bytes;
  var inner32 = Uint32List.view(inner.buffer);

  /// [length] = 128 * r = 2 * 64 * r = 4 * 32 * r bytes
  @pragma('vm:prefer-inline')
  void blockMix() {
    int i, j, p, q;
    p = 0;
    q = midRO;
    for (j = 0; j < 16; j++) {
      t[j] = inp[roLength32 - 16 + j];
    }
    for (i = 0; i < roLength32; i += 32) {
      // even
      for (j = 0; j < 16; j++) {
        t[j] ^= inp[i + j];
      }
      _salsa20(t);
      for (j = 0; j < 16; j++, p++) {
        out[p] = t[j];
      }

      // odd
      for (j = 0; j < 16; j++) {
        t[j] ^= inp[i + j + 16];
      }
      _salsa20(t);
      for (j = 0; j < 16; j++, q++) {
        out[q] = t[j];
      }
    }
  }

  // Mix the inner blocks to derive the outer salt
  for (int i, j, k = 0; k < innerKeyLength32; k += roLength32) {
    /// Number of iterations, [N] is a power of 2
    /// length of [x] = 128 * r = 2 * 64 * r = 4 * 32 * r bytes
    for (j = 0; j < roLength32; ++j) {
      inp[j] = inner32[j + k];
    }
    for (i = 0; i < N; ++i) {
      v = acc[i];
      for (j = 0; j < roLength32; ++j) {
        v[j] = inp[j];
      }
      blockMix();
      // swap inp <-> out
      v = inp;
      inp = out;
      out = v;
    }
    for (i = 0; i < N; ++i) {
      v = acc[inp[roLength32 - 16] & (N - 1)];
      for (j = 0; j < roLength32; ++j) {
        inp[j] ^= v[j];
      }
      blockMix();
      // swap inp <-> out
      v = inp;
      inp = out;
      out = v;
    }
    for (j = 0; j < roLength32; ++j) {
      inner32[j + k] = inp[j];
    }
  }

  // Derive final blocks with the outer salt
  return pbkdf2(password, inner, 1, derivedKeyLength);
}