I was able to get it to complete in ~16 min on my MacBookPro:
% time Crypto-Main
eefe3d61cd4da4e4e9945b3d6ba2158c2634e984
./Crypto-Main 1027.30s user 15.34s system 100% cpu 17:22.61 total
by changing the strictness of your fold:
let
-- ...
blockIterator message acc = foldl' (zipWith' xor) acc ms
where ms = take iterations . tail $ iterate (prf passwordOctets) message
zipWith' f as bs = let cs = zipWith f as bs in sum cs `seq` cs
in
dumpRaw $ take keyLength $ foldl' (\acc block ->
acc ++ blockIterator (saltOctets ++ intToOctets block)
(replicate hashLength 0)) [] [1..totalBlocks]
Note how I force the full evaluation of each zipWith xor
. In order to calculate
sum cs
into WHNF, we must know the exact value of each element in cs
.
This prevents building up a chain of thunks, which I think your existing code was attempting to do, but failing, as foldl'
only forces the accumulator into WHNF. Since your accumulator was a pair, the WHNF is just (_thunk, _another_thunk)
, so your intermediate thunks were not getting forced.