PythonでのLFSR実装を探していたので、このトピックに出くわしました。しかし、私のニーズに応じて、以下の方が少し正確であることがわかりました。
def lfsr(seed, mask):
result = seed
nbits = mask.bit_length()-1
while True:
result = (result << 1)
xor = result >> nbits
if xor != 0:
result ^= mask
yield xor, result
上記のLFSRジェネレーターは、GF(2 k)モジュラス計算(GF =ガロア体)に基づいています。代数コースを修了したばかりなので、これを数学的に説明します。
たとえば、GF(2 4 )を例にとってみましょう。これは、{a 4 x 4 + a 3 x 3 + a 2 x 2 + a 1 x 1 + a 0 x 0 | a 0、a 1、...、a4∈Z2 }(明確にするために、Z n = {0,1、...、n-1}、したがってZ 2 = { 0,1}、つまり1ビット)。これは、これが4次のすべての多項式のセットであり、すべての因子が存在するかどうかにかかわらず、これらの因子の倍数がないことを意味します(たとえば、2x kはありません)。バツ3、x 4 + x 3、1およびx 4 + x 3 + x 2 + x + 1は、すべてこのグループのメンバーの例です。
この設定されたモジュラスを4次の多項式(つまり、P(x)∈GF(2 4))とします。たとえば、P(x)= x 4 + x 1 +x0です。グループに対するこのモジュラス演算は、GF(2 4)/ P(x)としても表されます。参考までに、P(x)はLFSR内の「タップ」を表します。
また、次数3以下のランダム多項式を使用します(モジュラスの影響を受けないようにするため、モジュラス演算を直接実行することもできます)。たとえば、A 0(x)=x0です。これで、後続のすべてのA i(x)は、xを乗算して計算されます。Ai (x)= A i -1(x)* x mod P(x)。
私たちは限られた分野にいるので、モジュラス演算が効果を発揮する可能性がありますが、結果として得られるA i(x)が少なくとも係数x 4(P(x)で最も高い係数)を持つ場合に限ります。Z 2の数値を処理しているため、モジュラス演算自体を実行することは、P(x)とA i(x)の2つの値を足し合わせて、すべてのaiが0になるか1になるかを判断することに他なりません(つまり、0 + 0 = 0、0 + 1 = 1、1 + 1 = 0、またはこれら2つを「xoring」します。
すべての多項式は、ビットのセットとして記述できます。たとえば、x 4 + x 1 + x 0〜10011です。A0 ( x)はシードと見なすことができます。'times x'操作は、左シフト操作と見なすことができます。モジュラス演算はビットマスキング演算と見なすことができ、マスクはP(x)です。
したがって、上記のアルゴリズムは、有効な4ビットLFSRパターン(の無限ストリーム)を生成します。たとえば、定義したA 0(x)(x 0)およびP(x)(x 4 + x 1 + x 0)の場合、次の最初に生成された結果をGF(2 4 )で定義できます(A 0に注意してください) 。最初のラウンドが終了するまで生成されません-数学者は通常「1」から数え始めます):
i Ai(x) 'x⁴' bit pattern
0 0x³ + 0x² + 0x¹ + 1x⁰ 0 0001 (not yielded)
1 0x³ + 0x² + 1x¹ + 0x⁰ 0 0010
2 0x³ + 1x² + 0x¹ + 0x⁰ 0 0100
3 1x³ + 0x² + 0x¹ + 0x⁰ 0 1000
4 0x³ + 0x² + 1x¹ + 1x⁰ 1 0011 (first time we 'overflow')
5 0x³ + 1x² + 1x¹ + 0x⁰ 0 0110
6 1x³ + 1x² + 0x¹ + 0x⁰ 0 1100
7 1x³ + 0x² + 1x¹ + 1x⁰ 1 1011
8 0x³ + 1x² + 0x¹ + 1x⁰ 1 0101
9 1x³ + 0x² + 1x¹ + 0x⁰ 0 1010
10 0x³ + 1x² + 1x¹ + 1x⁰ 1 0111
11 1x³ + 1x² + 1x¹ + 0x⁰ 0 1110
12 1x³ + 1x² + 1x¹ + 1x⁰ 1 1111
13 1x³ + 1x² + 0x¹ + 1x⁰ 1 1101
14 1x³ + 0x² + 0x¹ + 1x⁰ 1 1001
15 0x³ + 0x² + 0x¹ + 1x⁰ 1 0001 (same as i=0)
LFSRが4ビットの結果を生成するようにするには、マスクの4番目の位置に「1」が含まれている必要があることに注意してください。また、ビットストリームが0000ビットパターンで終わらないようにするため、または最後のビットが未使用になるようにするために、「1」が0番目の位置に存在する必要があることに注意してください(すべてのビットが左にシフトされている場合は、また、1シフト後の0番目の位置がゼロになります)。
すべてのP(x)が必ずしもGF(2 k)のジェネレータであるとは限りません(つまり、kビットのすべてのマスクがすべての2 k-1 -1の数値を生成するわけではありません)。たとえば、x 4 + x 3 + x 2 + x 1 + x 0は、それぞれ5つの異なる多項式の3つのグループ、つまり「期間5の3サイクル」を生成します。0001,0010,0100,1000,1111; 0011,0110,1100,0111,1110; および0101,1010,1011,1001,1101。0000は生成できず、他の数値も生成できないことに注意してください。
通常、LFSRの出力は、「シフトアウト」されたビットです。これは、モジュラス演算が実行された場合は「1」であり、実行されていない場合は「0」です。周期が2k- 1-1のLFSRは、疑似ノイズまたはPN-LFSRとも呼ばれ、Golombのランダム性の仮定に準拠しています。これは、この出力ビットが「十分に」ランダムであると言っています。
したがって、これらのビットのシーケンスは、暗号化、たとえばA5/1およびA5/2モバイル暗号化標準、またはE0Bluetooth標準で使用されます。ただし、これらは希望するほど安全ではありません。Berlekamp-Masseyアルゴリズムを使用して、LFSRの特性多項式(P(x))をリバースエンジニアリングできます。したがって、強力な暗号化標準では、非線形FSRまたは同様の非線形関数が使用されます。これに関連するトピックは、AESで使用されるSボックスです。
int.bit_length()
操作を使用したことに注意してください。これはPython2.7まで実装されていませんでした。
有限ビットパターンのみが必要な場合は、シードが結果と等しいかどうかを確認してから、ループを中断できます。
私のLFSRメソッドをforループ(例for xor, pattern in lfsr(0b001,0b10011)
)で使用するか、メソッドの結果に対して操作を繰り返し呼び出して、毎回.next()
新しいペアを返すことができます。(xor, result)