AffineCipherDecode.mjs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /**
  2. * @author Matt C [matt@artemisbot.uk]
  3. * @copyright Crown Copyright 2018
  4. * @license Apache-2.0
  5. */
  6. import Operation from "../Operation";
  7. import Utils from "../Utils";
  8. import OperationError from "../errors/OperationError";
  9. /**
  10. * Affine Cipher Decode operation
  11. */
  12. class AffineCipherDecode extends Operation {
  13. /**
  14. * AffineCipherDecode constructor
  15. */
  16. constructor() {
  17. super();
  18. this.name = "Affine Cipher Decode";
  19. this.module = "Ciphers";
  20. this.description = "The Affine cipher is a type of monoalphabetic substitution cipher. To decrypt, each letter in an alphabet is mapped to its numeric equivalent, decrypted by a mathematical function, and converted back to a letter.";
  21. this.inputType = "string";
  22. this.outputType = "string";
  23. this.args = [
  24. {
  25. "name": "a",
  26. "type": "number",
  27. "value": 1
  28. },
  29. {
  30. "name": "b",
  31. "type": "number",
  32. "value": 0
  33. }
  34. ];
  35. }
  36. /**
  37. * @param {string} input
  38. * @param {Object[]} args
  39. * @returns {string}
  40. */
  41. run(input, args) {
  42. const alphabet = "abcdefghijklmnopqrstuvwxyz",
  43. a = args[0],
  44. b = args[1],
  45. aModInv = Utils.modInv(a, 26); // Calculates modular inverse of a
  46. let output = "";
  47. if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
  48. throw new OperationError("The values of a and b can only be integers.");
  49. }
  50. if (Utils.gcd(a, 26) !== 1) {
  51. throw new OperationError("The value of `a` must be coprime to 26.");
  52. }
  53. for (let i = 0; i < input.length; i++) {
  54. if (alphabet.indexOf(input[i]) >= 0) {
  55. // Uses the affine decode function (y-b * A') % m = x (where m is length of the alphabet and A' is modular inverse)
  56. output += alphabet[Utils.mod((alphabet.indexOf(input[i]) - b) * aModInv, 26)];
  57. } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
  58. // Same as above, accounting for uppercase
  59. output += alphabet[Utils.mod((alphabet.indexOf(input[i].toLowerCase()) - b) * aModInv, 26)].toUpperCase();
  60. } else {
  61. // Non-alphabetic characters
  62. output += input[i];
  63. }
  64. }
  65. return output;
  66. }
  67. /**
  68. * Highlight Affine Cipher Decode
  69. *
  70. * @param {Object[]} pos
  71. * @param {number} pos[].start
  72. * @param {number} pos[].end
  73. * @param {Object[]} args
  74. * @returns {Object[]} pos
  75. */
  76. highlight(pos, args) {
  77. return pos;
  78. }
  79. /**
  80. * Highlight Affine Cipher Decode in reverse
  81. *
  82. * @param {Object[]} pos
  83. * @param {number} pos[].start
  84. * @param {number} pos[].end
  85. * @param {Object[]} args
  86. * @returns {Object[]} pos
  87. */
  88. highlightReverse(pos, args) {
  89. return pos;
  90. }
  91. }
  92. export default AffineCipherDecode;