118 lines
2.8 KiB
Raku
118 lines
2.8 KiB
Raku
#!/usr/bin/env perl6
|
|
|
|
use v6.d;
|
|
|
|
my uint32 (@mm, @randrsl, $randcnt, $aa, $bb, $cc);
|
|
my \ϕ := 2654435769; constant MOD = 95; constant START = 32;
|
|
|
|
constant MAXINT = uint.Range.max;
|
|
enum CipherMode < ENCIPHER DECIPHER NONE >;
|
|
|
|
sub mix (\n) {
|
|
sub mix1 (\i, \v) {
|
|
n[i] +^= v;
|
|
n[(i+3)%8] += n[i];
|
|
n[(i+1)%8] += n[(i+2)%8];
|
|
}
|
|
mix1 0, n[1]+<11; mix1 1, n[2]+>2; mix1 2, n[3]+<8; mix1 3, n[4]+>16;
|
|
mix1 4, n[5]+<10; mix1 5, n[6]+>4; mix1 6, n[7]+<8; mix1 7, n[0]+>9 ;
|
|
}
|
|
|
|
sub randinit(\flag) {
|
|
$aa = $bb = $cc = 0;
|
|
my uint32 @n = [^8].map({ ϕ });
|
|
for ^4 { mix @n };
|
|
for 0,8 … 255 -> $i {
|
|
{ for (0..7) { @n[$^j] += @randrsl[$i + $^j] } } if flag;
|
|
mix @n;
|
|
for (0..7) { @mm[$i + $^j] = @n[$^j] }
|
|
}
|
|
if flag {
|
|
for 0,8 … 255 -> $i {
|
|
for ^8 { @n[$^j] += @mm[$i + $^j] };
|
|
mix @n;
|
|
for ^8 { @mm[$i + $^j] = @n[$^j] };
|
|
}
|
|
}
|
|
isaac;
|
|
$randcnt = 0;
|
|
}
|
|
|
|
sub isaac() {
|
|
$cc++;
|
|
$bb += $cc;
|
|
for ^256 -> $i {
|
|
my $x = @mm[$i];
|
|
given ($i % 4) {
|
|
when 0 { $aa +^= ($aa +< 13) }
|
|
when 1 { $aa +^= (($aa +& MAXINT) +> 6) }
|
|
when 2 { $aa +^= ($aa +< 2) }
|
|
when 3 { $aa +^= (($aa +& MAXINT) +> 16) }
|
|
}
|
|
$aa += @mm[($i + 128) % 256];
|
|
my $y = @mm[(($x +& MAXINT) +> 2) % 256] + $aa + $bb;
|
|
@mm[$i] = $y;
|
|
$bb = @mm[(($y +& MAXINT) +> 10) % 256] + $x;
|
|
@randrsl[$i] = $bb;
|
|
}
|
|
$randcnt = 0;
|
|
}
|
|
|
|
sub iRandom {
|
|
my $result = @randrsl[$randcnt++];
|
|
if ($randcnt > 255) {
|
|
isaac;
|
|
$randcnt = 0;
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
sub iSeed(\seed, \flag) {
|
|
@mm = [^256].race.map({0});
|
|
my \m = seed.chars;
|
|
@randrsl = [^256].hyper.map({ $^i ≥ m ?? 0 !! seed.substr($^i,1).ord });
|
|
randinit(flag);
|
|
}
|
|
|
|
sub iRandA { return iRandom() % MOD + START };
|
|
|
|
sub vernam(\M) { ( map { (iRandA() +^ .ord ).chr }, M.comb ).join };
|
|
|
|
sub caesar(CipherMode \m, \ch, $shift is copy, \Modulo, \Start) {
|
|
$shift = -$shift if m == DECIPHER;
|
|
my $n = (ch.ord - Start) + $shift;
|
|
$n %= Modulo;
|
|
$n += Modulo if $n < 0;
|
|
return (Start + $n).chr;
|
|
}
|
|
|
|
sub caesarStr(CipherMode \m, \msg, \Modulo, \Start) {
|
|
my $sb = '';
|
|
for msg.comb {
|
|
$sb ~= caesar m, $^c, iRandA(), Modulo, Start;
|
|
}
|
|
return $sb;
|
|
}
|
|
|
|
multi MAIN () {
|
|
my \msg = "a Top Secret secret";
|
|
my \key = "this is my secret key";
|
|
|
|
iSeed key, True ;
|
|
my $vctx = vernam msg;
|
|
my $cctx = caesarStr ENCIPHER, msg, MOD, START;
|
|
|
|
iSeed key, True ;
|
|
my $vptx = vernam $vctx;
|
|
my $cptx = caesarStr DECIPHER, $cctx, MOD, START;
|
|
|
|
my $vctx2hex = ( map { .ord.fmt('%02X') }, $vctx.comb ).join('');
|
|
my $cctx2hex = ( map { .ord.fmt('%02X') }, $cctx.comb ).join('');
|
|
|
|
say "Message : ", msg;
|
|
say "Key : ", key;
|
|
say "XOR : ", $vctx2hex;
|
|
say "XOR dcr : ", $vptx;
|
|
say "MOD : ", $cctx2hex;
|
|
say "MOD dcr : ", $cptx;
|
|
}
|