def find_special_state(poly_list, P_matrix, states): """Calculate the special state for each state, given the P matrix. Return format: (c, d) where T^c a^i_d = special_state for each i. """ n = P_matrix.rows special_s = zeros(1, n) special_s[0] = 1 special_s *= P_matrix.inv_mod(2) special_state = [] runsum = 0 for p in poly_list: special_state.append(special_s[runsum:runsum + degree(p)]) runsum += degree(p) special_param = [] for i, p in enumerate(poly_list): t = len(states[i]) - 1 e = (2**degree(p) - 1) / t found = False for j, state in enumerate(states[i]): cur_state = state[:] for k in range(e): if cur_state == special_state[i]: special_param.append({"shift": k, "state": j}) found = True break cur_state = LFSR_from_poly(p, cur_state) if found: break return special_param
def get_poly_list(list_): """Return a list of polynomials and the sum of their degrees.""" f = Poly(1, modulus=2) sum_degree = 0 poly_list = [] found_reduc = False found_const = False found_dup = False for bin_str in list_: polynum = int(bin_str, 2) p = poly_from_num(polynum) if not p.is_irreducible(): found_reduc = True elif p == Poly(1, modulus=2): found_const = True elif p in poly_list: found_dup = True else: f *= p poly_list.append(p) sum_degree += int(degree(p)) if found_reduc: print "WARNING: At least one input was reducible." if found_const: print "WARNING: At least one input was a constant polynomial." if found_dup: print "WARNING: Multiple entries found." return (f, sorted(poly_list, key=lambda x: int(degree(x))), sum_degree)
def find_pairs(p, poly_state, shift, state): """Find all pairs between states of a given polynomial such that T^l a_j + T^-m a_k = special_state.""" special_state = list(poly_state[state]) for i in range(shift): special_state = LFSR_from_poly(p, special_state) t = len(poly_state) - 1 e = (2**degree(p) - 1) / t pairs_list = {} for j in range(t + 1): state_j = poly_state[j] for k in range(j, t + 1): ctr = 0 for l in range(e): temp = [(state_j[i] + special_state[i]) % 2 for i in range(degree(p))] for m in range(e): if temp == poly_state[k]: if (j, k) in pairs_list: pairs_list[(j, k)].append((l, -m % e)) if j != k: pairs_list[(k, j)].append((-m % e, l)) else: pairs_list[(j, k)] = [(l, -m % e)] if j != k: pairs_list[(k, j)] = [(-m % e, l)] ctr += 1 break else: temp = LFSR_from_poly(p, temp) state_j = LFSR_from_poly(p, state_j) return pairs_list
def pair_generator(poly_list, lists): """Generate all combination of pairs as given from find_pairs.""" if poly_list: pairs = lists[0] t = max([key[0] for key in pairs]) e = (2**degree(poly_list[0]) - 1) / t for pair in pairs: state_1 = pair[0] state_2 = pair[1] for shift_pair in pairs[pair]: next_list = pair_generator(poly_list[1:], lists[1:]) ord_1 = e if state_1 != t else 1 ord_2 = e if state_2 != t else 1 cur_param = { "order_1": ord_1, "order_2": ord_2, "shift_pair_1": shift_pair[0], "shift_pair_2": shift_pair[1], "state_1": state_1, "state_2": state_2 } for next_pair in next_list: yield [cur_param] + next_pair else: yield []
def get_P_matrix(poly_list): """Return the P matrix as specified in the paper.""" n = sum([int(degree(p)) for p in poly_list]) P_matrix = zeros(n) runsum = 0 for p in poly_list: deg_p = int(degree(p)) for i in range(deg_p): P_matrix[runsum + i, i] = 1 cur_state = [0] * deg_p cur_state[i] = 1 for j in range(deg_p, n): cur_state = LFSR_from_poly(p, cur_state) P_matrix[runsum + i, j] = cur_state[-1] runsum += deg_p return P_matrix
def _get_base_matrix(p, q, t): """Return the basis-conversion matrix between the roots of two polynomials.""" n = int(degree(p)) M = zeros(n) M[0, 0] = 1 q_trimmed = q - Poly(LT(q), modulus=2) cur_poly = Poly(to_list([t]), modulus=2) div_poly = Poly(to_list([n]), modulus=2) for i in range(1, n): while degree(cur_poly) >= n: cur_poly = quo(cur_poly, div_poly) * q_trimmed + rem( cur_poly, div_poly) for j in range(len(cur_poly.all_coeffs())): M[i, j] = cur_poly.all_coeffs()[-j - 1] cur_poly = cur_poly * Poly(to_list([t]), modulus=2) return M.inv_mod(2)
def get_associate_poly(poly_list): """Return the associated primitive polynomial of a list of polynomials.""" associates = [] max_degree = max([int(degree(p)) for p in poly_list]) for i in range(1, max_degree + 1): poly_sublist = [p for p in poly_list if int(degree(p)) == i] if poly_sublist: primitive_poly = generate_primitive(i) m_seq = [] for p in primitive_poly: seq = [1] * (2**i - 1) state = [1] * i for j in range(i, 2**i - 1): state = LFSR_from_poly(p, state) seq[j] = state[-1] m_seq.append(seq) for p in poly_sublist: if check_primitive(p): associates.append({"poly": p, "t": 1}) else: for j in divisors(2**i - 1, proper=True)[1:]: found_associate = False if totient(2**i - 1) / totient( (2**i - 1) / j) <= len(primitive_poly): decimated_seq = map(lambda x: decimate(x, j), m_seq) while len(decimated_seq[0]) < 2 * i: for seq in decimated_seq: seq += seq[:min(len(seq), 2 * i - len(seq))] for idx, seq in enumerate(decimated_seq): state = seq[:i] cur_seq = state * 2 for k in range(i, 2 * i): state = LFSR_from_poly(p, state) cur_seq[k] = state[-1] if cur_seq == seq[:2 * i]: associates.append({ "poly": primitive_poly[idx], "t": j }) found_associate = True break if found_associate: break return associates
def LFSR_from_poly(char_poly, state): """Return the next state given the characteristic polynomial of a LFSR and a state.""" deg_p = int(degree(char_poly)) LFSR = zeros(deg_p, 1) for i in range(deg_p): LFSR[i] = int(char_poly.all_coeffs()[-i - 1]) next_state = state[:] + [(Matrix(1, deg_p, state) * LFSR)[0] % 2] return next_state[1:]
def check_primitive(p): """Check if a polynomial is primitive in F_2[X].""" if not p.is_irreducible(): return False deg_p = int(degree(p)) for i in [j for j in divisors(2**deg_p - 1, proper=True) if j > deg_p]: q = Poly(to_list([0, i]), modulus=2) if rem(q, p, modulus=2).is_zero(): return False return True
def _get_state(M, p, t): """Return the states of a polynomial, given its basis conversion matrix.""" deg_p = int(degree(p)) state = [1] * (t * deg_p) new_p = p - Poly(LT(p), modulus=2) cur_poly = Poly(1, modulus=2) div_poly = Poly(LT(p), modulus=2) for i in range(1, t * deg_p): cur_poly *= Poly([0, 1], modulus=2) if degree(cur_poly) == deg_p: cur_poly = quo(cur_poly, div_poly) * new_p + rem( cur_poly, div_poly) coeff = zeros(1, deg_p) for j in range(len(cur_poly.all_coeffs())): coeff[j] = int(cur_poly.all_coeffs()[-j - 1]) coeff = (coeff * M).applyfunc(lambda x: x % 2) state[i] = coeff[0] v = [] for i in range(t): v.append(state[i::t]) v.append([0] * deg_p) return v
def _get_associate_poly(poly_list): """Return the associated primitive polynomial of a list of polynomials.""" associates = [] max_degree = max([int(degree(p)) for p in poly_list]) for i in range(1, max_degree + 1): poly_sublist = [p for p in poly_list if int(degree(p)) == i] if poly_sublist: primitive_poly = generate_primitive(i) for p in poly_sublist: if check_primitive(p): associates.append({"poly": p, "t": 1}) else: for q in primitive_poly: found_associate = False for j in divisors(2**i - 1, proper=True): if rem(p(Poly(to_list([j]), modulus=2)), q).is_zero(): associates.append({"poly": q, "t": j}) found_associate = True break if found_associate: break return associates
def get_cycle(p, states, t): """Return the distinct cycles of LFSR with a given characteristic polynomial.""" n = degree(p) e = (2**n - 1) / t cycles = [] for state in states: if e <= n: cur_cycle = state[0:e] else: cur_cycle = [0] * e cur_cycle[0:n] = state temp_state = state for i in range(n, e): temp_state = LFSR_from_poly(p, temp_state) cur_cycle[i] = temp_state[-1] cycles.append(cur_cycle) return cycles
def get_state(q, t): deg = degree(q) seq = [1] * (2**deg - 1) state = [1] * deg for i in range(deg, 2**deg - 1): state = LFSR_from_poly(q, state) seq[i] = state[-1] states = [] for i in range(t): state = decimate(seq, t, i) while len(state) < deg: state += state states.append(state[:deg]) states.append([0] * deg) return states