Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- '''
- The first experiment!
- This code is used to predict truncated Galois LFSRs with known parameters.
- Suppose that the modulus and the state transition matrix are known, given the first Ni (i=1,2,...,n) high-order truncated digits of the i-th sequence output by the i-th register, we need to recover the initial state.
- The library used is the Sagemath.
- '''
- # Choose n1 registers from n registers and set the length of each sequence output by register. The total number of output digits is equal to d.
- def distribution(n, n1, d):
- N = vector(ZZ, n1)
- D = vector(ZZ, n)
- C = Combinations(range(n), n1)
- N = C.list()[randint(0, C.cardinality() - 1)]
- for i in N:
- D[i] = 1
- for i in range(n1, d):
- k = randint(0, n1 - 1)
- D[N[k]] = D[N[k]] + 1
- return N, D
- # Recover the initial state by the high-order truncated digits
- def recover_the_initial_state_by_high_order_truncated_digits(m, n, d, n1, beta):
- C = random_matrix(ZZ, n, n, x = 0, y = m)
- A = random_matrix(ZZ, d, n, x = 0, y = m)
- B = Matrix(ZZ, d, n)
- Y = Matrix(ZZ, d, n)
- N, D = distribution(n, n1, d)
- n2 = n - n1
- N2 = vector(ZZ, n2)
- a = Matrix(ZZ, d + 2 * n2 + 1, n)
- i2 = 0
- for i in range(0, n):
- if i in N:
- 0
- else:
- N2[i2] = i
- i2 = i2 + 1
- for i in range(1, d):
- A[i] = (A[i - 1] * C) % m
- for i in range(0, n):
- for j in range(0, D[i]):
- Y[j, i] = A[j, i] >> beta
- L = Matrix(ZZ, d + 2 * n2 + 1, d + 2 * n2 + 1)
- L[0, 0] = 2^(beta - 1)
- for i in range(1, n + 1):
- L[0, i] = 2^(beta - 1)
- L[i, i] = 1
- for i in range(n + 1, n + n2 + 1):
- L[0, i] = 2^(beta - 1)
- col = n + n2
- for i in N:
- CC = identity_matrix(ZZ, n)
- for j in range(1, D[i]):
- CC = (CC * C) % m
- B[j] = (2^beta * (Y[0] * CC - Y[j])) % m
- L[0, col + j] = -B[j, i] + 2^(beta - 1)
- for k in range(0, n2):
- L[n + k + 1, col + j] = 2^beta * CC[N2[k], i]
- L[col + j, col + j] = m
- for k in range(0, n):
- L[k + 1, col + j] = CC[k, i]
- col = col + D[i] - 1
- if beta >= alpha:
- for i in range(n + 1, n + n2 + 1):
- L[i, i] = 2^(beta - alpha)
- else:
- for i in range(0, d + 2 * n2 + 1):
- for j in range(0, d + 2 * n2 + 1):
- L[i, j] = L[i, j] * 2^(alpha - beta)
- for i in range(n + 1, n + n2 + 1):
- L[i, i] = 1
- reduced_L = L.BKZ(block_size = 20)
- flag = 0
- if beta >= alpha:
- for i in range(0, d + 2 * n2 + 1):
- if reduced_L[i, 0] == 2^(beta - 1):
- for j in range(1, n + 1):
- reduced_L[i, j] = -reduced_L[i, j] + 2^(beta - 1)
- for j in range(n + 1, n + n2 + 1):
- reduced_L[i, j] = (-reduced_L[i, j] + 2^(beta - 1)) * 2^alpha
- for j in range(0, n2):
- a[flag, N2[j]] = reduced_L[i, N2[j] + 1] + reduced_L[i, n + j + 1]
- for j in range(0, n1):
- a[flag, N[j]] = reduced_L[i, N[j] + 1] + Y[0, N[j]] * 2^beta
- flag = flag + 1
- if reduced_L[i, 0] == -2^(beta - 1):
- for j in range(1, n + 1):
- reduced_L[i, j] = reduced_L[i, j] + 2^(beta - 1)
- for j in range(n + 1, n + n2 + 1):
- reduced_L[i, j] = (reduced_L[i, j] + 2^(beta - 1)) * 2^alpha
- for j in range(0, n2):
- a[flag, N2[j]] = reduced_L[i, N2[j] + 1] + reduced_L[i, n + j + 1]
- for j in range(0, n1):
- a[flag, N[j]] = reduced_L[i, N[j] + 1] + Y[0, N[j]] * 2^beta
- flag = flag + 1
- if beta < alpha:
- for i in range(0, d + 2 * n2 + 1):
- if reduced_L[i, 0] == 2^(alpha - 1):
- for j in range(1, n + 1):
- reduced_L[i, j] = (-reduced_L[i, j] + 2^(alpha - 1)) / 2^(alpha - beta)
- for j in range(n + 1, n + n2 + 1):
- reduced_L[i, j] = -reduced_L[i, j] + 2^(alpha - 1)
- for j in range(0, n2):
- a[flag, N2[j]] = reduced_L[i, N2[j] + 1] + reduced_L[i, n + j + 1] * 2^beta
- for j in range(0, n1):
- a[flag, N[j]] = reduced_L[i, N[j] + 1] + Y[0, N[j]] * 2^beta
- flag = flag + 1
- if reduced_L[i, 0] == -2^(alpha - 1):
- for j in range(1, n + 1):
- reduced_L[i, j] = (reduced_L[i, j] + 2^(alpha - 1)) / 2^(alpha - beta)
- for j in range(n + 1, n + n2 + 1):
- reduced_L[i, j] = reduced_L[i, j] + 2^(alpha - 1)
- for j in range(0, n2):
- a[flag, N2[j]] = reduced_L[i, N2[j] + 1] + reduced_L[i, n + j + 1] * 2^beta
- for j in range(0, n1):
- a[flag, N[j]] = reduced_L[i, N[j] + 1] + Y[0, N[j]] * 2^beta
- flag = flag + 1
- return A[0], a
- # Determine whether the initial state is recovered
- def judge(m, n, d, n1, beta):
- A, a = recover_the_initial_state_by_high_order_truncated_digits(m, n, d, n1, beta)
- if A == a[0]:
- return 1
- else:
- return 0
- n = 16
- m = 2^31 - 1
- alpha = 17
- n1 = 4
- n2 = n - n1
- beta = 31 - alpha
- s = 100
- for d in range(31, 20, -1):
- tol = 0
- for i in range(0, s):
- jud = judge(m, n, d, n1, beta)
- if jud:
- tol = tol + 1
- print(d, tol)
- '''
- The second experiment!
- This code is used to predict truncated Galois LFSRs with known parameters.
- Suppose that the modulus and the state transition matrix are known, given the first Ni (i=1,2,...,n) low-order truncated digits of the i-th sequence output by the i-th register, we need to recover the initial state.
- The library used is the Sagemath.
- '''
- # Choose n1 registers from n registers and set the length of each sequence output by register. The total number of output digits is equal to d.
- def distribution(n, n1, d):
- N = vector(ZZ, n1)
- D = vector(ZZ, n)
- C = Combinations(range(n), n1)
- N = C.list()[randint(0, C.cardinality() - 1)]
- for i in N:
- D[i] = 1
- for i in range(n1, d):
- k = randint(0, n1 - 1)
- D[N[k]] = D[N[k]] + 1
- return N, D
- # Recover the initial state by the low-order truncated digits
- def recover_the_initial_state_by_low_order_truncated_digits(m, n, d, n1, alpha, beta):
- C = random_matrix(ZZ, n, n, x = 0, y = m)
- A = random_matrix(ZZ, d, n, x = 0, y = m)
- B = Matrix(ZZ, d, n)
- Z = Matrix(ZZ, d, n)
- N, D = distribution(n, n1, d)
- n2 = n - n1
- N2 = vector(ZZ, n2)
- dim = d + 2 * n2 + 1
- a = Matrix(ZZ, 2 * dim, n)
- i2 = 0
- for i in range(0, n):
- if i in N:
- 0
- else:
- N2[i2] = i
- i2 = i2 + 1
- for i in range(1, d):
- A[i] = (A[i - 1] * C) % m
- for i in range(0, n):
- for j in range(0, D[i]):
- Z[j, i] = A[j, i] % (2^beta)
- gamma = gcd(m, 2^beta)
- m_new = m / gamma
- L = Matrix(ZZ, dim, dim)
- L[0, 0] = 2^(alpha - 1)
- for i in range(1, n + 1):
- L[0, i] = 2^(alpha - 1)
- L[i, i] = 1
- for i in range(n + 1, n + n2 + 1):
- L[0, i] = 2^(alpha - 1)
- col = n + n2
- for i in N:
- CC = identity_matrix(ZZ, n)
- for j in range(1, D[i]):
- CC = (CC * C) % m
- B[j] = (2^(-beta) * (Z[0] * CC - Z[j])) % m_new
- L[0, col + j] = -B[j, i] + 2^(alpha - 1)
- for k in range(0, n2):
- L[n + k + 1, col + j] = (2^(-beta) * CC[N2[k], i]) % m_new
- L[col + j, col + j] = m_new
- for k in range(0, n):
- L[k + 1, col + j] = CC[k, i] % m_new
- col = col + D[i] - 1
- if alpha >= beta:
- for i in range(n + 1, n + n2 + 1):
- L[i, i] = 2^(alpha - beta)
- else:
- for i in range(0, dim):
- for j in range(0, dim):
- L[i, j] = L[i, j] * 2^(beta - alpha)
- for i in range(n + 1, n + n2 + 1):
- L[i, i] = 1
- reduced_L = L.BKZ(block_size = 20)
- flag = 0
- if alpha >= beta:
- for i in range(0, dim):
- if reduced_L[i, 0] == 2^(alpha - 1):
- for j in range(1, n + 1):
- reduced_L[i, j] = -reduced_L[i, j] + 2^(alpha - 1)
- for j in range(n + 1, n + n2 + 1):
- reduced_L[i, j] = (-reduced_L[i, j] + 2^(alpha - 1)) / 2^(alpha - beta)
- for j in range(0, n2):
- a[flag, N2[j]] = reduced_L[i, N2[j] + 1] * 2^beta + reduced_L[i, n + j + 1]
- for j in range(0, n1):
- a[flag, N[j]] = reduced_L[i, N[j] + 1] * 2^beta + Z[0, N[j]]
- flag = flag + 1
- for j in range(0, n2):
- if reduced_L[i, N2[j] + 1] < 2^(alpha - 1):
- a[flag, N2[j]] = (reduced_L[i, N2[j] + 1] + 2^(alpha - 1)) * 2^beta + reduced_L[i, n + j + 1] - 1
- if reduced_L[i, N2[j] + 1] > 2^(alpha - 1):
- a[flag, N2[j]] = (reduced_L[i, N2[j] + 1] - 2^(alpha - 1)) * 2^beta + reduced_L[i, n + j + 1] + 1
- flag = flag + 1
- if reduced_L[i, 0] == -2^(alpha - 1):
- for j in range(1, n + 1):
- reduced_L[i, j] = reduced_L[i, j] + 2^(alpha - 1)
- for j in range(n + 1, n + n2 + 1):
- reduced_L[i, j] = (reduced_L[i, j] + 2^(alpha - 1)) / 2^(alpha - beta)
- for j in range(0, n2):
- a[flag, N2[j]] = reduced_L[i, N2[j] + 1] * 2^beta + reduced_L[i, n + j + 1]
- for j in range(0, n1):
- a[flag, N[j]] = reduced_L[i, N[j] + 1] * 2^beta + Z[0, N[j]]
- flag = flag + 1
- for j in range(0, n2):
- if reduced_L[i, N2[j] + 1] < 2^(alpha - 1):
- a[flag, N2[j]] = (reduced_L[i, N2[j] + 1] + 2^(alpha - 1)) * 2^beta + reduced_L[i, n + j + 1] - 1
- if reduced_L[i, N2[j] + 1] > 2^(alpha - 1):
- a[flag, N2[j]] = (reduced_L[i, N2[j] + 1] - 2^(alpha - 1)) * 2^beta + reduced_L[i, n + j + 1] + 1
- flag = flag + 1
- if alpha < beta:
- for i in range(0, dim):
- if reduced_L[i, 0] == 2^(beta - 1):
- for j in range(1, n + 1):
- reduced_L[i, j] = (-reduced_L[i, j] + 2^(beta - 1)) / 2^(beta - alpha)
- for j in range(n + 1, n + n2 + 1):
- reduced_L[i, j] = -reduced_L[i, j] + 2^(beta - 1)
- for j in range(0, n2):
- a[flag, N2[j]] = reduced_L[i, N2[j] + 1] * 2^beta + reduced_L[i, n + j + 1]
- for j in range(0, n1):
- a[flag, N[j]] = reduced_L[i, N[j] + 1] * 2^beta + Z[0, N[j]]
- flag = flag + 1
- for j in range(0, n2):
- if reduced_L[i, N2[j] + 1] < 2^(alpha - 1):
- a[flag, N2[j]] = (reduced_L[i, N2[j] + 1] + 2^(alpha - 1)) * 2^beta + reduced_L[i, n + j + 1] - 1
- if reduced_L[i, N2[j] + 1] > 2^(alpha - 1):
- a[flag, N2[j]] = (reduced_L[i, N2[j] + 1] - 2^(alpha - 1)) * 2^beta + reduced_L[i, n + j + 1] + 1
- flag = flag + 1
- if reduced_L[i, 0] == -2^(beta - 1):
- for j in range(1, n + 1):
- reduced_L[i, j] = (reduced_L[i, j] + 2^(beta - 1)) / 2^(beta - alpha)
- for j in range(n + 1, n + n2 + 1):
- reduced_L[i, j] = reduced_L[i, j] + 2^(beta - 1)
- for j in range(0, n2):
- a[flag, N2[j]] = reduced_L[i, N2[j] + 1] * 2^beta + reduced_L[i, n + j + 1]
- for j in range(0, n1):
- a[flag, N[j]] = reduced_L[i, N[j] + 1] * 2^beta + Z[0, N[j]]
- flag = flag + 1
- for j in range(0, n2):
- if reduced_L[i, N2[j] + 1] < 2^(alpha - 1):
- a[flag, N2[j]] = (reduced_L[i, N2[j] + 1] + 2^(alpha - 1)) * 2^beta + reduced_L[i, n + j + 1] - 1
- if reduced_L[i, N2[j] + 1] > 2^(alpha - 1):
- a[flag, N2[j]] = (reduced_L[i, N2[j] + 1] - 2^(alpha - 1)) * 2^beta + reduced_L[i, n + j + 1] + 1
- flag = flag + 1
- return A[0], a
- # Determine whether the initial state is recovered
- def judge(m, n, d, n1, alpha, beta):
- A, a = recover_the_initial_state_by_low_order_truncated_digits(m, n, d, n1, alpha, beta)
- count = 0
- for j in range(0, n):
- if A[j] == a[0, j] or A[j] == a[1, j]:
- count = count + 1
- if count == n:
- return 1
- else:
- return 0
- n = 16
- m = 2^31 - 2
- beta = 17
- n1 = 4
- n2 = n - n1
- alpha = 31 - beta
- s = 100
- for d in range(32, 20, -1):
- tol = 0
- for i in range(0, s):
- result = judge(m, n, d, n1, alpha, beta)
- if result:
- tol = tol + 1
- print(d, tol)
- '''
- The third experiment!
- This code is used to predict truncated Galois LFSRs with unknown parameters.
- Suppose that the modulus and the state transition matrix are unknown, given the first Ni (Ni>r, i=1,2,...,n) low-order truncated digits of the i-th sequence output by the i-th register, we need to recover the modulus, the characteristic polynomial, the initial state, and the state transition matrix.
- The library used is the Sagemath.
- '''
- import time
- # Recover the modulus by the resultant
- def recover_the_modulus(m, n, r, t, D, A, Y):
- time_start = time.clock()
- L = Matrix(ZZ, r, t + r)
- for i in range(0, r):
- L[i, t + i] = 1
- p = 0
- for j in range(0, n):
- for k in range(0, D[j] - r + 1):
- L[i, p + k] = Y[i + k, j]
- p = p + D[j] - r + 1
- reduced_L = L.BKZ(block_size = 20)
- count = vector(ZZ, r)
- for i in range(0, r):
- yy = 0
- for j in range(0, n):
- for k in range(0, D[j] - r + 1):
- z = 0
- for zz in range(0, r):
- z = z + reduced_L[i, t + zz] * A[k + zz, j]
- if z == 0:
- yy = yy + 1
- if z != 0:
- yy = 0
- break
- if yy == 0:
- break
- if yy == t:
- count[i] = count[i] + 1
- time_end = time.clock()
- print('Step 1: time of searching polynomials that annihilate the sequence: ', time_end - time_start, 's\n')
- time_start = time.clock()
- R.<x> = ZZ[]
- f = []
- fi = reduced_L[0, t] * x^0
- for i in range(1, r):
- fi = fi + x^i * reduced_L[0, i + t]
- f.append(fi)
- fi = reduced_L[1, t] * x^0
- for i in range(1, r):
- fi = fi + x^i * reduced_L[1, i + t]
- f.append(fi)
- recovered_m_n = f[0].resultant(f[1])
- flag = 2
- while recovered_m_n != m^n:
- if flag == r - t:
- flag = -1
- break
- fi = reduced_L[flag, t] * x^0
- for i in range(1, r):
- fi = fi + x^i * reduced_L[flag, i + t]
- f.append(fi)
- for i in range(0, flag):
- res = f[flag].resultant(f[i])
- recovered_m_n = gcd(recovered_m_n, res)
- flag = flag + 1
- if flag > 0:
- recovered_m = recovered_m_n^(1/n)
- print("Success to recover m by ", flag, " polynomials!")
- print("m == ", recovered_m, "\n")
- else:
- print("Fail to recover m!")
- print("The wrong m == ", recovered_m_n^(1/n), "\n")
- time_end = time.clock()
- print('Step 2: time of recovering the modulus: ', time_end - time_start, 's\n')
- return count, reduced_L, flag
- # Recover the coefficients by the Chinese Remainder Theorem
- def recover_the_coefficients(L, m, F, r, t):
- time_start = time.clock()
- R.<x> = PolynomialRing(Integers(m), implementation='NTL')
- for i in range(0, r):
- mark = r - 1
- while L[i, mark + t] == 0:
- mark = mark - 1
- for j in range(0, t + r):
- L[i, j] = L[i, j] * ((L[i, mark + t]^(-1)) % m)
- f = []
- fi = L[0, t]
- for i in range(1, r):
- fi = fi + x^i * L[0, i + t]
- f.append(fi)
- fi = L[1, t]
- for i in range(1, r):
- fi = fi + x^i * L[1, i + t]
- f.append(fi)
- g = f[0].gcd(f[1])
- flag = 2
- while g != F:
- if flag == r - t:
- flag = -1
- break
- fi = L[flag, t]
- for i in range(1, r):
- fi = fi + x^i * L[flag, i + t]
- f.append(fi)
- for i in range(0, flag):
- g = g.gcd(f[flag])
- flag = flag + 1
- if flag > 0:
- print("Success to recover f by ", flag, " polynomials!")
- print("f == ", g, "\n")
- else:
- print("Fail to recover f!")
- print("The correct f == ", F, "\n")
- print("The wrong f == ", g, "\n")
- time_end = time.clock()
- print('Step 3: time of recovering the coefficients: ', time_end - time_start, 's\n')
- return flag
- # Recover the initial state by Kannan's embedding technique
- def recover_the_initial_state(m, n, beta, F, Y, A):
- time_start = time.clock()
- flag = vector(ZZ, n)
- for ni in range(0, n):
- Q = Matrix(ZZ, n, n)
- Q[0, n - 1] = (-F.list()[0]) % m
- for i in range(1, n):
- Q[i, i - 1] = 1
- Q[i, n - 1] = (-F.list()[i]) % m
- for d in range(25, 40):
- Q_power = identity_matrix(ZZ, n)
- recovered_a = vector(ZZ, n)
- recovered_z = vector(ZZ, n)
- L = Matrix(ZZ, d + 1, d + 1)
- for i in range(1, n):
- Q_power = (Q_power * Q) % m
- for i in range(n, d):
- Q_power = (Q_power * Q) % m
- b = 0
- for j in range(0, n):
- L[j + 1, i + 1] = Q_power[j, 0]
- b = b + Q_power[j, 0] * Y[j, ni]
- L[0, i + 1] = (2^beta * (Y[i, ni] - b)) % m + 2^(beta - 1)
- L[0, 0] = 2^(beta - 1)
- for i in range(1, n + 1):
- L[0, i] = 2^(beta - 1)
- L[i, i] = 1
- for i in range(n + 1, d + 1):
- L[i, i] = m
- reduced_L = L.BKZ(block_size = 20)
- if reduced_L[0, 0] == -2^(beta - 1):
- for i in range(0, n):
- recovered_z[i] = reduced_L[0, i + 1] + 2^(beta - 1)
- recovered_a[i] = Y[i, ni] * 2^(beta) + recovered_z[i]
- if reduced_L[0, 0] == 2^(beta - 1):
- for i in range(0, n):
- recovered_z[i] = -reduced_L[0, i + 1] + 2^(beta - 1)
- recovered_a[i] = Y[i, ni] * 2^(beta) + recovered_z[i]
- tol = 0
- for i in range(0, n):
- if recovered_a[i] == A[i, ni]:
- tol = tol + 1
- if tol == n:
- break
- flag[ni] = d
- print("Success to recover the initial states by ", flag, " truncated digits!")
- time_end = time.clock()
- print('Step 4: time of recovering the initial states: ', time_end - time_start, 's\n')
- return flag
- # Recover the state transition matrix
- def recover_the_state_transition_matrix(m, n, A, C):
- A0 = A[0:n]
- A1 = A[1:n + 1]
- recovered_C = (A0^(-1) * A1) % m
- if recovered_C == C:
- print("Success to recover the state transition matrix!")
- else:
- print("Fail to recover the state transition matrix!")
- return recovered_C == C
- m = 2^31 - 1
- n = 16
- I = identity_matrix(ZZ, n)
- R.<x> = PolynomialRing(Integers(m))
- c = vector(ZZ, n)
- tol = 0
- r = 170
- t = 65
- beta = 14
- d = n * r + t - n
- count = vector(ZZ, r)
- sum_count = vector(ZZ, r)
- for i in range(0, 100):
- time_start = time.clock()
- print(i)
- find_polynomial = 0
- while find_polynomial == 0:
- C = random_matrix(ZZ, n, n, x = 0, y = m)
- F = x * I - C
- find_polynomial = F.determinant().is_irreducible()
- di = r + t - n
- A = random_matrix(ZZ, di, n, x = 0, y = m)
- Y = Matrix(ZZ, di, n)
- Z = Matrix(ZZ, di, n)
- D = vector(ZZ, n)
- for i in range(0, n):
- D[i] = r
- for i in range(n * r, d):
- p = randint(1, n - 1)
- D[p] = D[p] + 1
- for i in range(1, di):
- A[i] = (A[i - 1] * C) % m
- for i in range(0, n):
- for j in range(0, D[i]):
- Y[j, i] = A[j, i] >> beta
- Z[j, i] = A[j, i] % (2^beta)
- count, reduced_L, flag_m = recover_the_modulus(m, n, r, t, D, A, Y)
- flag_f = recover_the_coefficients(reduced_L, m, F.determinant(), r, t)
- sum_count = count + sum_count
- print("sum_count == ", sum_count, "\n")
- if flag_m > 0 and flag_f > 0:
- flag_a = recover_the_initial_state(m, n, beta, F.determinant(), Y, A)
- flag_C = recover_the_state_transition_matrix(m, n, A, C)
- time_end = time.clock()
- print('Total time: ', time_end - time_start, 's\n\n')
Add Comment
Please, Sign In to add comment