Created
November 26, 2010 19:13
-
-
Save chischaschos/717112 to your computer and use it in GitHub Desktop.
A Playfair Cypher ruby example from the ruby core rubylearning.org course
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*.swp |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
source :gemcutter | |
gem "rspec" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
GEM | |
remote: http://rubygems.org/ | |
specs: | |
diff-lcs (1.1.2) | |
rspec (2.1.0) | |
rspec-core (~> 2.1.0) | |
rspec-expectations (~> 2.1.0) | |
rspec-mocks (~> 2.1.0) | |
rspec-core (2.1.0) | |
rspec-expectations (2.1.0) | |
diff-lcs (~> 1.1.2) | |
rspec-mocks (2.1.0) | |
PLATFORMS | |
ruby | |
DEPENDENCIES | |
rspec |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) | |
require 'playfair_square' | |
require 'playfair_encoder' | |
require 'playfair_cipher' | |
puts "-----------------------------------------------------------" | |
puts "Welcome to Plyfair cipher" | |
puts "At any time pres <CTR + C> to exit or just press enter\n\n" | |
puts "-----------------------------------------------------------" | |
loop do | |
print "Input key: " | |
key = gets.chop! | |
exit(0) if key.empty? | |
pfc = PlayfairCipher.new(key) | |
puts "Formed key: %s" % pfc.key.to_s | |
print "Message to encode: " | |
message = gets.chop! | |
exit(0) if message.empty? | |
puts "Encoded message: %s" % pfc.encode(message).to_s | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'playfair_square' | |
require 'playfair_encoder' | |
class PlayfairCipher | |
attr_reader :key | |
def initialize(key) | |
@square = PlayfairSquare.new(clean_key(key)) | |
@key = @square.rows | |
@encoder = PlayfairEncoder.new(@square) | |
end | |
def encode(message) | |
message.gsub!(/[jJ]/i, 'I') | |
digraph_ary = prepare_digraph(message) | |
result_digraph = [] | |
digraph_ary.each do |digraph| | |
result_digraph << (@encoder.row(digraph) || @encoder.col(digraph) || @encoder.rect(digraph)) | |
end | |
result_digraph | |
end | |
def decode(message) | |
message.gsub!(/[jJ]/i, 'I') | |
digraph_ary = prepare_digraph(message) | |
result_digraph = [] | |
digraph_ary.each do |digraph| | |
result_digraph << (@encoder.row(digraph, true) || @encoder.col(digraph, true) || @encoder.rect(digraph)) | |
end | |
result_digraph | |
end | |
private | |
def prepare_digraph(message) | |
message = (message.upcase! || message).gsub(/[\s]/, '') | |
prepared_message = '' | |
index = 0 | |
x_added = false | |
loop do | |
current_char = message[index].chr | |
last_prepared_char = prepared_message[-1] | |
if last_prepared_char && current_char == last_prepared_char.chr | |
prepared_message << (x_added ? 'Z' : 'X') | |
x_added = !x_added | |
else | |
prepared_message << current_char | |
index += 1 | |
end | |
break if current_char == nil || index >= message.size | |
end | |
(prepared_message.size % 2 == 0 ? prepared_message : prepared_message << 'X').scan(/../) | |
end | |
def clean_key(key) | |
key.gsub!(/[jJ]/i, 'I') | |
cleaned_key_ary = key.gsub(/[^a-zA-Z]+/, '').upcase.scan(/./) | |
cleaned_key_ary = cleaned_key_ary.uniq! || cleaned_key_ary.uniq | |
cleaned_key_ary | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) | |
require 'spec_helper' | |
require 'playfair_cipher' | |
describe PlayfairCipher do | |
subject { PlayfairCipher.new('') } | |
context 'with cleaned up key phrase' do | |
it 'coverts a key phrase to an array' do | |
subject.send(:clean_key, 'A Key Phrase').should be_an(Array) | |
end | |
it 'removes all spaces and non letter characters' do | |
subject.send(:clean_key, 'a b c d e f g').to_s.downcase.should eq('abcdefg') | |
subject.send(:clean_key, 'a 123 ').to_s.downcase.should eq('a') | |
subject.send(:clean_key, 'a !"#1 23dfg/(?\' ').to_s.downcase.should eq('adfg') | |
end | |
it 'all duplicated characters are ignored' do | |
subject.send(:clean_key, 'How are you doing today?').to_s.should eq('HOWAREYUDINGT') | |
end | |
it 'converts the key phrase to upper case' do | |
subject.send(:clean_key, 'abcdefg').to_s.should eq('ABCDEFG') | |
end | |
it 'creates squares' do | |
expected_square = "P L A Y F " | |
expected_square << "I R E X M " | |
expected_square << "B C D G H " | |
expected_square << "K N O Q S " | |
expected_square << "T U V W Z" | |
PlayfairCipher.new('playfair example').key.should eq(expected_square.split) | |
expected_square = "I L O V E " | |
expected_square << "R U B Y A " | |
expected_square << "C D F G H " | |
expected_square << "K M N P Q " | |
expected_square << "S T W X Z" | |
PlayfairCipher.new('I love ruby').key.should eq(expected_square.split) | |
expected_square = "F I R S T " | |
expected_square << "A M E N D " | |
expected_square << "B C G H K " | |
expected_square << "L O P Q U " | |
expected_square << "V W X Y Z " | |
PlayfairCipher.new('First Amendment').key.should eq(expected_square.split) | |
end | |
end | |
context 'prepare digraph' do | |
it 'should insert an X between consecutive identical characters' do | |
subject.send(:prepare_digraph, 'EE').should eq(['EX', 'EX']) | |
end | |
it "should append an X when a message's size is odd" do | |
subject.send(:prepare_digraph, 'EPS').should eq(['EP', 'SX']) | |
end | |
it 'should alternate X and Z when replacing consecutive indentical characters' do | |
subject.send(:prepare_digraph, 'EE PP YY').should eq(['EX', 'EP', 'ZP', 'YX', 'YX']) | |
end | |
it 'should work' do | |
expected_digraph = 'HIDETHEGOLDINTHETREXESTUMP'.scan(/../) | |
subject.send(:prepare_digraph, 'Hide the gold in the tree stump').should eq(expected_digraph) | |
end | |
end | |
context 'encoding messages' do | |
subject { PlayfairCipher.new('playfair example') } | |
it 'should encode a digraph located in the same row' do | |
subject.encode('PL').should eq(['LA']) | |
end | |
it 'should decode a digraph located in the same row' do | |
subject.decode('LA').should eq(['PL']) | |
end | |
it 'should encode a whole message' do | |
result = 'BM OD ZB XD NA BE KU DM UI XM MO UV IF' | |
subject.encode('Hide the gold in the tree stump').should eq(result.split) | |
end | |
it 'should decode a whole message' do | |
result = 'HI DE TH EG OL DI NT HE TR EX ES TU MP' | |
subject.decode('BMODZBXDNABEKUDMUIXMMOUVIF').should eq(result.split) | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PlayfairEncoder | |
def initialize(playfair_square) | |
raise "A #{PlayfairSquare} instance is expected" unless playfair_square.is_a? PlayfairSquare | |
@square = playfair_square | |
end | |
def row(digraph, reverse = false) | |
linear_digraph(:row, digraph, reverse) | |
end | |
def col(digraph, reverse = false) | |
linear_digraph(:col, digraph, reverse) | |
end | |
def rect(digraph) | |
char0 = digraph[0].chr | |
char1 = digraph[1].chr | |
cols = @square.cols | |
rows = @square.rows | |
cols_diff = cols.index(char1) / 5 - cols.index(char0) / 5 | |
rows[rows.index(char0) + cols_diff] + rows[rows.index(char1) - cols_diff] | |
end | |
private | |
def linear_digraph(type, digraph, reverse = false) | |
square = type == :row ? @square.rows : @square.cols | |
row_index = 0 | |
result = nil | |
char0 = digraph[0].chr | |
char1 = digraph[1].chr | |
while row_index < 6 do | |
iteration = row_index * 5 | |
row = square[iteration..(iteration + 4)] | |
indexes = [] | |
if (indexes[0] = row.index(char0)) && (indexes[1] = row.index(char1)) | |
indexes.map! do |index| | |
if reverse | |
index += iteration - 1 | |
else | |
index += iteration + 1 | |
index == square.size ? 0 : index | |
end | |
end | |
result = square[indexes[0]] + square[indexes[1]] | |
break | |
end | |
row_index += 1 | |
end | |
result | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) | |
require 'spec_helper' | |
require 'playfair_cipher' | |
describe PlayfairEncoder do | |
subject do | |
pfc = PlayfairCipher.new("playfair example") | |
PlayfairEncoder.new(pfc.instance_eval { @square }) | |
end | |
context 'digraph encoding' do | |
it 'should encode digraphs in same row' do | |
subject.row('PL').should eq('LA') | |
subject.row('AY').should eq('YF') | |
subject.row('PY').should eq('LF') | |
subject.row('RX').should eq('EM') | |
subject.row('KQ').should eq('NS') | |
subject.row('VW').should eq('WZ') | |
subject.row('YF').should eq('FI') | |
subject.row('WZ').should eq('ZP') | |
end | |
it 'should encode digraphs on same column' do | |
subject.col('DE').should eq('OD') | |
subject.col('LN').should eq('RU') | |
subject.col('LU').should eq('RA') | |
subject.col('FZ').should eq('MP') | |
end | |
it 'should encode rectangle digraps' do | |
subject.rect('HI').should eq('BM') | |
subject.rect('HT').should eq('BZ') | |
subject.rect('MP').should eq('IF') | |
subject.rect('TH').should eq('ZB') | |
subject.rect('EG').should eq('XD') | |
subject.rect('OL').should eq('NA') | |
subject.rect('DI').should eq('BE') | |
subject.rect('NT').should eq('KU') | |
subject.rect('ES').should eq('MO') | |
end | |
end | |
context 'digraph decoding' do | |
it 'should encode digraphs in same row' do | |
subject.row('LA', true).should eq('PL') | |
subject.row('YF', true).should eq('AY') | |
subject.row('LF', true).should eq('PY') | |
subject.row('EM', true).should eq('RX') | |
subject.row('NS', true).should eq('KQ') | |
subject.row('WZ', true).should eq('VW') | |
end | |
it 'should encode digraphs on same column' do | |
subject.col('OD', true).should eq('DE') | |
subject.col('RU', true).should eq('LN') | |
end | |
it 'should encode rectangle digraps' do | |
subject.rect('BM').should eq('HI') | |
subject.rect('BZ').should eq('HT') | |
subject.rect('IF').should eq('MP') | |
subject.rect('ZB').should eq('TH') | |
subject.rect('XD').should eq('EG') | |
subject.rect('NA').should eq('OL') | |
subject.rect('BE').should eq('DI') | |
subject.rect('KU').should eq('NT') | |
subject.rect('MO').should eq('ES') | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PlayfairSquare | |
SQUARE = (97..(97+25)).map(&:chr).map!(&:upcase) | |
SQUARE.delete('J') | |
attr_reader :rows, :cols | |
def initialize(key_ary) | |
raise "A #{Array} instance is expected" unless key_ary.is_a? Array | |
@rows = key_ary + (SQUARE - key_ary) | |
@cols = [rows[0..4], rows[5..9], rows[10..14], rows[15..19], rows[20..24]].transpose.flatten | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) | |
require 'spec_helper' | |
require 'playfair_cipher' | |
describe PlayfairSquare do | |
describe 'fills square by default' do | |
subject { PlayfairSquare.new([]) } | |
it 'should return all square rows' do | |
expected_square = "A B C D E " | |
expected_square << "F G H I K " | |
expected_square << "L M N O P " | |
expected_square << "Q R S T U " | |
expected_square << "V W X Y Z " | |
subject.rows.should eq(expected_square.split) | |
end | |
it 'should return all square cols' do | |
expected_square = "A F L Q V " | |
expected_square << "B G M R W " | |
expected_square << "C H N S X " | |
expected_square << "D I O T Y " | |
expected_square << "E K P U Z " | |
subject.cols.should eq(expected_square.split) | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) | |
$:.unshift(File.dirname(__FILE__)) | |
require 'rubygems' | |
require 'rspec' | |
require 'playfair_square' | |
require 'playfair_encoder' | |
require 'playfair_cipher' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment