def mat_from_linear_func(m, n, func): mat = matrix(GF(2), n, m) for i, e in enumerate(reversed(range(m))): x = 1 << e res = tobin(func(x), n) mat.set_column(i, res) return mat
def split_by_width(x, n, w): l = n * w b = tobin(x, l) res = [] for i in range(0, len(b), w): res.append(frombin(b[i:i + w])) return res
def as_matrix(self): assert self.is_linear() m = matrix(GF(2), self.n, self.m) for e in range(self.m): x = 1 << e m.set_column(self.m - 1 - e, tobin(self[x], self.n)) return m
def mat_field_mul_const(field, c): assert field.base_ring() == GF(2) d = field.degree() m = matrix(GF(2), d, d) for i, e in enumerate(reversed(range(d))): x = 1 << e res = field.fetch_int(x) * field.fetch_int(c) res = tobin(res.integer_representation(), d) m.set_column(i, res) return m
def matrix_mult_int(mat, x): """ MSB to LSB vector >>> matrix_mult_int( \ matrix(GF(2), [[1, 0, 1], [1, 0, 0]]), \ 0b110) # read as 6 -> 1,1,0 -> 1,1 -> 3 3 """ assert mat.base_ring() == GF(2) n = mat.ncols() x = vector(GF(2), tobin(x, n)) y = mat * x return frombin(y)
def matrix_mult_int_rev(mat, x): """ LSB to MSB vector >>> matrix_mult_int_rev( \ matrix(GF(2), [[1, 0, 1], [1, 0, 0]]), \ 0b110) # read as 6 -> 0,1,1 -> 1,0 -> 1 1 """ assert mat.base_ring() == GF(2) n = mat.ncols() x = vector(GF(2), tobin(x, n)[::-1]) y = mat * x return frombin(y[::-1])
def hdim(self, right_to_left=False): """ hdim[i,j] = i-th output bit contains monomial x1...xn/xj """ res = matrix(GF(2), self.in_bits, self.out_bits) anf = mobius(tuple(self)) for j in xrange(self.in_bits): mask = (1 << self.in_bits) - 1 mask ^= 1 << (self.in_bits - 1 - j) res.set_column(j, tobin(anf[mask], self.out_bits)) if right_to_left: res = res[::-1, ::-1] return res
def anfs(self): names = ["x%d" % e for e in xrange(self.in_bits)] bpr = BooleanPolynomialRing(names=names) vs = list((bpr.gens())) res = [] for f in self.coordinates(): anf = bpr(0) for mask, take in enumerate(mobius(tuple(f))): if not take: continue clause = bpr(1) for b, v in zip(tobin(mask, self.in_bits), vs): if b: clause *= v anf += clause res.append(anf) return res
def are_CCZ_equivalent(s1, s2): s1, s2 = convert_sboxes(s1, s2) assert_equal_sizes(s1, s2) lin1 = s1.is_linear() lin2 = s2.is_linear() if lin1 ^ lin2: return False if lin1 and lin2: return True inp, out = s1.m, s1.n M1 = Matrix(GF(2), 1 + inp + out, 2**inp) M2 = Matrix(GF(2), 1 + inp + out, 2**inp) for x in range(2**inp): M1.set_column(x, tobin(1, 1) + tobin(x, inp) + tobin(s1[x], out)) M2.set_column(x, tobin(1, 1) + tobin(x, inp) + tobin(s2[x], out)) L1 = LinearCode(M1) L2 = LinearCode(M2) # Annoying: this is not checked in "is_permutation_equivalent" code! # raises a TypeError instead if L1.generator_matrix().nrows() != L2.generator_matrix().nrows(): return False return L1.is_permutation_equivalent(L2)