Algorithms_in_C++ 1.0.0
Set of algorithms implemented in C++.
Loading...
Searching...
No Matches
ciphers::HillCipher Class Reference

Implementation of Hill Cipher algorithm. More...

Static Public Member Functions

static matrix< int > generate_encryption_key (size_t size, int limit1=0, int limit2=10)
 Generate encryption matrix of a given size. Larger size matrices are difficult to generate but provide more security. Important conditions are:
 
static matrix< int > generate_decryption_key (matrix< int > const &encrypt_key)
 Generate decryption matrix from an encryption matrix key.
 
static std::pair< matrix< int >, matrix< int > > generate_keys (size_t size, int limit1=0, int limit2=10)
 Generate encryption and decryption key pair.
 
static const std::string encrypt_text (const std::string &text, const matrix< int > &encrypt_key)
 Encrypt a given text using a given key.
 
static const std::string decrypt_text (const std::string &text, const matrix< int > &decrypt_key)
 Decrypt a given text using a given key.
 

Static Private Member Functions

template<typename T1 , typename T2 >
static const T2 rand_range (T1 a, T1 b)
 Function to generate a random integer in a given interval.
 
template<typename T1 , typename T2 >
static double rand_range (matrix< T2 > *M, T1 a, T1 b)
 Function overload to fill a matrix with random integers in a given interval.
 
template<typename T >
static const T gcd (T a, T b)
 Compute GCD of two integers using Euler's algorithm.
 
static const std::valarray< uint8_t > mat_mul (const std::valarray< uint8_t > &vector, const matrix< int > &key)
 helper function to perform vector multiplication with encryption or decryption matrix
 
static char get_idx_char (const uint8_t idx)
 Get the character at a given index in the STRKEY.
 
static uint8_t get_char_idx (const char ch)
 Get the index of a character in the STRKEY.
 
static const std::string codec (const std::string &text, const matrix< int > &key)
 Convenience function to perform block cipher operations. The operations are identical for both encryption and decryption.
 
template<typename T >
static matrix< double > get_inverse (matrix< T > const &A)
 
static int modulo (int a, int b)
 

Detailed Description

Implementation of Hill Cipher algorithm.

Member Function Documentation

◆ codec()

static const std::string ciphers::HillCipher::codec ( const std::string & text,
const matrix< int > & key )
inlinestaticprivate

Convenience function to perform block cipher operations. The operations are identical for both encryption and decryption.

Parameters
textinput text to encrypt or decrypt
keykey for encryption or decryption
Returns
encrypted/decrypted output
212 {
213 size_t text_len = text.length();
214 size_t key_len = key.size();
215
216 // length of output string must be a multiple of key_len
217 // create output string and initialize with '\0' character
218 size_t L2 = text_len % key_len == 0
219 ? text_len
220 : text_len + key_len - (text_len % key_len);
221 std::string coded_text(L2, '\0');
222
223 // temporary array for batch processing
224 int i;
225#ifdef _OPENMP
226#pragma parallel omp for private(i)
227#endif
228 for (i = 0; i < L2 - key_len + 1; i += key_len) {
229 std::valarray<uint8_t> batch_int(key_len);
230 for (size_t j = 0; j < key_len; j++) {
231 batch_int[j] = get_char_idx(text[i + j]);
232 }
233
234 batch_int = mat_mul(batch_int, key);
235
236 for (size_t j = 0; j < key_len; j++) {
237 coded_text[i + j] =
238 STRKEY[batch_int[j]]; // get character at key
239 }
240 }
241
242 return coded_text;
243 }
static const std::valarray< uint8_t > mat_mul(const std::valarray< uint8_t > &vector, const matrix< int > &key)
helper function to perform vector multiplication with encryption or decryption matrix
Definition hill_cipher.cpp:160
static uint8_t get_char_idx(const char ch)
Get the index of a character in the STRKEY.
Definition hill_cipher.cpp:191
static const char * STRKEY
Definition hill_cipher.cpp:74
T length(T... args)
Here is the call graph for this function:

◆ decrypt_text()

static const std::string ciphers::HillCipher::decrypt_text ( const std::string & text,
const matrix< int > & decrypt_key )
inlinestatic

Decrypt a given text using a given key.

