Linear feedback shift register (LFSR) sequence commands

Stream ciphers have been used for a long time as a source of pseudo-random number generators.

S. Golomb [Go1967] gives a list of three statistical properties that a sequence of numbers a={an}n=1, an{0,1} should display to be considered “random”. Define the autocorrelation of a to be

C(k)=C(k,a)=limN1NNn=1(1)an+an+k.

In the case where a is periodic with period P, then this reduces to

C(k)=1PPn=1(1)an+an+k.

Assume a is periodic with period P.

  • balance: |Pn=1(1)an|1.

  • low autocorrelation:

    C(k)={1,k=0,ϵ,k0.

    (For sequences satisfying these first two properties, it is known that ϵ=1/P must hold.)

  • proportional runs property: In each period, half the runs have length 1, one-fourth have length 2, etc. Moreover, there are as many runs of 1’s as there are of 0’s.

A general feedback shift register is a map f:FdqFdq of the form

f(x0,...,xn1)=(x1,x2,...,xn),xn=C(x0,...,xn1),

where C:FdqFq is a given function. When C is of the form

C(x0,...,xn1)=a0x0+...+an1xn1,

for some given constants aiFq, the map is called a linear feedback shift register (LFSR).

Example of an LFSR: Let

f(x)=a0+a1x+...+anxn+...,
g(x)=b0+b1x+...+bnxn+...,

be given polynomials in F2[x] and let

h(x)=f(x)g(x)=c0+c1x+...+cnxn+... .

We can compute a recursion formula which allows us to rapidly compute the coefficients of h(x) (take f(x)=1):

cn=ni=1bib0cni.

The coefficients of h(x) can, under certain conditions on f(x) and g(x), be considered “random” from certain statistical points of view.

Example: For instance, if

f(x)=1,    g(x)=x4+x+1,

then

h(x)=1+x+x2+x3+x5+x7+x8+... .

The coefficients of h are

1,1,1,0,1,0,1,1,0,0,1,0,0,0,1,1,1,1,0,1,0,1,1,0,0,1,0,0,0,1,... .

The sequence of 0,1’s is periodic with period P=241=15 and satisfies Golomb’s three randomness conditions. However, this sequence of period 15 can be “cracked” (i.e., a procedure to reproduce g(x)) by knowing only 8 terms! This is the function of the Berlekamp-Massey algorithm [Mas1969], implemented in berlekamp_massey.py.

AUTHORS:

  • David Joyner (2005-11-24): initial creation.
  • Timothy Brock (2005-11): added lfsr_sequence with code modified from Python Cookbook, http://aspn.activestate.com/ASPN/Python/Cookbook/
  • Timothy Brock (2006-04-17): added lfsr_autocorrelation and lfsr_connection_polynomial.
sage.crypto.lfsr.lfsr_autocorrelation(L, p, k)

INPUT:

  • L – a periodic sequence of elements of ZZ or GF(2); must have length p
  • p – the period of L
  • k – an integer between 0 and p

OUTPUT: autocorrelation sequence of L

EXAMPLES:

sage: F = GF(2)
sage: o = F(0)
sage: l = F(1)
sage: key = [l,o,o,l]; fill = [l,l,o,l]; n = 20
sage: s = lfsr_sequence(key,fill,n)
sage: lfsr_autocorrelation(s,15,7)
4/15
sage: lfsr_autocorrelation(s,int(15),7)
4/15
sage.crypto.lfsr.lfsr_connection_polynomial(s)

INPUT:

  • s – a sequence of elements of a finite field of even length

OUTPUT:

  • C(x) – the connection polynomial of the minimal LFSR.

This implements the algorithm in section 3 of J. L. Massey’s article [Mas1969].

EXAMPLES:

sage: F = GF(2)
sage: F
Finite Field of size 2
sage: o = F(0); l = F(1)
sage: key = [l,o,o,l]; fill = [l,l,o,l]; n = 20
sage: s = lfsr_sequence(key,fill,n); s
[1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0]
sage: lfsr_connection_polynomial(s)
x^4 + x + 1
sage: from sage.matrix.berlekamp_massey import berlekamp_massey
sage: berlekamp_massey(s)
x^4 + x^3 + 1

Notice that berlekamp_massey returns the reverse of the connection polynomial (and is potentially must faster than this implementation).

sage.crypto.lfsr.lfsr_sequence(key, fill, n)

Create an LFSR sequence.

INPUT:

  • key – a list of finite field elements, [c0,c1,,ck]
  • fill – the list of the initial terms of the LFSR sequence, [x0,x1,,xk]
  • n – number of terms of the sequence that the function returns

OUTPUT:

The LFSR sequence defined by xn+1=ckxn+...+c0xnk for nk.

EXAMPLES:

sage: F = GF(2); l = F(1); o = F(0)
sage: F = GF(2); S = LaurentSeriesRing(F,'x'); x = S.gen()
sage: fill = [l,l,o,l]; key = [1,o,o,l]; n = 20
sage: L = lfsr_sequence(key,fill,20); L
[1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0]
sage: from sage.matrix.berlekamp_massey import berlekamp_massey
sage: g = berlekamp_massey(L); g
x^4 + x^3 + 1
sage: (1)/(g.reverse()+O(x^20))
1 + x + x^2 + x^3 + x^5 + x^7 + x^8 + x^11 + x^15 + x^16 + x^17 + x^18 + O(x^20)
sage: (1+x^2)/(g.reverse()+O(x^20))
1 + x + x^4 + x^8 + x^9 + x^10 + x^11 + x^13 + x^15 + x^16 + x^19 + O(x^20)
sage: (1+x^2+x^3)/(g.reverse()+O(x^20))
1 + x + x^3 + x^5 + x^6 + x^9 + x^13 + x^14 + x^15 + x^16 + x^18 + O(x^20)
sage: fill = [l,l,o,l]; key = [l,o,o,o]; n = 20
sage: L = lfsr_sequence(key,fill,20); L
[1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1]
sage: g = berlekamp_massey(L); g
x^4 + 1
sage: (1+x)/(g.reverse()+O(x^20))
1 + x + x^4 + x^5 + x^8 + x^9 + x^12 + x^13 + x^16 + x^17 + O(x^20)
sage: (1+x+x^3)/(g.reverse()+O(x^20))
1 + x + x^3 + x^4 + x^5 + x^7 + x^8 + x^9 + x^11 + x^12 + x^13 + x^15 + x^16 + x^17 + x^19 + O(x^20)