Other

ガロア体 GF(28)

GF(2)は1ビットの演算で、加算を排他論理和 (XOR) で行います。これによってGF(2)は0~1の集合になります。GF(28)はGF(2)を拡張したもので、ほぼ8ビット(1バイト)のビット演算です。ただし、適切なp(x)を決めてあって、ビットがあふれてしまったときの処理を定めてあります。GF(28)のp(x)は

    p(x) = x8 + x4 + x3 + x2 + 1

です。ガロア体の定義で p(x) = 0 なので、以下の関係が成り立ちます。

    p(x) = x8 + x4 + x3 + x2 + 1 = 0

    より

    x8 = -x4 - x3 - x2 - 1

    1 + 1 = 0

    より

    1 = -1

    よって

    x8 = x4 + x3 + x2 + 1

つまり演算によってビットがあふれ、ビット8が1になってしまったとき、その値は下位の8ビット(x4 + x3 + x2 + 1)に置き換えられることを意味します。そして下位8ビットとの加算によって8ビット幅の値を得ます。ここでの加算は排他論理和で行うので、演算結果が8ビット幅を超えることはありません。

    n = ((n >> 8) * ((1 << 4) | (1 << 3) | (1 << 2) | 1)) ^ (n & 0xff);

以下にGF(28)を列挙するコードを書きます。

    int s = (1 << 4) | (1 << 3) | (1 << 2) | 1;
    int n = 1;

    byte[] nof = new byte[256];
    byte[] iof = new byte[256];

    for (int i = 0; i < 255; i++)
    {
        nof[i] = (byte)n;
        iof[n] = (byte)i;

        n <<= 1;
        n = ((n >> 8) * s) ^ (n & 0xff);
    }

    nof[255] = (byte)n;

i は a の指数であり、ai = n の関係が成り立ちます。a の指数 i に対する n を求めるには nof[i] を、 n に対する a の指数 i を求めるには iof[n] を参照します。a とはほぼ 2 のことですが、おそらく GF(28) の要素を指しているのだと思います。

このプログラム・コードでは iof[0] には値が代入されません。a を i 乗して 0 になるような i はないので、かまわないだろうと思います。また、forループは255回しかまわしません。実は ai = 1 となる i は i = 0 と i = 255 があり、256回ループさせると iof[1] = 0 に iof[1] = 255 が上書きされてしまうためです。 iof[1] = 255 より iof[1] = 0 のほうがプログラム的に都合が良いです。

ここで a0 = a255 = 1 より、ai = ai % 255 とすることができます。よって nof[i] を nof[i % 255] としても良いです。