Converted Vignere, added more tests and cleaned stuff up

This commit is contained in:
Matt C 2018-05-09 21:13:09 +01:00
parent 789ec94eff
commit 6bec68021c
7 changed files with 358 additions and 357 deletions

View file

@ -569,349 +569,6 @@ DES uses a key length of 8 bytes (64 bits).`;
},
/**
* Vigenère Encode operation.
*
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runVigenereEnc: function (input, args) {
let alphabet = "abcdefghijklmnopqrstuvwxyz",
key = args[0].toLowerCase(),
output = "",
fail = 0,
keyIndex,
msgIndex,
chr;
if (!key) return "No key entered";
if (!/^[a-zA-Z]+$/.test(key)) return "The key must consist only of letters";
for (let i = 0; i < input.length; i++) {
if (alphabet.indexOf(input[i]) >= 0) {
// Get the corresponding character of key for the current letter, accounting
// for chars not in alphabet
chr = key[(i - fail) % key.length];
// Get the location in the vigenere square of the key char
keyIndex = alphabet.indexOf(chr);
// Get the location in the vigenere square of the message char
msgIndex = alphabet.indexOf(input[i]);
// Get the encoded letter by finding the sum of indexes modulo 26 and finding
// the letter corresponding to that
output += alphabet[(keyIndex + msgIndex) % 26];
} else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
chr = key[(i - fail) % key.length].toLowerCase();
keyIndex = alphabet.indexOf(chr);
msgIndex = alphabet.indexOf(input[i].toLowerCase());
output += alphabet[(keyIndex + msgIndex) % 26].toUpperCase();
} else {
output += input[i];
fail++;
}
}
return output;
},
/**
* Vigenère Decode operation.
*
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runVigenereDec: function (input, args) {
let alphabet = "abcdefghijklmnopqrstuvwxyz",
key = args[0].toLowerCase(),
output = "",
fail = 0,
keyIndex,
msgIndex,
chr;
if (!key) return "No key entered";
if (!/^[a-zA-Z]+$/.test(key)) return "The key must consist only of letters";
for (let i = 0; i < input.length; i++) {
if (alphabet.indexOf(input[i]) >= 0) {
chr = key[(i - fail) % key.length];
keyIndex = alphabet.indexOf(chr);
msgIndex = alphabet.indexOf(input[i]);
// Subtract indexes from each other, add 26 just in case the value is negative,
// modulo to remove if neccessary
output += alphabet[(msgIndex - keyIndex + alphabet.length) % 26];
} else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
chr = key[(i - fail) % key.length].toLowerCase();
keyIndex = alphabet.indexOf(chr);
msgIndex = alphabet.indexOf(input[i].toLowerCase());
output += alphabet[(msgIndex + alphabet.length - keyIndex) % 26].toUpperCase();
} else {
output += input[i];
fail++;
}
}
return output;
},
/**
* @constant
* @default
*/
AFFINE_A: 1,
/**
* @constant
* @default
*/
AFFINE_B: 0,
/**
* Affine Cipher Encode operation.
*
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runAffineEnc: function (input, args) {
let alphabet = "abcdefghijklmnopqrstuvwxyz",
a = args[0],
b = args[1],
output = "";
if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
return "The values of a and b can only be integers.";
}
for (let i = 0; i < input.length; i++) {
if (alphabet.indexOf(input[i]) >= 0) {
// Uses the affine function ax+b % m = y (where m is length of the alphabet)
output += alphabet[((a * alphabet.indexOf(input[i])) + b) % 26];
} else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
// Same as above, accounting for uppercase
output += alphabet[((a * alphabet.indexOf(input[i].toLowerCase())) + b) % 26].toUpperCase();
} else {
// Non-alphabetic characters
output += input[i];
}
}
return output;
},
/**
* Affine Cipher Decode operation.
*
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runAffineDec: function (input, args) {
let alphabet = "abcdefghijklmnopqrstuvwxyz",
a = args[0],
b = args[1],
output = "",
aModInv;
if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
return "The values of a and b can only be integers.";
}
if (Utils.gcd(a, 26) !== 1) {
return "The value of a must be coprime to 26.";
}
// Calculates modular inverse of a
aModInv = Utils.modInv(a, 26);
for (let i = 0; i < input.length; i++) {
if (alphabet.indexOf(input[i]) >= 0) {
// Uses the affine decode function (y-b * A') % m = x (where m is length of the alphabet and A' is modular inverse)
output += alphabet[Utils.mod((alphabet.indexOf(input[i]) - b) * aModInv, 26)];
} else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
// Same as above, accounting for uppercase
output += alphabet[Utils.mod((alphabet.indexOf(input[i].toLowerCase()) - b) * aModInv, 26)].toUpperCase();
} else {
// Non-alphabetic characters
output += input[i];
}
}
return output;
},
/**
* Atbash Cipher Encode operation.
*
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runAtbash: function (input, args) {
return Cipher.runAffineEnc(input, [25, 25]);
},
/**
* Generates a polybius square for the given keyword
*
* @private
* @author Matt C [matt@artemisbot.uk]
* @param {string} keyword - Must be upper case
* @returns {string}
*/
_genPolybiusSquare: function (keyword) {
const alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
const polArray = `${keyword}${alpha}`.split("").unique();
let polybius = [];
for (let i = 0; i < 5; i++) {
polybius[i] = polArray.slice(i*5, i*5 + 5);
}
return polybius;
},
/**
* Bifid Cipher Encode operation
*
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runBifidEnc: function (input, args) {
const keywordStr = args[0].toUpperCase().replace("J", "I"),
keyword = keywordStr.split("").unique(),
alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
let output = "",
xCo = [],
yCo = [],
structure = [],
count = 0;
if (keyword.length > 25)
return "The alphabet keyword must be less than 25 characters.";
if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
return "The key must consist only of letters";
const polybius = Cipher._genPolybiusSquare(keywordStr);
input.replace("J", "I").split("").forEach(letter => {
let alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0,
polInd;
if (alpInd) {
for (let i = 0; i < 5; i++) {
polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
if (polInd >= 0) {
xCo.push(polInd);
yCo.push(i);
}
}
if (alpha.split("").indexOf(letter) >= 0) {
structure.push(true);
} else if (alpInd) {
structure.push(false);
}
} else {
structure.push(letter);
}
});
const trans = `${yCo.join("")}${xCo.join("")}`;
structure.forEach(pos => {
if (typeof pos === "boolean") {
let coords = trans.substr(2*count, 2).split("");
output += pos ?
polybius[coords[0]][coords[1]] :
polybius[coords[0]][coords[1]].toLocaleLowerCase();
count++;
} else {
output += pos;
}
});
return output;
},
/**
* Bifid Cipher Decode operation
*
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runBifidDec: function (input, args) {
const keywordStr = args[0].toUpperCase().replace("J", "I"),
keyword = keywordStr.split("").unique(),
alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
let output = "",
structure = [],
count = 0,
trans = "";
if (keyword.length > 25)
return "The alphabet keyword must be less than 25 characters.";
if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
return "The key must consist only of letters";
const polybius = Cipher._genPolybiusSquare(keywordStr);
input.replace("J", "I").split("").forEach((letter) => {
let alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0,
polInd;
if (alpInd) {
for (let i = 0; i < 5; i++) {
polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
if (polInd >= 0) {
trans += `${i}${polInd}`;
}
}
if (alpha.split("").indexOf(letter) >= 0) {
structure.push(true);
} else if (alpInd) {
structure.push(false);
}
} else {
structure.push(letter);
}
});
structure.forEach(pos => {
if (typeof pos === "boolean") {
let coords = [trans[count], trans[count+trans.length/2]];
output += pos ?
polybius[coords[0]][coords[1]] :
polybius[coords[0]][coords[1]].toLocaleLowerCase();
count++;
} else {
output += pos;
}
});
return output;
},
/**
* @constant
* @default