convert method
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);
}