Jump to content

Chaocipher: Difference between revisions

m (→‎{{header|Phix}}: added syntax colouring, marked p2js compatible)
(insert →‎Pascal)
Line 2,265:
The recovered plaintext is: WELLDONEISBETTERTHANWELLSAID
</pre>
 
=={{header|Pascal}}==
{{works with|Extended Pascal}}
<lang pascal>program chaocipher(input, output);
 
const
{ This denotes a `set` literal: }
alphabet = ['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'];
{ The `card` function is an Extended Pascal (ISO 10206) extension. }
alphabetCardinality = card(alphabet);
{ 1st character denotes “zenith”. }
zenith = 1;
{ In a 26-character alphabet the 14th character denotes “nadir”. }
nadir = alphabetCardinality div 2 + 1;
{ For simplicity use compile-time-defined maximum lengths. }
messageMaximumLength = 80;
 
type
{ This “discriminates” the Extended Pascal schema data type `string` to be }
{ capable of holding strings up to `alphabetCardinality` `char` values. }
map = string(alphabetCardinality);
{ Variables of this data type can only assume integer values within 1..26: }
mapCharacterIndex = 1..alphabetCardinality;
{ Later used as a buffer for the input/output. }
message = string(messageMaximumLength);
messageCharacterIndex = 1..messageMaximumLength;
{ Stores a key for the Chaocipher algorithm. }
key = record
cipherText: map;
plainText: map;
end;
 
{ --- auxilliary routines ---------------------------------------------- }
 
{
\brief verifies that a key is valid for the Chaocipher
\param sample a potential `key` for a Chaocipher
\return `true` iff \param sample is an acceptable `key`
}
{ `protected` (Extended Pascal extension) denotes an immutable parameter. }
function isValid(protected sample: key): Boolean;
{ Determines whether a `map` contains all characters of `alphabet`. }
{ Nesting this function allows for a neat expression below. }
function isComplete(text: map): Boolean;
var
i: integer;
{ `value []` will initialize this variable to an empty set value. }
{ This is an Extended Pascal (ISO 10206) extension. }
s: set of char value [];
begin
{ NB: In Pascal `for`-loop limits are inclusive. }
for i := 1 to length(text) do
begin
{ This adds the set containing one character to the set `s`. }
s := s + [text[i]]
end;
isComplete := card(s) = alphabetCardinality
end;
begin
{ This way `sample.cipherText` can be simply written as `cipherText`. }
with sample do
begin
{ `and_then` is an EP extension indicating “lazy evaluation”. }
isValid := (alphabetCardinality > 8) and_then
isComplete(cipherText) and_then isComplete(plainText)
end
end;
 
{
\brief permutes a key for the next encryption/decryption step
\param shift the index of the characters just substituted
}
{ `var` means the parameter value will be modified _at_ the call site. }
procedure permute(var state: key; protected shift: mapCharacterIndex);
begin
with state do
begin
{ Indices in `cipherText[1..pred(shift)]` _must_ be non-descending: }
if shift > 1 then
begin
cipherText := subStr(cipherText, shift) + cipherText[1..pred(shift)]
{ `subStr(str, ini)` is equivalent to `str[ini..length(str)]`. }
end;
{ Likewise, `succ(shift)` must be a valid index in `plainText`: }
if shift < alphabetCardinality then
begin
plainText := subStr(plainText, succ(shift)) + plainText[1..shift]
end;
{ If it does _not_ _alter_ the _entire_ string’s _length_, you can }
{ modify parts of a string like this (Extended Pascal extension): }
cipherText[zenith+1..nadir] := cipherText[zenith+2..nadir] + cipherText[zenith+1];
plainText[zenith+2..nadir] := plainText[zenith+3..nadir] + plainText[zenith+2]
end
end;
 
{ --- the core routine of the algorithm -------------------------------- }
 
{
\brief performs Chaocipher common steps
\param line the message to encrypt/decrypt
\param state the initial key to start encrpytion/decryption with
\param locate a function determining the 2-tuple index in the key
\param substitute the procedure substituting the correct characters
}
procedure chaocipher(
var line: message;
var state: key;
{ These are “routine parameters”. Essentially the address of a routine }
{ matching the specified routine signature is passed to `chaocipher`. }
function locate(protected i: messageCharacterIndex): mapCharacterIndex;
procedure substitute(
protected i: messageCharacterIndex;
protected z: mapCharacterIndex
)
);
var
{ For demonstration purposes: In this program }
{ `line.capacity` refers to `messageMaximumLength`. }
i: 1..line.capacity;
substitutionPairIndex: mapCharacterIndex;
begin
{ Don’t trust user input, even though this is just a RosettaCode example. }
if not isValid(state) then
begin
writeLn('Error: Key is invalid. Got:');
writeLn('Cipher text: ', state.cipherText);
writeLn(' Plain text: ', state.plainText);
halt
end;
for i := 1 to length(line) do
begin
{ We’ll better skip characters that aren’t in the `alphabet`. }
if line[i] in alphabet then
begin
{ Here you see the beauty of using routine parameters. }
{ Depending on whether we’re encrypting or decrypting, }
{ you need to find a character in the `cipherText` or }
{ `plainText` key value respectively, yet the basic order
{ of the steps are still the same. }
substitutionPairIndex := locate(i);
substitute(i, substitutionPairIndex);
permute(state, substitutionPairIndex)
end
end
end;
 
{ --- entry routines --------------------------------------------------- }
 
{
\brief encrypts a message according to Chaocipher
}
{ Note: without `var` or `protected` both `encrypt` and `decrypt`get }
{ and have their own independent copies of the parameter values. }
function encrypt(line: message; state: key): message;
function encryptor(protected i: messageCharacterIndex): mapCharacterIndex;
begin
encryptor := index(state.plainText, line[i])
end;
procedure substitutor(
protected i: messageCharacterIndex;
protected z: mapCharacterIndex
);
begin
line[i] := state.cipherText[z]
end;
begin
chaocipher(line, state, encryptor, substitutor);
encrypt := line
end;
 
function decrypt(line: message; state: key): message;
function decryptor(protected i: messageCharacterIndex): mapCharacterIndex;
begin
decryptor := index(state.cipherText, line[i])
end;
procedure substitutor(
protected i: messageCharacterIndex;
protected z: mapCharacterIndex
);
begin
line[i] := state.plainText[z]
end;
begin
chaocipher(line, state, decryptor, substitutor);
decrypt := line
end;
 
{ === MAIN ============================================================= }
var
exampleKey: key;
line: message;
begin
{ Instead of writing `exampleKey.cipherText := '…', you can }
{ write in Extended Pascal a `record` literal like this: }
exampleKey := key[
cipherText: 'HXUCZVAMDSLKPEFJRIGTWOBNYQ';
plainText: 'PTLNBQDEOYSFAVZKGJRIHWXUMC';
];
{ `EOF` is shorthand for `EOF(input)`. }
while not EOF do
begin
{ `readLn(line)` is shorthand for `readLn(input, line)`. }
readLn(line);
line := encrypt(line, exampleKey);
writeLn(decrypt(line, exampleKey));
{ Likewise, `writeLn(line)` is short for `writeLn(output, line)`. }
writeLn(line)
end
end.</lang>
{{in}}
WELLDONEISBETTERTHANWELLSAID
{{out}}
WELLDONEISBETTERTHANWELLSAID
OAHQHCNYNXTSZJRRHJBYHQKSOUJY
 
=={{header|Perl}}==
149

edits

Cookies help us deliver our services. By using our services, you agree to our use of cookies.