1+ // The code of an 'A' character (equals to 65).
2+ const alphabetCodeShift = 'A' . codePointAt ( 0 ) ;
3+ const englishAlphabetSize = 26 ;
14
25/**
3- * generate key matrix from given keyString
6+ * Generates key matrix from given keyString.
47 *
5- * @param {integer } length
6- * @param {string } keyString
7- * @return {Array[][] } keyMatrix
8+ * @param {string } keyString - a string to build a key matrix (must be of matrixSize^2 length).
9+ * @return {number[][] } keyMatrix
810 */
9- const generateKeyMatrix = ( length , keyString ) => {
11+ const generateKeyMatrix = ( keyString ) => {
12+ const matrixSize = Math . sqrt ( keyString . length ) ;
13+ if ( ! Number . isInteger ( matrixSize ) ) {
14+ throw new Error (
15+ 'Invalid key string length. The square root of the key string must be an integer' ,
16+ ) ;
17+ }
1018 const keyMatrix = [ ] ;
1119 let keyStringIndex = 0 ;
12- for ( let i = 0 ; i < length ; i += 1 ) {
20+ for ( let i = 0 ; i < matrixSize ; i += 1 ) {
1321 const keyMatrixRow = [ ] ;
14- for ( let j = 0 ; j < length ; j += 1 ) {
15- keyMatrixRow . push ( ( keyString . codePointAt ( keyStringIndex ) ) % 65 ) ;
22+ for ( let j = 0 ; j < matrixSize ; j += 1 ) {
23+ // A → 0, B → 1, ..., a → 32, b → 33, ...
24+ const charCodeShifted = ( keyString . codePointAt ( keyStringIndex ) ) % alphabetCodeShift ;
25+ keyMatrixRow . push ( charCodeShifted ) ;
1626 keyStringIndex += 1 ;
1727 }
1828 keyMatrix . push ( keyMatrixRow ) ;
@@ -21,48 +31,54 @@ const generateKeyMatrix = (length, keyString) => {
2131} ;
2232
2333/**
24- * generate message vector from given message
34+ * Generates a message vector from a given message.
2535 *
26- * @param {* } message
27- * @return {Array } messageVector
36+ * @param {string } message - the message to encrypt.
37+ * @return {number[] } messageVector
2838 */
2939const generateMessageVector = ( message ) => {
3040 const messageVector = [ ] ;
3141 for ( let i = 0 ; i < message . length ; i += 1 ) {
32- messageVector . push ( message . codePointAt ( i ) % 65 ) ;
42+ messageVector . push ( message . codePointAt ( i ) % alphabetCodeShift ) ;
3343 }
3444 return messageVector ;
3545} ;
3646
3747/**
38- * validate data and encrypt message from given message and keyString
48+ * Encrypts the given message using Hill Cipher.
3949 *
4050 * @param {string } message plaintext
4151 * @param {string } keyString
4252 * @return {string } cipherString
43- *
4453 */
54+ export function hillCipherEncrypt ( message , keyString ) {
55+ // The keyString and message can only contain letters.
56+ const onlyLettersRegExp = / ^ [ a - z A - Z ] + $ / ;
57+ if ( ! onlyLettersRegExp . test ( message ) || ! onlyLettersRegExp . test ( keyString ) ) {
58+ throw new Error ( 'The message and key string can only contain letters' ) ;
59+ }
60+
61+ const keyMatrix = generateKeyMatrix ( keyString ) ;
4562
46- export default function hillCipherEncrypt ( message , keyString ) {
47- const length = keyString . length ** ( 0.5 ) ;
4863 // keyString.length must equal to square of message.length
49- if ( ! Number . isInteger ( length ) && length !== message . length ) {
50- throw new Error ( 'invalid key string length' ) ;
51- }
52- // keyString and messange can only contain letters
53- if ( ! ( / ^ [ a - z A - Z ] + $ / . test ( message ) ) || ! ( / ^ [ A - Z a - z ] + $ / . test ( keyString ) ) ) {
54- throw new Error ( 'messange and key string can only contain letters' ) ;
64+ if ( keyMatrix . length !== message . length ) {
65+ throw new Error ( 'Invalid key string length. The key length must be a square of message length' ) ;
5566 }
5667
57- const keyMatrix = generateKeyMatrix ( length , keyString ) ;
5868 const messageVector = generateMessageVector ( message ) ;
59- let ciperString = '' ;
60- for ( let row = 0 ; row < length ; row += 1 ) {
69+ let cipherString = '' ;
70+ for ( let row = 0 ; row < keyMatrix . length ; row += 1 ) {
6171 let item = 0 ;
62- for ( let column = 0 ; column < length ; column += 1 ) {
72+ for ( let column = 0 ; column < keyMatrix . length ; column += 1 ) {
6373 item += keyMatrix [ row ] [ column ] * messageVector [ column ] ;
6474 }
65- ciperString += String . fromCharCode ( ( item % 26 ) + 65 ) ;
75+ cipherString += String . fromCharCode ( ( item % englishAlphabetSize ) + alphabetCodeShift ) ;
6676 }
67- return ciperString ;
77+
78+ return cipherString ;
6879}
80+
81+ // @TODO : Implement this method.
82+ export const hillCipherDecrypt = ( ) => {
83+ throw new Error ( 'This method is not implemented yet' ) ;
84+ } ;
0 commit comments