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.n, s1.m 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, Bin.concat(Bin(1, 1) + Bin(x, inp) + Bin(s1[x], out)).tuple ) M2.set_column( x, Bin.concat(Bin(1, 1) + Bin(x, inp) + Bin(s2[x], out)).tuple ) 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)
def concat(funcs): assert len(set(f.input_size() for f in funcs)) == 1 sizes = tuple(f.output_size() for f in funcs) return SBox2( [Bin.concat(*Bin.array(ys, ns=sizes)) for ys in zip(*funcs)], m=sum(sizes) )
def __getitem__(self, lst): assert len(lst) == self.num_in x = Bin.concat(Bin.array(lst, n=self.width_in)) y = self.s[x] return Bin(y, self.width_out).split(parts=self.num_out)