141 lines
6.5 KiB
Text
141 lines
6.5 KiB
Text
BEGIN # Bifid cipher #
|
|
|
|
# mode to hold the details of a Bifid cipher #
|
|
MODE BIFID = STRUCT( STRING key # the Polybius square, linearised #
|
|
, STRING pre from # pre-translation, "from" string #
|
|
, STRING pre to # pre-tramslatiion "to" string #
|
|
);
|
|
|
|
# string utilities #
|
|
|
|
# returns the length of s #
|
|
OP LENGTH = ( STRING s )INT: ( UPB s - LWB s ) + 1;
|
|
# returns the index of c in s, or LWB s - 1 if it is not present #
|
|
PRIO INDEXOF = 1;
|
|
OP INDEXOF = ( STRING s, CHAR c )INT:
|
|
BEGIN
|
|
INT index := LWB s - 1;
|
|
VOID( char in string( c, index, s ) ); # discard the result #
|
|
index
|
|
END # INDEXOF # ;
|
|
# returns text with the characters in from chars replaced with the #
|
|
# corresponding characters in to chars #
|
|
PROC translate = ( STRING text, from chars, to chars )STRING:
|
|
IF LWB from chars /= LWB to chars OR UPB from chars /= UPB to chars
|
|
THEN """from"" and ""to"" have different bounds (translate)"
|
|
ELIF from chars = ""
|
|
THEN text
|
|
ELSE # the from and to strings have the same bounds #
|
|
STRING result := text;
|
|
FOR r pos FROM LWB result TO UPB result DO
|
|
INT t pos = from chars INDEXOF result[ r pos ];
|
|
IF t pos >= LWB from chars THEN result[ r pos ] := to chars[ t pos ] FI
|
|
OD;
|
|
result
|
|
FI # translate # ;
|
|
# end string utilities #
|
|
|
|
# returns text encrypted according to cipher #
|
|
PRIO ENCRYPT = 9;
|
|
OP ENCRYPT = ( STRING text, BIFID cipher )STRING:
|
|
IF STRING key = ( key OF cipher )[ AT 1 ];
|
|
INT key length = LENGTH key;
|
|
INT sq width = ENTIER sqrt( key length );
|
|
sq width * sq width /= key length
|
|
THEN "**** Bifid key is not a square"
|
|
ELSE # the key is a square #
|
|
STRING msg1 = translate( text, pre from OF cipher, pre to OF cipher )[ AT 1 ];
|
|
STRING msg := "";
|
|
FOR m pos FROM LWB msg1 TO UPB msg1 DO
|
|
IF msg1[ m pos ] /= " " THEN msg +:= msg1[ m pos ] FI
|
|
OD;
|
|
INT m max = LENGTH msg;
|
|
[ 1 : 2 * m max ]INT coordinates;
|
|
FOR m pos TO m max DO
|
|
INT c index := key INDEXOF msg[ m pos ];
|
|
IF c index >= LWB key THEN c index -:= 1 FI;
|
|
coordinates[ m pos ] := c index OVER sq width;
|
|
coordinates[ m pos + m max ] := c index MOD sq width
|
|
OD;
|
|
STRING result := "";
|
|
FOR c pos BY 2 TO UPB coordinates DO
|
|
result +:= key[ ( coordinates[ c pos ] * sq width )
|
|
+ coordinates[ c pos + 1 ]
|
|
+ 1
|
|
]
|
|
OD;
|
|
result
|
|
FI # ENCRYPT # ;
|
|
|
|
# returns text decrypted according to cipher #
|
|
PRIO DECRYPT = 9;
|
|
OP DECRYPT = ( STRING text, BIFID cipher )STRING:
|
|
IF STRING key = ( key OF cipher )[ AT 1 ];
|
|
INT key length = LENGTH key;
|
|
INT sq width = ENTIER sqrt( key length );
|
|
sq width * sq width /= key length
|
|
THEN "**** Bifid key is not a square"
|
|
ELSE # the key is a square #
|
|
STRING msg = text[ AT 1 ];
|
|
INT m max = LENGTH msg;
|
|
[ 1 : 2 * m max ]INT coordinates;
|
|
INT c pos := 0;
|
|
FOR m pos TO m max DO
|
|
INT c index := key INDEXOF msg[ m pos ];
|
|
IF c index >= LWB key THEN c index -:= 1 FI;
|
|
coordinates[ c pos +:= 1 ] := c index OVER sq width;
|
|
coordinates[ c pos +:= 1 ] := c index MOD sq width
|
|
OD;
|
|
STRING result := "";
|
|
FOR i TO m max DO
|
|
result +:= key[ ( coordinates[ i ] * sq width )
|
|
+ coordinates[ i + m max ]
|
|
+ 1
|
|
]
|
|
OD;
|
|
result
|
|
FI # DECRYPT # ;
|
|
|
|
# tests the ENCRYPT and DECRYPT operators #
|
|
PROC test bifid = ( BIFID cipher, STRING text )VOID:
|
|
BEGIN
|
|
STRING code = text ENCRYPT cipher;
|
|
print( ( text, " -> ", code, newline ) );
|
|
print( ( code, " -> ", code DECRYPT cipher, newline ) )
|
|
END # text bifid # ;
|
|
|
|
# Bifid ciphers for tests #
|
|
|
|
BIFID bifid 5 abc = ( "ABCDEFGHIKLMNOPQRSTUVWXYZ"
|
|
, "Jabcdefghijklmnopqrstuvwxyz"
|
|
, "IABCDEFGHIIKLMNOPQRSTUVWXYZ"
|
|
);
|
|
BIFID bifid 5 bgw = ( "BGWKZQPNDSIOAXEFCLUMTHYVR"
|
|
, "Jabcdefghijklmnopqrstuvwxyz"
|
|
, "IABCDEFGHIIKLMNOPQRSTUVWXYZ"
|
|
);
|
|
BIFID bifid 6 abc = ( "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
, "abcdefghijklmnopqrstuvwxyz"
|
|
, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
);
|
|
BIFID bifid 8 abc = ( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\/"
|
|
, " "
|
|
, "/"
|
|
);
|
|
|
|
# basic task - using 5x5 Polybius squares #
|
|
test bifid( bifid 5 abc, "ATTACKATDAWN" );
|
|
print( ( newline ) );
|
|
test bifid( bifid 5 bgw, "FLEEATONCE" );
|
|
test bifid( bifid 5 bgw, "ATTACKATDAWN" );
|
|
test bifid( bifid 5 bgw, "The invasion will begin on the first of January" );
|
|
print( ( newline ) );
|
|
|
|
# bonus - using a 6x6 square #
|
|
test bifid( bifid 6 abc, "The invasion will begin on the first of January" );
|
|
print( ( newline ) );
|
|
|
|
# bonus - using an 8x8 square #
|
|
test bifid( bifid 8 abc, "The invasion will begin on the first of January" )
|
|
|
|
END
|