summaryrefslogtreecommitdiff
path: root/lib/Enigmatic/CryptTrain.pm
blob: 06a11d20b62c4466d96d569eb8ecd382506be3cb (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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package Enigmatic::CryptTrain; 
use DAKKAR::p 'class';
use Enigmatic::Types qw(Letter RotorPos);
use MooseX::Types::Moose qw(ArrayRef);
use Moose::Util::TypeConstraints;
 
has rotors => (
    isa => ArrayRef[class_type('Enigmatic::Rotor')],
    traits => ['Array'],
    writer => 'set_rotors',
    handles => {
        set_rotor => 'set',
        rotor_at => 'get',
        rotors => 'elements',
    },
);
 
sub rotor_count {
    my ($self) = @_;
 
    return scalar $self->rotors;
}
 
has reflector => (
    isa => class_type('Enigmatic::Reflector'),
    writer => 'set_reflector',
    reader => 'reflector',
);
 
has positions => (
    isa => ArrayRef[RotorPos],
    traits => ['Array'],
    writer => 'set_positions',
    handles => {
        set_position => 'set',
        position_at => 'get',
        positions => 'elements',
    },
);
 
sub map {
    my $self = shift;
    my ($letter) = pos_validated_list(
        \@_,
        isa => Letter },
    );
 
    for my $element (
        $self->rotors,
        $self->reflector,
        (reverse $self->rotors),
    ) {
        $letter = $element->map($letter);
    }
    $self->step_positions();
 
    return $letter;
}
 
sub _inc_position {
    my ($self,$idx) = @_;
 
    my $cur = $self->position_at($idx);
    $cur = ($cur+1)%26;
    $self->set_position($idx,$cur);
    return $cur;
}
 
sub rotor_window_at {
    my ($self,$idx) = @_;
 
    return ['A'..'Z']->[$self->position_at($idx)]
}
 
sub step_positions {
    my ($self) = @_;
 
    for my $pos (0 .. $self->rotor_count -1) {
        $self->_inc_position($pos);
        my $rot = $self->rotor_at($pos);
        last
            unless $rot->has_notch_at($self->rotor_window_at($pos));
    }
 
    return;
}