[mob] Use file stream to improve hashing speed (#6163)
## Description
## Tests
For 3.38 GB file on iPhone 11
Old Hashing took 24792 ms
Hashing v2 took 10365 ms
Also tested it on a smaller file
```dart
// Returns the hash for a given file, chunking it in batches of hashChunkSize
Future<Uint8List> cryptoGenericHash(Map<String, dynamic> args) async {
final int startTime = DateTime.now().millisecondsSinceEpoch;
final sourceFile = File(args["sourceFilePath"]);
final sourceFileLength = await sourceFile.length();
final inputFile = sourceFile.openSync(mode: FileMode.read);
final state =
Sodium.cryptoGenerichashInit(null, Sodium.cryptoGenerichashBytesMax);
var bytesRead = 0;
bool isDone = false;
while (!isDone) {
var chunkSize = hashChunkSize;
if (bytesRead + chunkSize >= sourceFileLength) {
chunkSize = sourceFileLength - bytesRead;
isDone = true;
}
final buffer = await inputFile.read(chunkSize);
bytesRead += chunkSize;
Sodium.cryptoGenerichashUpdate(state, buffer);
}
await inputFile.close();
final hash =
Sodium.cryptoGenerichashFinal(state, Sodium.cryptoGenerichashBytesMax);
final int endTime = DateTime.now().millisecondsSinceEpoch;
final hash2 = await cryptoGenericHashV2(args);
final endTime2 = DateTime.now().millisecondsSinceEpoch;
if (hash.length != hash2.length) {
throw Exception(
"Hash length mismatch: ${hash.length} != ${hash2.length}",
);
}
if (!const ListEquality().equals(hash, hash2)) {
throw Exception("not equal: hash");
}
print("Hashing took ${endTime2 - startTime} ms");
print("Hashing v2 took ${endTime2 - endTime} ms");
return hash;
}
Future<Uint8List> cryptoGenericHashV2(Map<String, dynamic> args) async {
final file = File(args["sourceFilePath"]);
final state =
Sodium.cryptoGenerichashInit(null, Sodium.cryptoGenerichashBytesMax);
await for (final chunk in file.openRead()) {
Sodium.cryptoGenerichashUpdate(state, Uint8List.fromList(chunk));
}
return Sodium.cryptoGenerichashFinal(state, Sodium.cryptoGenerichashBytesMax);
}
```
This commit is contained in:
@@ -51,26 +51,18 @@ Uint8List cryptoKdfDeriveFromKey(
|
||||
);
|
||||
}
|
||||
|
||||
// Returns the hash for a given file, chunking it in batches of hashChunkSize
|
||||
// Returns the hash for a given file
|
||||
Future<Uint8List> cryptoGenericHash(Map<String, dynamic> args) async {
|
||||
final sourceFile = File(args["sourceFilePath"]);
|
||||
final sourceFileLength = await sourceFile.length();
|
||||
final inputFile = sourceFile.openSync(mode: FileMode.read);
|
||||
final file = File(args["sourceFilePath"]);
|
||||
final state =
|
||||
Sodium.cryptoGenerichashInit(null, Sodium.cryptoGenerichashBytesMax);
|
||||
var bytesRead = 0;
|
||||
bool isDone = false;
|
||||
while (!isDone) {
|
||||
var chunkSize = hashChunkSize;
|
||||
if (bytesRead + chunkSize >= sourceFileLength) {
|
||||
chunkSize = sourceFileLength - bytesRead;
|
||||
isDone = true;
|
||||
await for (final chunk in file.openRead()) {
|
||||
if (chunk is Uint8List) {
|
||||
Sodium.cryptoGenerichashUpdate(state, chunk);
|
||||
} else {
|
||||
Sodium.cryptoGenerichashUpdate(state, Uint8List.fromList(chunk));
|
||||
}
|
||||
final buffer = await inputFile.read(chunkSize);
|
||||
bytesRead += chunkSize;
|
||||
Sodium.cryptoGenerichashUpdate(state, buffer);
|
||||
}
|
||||
await inputFile.close();
|
||||
return Sodium.cryptoGenerichashFinal(state, Sodium.cryptoGenerichashBytesMax);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user