#!/usr/bin/env perl6
use v6.c;
#use Digest::MD5; # Too slow, use Perl 5 version through Inline::Perl5
use Digest::MD5:from<Perl5> 'md5_hex';
sub md5_repeated(Str $str is copy, Int $iterations)
{
# Way too slow - probably overhead of using Inline::Perl5 2017 times
#$str = md5_hex($str) for ^$iterations;
#return $str;
# Do the whole thing in Perl 5 code instead
use MONKEY-SEE-NO-EVAL;
return EVAL "my \$s = '$str'; for (1..$iterations) \{ \$s = md5_hex(\$s); \}; \$s;", :lang<Perl5>;
}
my regex triple { (\w) ** 3 <?{ [eq] @($/[0]) }> }
sub triples(Str $s)
{
# Only the first one!
#return $s.comb(&triple).unique».substr(0, 1);
return $s.comb(&triple, 1)».substr(0, 1);
}
my regex quintuple { (\w) ** 5 <?{ [eq] @($/[0]) }> }
sub quintuples(Str $s)
{
return $s.comb(&quintuple).unique».substr(0, 1);
}
sub key-info(Str $salted-index)
{
#my $hash = md5_hex($salted-index); # part 1
my $hash = md5_repeated($salted-index, 2017); # part 2
return { hash=>$hash, triples=>triples($hash), quintuples=>quintuples($hash) };
}
sub test-key(Str $salt, Int $index)
{
state %key-info;
%key-info{$salt~$index} //= key-info($salt~$index);
my @triples = %key-info{$salt~$index}<triples>.flat; # Not sure why flat is needed
return Nil unless @triples;
for $index+1 .. $index+1000 -> $i {
%key-info{$salt~$i} //= key-info($salt~$i);
my @quintuples = %key-info{$salt~$i}<quintuples>.flat;
return %key-info{$salt~$index}<hash> if @quintuples && any(@triples) eq any(@quintuples);
}
return Nil;
}
multi sub MAIN(IO() $inputfile where *.f)
{
my ($salt) = $inputfile.words;
MAIN($salt);
}
multi sub MAIN(Str $salt where !*.IO.f)
{
my @keys;
for 1..∞ -> $i {
if my $hash = test-key($salt, $i) {
@keys.push($hash);
say "[#@keys.elems()] $i: $hash";
last if @keys.elems == 64;
}
}
}
Comments