This is how I was able to compute this result.
I want to show the C++ code I was able to write with these two answers. With the code we can invert any N sized matrix in the $GF(2^8)$ field. The full code can be found here.
These are the galois operations as shown by Thomas Pornin:
#include <iostream>
#include <array>
namespace galois {
constexpr int add(int x, int y) {
return x ^ y;
}
constexpr int mul(int x, int y) {
int z = 0;
for (int i = 0; i < 8; ++i) {
z ^= x & -(y & 1);
y >>= 1;
x <<= 1;
x ^= (0x11B & -(x >> 8));
}
return z;
}
constexpr int inverse(int x) {
int z = x;
for (int i = 0; i < 6; ++i) {
z = galois::mul(z, z);
z = galois::mul(z, x);
}
return galois::mul(z, z);
}
constexpr int divide(int x, int y) {
return mul(x, inverse(y));
}
}
And this is the matrix_inverse as described by Jyrki Lahtonen, but with using the galois operations:
template<std::size_t N>
using matrix = std::array<std::array<int, N>, N>;
template<std::size_t N>
matrix<N> matrix_inverse(matrix<N> M) {
matrix<N> R{}; //fills R with 0s
for (unsigned i = 0; i < N; ++i) {
R[i][i] = 1; //makes the matrix the identity matrix
}
for (unsigned i = 0; i < N; ++i) {
//sets M[i][i] to 1, divide by row by inverse
auto diagonal = M[i][i];
auto inv = galois::inverse(diagonal);
for (unsigned row = 0; row < N; ++row) {
M[i][row] = galois::mul(inv, M[i][row]);
R[i][row] = galois::mul(inv, R[i][row]);
}
//pivots the column
for (unsigned col = 0; col < N; ++col) {
if (col == i) continue;
auto n = M[col][i];
for (unsigned row = 0; row < N; ++row) {
M[col][row] = galois::add(galois::mul(n, M[i][row]), M[col][row]);
R[col][row] = galois::add(galois::mul(n, R[i][row]), R[col][row]);
}
}
}
return R;
}
And this is how we can call matrix_inverse to test the result:
template<std::size_t N>
void print_matrix(matrix<N> m) {
for (auto& i : m) {
for (auto& i : i) {
std::cout << i << ' ';
}
std::cout << '\n';
}
}
int main() {
matrix<3> m =
{ {
{1, 2, 2},
{2, 2, 1},
{2, 1, 2},
} };
std::cout << "Input -\n";
print_matrix(m);
matrix<3> inverse = matrix_inverse(m);
std::cout << "\nInverse -\n";
print_matrix(inverse);
}
As can be seen in the output, we calculated the correct inverse of your matrix:
Input -
1 2 2
2 2 1
2 1 2
Inverse -
1 247 247
247 247 1
247 1 247
As a second test, we can replicate the correct AES decryption MixColumns matrix:
matrix<4> m =
{ {
{2, 3, 1, 1},
{1, 2, 3, 1},
{1, 1, 2, 3},
{3, 1, 1, 2},
} };
matrix<4> inverse = matrix_inverse(m);
std::cout << "Inverse -\n";
print_matrix(inverse);
Output:
Inverse -
14 11 13 9
9 14 11 13
13 9 14 11
11 13 9 14