diff --git a/Ciphers/SubstitutionCipher.js b/Ciphers/SubstitutionCipher.js new file mode 100644 index 0000000000..2383a99796 --- /dev/null +++ b/Ciphers/SubstitutionCipher.js @@ -0,0 +1,59 @@ +/** + * Substitution Cipher + * + * A monoalphabetic substitution cipher replaces each letter of the plaintext + * with another letter based on a fixed permutation (key) of the alphabet. + * https://en.wikipedia.org/wiki/Substitution_cipher + */ + +const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +const defaultKey = 'QWERTYUIOPASDFGHJKLZXCVBNM' + +/** + * Encrypts a string using a monoalphabetic substitution cipher + * @param {string} text - The text to encrypt + * @param {string} key - The substitution key (must be 26 uppercase letters) + * @returns {string} + */ +export function substitutionCipherEncryption(text, key = defaultKey) { + if (key.length !== 26 || !/^[A-Z]+$/.test(key)) { + throw new RangeError('Key must be 26 uppercase English letters.') + } + + let result = '' + const textUpper = text.toUpperCase() + for (let i = 0; i < textUpper.length; i++) { + const char = textUpper[i] + const index = alphabet.indexOf(char) + if (index !== -1) { + result += key[index] + } else { + result += char + } + } + return result +} +/** + * Decrypts a string encrypted with the substitution cipher + * @param {string} text - The encrypted text + * @param {string} key - The substitution key used during encryption + * @returns {string} + */ +export function substitutionCipherDecryption(text, key = defaultKey) { + if (key.length !== 26 || !/^[A-Z]+$/.test(key)) { + throw new RangeError('Key must be 26 uppercase English letters.') + } + + let result = '' + const textUpper = text.toUpperCase() + for (let i = 0; i < textUpper.length; i++) { + const char = textUpper[i] + const index = key.indexOf(char) + if (index !== -1) { + result += alphabet[index] + } else { + result += char + } + } + return result +} diff --git a/Ciphers/test/SubstitutionCipher.test.js b/Ciphers/test/SubstitutionCipher.test.js new file mode 100644 index 0000000000..820d0303d6 --- /dev/null +++ b/Ciphers/test/SubstitutionCipher.test.js @@ -0,0 +1,44 @@ +import { describe, it, expect } from 'vitest' +import { + substitutionCipherEncryption, + substitutionCipherDecryption +} from '../SubstitutionCipher.js' + +describe('Substitution Cipher', () => { + const key = 'QWERTYUIOPASDFGHJKLZXCVBNM' + + it('correctly encrypts a message', () => { + const encrypted = substitutionCipherEncryption('HELLO WORLD', key) + expect(encrypted).toBe('ITSSG VGKSR') + }) + + it('correctly decrypts a message', () => { + const decrypted = substitutionCipherDecryption('ITSSG VGKSR', key) + expect(decrypted).toBe('HELLO WORLD') + }) + + it('handles non-alphabetic characters', () => { + const encrypted = substitutionCipherEncryption('Test! 123', key) + expect(encrypted).toBe('ZTLZ! 123') + }) + + it('throws error for invalid key', () => { + expect(() => substitutionCipherEncryption('HELLO', 'BADKEY')).toThrow( + RangeError + ) + }) + it('encrypts using default key if none provided', () => { + const encrypted = substitutionCipherEncryption('HELLO WORLD') + expect(encrypted).toBe('ITSSG VGKSR') + }) + + it('decrypts using default key if none provided', () => { + const decrypted = substitutionCipherDecryption('ITSSG VGKSR') + expect(decrypted).toBe('HELLO WORLD') + }) + + it('throws error for invalid key in decryption', () => { + expect(() => substitutionCipherDecryption('HELLO', 'BADKEY')).toThrow(RangeError) + }) + +}) diff --git a/Maths/MobiusFunction.js b/Maths/MobiusFunction.js index bd268b8bbd..4239d6ab31 100644 --- a/Maths/MobiusFunction.js +++ b/Maths/MobiusFunction.js @@ -28,6 +28,6 @@ export const mobiusFunction = (number) => { return primeFactorsArray.length !== new Set(primeFactorsArray).size ? 0 : primeFactorsArray.length % 2 === 0 - ? 1 - : -1 + ? 1 + : -1 }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: