aboutsummaryrefslogtreecommitdiff
path: root/challenge-025/yet-ebreo/perl5/ch-2.pl
blob: 8d5a8c63cfe0ff9f1312c211d4de460ef543f584 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# Create script to implement Chaocipher. Please checkout wiki page for more information
# Visualizing it using rotating disk is a bit difficult, here's a video illustration of the algo
# https://www.youtube.com/watch?v=0tL9A69olRc , that helped me understand it

use strict;
use warnings;
use 5.010;

die "Usage:\n\tch-2.pl <-d|e> \"<string to encrypt>\"\n\n" if @ARGV<2;
my $encrypt     = $ARGV[0] eq '-e';
my $text_string = $ARGV[1];

#It should be okay to modify the zenith/nadir (0 to $wheelsize)
use constant ZENITH  => 0;
use constant NADIR   => 13;

#Initialize  wheels (chaocipher with bigger wheels!)
my @pt = "7bqkj9l2hOWyzA8SLPEtRvBwUQVmxa45g ufspeTF1KHd0DrGMCZoJXi3YIN6nc"=~/./g;
my @ct = "vEDclCHZYeWo9drb6Jnkf5MRXOt UgN4Fi231GzQIx7sPaLK8TBuVpA0yjShqwm"=~/./g;

my $wheel_size = $#pt;

# This function rotates the given array or a portion of the given array 
# Rotation count is defined by $r
# The whole array will be rotated by default
# but the range can be specified in $from and $to variable
sub rot {
    my ($r,$array, $from, $to) = @_;
    $r %= ($wheel_size+1);
    return if $r == 0;
    if (!(defined $to && defined $from)) {
        @{$array} = (@{$array}[$r..$#{$array}], @{$array}[0..~-$r]);
    } else {
        $r += $from;
        @{$array} = (@{$array}[0..~-$from], @{$array}[$r..$to], @{$array}[$from..~-$r],@{$array}[$to+1..$#{$array}]);
    }
}

sub cipher {
    my ($text,$enc,$ret) = @_;
    
    for my $c ($text=~/./g) {
        #find where $c is in the plain text @pt (or @ct when decrypting)
        #grep wont stop when first occurence was found
        my $pt_pos = (grep {($enc?$pt[$_]:$ct[$_]) eq $c} 0..$wheel_size)[0];

        #Get the character from the cipher text in that position($pt_pos)
        $ret .= $enc?$ct[$pt_pos]:$pt[$pt_pos];
        
        #rotate @pt and @ct from $pt_pos to ZENITH
        &rot($pt_pos-ZENITH, \@pt);
        &rot($pt_pos-ZENITH, \@ct);

        #permute @ct: move the char in ZENITH + 1 to NADIR
        &rot(1,\@ct,ZENITH+1,NADIR);

        #permute @pt: rotate1 then move the char in ZENITH + 2 to NADIR
        &rot(1,\@pt);
        &rot(1,\@pt,ZENITH+2,NADIR);
    }
    return $ret;
}
say &cipher($text_string,$encrypt);
=begin
perl .\ch-2.pl -e "a quick brown fox jumps over the lazy dog"
gFv4ujqOyIPdTk5I9bKrYUXY4DwkCygHDKmQmyqUh

perl .\ch-2.pl -d "gFv4ujqOyIPdTk5I9bKrYUXY4DwkCygHDKmQmyqUh"
a quick brown fox jumps over the lazy dog
=cut