def tu_decomposition(s, v, verbose=False): """Using the knowledge that v is a subspace of Z_s of dimension n, a TU-decomposition (as defined in [Perrin17]) of s is performed and T and U are returned. """ N = int(log(len(s), 2)) # building B basis = extract_basis(v[0], N) t = len(basis) basis = complete_basis(basis, N) B = Matrix(GF(2), N, N, [tobin(x, N) for x in reversed(basis)]) if verbose: print "B= (rank={})\n{}".format(B.rank(), B.str()) # building A basis = complete_basis(extract_basis(v[1], N), N) A = Matrix(GF(2), N, N, [tobin(x, N) for x in reversed(basis)]) if verbose: print "A= (rank={})\n{}".format(A.rank(), A.str()) # building linear equivalent s_prime s_prime = [ apply_bin_mat(s[apply_bin_mat(x, A.inverse())], B) for x in xrange(0, 2**N) ] # TU decomposition of s' T, U = get_tu_open(s_prime, t) if verbose: print "T=[" for i in xrange(0, 2**(N - t)): print " {} {}".format(T[i], is_permutation(T[i])) print "]\nU=[" for i in xrange(0, 2**t): print " {} {}".format(U[i], is_permutation(U[i])) print "]" return T, U
def NonCubicSet(K,S, verbose=False): u = -1 if K==QQ else K(K.unit_group().torsion_generator()) from KSp import IdealGenerator Sx = [u] + [IdealGenerator(P) for P in S] r = len(Sx) d123 = r + binomial(r,2) + binomial(r,3) vecP = vec123(K,Sx) A = Matrix(GF(2),0,d123) N = prod(S,1) primes = primes_iter(K,None) T = [] while A.rank() < d123: p = primes.next() while p.divides(N): p = primes.next() v = vecP(p) if verbose: print("v={}".format(v)) A1 = A.stack(vector(v)) if A1.rank() > A.rank(): A = A1 T.append(p) if verbose: print("new A={} with {} rows and {} cols".format(A,A.nrows(),A.ncols())) print("T increases to {}".format(T)) return T
def delta_rank(f): """Returns the Gamma-rank of the function with LUT f. The Gamma-rank is the rank of the 2^{2n} \times 2^{2n} binary matrix M defined by M[x][y] = 1 if and only if x + y \in \Delta, where \Delta is defined as \Delta = \{ (a, b), DDT_f[a][b] == 2 \} ~. """ n = int(log(len(f), 2)) dim = 2**(2 * n) d = ddt(f) gamma = [(a << n) | b for a, b in itertools.product(xrange(1, 2**n), xrange(0, 2**n)) if d[a][b] == 2] mat_content = [] for x in xrange(0, dim): row = [0 for j in xrange(0, dim)] for y in gamma: row[oplus(x, y)] = 1 mat_content.append(row) mat_gf2 = Matrix(GF(2), dim, dim, mat_content) return mat_gf2.rank()
def get_T1(K, S, unit_first=True, verbose=False): # Sx is a list of generators of K(S,2) with the unit first or last, assuming h(K)=1 u = -1 if K==QQ else K(K.unit_group().torsion_generator()) from KSp import IdealGenerator Sx = [IdealGenerator(P) for P in S] if unit_first: Sx = [u] + Sx else: Sx = Sx + [u] r = len(Sx) N = prod(S,1) # Initialize T1 to be empty and A to be a matric with 0 rows and r=#Sx columns T1 = [] A = Matrix(GF(2),0,len(Sx)) primes = primes_iter(K,1) p = primes.next() # Repeat the following until A has full rank: take the next prime p # from the iterator, skip if it divides N (=product over S), form the # vector v, and keep p and append v to the bottom of A if it increases # the rank: while A.rank() < r: p = primes.next() while p.divides(N): p = primes.next() if verbose: print("A={} with {} rows and {} cols".format(A,A.nrows(),A.ncols())) v = vector(alphalist(p, Sx)) if verbose: print("v={}".format(v)) A1 = A.stack(v) if A1.rank() > A.rank(): A = A1 T1 = T1 + [p] if verbose: print("new A={} with {} rows and {} cols".format(A,A.nrows(),A.ncols())) print("T1 increases to {}".format(T1)) # the last thing returned is a "decoder" which returns the # discriminant Delta given the splitting beavious at the primes in # T1: B = A.inverse() def decoder(alphalist): e = list(B*vector(alphalist)) return prod([D**ZZ(ei) for D,ei in zip(Sx,e)], 1) return T1, A, decoder
def get_ccz_equivalent_permutation_cartesian(s, v0, v1, verbose=False): """Takes as input two vector spaces v0 and v1 of the set of zeroes in the LAT of s, each being the cartesian product of two spaces, and returns a permutation CCZ equivalent to s obtained using these CCZ spaces. """ N = int(log(len(s), 2)) # building B e1 = extract_basis(v0[0], N) t = len(e1) e2 = extract_basis(v1[0], N) B = Matrix(GF(2), N, N, [tobin(x, N) for x in e1 + e2]) if verbose: print "B= (rank={})\n{}".format(B.rank(), B.str()) # building A e1 = extract_basis(v0[1], N) e2 = extract_basis(v1[1], N) A = Matrix(GF(2), N, N, [tobin(x, N) for x in e1 + e2]) if verbose: print "A= (rank={})\n{}".format(A.rank(), A.str()) # building linear equivalent s_prime s_prime = [ apply_bin_mat(s[apply_bin_mat(x, A.inverse())], B) for x in xrange(0, 2**N) ] # TU decomposition of s' T_inv, U = get_tu_closed(s_prime, t) if verbose: print "T_inv=[" for i in xrange(0, 2**t): print " {} {}".format(T_inv[i], is_permutation(T_inv[i])) print "]\nU=[" for i in xrange(0, 2**t): print " {} {}".format(U[i], is_permutation(U[i])) print "]" # TU-unfolding T = [inverse(row) for row in T_inv] result = [0 for x in xrange(0, 2**N)] for l in xrange(0, 2**t): for r in xrange(0, 2**(N - t)): x = (l << (N - t)) | r y_r = T[r][l] y_l = U[y_r][r] result[x] = (y_l << (t)) | y_r return result
def get_ccz_equivalent_permutation(l, v0, v1, verbose=False): N = int(log(len(l), 2)) mask = sum(int(1 << i) for i in xrange(0, N)) L = v0 + v1 L = Matrix(GF(2), 2 * N, 2 * N, [tobin(x, 2 * N) for x in L]).transpose() if verbose: print "\n\nrank={}\n{}".format(L.rank(), L.str()) new_l = [[0 for b in xrange(0, 2**N)] for a in xrange(0, 2**N)] for a, b in itertools.product(xrange(0, 2**N), xrange(0, 2**N)): v = apply_bin_mat((a << N) | b, L) a_prime, b_prime = v >> N, v & mask new_l[a][b] = l[a_prime][b_prime] return invert_lat(new_l)
def rand_linear_permutation(n, density=0.5): """Returns the matrix representation of a linear permutation of {0,1}^n. This is done by generating random n x n binary matrices until one with full rank is found. As a random binary matrix has full rank with probability more than 1/2, this method is fine. """ while True: result = [[0 for j in xrange(0, n)] for i in xrange(0, n)] for i, j in itertools.product(xrange(0, n), repeat=2): if random.random() < density: result[i][j] = 1 result = Matrix(GF(2), n, n, result) if result.rank() == n: return result
def gamma_rank(f): """Returns the Gamma-rank of the function with LUT f. The Gamma-rank is the rank of the 2^{2n} \times 2^{2n} binary matrix M defined by M[x][y] = 1 if and only if x + y \in \Gamma, where \Gamma is the codebook of f, i.e. \Gamma = \{ (x, f(x)), x \in \F_2^n \} ~. """ n = int(log(len(f), 2)) dim = 2**(2 * n) gamma = [(x << n) | f[x] for x in xrange(0, 2**n)] mat_content = [] for x in xrange(0, dim): row = [0 for j in xrange(0, dim)] for y in gamma: row[oplus(x, y)] = 1 mat_content.append(row) mat_gf2 = Matrix(GF(2), dim, dim, mat_content) return mat_gf2.rank()
def algo64(K, S, BB, T2=None, unit_first = True, verbose=False): r = 1+len(S) if T2 is None: T2 = get_T2(QQ,S, unit_first) if verbose: print("T2 = {}".format(T2)) assert len(T2)==r*(r+1)//2 from KSp import IdealGenerator Sx = [IdealGenerator(P) for P in S] u = -1 if K==QQ else K(K.unit_group().torsion_generator()) Sx = [u] + Sx if unit_first else Sx+[u] if verbose: print("Basis for K(S,2): {}".format(Sx)) #BBdict = dict((k,BB(T2[k])) for k in T2) ap = BB_trace(BB) apdict = dict((k,ap(T2[k])) for k in T2) t4 = BB_t4(BB) t4dict = dict((k,t4(T2[k])) for k in T2) if verbose: print("apdict = {}".format(apdict)) print("t4dict = {}".format(t4dict)) v = vector(GF(2),[t4dict[Set([i])] for i in range(r)]) if verbose: print("v = {}".format(v)) def w(i,j): if i==j: return 0 else: return (t4dict[Set([i,j])] + t4dict[Set([i])] + t4dict[Set([j])]) # Note that W ignores the first coordinate Wd = Matrix(GF(2),[[w(i,j) for j in range(1,r)] for i in range(1,r)]) vd = vector(v.list()[1:]) rkWd = Wd.rank() if verbose: print("W' = \n{} with rank {}".format(Wd,rkWd)) # Case 1: rank(W)=2 if rkWd==2: # x' and y' are any two distinct nonzero rows of W Wrows = [wr for wr in Wd.rows() if wr] xd = Wrows[0] yd = next(wr for wr in Wrows if wr!=xd) zd = xd+yd ud = vd - vector(xi*yi for xi,yi in zip(list(xd),list(yd))) if verbose: print("x' = {}".format(xd)) print("y' = {}".format(yd)) print("z' = {}".format(zd)) print("u' = {}".format(ud)) print("v' = {}".format(vd)) u = vector([1]+ud.list()) v = vector([0]+vd.list()) if t4dict[Set([0])]==1: x = vector([1]+xd.list()) y = vector([1]+yd.list()) z = vector([1]+zd.list()) if verbose: print("x = {}".format(x)) print("y = {}".format(y)) print("z = {}".format(z)) print("u = {}".format(u)) print("v = {}".format(v)) else: raise NotImplementedError("t_4(p_1) case not yet implemented in algo64") return [vec_to_disc(Sx,vec) for vec in [u,x,y,z]] # W==0 raise NotImplementedError("rank(W)=0 case not yet implemented in algo64")
def algo63(K, S, BB, T2=None, unit_first = True, verbose=False): r = 1+len(S) if T2 is None: T2 = get_T2(QQ,S, unit_first) if verbose: print("T2 = {}".format(T2)) assert len(T2)==r*(r+1)//2 from KSp import IdealGenerator Sx = [IdealGenerator(P) for P in S] u = -1 if K==QQ else K(K.unit_group().torsion_generator()) Sx = [u] + Sx if unit_first else Sx+[u] if verbose: print("Basis for K(S,2): {}".format(Sx)) BBdict = dict((k,BB(T2[k])) for k in T2) ap = BB_trace(BB) apdict = dict((k,ap(T2[k])) for k in T2) t2 = BB_t2(BB) t2dict = dict((k,t2(T2[k])) for k in T2) if verbose: print("apdict = {}".format(apdict)) print("t2dict = {}".format(t2dict)) v = vector(GF(2),[t2dict[Set([i])] for i in range(r)]) if verbose: print("v = {}".format(v)) def w(i,j): if i==j: return 0 else: return (t2dict[Set([i,j])] + t2dict[Set([i])] + t2dict[Set([j])]) W = Matrix(GF(2),[[w(i,j) for j in range(r)] for i in range(r)]) rkW = W.rank() if verbose: print("W = \n{} with rank {}".format(W,rkW)) # Case 1: rank(W)=2 if rkW==2: # x and y are any two distinct nonzero rows of W Wrows = [wr for wr in W.rows() if wr] x = Wrows[0] y = next(wr for wr in Wrows if wr!=x) z = x+y u = v - vector(xi*yi for xi,yi in zip(list(x),list(y))) if verbose: print("x = {}".format(x)) print("y = {}".format(y)) print("z = {}".format(z)) print("u = {}".format(u)) else: # W==0 # y=0, x=z u = v y = u-u # zero vector if verbose: print("u = {}".format(u)) print("y = {}".format(y)) t3dict = {} for k in T2: t = 1 if t2dict[k]==0 else -1 t3dict[k] = (BBdict[k](t)//8)%2 s = solve_vectors(r,t3dict) if not s: z = x = y # = 0 if verbose: print("x and y are both zero, so class has >4 vertices") else: x, _ = s z = x if verbose: print("x = {}".format(x)) print("y = {}".format(y)) print("z = {}".format(z)) return [vec_to_disc(Sx,vec) for vec in [u,x,y,z]]