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