Parameters
textstring to decrypt
decrypt_keykey for decryption
Returns
decrypted text
459 {
460 return codec(text, decrypt_key);
461 }
static const std::string codec(const std::string &text, const matrix< int > &key)
Convenience function to perform block cipher operations. The operations are identical for both encryp...
Definition hill_cipher.cpp:211
Here is the call graph for this function:

◆ encrypt_text()

static const std::string ciphers::HillCipher::encrypt_text ( const std::string & text,
const matrix< int > & encrypt_key )
inlinestatic

Encrypt a given text using a given key.

Parameters
textstring to encrypt
encrypt_keykey for encryption
Returns
encrypted text
447 {
448 return codec(text, encrypt_key);
449 }
Here is the call graph for this function:

◆ gcd()

template<typename T >
static const T ciphers::HillCipher::gcd ( T a,
T b )
inlinestaticprivate

Compute GCD of two integers using Euler's algorithm.

Parameters
afirst number
bsecond number
Returns
GCD of \(a\) and \(b\)
139 {
140 if (b > a) // ensure always a < b
141 std::swap(a, b);
142
143 while (b != 0) {
144 T tmp = b;
145 b = a % b;
146 a = tmp;
147 }
148
149 return a;
150 }
T swap(T... args)
Here is the call graph for this function:

◆ generate_decryption_key()

static matrix< int > ciphers::HillCipher::generate_decryption_key ( matrix< int > const & encrypt_key)
inlinestatic

Generate decryption matrix from an encryption matrix key.

Parameters
encrypt_keyencryption key for which to create a decrypt key
Returns
Decryption martix
372 {
373 size_t size = encrypt_key.size();
374 int L = std::strlen(STRKEY);
375
376 matrix<int> decrypt_key(size, std::valarray<int>(size));
377 int det_encrypt = static_cast<int>(determinant_lu(encrypt_key));
378
379 int mat_determinant = det_encrypt < 0 ? det_encrypt % L : det_encrypt;
380
381 matrix<double> tmp_inverse = get_inverse(encrypt_key);
382 double d2 = determinant_lu(decrypt_key);
383
384 // find co-prime factor for inversion
385 int det_inv = -1;
386 for (int i = 0; i < L; i++) {
387 if (modulo(mat_determinant * i, L) == 1) {
388 det_inv = i;
389 break;
390 }
391 }
392
393 if (det_inv == -1) {
394 std::cerr << "Could not find a co-prime for inversion\n";
395 std::exit(EXIT_FAILURE);
396 }
397
398 mat_determinant = det_inv * det_encrypt;
399
400 // perform modular inverse of encryption matrix
401 int i;
402#ifdef _OPENMP
403#pragma parallel omp for private(i)
404#endif
405 for (i = 0; i < size; i++) {
406 for (int j = 0; j < size; j++) {
407 int temp = std::round(tmp_inverse[i][j] * mat_determinant);
408 decrypt_key[i][j] = modulo(temp, L);
409 }
410 }
411 return decrypt_key;
412 }
static matrix< double > get_inverse(matrix< T > const &A)
Definition hill_cipher.cpp:251
T exit(T... args)
double determinant_lu(const matrix< T > &A)
Definition lu_decomposition.h:90
T round(T... args)
T strlen(T... args)
Here is the call graph for this function:

◆ generate_encryption_key()

static matrix< int > ciphers::HillCipher::generate_encryption_key ( size_t size,
int limit1 = 0,
int limit2 = 10 )
inlinestatic

Generate encryption matrix of a given size. Larger size matrices are difficult to generate but provide more security. Important conditions are:

  1. matrix should be invertible
  2. determinant must not have any common factors with the length of character key There is no head-fast way to generate hte matrix under the given numerical restrictions of the machine but the conditions added achieve the goals. Bigger the matrix, greater is the probability of the matrix being ill-defined.
Parameters
sizesize of matrix (typically \(\text{size}\le10\))
limit1lower limit of range of random elements (default=0)
limit2upper limit of range of random elements (default=10)
Returns
Encryption martix
341 {
342 matrix<int> encrypt_key(size, std::valarray<int>(size));
343 matrix<int> min_mat = encrypt_key;
344 int mat_determinant = -1; // because matrix has only ints, the
345 // determinant will also be an int
346 int L = std::strlen(STRKEY);
347
348 double dd;
349 do {
350 // keeping the random number range smaller generates better
351 // defined matrices with more ease of cracking
352 dd = rand_range(&encrypt_key, limit1, limit2);
353 mat_determinant = static_cast<int>(dd);
354
355 if (mat_determinant < 0)
356 mat_determinant = (mat_determinant % L);
357 } while (std::abs(dd) > 1e3 || // while ill-defined
358 dd < 0.1 || // while singular or negative determinant
359 !std::isfinite(dd) || // while determinant is not finite
360 gcd(mat_determinant, L) != 1); // while no common factors
361 // std::cout <<
362
363 return encrypt_key;
364 }
static const T2 rand_range(T1 a, T1 b)
Function to generate a random integer in a given interval.
Definition hill_cipher.cpp:93
static const T gcd(T a, T b)
Compute GCD of two integers using Euler's algorithm.
Definition hill_cipher.cpp:139
T isfinite(T... args)
Here is the call graph for this function:

◆ generate_keys()

static std::pair< matrix< int >, matrix< int > > ciphers::HillCipher::generate_keys ( size_t size,
int limit1 = 0,
int limit2 = 10 )
inlinestatic

Generate encryption and decryption key pair.

Parameters
sizesize of matrix key (typically \(\text{size}\le10\))
limit1lower limit of range of random elements (default=0)
limit2upper limit of range of random elements (default=10)
Returns
std::pair<matrix<int>, matrix<int>> encryption and decryption keys as a pair
See also
generate_encryption_key
427 {
428 matrix<int> encrypt_key = generate_encryption_key(size);
429 matrix<int> decrypt_key = generate_decryption_key(encrypt_key);
430 double det2 = determinant_lu(decrypt_key);
431 while (std::abs(det2) < 0.1 || std::abs(det2) > 1e3) {
432 encrypt_key = generate_encryption_key(size, limit1, limit2);
433 decrypt_key = generate_decryption_key(encrypt_key);
434 det2 = determinant_lu(decrypt_key);
435 }
436 return std::make_pair(encrypt_key, decrypt_key);
437 }
static matrix< int > generate_encryption_key(size_t size, int limit1=0, int limit2=10)
Generate encryption matrix of a given size. Larger size matrices are difficult to generate but provid...
Definition hill_cipher.cpp:340
static matrix< int > generate_decryption_key(matrix< int > const &encrypt_key)
Generate decryption matrix from an encryption matrix key.
Definition hill_cipher.cpp:372
T make_pair(T... args)
Here is the call graph for this function:

◆ get_char_idx()

static uint8_t ciphers::HillCipher::get_char_idx ( const char ch)
inlinestaticprivate

Get the index of a character in the STRKEY.

Parameters
chcharacter to search
Returns
index of character
191 {
192 size_t L = std::strlen(STRKEY);
193
194 for (size_t idx = 0; idx <= L; idx++)
195 if (STRKEY[idx] == ch)
196 return idx;
197
198 std::cerr << __func__ << ":" << __LINE__ << ": (" << ch
199 << ") Should not reach here!\n";
200 return 0;
201 }
Here is the call graph for this function:

◆ get_idx_char()

static char ciphers::HillCipher::get_idx_char ( const uint8_t idx)
inlinestaticprivate

Get the character at a given index in the STRKEY.

Parameters
idxindex value
Returns
character at the index
183{ return STRKEY[idx]; }

◆ get_inverse()

template<typename T >
static matrix< double > ciphers::HillCipher::get_inverse ( matrix< T > const & A)
inlinestaticprivate

Get matrix inverse using Row-transformations. Given matrix must be a square and non-singular.

