EN | ZH

# Linear Feedback Shift Register - LFSR¶

## Introduction¶

The feedback function of the linear feedback shift register is generally as follows

$a_{i+n}=\sum\limits_{j=1}^{n}c_ja_{i+n-j}$

Where $c_j$ is in a finite field $F_q$.

Since the linear space is a linear transformation, we can know that this linear transformation is

\left[ \begin{matrix} 0 & 0 & \cdots & 0 & c_n \\ 1 & 0 & \cdots & 0 & c_{n-1} \\ 0 & 1 & \cdots & 0 & c_{n-2}\\\vdots & \vdots & \ddots & \vdots \\ 0 & 0 & \cdots & 1 & c_1 \\ \end{matrix} \right]

Furthermore, we can find the characteristic polynomial as

$f (x) = x ^ n- sum limit_ {i = 1} ^ {n} c_ix ^ {in}$

At the same time, we define its reciprocal polynomial as

$\overline f(x)=x^nf(\frac{1}{x})=1-\sum\limits_{i=1}^{n}c_ix^{i}$

We also call the reciprocal polynomial as the joint polynomial of the linear feedback shift register.

Here are some theorems that we need to remember. Interesting can be derived by ourselves.

## Characteristic Polynomial and Generator¶

Knowing the characteristic polynomial of an n-level linear feedback shift register, then the corresponding generation function of the sequence is

$A(x)=\frac{p(x)}{\overline f(x)}$

Where $p(x)=\sum\limits_{i=1}^{n}(c_{ni}x^{ni}\sum\limits_{j=1}^{i}a_jx^{j-1 })$. It can be seen that p(x) is completely determined by the initial state and the coefficient of the feedback function.

## Sequence cycle and generation function¶

The period of the sequence is the period of the denominator of the resulting true fraction of the function.

For n-level linear feedback shift registers, the longest period is $2^{n-1}$ (excluding all zeros). The sequence that reaches the longest period is generally referred to as the m sequence.

## Special nature¶

• The two sequences are accumulated to give a new sequence whose period is the sum of the periods of the two sequences.
• The sequence is an n-level m sequence if and only if the minimal polynomial of the sequence is n primitive polynomials.

## BM algorithm¶

In general, we can consider LFSR from two perspectives.

• Key generation angle. Generally, we want to use a LFSR with as low a level as possible to generate a sequence with a large period and good randomness.
• Cryptographic analysis, given a sequence a of length n, how to construct a LFSR with as few stages as possible to generate it. In fact, this is the source of the BM algorithm.

In general, we define the linear complexity of a sequence as follows

• If s is an all-zero sequence, the linear complexity is zero.
• If no LFSR can generate s, the linear complexity is infinite.
• Otherwise, the linear complexity of s is the minimum level of LFSR that generates L(s).

The requirements of the BM algorithm we need to know the sequence of length 2n. Complexity

• Time complexity: O(n^2) sub-bit operation
• Space complexity: O(n) bits.

Details about the BM algorithm, added later, are currently in the learning process.

But in fact, if we know the sequence of length 2n, we can also get a stupid way to get the original sequence. Let's assume that the known sequence is $a_1,...,a_{2n}$, we can make

$S_1=(a_1,...,a_n)$

$S_2=(a_2,...,a_{n+1})$

....

$S_{n+1}=(a_{n+1},...,a_{2n})$

Then we can construct the matrix $X=(S_1,...,S_n)$, then

$S_{n+1}=(c_n,...,c_1)X$

and so

$(c_n,...,c_1)=S_{n+1}X^{-1}$

Then we also know the feedback expression of the LFSR, and then we can introduce the initialization seed.

## 2018 强网杯streamgame1¶

Simply look at the topic

from flag import flag

assert flag.startswith("flag{")

assert flag.endswith("}")

assert len(flag)==25

output = (R << 1) & 0xffffff

lastbit=0

while i!=0:

lastbit^=(i&1)

i=i>>1

output^=lastbit

return (output,lastbit)

R=int(flag[5:-1],2)

f=open("key","ab")

for i in range(12):

tmp=0

for j in range(8):

tmp=(tmp << 1)^out

f.write(chr(tmp))

f.close()


It can be found that the length of the flag is 25-5-1=19, so it can be violently enumerated. result

➜ 2018-Strong Net Cup-streamgame1 git:(master) ✗ python exp.py
12

0b1110101100001101011


Therefore flag is flag{1110101100001101011}.

## 2018 CISCN preliminary match oldstreamgame¶

Simply look at the topic

flag = "flag{xxxxxxxxxxxxxxxx}"

assert flag.startswith("flag{")

assert flag.endswith("}")

assert len(flag)==14

output = (R << 1) & 0xffffffff

lastbit=0

while i!=0:

lastbit^=(i&1)

i=i>>1

output^=lastbit

return (output,lastbit)

R=int(flag[5:-1],16)

f=open("key","w")

for i in range(100):

tmp=0

for j in range(8):

tmp=(tmp << 1)^out

f.write(chr(tmp))

f.close()


The program is very simple, it is still an LFSR, but the initial state is 32 bits. Of course, we can also choose to blast, but here we do not choose blasting.

Here are two approaches.

In the first method, the 32th bit of the program output is determined by the first 31 bits of the program output and the first bit of the initial seed, so we can know the first bit of the initial seed, and then we can know the initial seed. The second bit, and so on. code show as below

mask = 0b10100100000010000000100010010100

b = ''

N = 32

with open('key', 'rb') as f:

key = ''

for i in range(N / 8):

t = ord(b[i])

for j in xrange(7, -1, -1):

key += str(t >> j & 1)

idx = 0

ans = &quot;&quot;
key = key[31] + key[:32]

while idx < 32:

tmp = 0

for i in range(32):

if mask >> i & 1:

tmp ^= int(key[31 - i])

ans = str (tmp) + years
idx += 1

key = key[31] + str(tmp) + key[1:31]

Surely = int (ans, 2)
Print Hex (whether)


run

➜  2018-CISCN-start-oldstreamgame git:(master) ✗ python exp1.py

0x926201d7


In the second approach, we can consider the process of matrix conversion. If 32 linear transformations are performed, the first 32 bits of the output stream can be obtained. In fact, we only need the first 32 bits to restore the initial state.

mask = 0b10100100000010000000100010010100

N = 32

F = GF(2)

b = ''

with open('key', 'rb') as f:

R = [vector(F, N) for i in range(N)]

for i in range(N):

R[i][N - 1] = mask >> (31 - i) & 1

for i in range(N - 1):

R[i + 1][i] = 1

M = Matrix(F, R)

M = M ^ N

vec = vector(F, N)

row = 0

for i in range(N / 8):

t = ord(b[i])

for j in xrange(7, -1, -1):

vec[row] = t >> j & 1

row += 1

print rank(M)

num = int(''.join(map(str, list(M.solve_left(vec)))), 2)

Print Hex (whether)


Running script

➜  2018-CISCN-start-oldstreamgame git:(master) ✗ sage exp.sage

32

0x926201d7


Thus flag is flag{926201d7}.

Another way is for TokyoWesterns, you can refer to the corresponding folder file.

## references¶

• Cryptography handouts, edited by Li Chao, Qu Longjiang