From c93cda32b70e2943411c7da7b03e65e255de68c9 Mon Sep 17 00:00:00 2001 From: mmohamedkhaled <144614579+mmohamedkhaled@users.noreply.github.com> Date: Fri, 4 Apr 2025 02:50:40 +0200 Subject: [PATCH 01/10] feat: add Substitution Cipher algorithm and tests --- Ciphers/SubstitutionCipher.js | 59 +++++++++++++++++++++++++ Ciphers/test/SubstitutionCipher.test.js | 30 +++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 Ciphers/SubstitutionCipher.js create mode 100644 Ciphers/test/SubstitutionCipher.test.js 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..583ea99fb4 --- /dev/null +++ b/Ciphers/test/SubstitutionCipher.test.js @@ -0,0 +1,30 @@ +import { describe, it, expect } from 'vitest' +import { + substitutionCipherEncryption, + substitutionCipherDecryption +} from './SubstitutionCipher' + +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 + ) + }) +}) From 9f44c2f34a2e15af641cf0f3d290765727338ed3 Mon Sep 17 00:00:00 2001 From: mmohamedkhaled <144614579+mmohamedkhaled@users.noreply.github.com> Date: Fri, 4 Apr 2025 02:59:15 +0200 Subject: [PATCH 02/10] fix: correct import path in SubstitutionCipher test --- Ciphers/test/SubstitutionCipher.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ciphers/test/SubstitutionCipher.test.js b/Ciphers/test/SubstitutionCipher.test.js index 583ea99fb4..c608b534c2 100644 --- a/Ciphers/test/SubstitutionCipher.test.js +++ b/Ciphers/test/SubstitutionCipher.test.js @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest' import { substitutionCipherEncryption, substitutionCipherDecryption -} from './SubstitutionCipher' +} from '../ciphers/SubstitutionCipher.js' describe('Substitution Cipher', () => { const key = 'QWERTYUIOPASDFGHJKLZXCVBNM' From 417fb61dd093ca437caae44269296df73ed5165f Mon Sep 17 00:00:00 2001 From: mmohamedkhaled <144614579+mmohamedkhaled@users.noreply.github.com> Date: Fri, 4 Apr 2025 03:02:57 +0200 Subject: [PATCH 03/10] fix: correct casing in import path for CI compatibility --- Ciphers/test/SubstitutionCipher.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ciphers/test/SubstitutionCipher.test.js b/Ciphers/test/SubstitutionCipher.test.js index c608b534c2..cd377cf059 100644 --- a/Ciphers/test/SubstitutionCipher.test.js +++ b/Ciphers/test/SubstitutionCipher.test.js @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest' import { substitutionCipherEncryption, substitutionCipherDecryption -} from '../ciphers/SubstitutionCipher.js' +} from '../Ciphers/SubstitutionCipher.js' describe('Substitution Cipher', () => { const key = 'QWERTYUIOPASDFGHJKLZXCVBNM' From 73c15ce69dc0029a21a343222b11e39c2c2781c5 Mon Sep 17 00:00:00 2001 From: mmohamedkhaled <144614579+mmohamedkhaled@users.noreply.github.com> Date: Fri, 4 Apr 2025 03:08:01 +0200 Subject: [PATCH 04/10] fix: correct import path and folder name for CI --- Ciphers/test/SubstitutionCipher.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ciphers/test/SubstitutionCipher.test.js b/Ciphers/test/SubstitutionCipher.test.js index cd377cf059..c608b534c2 100644 --- a/Ciphers/test/SubstitutionCipher.test.js +++ b/Ciphers/test/SubstitutionCipher.test.js @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest' import { substitutionCipherEncryption, substitutionCipherDecryption -} from '../Ciphers/SubstitutionCipher.js' +} from '../ciphers/SubstitutionCipher.js' describe('Substitution Cipher', () => { const key = 'QWERTYUIOPASDFGHJKLZXCVBNM' From 7adf020c9a05e8262611643b9cb82bfdafc26284 Mon Sep 17 00:00:00 2001 From: mmohamedkhaled <144614579+mmohamedkhaled@users.noreply.github.com> Date: Fri, 4 Apr 2025 03:18:45 +0200 Subject: [PATCH 05/10] fix: update import path in SubstitutionCipher test for correct folder structure --- {Ciphers => ciphers}/SubstitutionCipher.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {Ciphers => ciphers}/SubstitutionCipher.js (100%) diff --git a/Ciphers/SubstitutionCipher.js b/ciphers/SubstitutionCipher.js similarity index 100% rename from Ciphers/SubstitutionCipher.js rename to ciphers/SubstitutionCipher.js From 56542d68a647252e13531028df6a5751006138a4 Mon Sep 17 00:00:00 2001 From: mmohamedkhaled <144614579+mmohamedkhaled@users.noreply.github.com> Date: Fri, 4 Apr 2025 03:25:27 +0200 Subject: [PATCH 06/10] fix: update import path in SubstitutionCipher test for correct folder structure --- Ciphers/test/SubstitutionCipher.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Ciphers/test/SubstitutionCipher.test.js b/Ciphers/test/SubstitutionCipher.test.js index c608b534c2..871ee40671 100644 --- a/Ciphers/test/SubstitutionCipher.test.js +++ b/Ciphers/test/SubstitutionCipher.test.js @@ -2,7 +2,8 @@ import { describe, it, expect } from 'vitest' import { substitutionCipherEncryption, substitutionCipherDecryption -} from '../ciphers/SubstitutionCipher.js' +} from '../SubstitutionCipher.js' + describe('Substitution Cipher', () => { const key = 'QWERTYUIOPASDFGHJKLZXCVBNM' From 5f1ed3ee0985248cb12a9db7ae6c0f5464b99bcd Mon Sep 17 00:00:00 2001 From: mmohamedkhaled <144614579+mmohamedkhaled@users.noreply.github.com> Date: Fri, 4 Apr 2025 03:53:19 +0200 Subject: [PATCH 07/10] removed --- Ciphers/test/SubstitutionCipher.test.js | 31 ------------- ciphers/SubstitutionCipher.js | 59 ------------------------- 2 files changed, 90 deletions(-) delete mode 100644 Ciphers/test/SubstitutionCipher.test.js delete mode 100644 ciphers/SubstitutionCipher.js diff --git a/Ciphers/test/SubstitutionCipher.test.js b/Ciphers/test/SubstitutionCipher.test.js deleted file mode 100644 index 871ee40671..0000000000 --- a/Ciphers/test/SubstitutionCipher.test.js +++ /dev/null @@ -1,31 +0,0 @@ -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 - ) - }) -}) diff --git a/ciphers/SubstitutionCipher.js b/ciphers/SubstitutionCipher.js deleted file mode 100644 index 2383a99796..0000000000 --- a/ciphers/SubstitutionCipher.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * 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 -} From c4035dee32e740c0f242c282552c0d636aeb2d3a Mon Sep 17 00:00:00 2001 From: mmohamedkhaled <144614579+mmohamedkhaled@users.noreply.github.com> Date: Fri, 4 Apr 2025 03:57:48 +0200 Subject: [PATCH 08/10] added Substitution Cipher and its test --- Ciphers/SubstitutionCipher.js | 59 +++++++++++++++++++++++++ Ciphers/test/SubstitutionCipher.test.js | 31 +++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 Ciphers/SubstitutionCipher.js create mode 100644 Ciphers/test/SubstitutionCipher.test.js 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..871ee40671 --- /dev/null +++ b/Ciphers/test/SubstitutionCipher.test.js @@ -0,0 +1,31 @@ +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 + ) + }) +}) From b9432a02e087b59fd1e740c18fbcf785fab85e74 Mon Sep 17 00:00:00 2001 From: mmohamedkhaled <144614579+mmohamedkhaled@users.noreply.github.com> Date: Fri, 4 Apr 2025 04:00:58 +0200 Subject: [PATCH 09/10] edited the style --- Ciphers/test/SubstitutionCipher.test.js | 1 - Maths/MobiusFunction.js | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Ciphers/test/SubstitutionCipher.test.js b/Ciphers/test/SubstitutionCipher.test.js index 871ee40671..599dfea8fc 100644 --- a/Ciphers/test/SubstitutionCipher.test.js +++ b/Ciphers/test/SubstitutionCipher.test.js @@ -4,7 +4,6 @@ import { substitutionCipherDecryption } from '../SubstitutionCipher.js' - describe('Substitution Cipher', () => { const key = 'QWERTYUIOPASDFGHJKLZXCVBNM' 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 } From 25add224447e68fe534b44298ebb5284ceb28d0f Mon Sep 17 00:00:00 2001 From: mmohamedkhaled <144614579+mmohamedkhaled@users.noreply.github.com> Date: Fri, 4 Apr 2025 04:16:05 +0200 Subject: [PATCH 10/10] "test: add missing coverage for Substitution Cipher decryption edge cases" --- Ciphers/test/SubstitutionCipher.test.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Ciphers/test/SubstitutionCipher.test.js b/Ciphers/test/SubstitutionCipher.test.js index 599dfea8fc..820d0303d6 100644 --- a/Ciphers/test/SubstitutionCipher.test.js +++ b/Ciphers/test/SubstitutionCipher.test.js @@ -27,4 +27,18 @@ describe('Substitution Cipher', () => { 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) + }) + }) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

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:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy