简体   繁体   中英

Inverting matrices mod-26 with Eigen C++ library

I'm trying to write a program to crack a Hill cipher of arbitrary dimensions (MxM) in C++. Part of the process requires me to calculate the mod-26 inverse of a matrix.

For example, the modular inverse of 2x2 array

14 3 11 0

is

0 19 9 24

I have a function that can accomplish this for 2x2 arrays only, which is not sufficient. I know that calculating inverses on larger-dimension arrays is difficult, so I'm using the Eigen C++ library. However, the Eigen inverse() function gives me this as the inverse of the above matrix:

0.000 0.091 0.333 -0.424

How can I calculate the modular 26 inverse that I need for a matrix of any dimensions with Eigen?

Try this:

#include <iostream>
#include <functional>
#include <Eigen/Dense>

using namespace Eigen;                                                                                       
using namespace std;                                                                                         

int inverse_mod_26(int d)                                                                                    
{                                                                                                            
   // We're not going to use Euclidean Alg. or                                                               
   // even Fermat's Little Theorem, but brute force                                                          
   int base = 26, inv = 1;                                                                                   

   while ( (inv < base) &&                                                                                   
       (((d * ++inv) % 26) != 1)) {}                                                                         

   return inv;                                                                                               
}                                                                                                            

int main(int argc, char **argv)                                                                              
{                                                                                                            

   Matrix2d m, minv;                                                                                         
   int inv_factor;                                                                                           
   m << 14, 3, 15, 0;                                                                                        
   double mdet = m.determinant();                                                                            

   minv = mdet * m.inverse();                                                                                
   transform(&minv.data()[0], &minv.data()[4], &minv.data()[0],                                              
         [](double d){ return static_cast<int>(d) % 26;});                                                   
   if ((static_cast<int>(mdet) % 26) == 1) { // no further modification}                                     
   else                                       
     {                                                                                                       
        inv_factor = inverse_mod_26(std::abs((m * minv)(0,0)));                                              
        if (inv_factor == 26)                                                                                
          {                                                                                                  
             cerr << "No inverse exists!" << endl;                                                           
             return EXIT_FAILURE;                                                                            
          }                                                                                                  

        transform(&minv.data()[0], &minv.data()[4], &minv.data()[0],                                         
              [=](double d){ return static_cast<int>(d) * inv_factor;});                                     
     }                                                                                                       

   cout << "m = " << endl << m << endl;                                                                      
   cout << "minv = " << endl << minv << endl;                                                                
   cout << "(m * minv) = " << endl << m * minv << endl;                                                      

   return 0;                                                                                                 
}                            

This is a 2x2 case, for base 26, but can easily be modified. The algorithm relies on modifying the normal matrix inverse, and can easily be explained, if you wish. If your original matrix has determinant (in the normal sense) that is not relatively prime to 26; ie, if GCD(det(m), 26) != 1 , then it will not have an inverse.

Tip: to avoid this problem, and the else clause above, pad your dictionary with three arbitrary characters, bringing the size to 29, which is prime, and will trivially satisfy the GCD property above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM