diff --git a/README.md b/README.md index 449ea54..63bb693 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ document.getElementById("t").innerHTML = this["cipher-collection"].wolfenbuettel - AER-256 - ARMON-64 - Polybius +- Bifid ## 📖 Documentation diff --git a/docs/ciphers/bifid.md b/docs/ciphers/bifid.md new file mode 100644 index 0000000..d8a0e61 --- /dev/null +++ b/docs/ciphers/bifid.md @@ -0,0 +1,64 @@ +# Code code + +> The Code code is a code + +## Cipher behavior information + +* Case sensitive? ✓❌ +* Deterministic? ✓❌ +* Alphabet: **Which alphabet does the cipher use** +* Characters not in alphabet will be: (**omitted**, **preserved**, **throw an error**, **N/A**) + +## Default options object + +``` +const options = { + optionHere: true // What does this option change +} +``` + +## Usage + +### Encoding + +#### Default + +``` +import { code } from 'cipher-collection' + + +console.log(code.encode('text')) // Result +``` + +#### Special case one + +``` +import { code } from 'cipher-collection' + +const specialOptions = { special: true } + +console.log(code.encode('text', specialOptions)) // Special result +``` + + +### Decoding + +#### Default + +``` +import { code } from 'cipher-collection' + + +console.log(code.decode('ciphertext')) // Cleartext +``` + +#### Special case one + +``` +import { code } from 'cipher-collection' + +const specialOptions = { special: true } + +console.log(code.encode('ciphertext', specialOptions)) // Cleartext +``` + diff --git a/docs/index.md b/docs/index.md index bf06e71..7cfef25 100644 --- a/docs/index.md +++ b/docs/index.md @@ -21,3 +21,4 @@ * [AER-256](./ciphers/aer256.md) * [ARMON-64](./ciphers/armon64.md) * [Polybius](./ciphers/polybius.md) +* [Bifid](./ciphers/bifid.md) diff --git a/src/bifid.js b/src/bifid.js new file mode 100644 index 0000000..d9b8202 --- /dev/null +++ b/src/bifid.js @@ -0,0 +1,41 @@ +import polybius from './polybius' + +const encode = (input, options = {}) => { + options = { ...DEFAULT_OPTIONS, ...options } + const polybiusNumbers = polybius.encode(input, options).replace(/ /g, '') + + const polybiusNumbersByEvenOdd = Object.values([...polybiusNumbers].reduce((evenOddObj, char, index) => { + evenOddObj[isEvenOrOdd(index)] += char + return evenOddObj + }, { even: '', odd: '' })).join('') + + const separatedPolybiusNumber = polybiusNumbersByEvenOdd.match(/\d{2}/g).join(' ') + + return polybius.decode(separatedPolybiusNumber, options) +} + +const decode = (input, options = {}) => { + options = { ...DEFAULT_OPTIONS, ...options } + const polybiusNumbers = polybius.encode(input, options).replace(/ /g, '') + const numberMiddle = polybiusNumbers.length / 2 + const splitNumbers = [polybiusNumbers.substr(0, numberMiddle), polybiusNumbers.substr(numberMiddle)] + + const zippedString = Array.from(new Array(numberMiddle)).map((_, i) => splitNumbers[0][i] + splitNumbers[1][i]).join('') + + const separatedPolybiusNumber = zippedString.match(/\d{2}/g).join(' ') + + return polybius.decode(separatedPolybiusNumber, options) +} + +const isEvenOrOdd = i => i % 2 === 0 ? 'even' : 'odd' + +const DEFAULT_OPTIONS = { + key: '', + equalLetters: 'IJ', + withNumbers: false +} + +export default { + encode, + decode +} diff --git a/src/index.js b/src/index.js index f1b1c0c..7bd94eb 100644 --- a/src/index.js +++ b/src/index.js @@ -11,6 +11,7 @@ import affine from './affine' import aer256 from './aer256' import armon64 from './armon64' import polybius from './polybius' +import bifid from './bifid' export default { rot, @@ -25,5 +26,6 @@ export default { affine, aer256, armon64, - polybius + polybius, + bifid } diff --git a/test/bifid.test.js b/test/bifid.test.js new file mode 100644 index 0000000..3181030 --- /dev/null +++ b/test/bifid.test.js @@ -0,0 +1,65 @@ +import bifid from 'bifid' + +describe('encoding', () => { + test('default', () => { + expect(bifid.encode('ABCDEFGHIJKLMNOPQRSTUVWXYZ')).toBe('AABGGHNNTTUZZBOVHTVHUBOVHU') + expect(bifid.encode('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.toLowerCase())).toBe('AABGGHNNTTUZZBOVHTVHUBOVHU') + }) + test('default with illegal character', () => { + expect(() => { bifid.encode('*') }).toThrowError('Unknown character *') + }) + + test('with custom key', () => { + expect(bifid.encode('ABCDEFGHIJKLMNOPQRSTUVWXYZ', { key: 'OHA' })) + .toBe('OHEDEMMATTUZZNVFRZHNCHNVFU') + expect(bifid.encode('ABCDEFGHIJKLMNOPQRSTUVWXYZ', { key: 'oHa' })) + .toBe('OHEDEMMATTUZZNVFRZHNCHNVFU') + }) + + test('with numbers', () => { + expect(bifid.encode('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', { withNumbers: true })) + .toBe('AAAHHHOOOVVV222999BP3BP3BP3BP3BP3BP3') + }) + + test('with numbers and custom key', () => { + expect(bifid.encode('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', { withNumbers: true, key: 'oHa' })) + .toBe('OOFEFGNANVVV222999P3HMW4GB3HP3HP3HP3') + }) + + test('with custom substitution', () => { + expect(bifid.encode('ABCDEFGHIJKLMNOPQRSTUVWXYZ', { equalLetters: 'UV' })) + .toBe('AABGGMMNSSZZZBNUHTBNUHTAHT') + }) +}) + +describe('decoding', () => { + test('default', () => { + expect(bifid.decode('AABGGHNNTTUZZBOVHTVHUBOVHU')).toBe('ABCDEFGHIIKLMNOPQRSTUVWXYZ') + }) + test('default with illegal character', () => { + expect(() => { bifid.decode('*') }).toThrowError('Unknown character *') + expect(() => { bifid.decode('88') }).toThrowError('Unknown character 8') + }) + + test('with custom key', () => { + expect(bifid.decode('OHEDEMMATTUZZNVFRZHNCHNVFU', { key: 'OHA' })).toBe('ABCDEFGHIIKLMNOPQRSTUVWXYZ') + expect(bifid.decode('OHEDEMMATTUZZNVFRZHNCHNVFU', { key: 'oHa' })).toBe('ABCDEFGHIIKLMNOPQRSTUVWXYZ') + }) + + test('with numbers', () => { + expect(bifid.decode('AAAHHHOOOVVV222999BP3BP3BP3BP3BP3BP3', { withNumbers: true })) + .toBe('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') + }) + + test('with numbers and custom key', () => { + expect(bifid.decode('OOFEFGNANVVV222999P3HMW4GB3HP3HP3HP3', { withNumbers: true, key: 'oHa' })) + .toBe('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') + }) + + test('with custom substitution', () => { + expect(bifid.decode('AABGGMMNSSZZZBNUHTBNUHTAHT', { equalLetters: 'UV' })) + .toBe('ABCDEFGHIJKLMNOPQRSTUUWXYZ') + expect(bifid.decode('AABGGMMNSSZZZBNUHTBNUHTAHT', { equalLetters: 'VU' })) + .toBe('ABCDEFGHIJKLMNOPQRSTVVWXYZ') + }) +})