-
Notifications
You must be signed in to change notification settings - Fork 33
Description
The current findIterations
method is too slow for my use-case. I intend to re-evaluate the number of iterations in a random interval to tailor the parameters to my hardware, and the current implementation is too inefficient and wasting a lot of resources when it is run multiple times during application runtime.
I have written a custom implementation that takes advantage of the fact that the hashing time grows roughly linear with the number of iterations.
My custom findIterations
method
private int measure(long start) {
final long end = System.nanoTime();
return Long.valueOf((end - start) / 1_000_000).intValue();
}
protected int findIterations(Argon2Factory.Argon2Types type, int maxMillis, int m, int p) {
final var argon = Argon2Factory.create(type);
warmup(argon, "password".toCharArray());
// first do single iteration and see where we're at
int iterations = 1;
long start = System.nanoTime();
argon.hash(iterations, m, p, "password".toCharArray());
int took = measure(start);
// if one iteration already takes more than maxMillis, use one iteration
if (took > maxMillis) return 1;
// if one iteration takes less than a third of maxMillis, bump iterations to 3 to get more accurate results
if (took < (maxMillis / 3)) iterations = 3;
// do five rounds of hashing with those iterations and measure the execution time
int[] measurements = new int[5];
for (int i = 0; i < measurements.length; i++) {
start = System.nanoTime();
argon.hash(iterations, m, p, "password".toCharArray());
// divide measurement by amount of iterations, to get the approximate time one iteration would take
measurements[i] = measure(start) / iterations;
}
// get the average time it took for one iteration
var avg = Arrays.stream(measurements).average().orElse(0.0);
// return the approximated amount of iterations to stay within maxMillis, with a lower bound of 1 iteration
return Math.max(1, Math.floorDiv(maxMillis, Double.valueOf(avg).intValue()));
}
My custom implementation vastly outperforms the library method, and the results of
variant | max millis | memory | parallelism | result | hash time (5/avg) |
|
---|---|---|---|---|---|---|
library method | 1000 | 8192 kiB | 1 | 848 ms |
54997 ms |
|
my method | 1000 | 8192 kiB | 1 | 1005 ms |
99 ms |
variant | max millis | memory | parallelism | result | hash time (5/avg) |
|
---|---|---|---|---|---|---|
library method | 1000 | 65536 kiB | 1 | 967 ms |
10751 ms |
|
my method | 1000 | 65536 kiB | 1 | 1028 ms |
875 ms |
variant | max millis | memory | parallelism | result | hash time (5/avg) |
|
---|---|---|---|---|---|---|
library method | 1000 | 1048576 kiB | 1 | 1135 ms |
1131 ms |
|
my method | 1000 | 1048576 kiB | 1 | 1136 ms |
1135 ms |
variant | max millis | memory | parallelism | result | hash time (5/avg) |
|
---|---|---|---|---|---|---|
library method | 1000 | 8192 kiB | 4 | 939 ms |
145418 ms |
|
my method | 1000 | 8192 kiB | 4 | 1002 ms |
57 ms |
variant | max millis | memory | parallelism | result | hash time (5/avg) |
|
---|---|---|---|---|---|---|
library method | 1000 | 65536 kiB | 4 | 920 ms |
20730 ms |
|
my method | 1000 | 65536 kiB | 4 | 977 ms |
351 ms |
variant | max millis | memory | parallelism | result | hash time (5/avg) |
|
---|---|---|---|---|---|---|
library method | 1000 | 1048576 kiB | 4 | 872 ms |
2623 ms |
|
my method | 1000 | 1048576 kiB | 4 | 791 ms |
2411 ms |
Note
The second to last column shows the time it takes to hash with the evaluated