Returns
inverse matrix
251 {
252 // Assuming A is square matrix
253 size_t N = A.size();
254
256 for (size_t row = 0; row < N; row++) {
257 for (size_t col = 0; col < N; col++) {
258 // create identity matrix
259 inverse[row][col] = (row == col) ? 1.f : 0.f;
260 }
261 }
262
263 if (A.size() != A[0].size()) {
264 std::cerr << "A must be a square matrix!" << std::endl;
265 return inverse;
266 }
267
268 // preallocate a temporary matrix identical to A
270 for (size_t row = 0; row < N; row++) {
271 for (size_t col = 0; col < N; col++)
272 temp[row][col] = static_cast<double>(A[row][col]);
273 }
274
275 // start transformations
276 for (size_t row = 0; row < N; row++) {
277 for (size_t row2 = row; row2 < N && temp[row][row] == 0; row2++) {
278 // this to ensure diagonal elements are not 0
279 temp[row] = temp[row] + temp[row2];
280 inverse[row] = inverse[row] + inverse[row2];
281 }
282
283 for (size_t col2 = row; col2 < N && temp[row][row] == 0; col2++) {
284 // this to further ensure diagonal elements are not 0
285 for (size_t row2 = 0; row2 < N; row2++) {
286 temp[row2][row] = temp[row2][row] + temp[row2][col2];
287 inverse[row2][row] =
288 inverse[row2][row] + inverse[row2][col2];
289 }
290 }
291
292 if (temp[row][row] == 0) {
293 // Probably a low-rank matrix and hence singular
294 std::cerr << "Low-rank matrix, no inverse!" << std::endl;
295 return inverse;
296 }
297
298 // set diagonal to 1
299 double divisor = temp[row][row];
300 temp[row] = temp[row] / divisor;
301 inverse[row] = inverse[row] / divisor;
302 // Row transformations
303 for (size_t row2 = 0; row2 < N; row2++) {
304 if (row2 == row)
305 continue;
306 double factor = temp[row2][row];
307 temp[row2] = temp[row2] - factor * temp[row];
308 inverse[row2] = inverse[row2] - factor * inverse[row];
309 }
310 }
311
312 return inverse;
313 }
T endl(T... args)
constexpr uint32_t N
A struct to represent sparse table for min() as their invariant function, for the given array A....
Definition sparse_table.cpp:48
Here is the call graph for this function:

◆ mat_mul()

static const std::valarray< uint8_t > ciphers::HillCipher::mat_mul ( const std::valarray< uint8_t > & vector,
const matrix< int > & key )
inlinestaticprivate

helper function to perform vector multiplication with encryption or decryption matrix

Parameters
vectorvector to multiply
keyencryption or decryption key matrix
Returns
corresponding encrypted or decrypted text
161 {
162 std::valarray<uint8_t> out(vector); // make a copy
163
164 size_t L = std::strlen(STRKEY);
165
166 for (size_t i = 0; i < key.size(); i++) {
167 int tmp = 0;
168 for (size_t j = 0; j < vector.size(); j++) {
169 tmp += key[i][j] * vector[j];
170 }
171 out[i] = static_cast<uint8_t>(tmp % L);
172 }
173
174 return out;
175 }
Here is the call graph for this function:

◆ modulo()

static int ciphers::HillCipher::modulo ( int a,
int b )
inlinestaticprivate
315 {
316 int ret = a % b;
317 if (ret < 0)
318 ret += b;
319 return ret;
320 }

◆ rand_range() [1/2]

template<typename T1 , typename T2 >
static double ciphers::HillCipher::rand_range ( matrix< T2 > * M,
T1 a,
T1 b )
inlinestaticprivate

Function overload to fill a matrix with random integers in a given interval.

Parameters
Mpointer to matrix to be filled with random numbers
alower limit of interval
bupper limit of interval
Template Parameters
T1type of input range
T2type of matrix
Returns
determinant of generated random matrix
Warning
There will need to be a balance between the matrix size and the range of random numbers. If the matrix is large, the range of random numbers must be small to have a well defined keys. Or if the matrix is smaller, the random numbers range can be larger. For an 8x8 matrix, range should be no more than \([0,10]\)
119 {
120 for (size_t i = 0; i < M->size(); i++) {
121 for (size_t j = 0; j < M[0][0].size(); j++) {
122 M[0][i][j] = rand_range<T1, T2>(a, b);
123 }
124 }
125
126 return determinant_lu(*M);
127 }
constexpr uint8_t M
ceil(log2(N)).
Definition sparse_table.cpp:49
Here is the call graph for this function:

◆ rand_range() [2/2]

template<typename T1 , typename T2 >
static const T2 ciphers::HillCipher::rand_range ( T1 a,
T1 b )
inlinestaticprivate

Function to generate a random integer in a given interval.

Parameters
alower limit of interval
bupper limit of interval
Template Parameters
Ttype of output
Returns
random integer in the interval \([a,b)\)
93 {
94 // generate random number between 0 and 1
95 long double r = static_cast<long double>(std::rand()) / RAND_MAX;
96
97 // scale and return random number as integer
98 return static_cast<T2>(r * (b - a) + a);
99 }
T rand(T... args)
Here is the call graph for this function:

The documentation for this class was generated from the following file: