File Coverage

blib/lib/MAD/Scrambler.pm
Criterion Covered Total %
statement 40 40 100.0
branch n/a
condition n/a
subroutine 8 8 100.0
pod 4 4 100.0
total 52 52 100.0


line stmt bran cond sub pod time code
1             package MAD::Scrambler;
2             $MAD::Scrambler::VERSION = '0.000005';
3             ## no critic (Bangs::ProhibitBitwiseOperators)
4              
5 2     2   119043 use Moo;
  2         24478  
  2         10  
6             extends 'Exporter';
7              
8             our @EXPORT_OK = qw{
9             nibble_split
10             nibble_join
11             };
12              
13 2     2   3319 use List::Util qw{ shuffle };
  2         3  
  2         157  
14              
15 2     2   933 use Const::Fast;
  2         1519  
  2         11  
16              
17             const our $MAX_BIT_MASK => 2**32;
18              
19             const my $MIN_BIT => 0;
20             const my $MAX_BIT => 7;
21             const my $NIBBLE_SIZE => 4;
22             const my $NIBBLE_MASK => 0x0000000f;
23              
24             has 'scrambler' => (
25             is => 'ro',
26             lazy => 1,
27             default => sub { [ shuffle $MIN_BIT .. $MAX_BIT ] },
28             );
29              
30             has 'unscrambler' => (
31             is => 'ro',
32             lazy => 1,
33             builder => sub {
34 1     1   342 my ($self) = @_;
35              
36 1         2 my @scrambler = @{ $self->scrambler };
  1         19  
37 1         7 my @unscrambler = ();
38              
39 1         3 for ( $MIN_BIT .. $MAX_BIT ) {
40 8         10 $unscrambler[ $scrambler[$_] ] = $_;
41             }
42              
43 1         4 return \@unscrambler;
44             },
45             );
46              
47             has 'bit_mask' => (
48             is => 'ro',
49             default => sub { int rand $MAX_BIT_MASK },
50             );
51              
52             sub encode {
53 3     3 1 1705 my ( $self, $number ) = @_;
54              
55 3         4 my @slice = @{ $self->scrambler };
  3         42  
56 3         371 my @nibbles = nibble_split($number);
57 3         9 my $scrambled = nibble_join( @nibbles[@slice] );
58 3         7 my $encoded = $scrambled ^ $self->bit_mask;
59              
60 3         7 return $encoded;
61             }
62              
63             sub decode {
64 3     3 1 1037 my ( $self, $encoded ) = @_;
65              
66 3         4 my @slice = @{ $self->unscrambler };
  3         43  
67 3         17 my $number = $encoded ^ $self->bit_mask;
68 3         8 my @nibbles = nibble_split($number);
69 3         7 my $decoded = nibble_join( @nibbles[@slice] );
70              
71 3         7 return $decoded;
72             }
73              
74             sub nibble_split {
75 7     7 1 14 my ($number) = @_;
76              
77 7         8 my @nibbles;
78 7         11 for ( $MIN_BIT .. $MAX_BIT ) {
79 56         68 $nibbles[$_] = ( $number >> ( $_ * $NIBBLE_SIZE ) ) & $NIBBLE_MASK;
80             }
81              
82 7         18 return @nibbles;
83             }
84              
85             sub nibble_join {
86 7     7 1 600 my (@nibbles) = @_;
87              
88 7         8 my $number = 0;
89 7         9 for ( $MIN_BIT .. $MAX_BIT ) {
90 56         63 $number = $number | ( $nibbles[$_] << ( $_ * $NIBBLE_SIZE ) );
91             }
92              
93 7         12 return $number;
94             }
95              
96             1;
97              
98             # ABSTRACT: Scramble nibbles of a 32-bit integer
99              
100             __END__