RosettaCodeData/Task/Bifid-cipher/ALGOL-68/bifid-cipher.alg
2024-10-16 18:07:41 -07:00

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