*Update 9/10/08: you get better results if you calculate the advance a bit differently. Start with 1. If ring 2 has a dot above, add 2; if it has a dot below, add 1. If ring 3 has a dot above, add 6; if it has a dot below, add 3. I'm still experimenting with the advance, though.*

#!/usr/bin/perl -w

# Calculates how many positions to advance a ring to get to the desired letter

sub calcAdvance {

my ($pos, $newPos) = @_;

my $advance = $newPos - $pos;

if ($advance < 0) {

$advance = $advance + 26;

}

return $advance;

}

# Ring1 is inner-most, Ring3 is outer-most.

#

# A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

my @ring2Dots = (9,9,0,0,3,3,9,9,0,0,3,3,9,9,0,0,3,3,9,9,0,0,3,3,9,9);

my @ring3Dots = (2,2,2,0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,0,0,0,1,1);

#

# The Conjugal Encryption Algorithm.

#

# Initialization using the crypto key.

#

# Start by aligning all the "A"'s.

my $ring2Pos = 0;

my $ring3Pos = 0;

# Then initialize the ring.

my $key = "congratulations";

while ($key ne "") {

# 1. Get the next character of the key

my $keyChar = substr ($key, 0, 1);

$key = substr ($key, 1);

# 2. Rotate rings 2 and 3 together so the A on

# Ring 1 aligns with the key character on

# Ring 3.

my $advance = calcAdvance ($ring3Pos,

ord (lc ($keyChar)) - ord ("a"));

$ring2Pos = ($ring2Pos + $advance) % 26;

$ring3Pos = ($ring3Pos + $advance) % 26;

# 3. Calculate an advancement amount.

# a. Start with 1.

# b. Look at the Ring 2 letter next to the A of Ring 1.

# If there's a dot above, add 9. If there's a dot

# below, add 3.

# c. Look at the Ring 3 letter next to the A of Ring 1.

# If there's a dot above, add 2. If there's a dot

# below, add 1.

$advance = 1 + $ring2Dots[$ring2Pos] + $ring3Dots[$ring3Pos];

# 4. Advance Ring 3 that many letters.

$ring3Pos = ($ring3Pos + $advance) % 26;

}

# Generate some useful output

my $plaintext = "Wishing you a happy life together!";

print $plaintext, "\n";

# Skip whitespace and punctuation when encrypting.

$plaintext = lc($plaintext);

$plaintext =~ tr/a-z//cd;

print uc($plaintext), "\n";

#

# Encrypt text. Initialization vector omitted for clarity.

#

my $cyphertext = "";

while ($plaintext ne "") {

# 1. Look at the letter on Ring 3 adjacent to the A on Ring 1.

# Rotate Rings 2 and 3 together so that same letter on

# Ring 2 is adjacent to the A on Ring 1 (and some different

# letter on Ring 3 will now be adjacent.)

my $advance = calcAdvance ($ring2Pos, $ring3Pos);

$ring2Pos = ($ring2Pos + $advance) % 26;

$ring3Pos = ($ring3Pos + $advance) % 26;

# 2. Calculate an advancement amount.

# a. Start with 1.

# b. Look at the Ring 2 letter next to the A of Ring 1.

# If there's a dot above, add 9. If there's a dot

# below, add 3.

# c. Look at the Ring 3 letter next to the A of Ring 1.

# If there's a dot above, add 2. If there's a dot

# below, add 1.

$advance = 1 + $ring2Dots[$ring2Pos] + $ring3Dots[$ring3Pos];

# 3. Advance Ring 3 that many letters.

$ring3Pos = ($ring3Pos + $advance) % 26;

# 4. Get the next character of the plaintext.

my $plainChar = substr ($plaintext, 0, 1);

$plaintext = substr ($plaintext, 1);

# 5. To encrypt this letter of plaintext, find the

# plaintext on Ring 1 and write down the matching

# cyphertext on Ring 3. (To decrypt, look at

# the cyphertext on Ring 3 and write down the matching

# plaintext on Ring 1.)

my $ring3CryptoPos

= (ord ($plainChar) - ord ("a") + $ring3Pos) % 26;

$cyphertext = $cyphertext . chr ($ring3CryptoPos + ord ("A"));

}

# Print the cyphertext.

print $cyphertext, "\n";

## No comments:

Post a Comment