def test_inversion(): s = SBox2([5, 6, 3, 2, 1, 7, 0, 4]) assert ~s == s**(-1) == [6, 4, 3, 2, 7, 0, 1, 5] s = SBox2([3, 4, 7, 2, 1, 1, 6, 6], m=4) assert s.image() == {1, 2, 3, 4, 6, 7} assert s.preimage(2) == 3 assert s.preimage(1) == 4 assert s.preimage(6) == 6 assert s.preimages(2) == (3, ) assert s.preimages(1) == (4, 5) assert s.preimages(6) == (6, 7) assert sorted(s.preimage_structure().items()) == [(1, 4), (2, 2)]
def random_permutation(n, zero_zero=False): s = list(range(2**n)) shuffle(s) if zero_zero: i = s.index(0) s[0], s[i] = s[i], s[0] return SBox2(s)
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 random_minicipher(n, kn=None): s = [] for k in range(2**kn): p = list(range(2**n)) shuffle(p) s.extend(p) return SBox2(s)
def test_degrees(): s = SBox2([0] * 15 + [1]) assert s.degrees() == (4, ) assert str(s.anfs()) == "[x0*x1*x2*x3]" s = SBox2([1] * 8 + [0] * 8) assert s.degrees() == (1, ) assert str(s.anfs()) == "[x0 + 1]" s = SBox2([0] * 16) assert s.degrees() == () assert str(s.anfs()) == "[]" s = SBox2([1] * 16) assert s.degrees() == (0, ) assert str(s.anfs()) == "[1]"
def random_involution(n, allow_fixed_points=True): s = list(range(2**n)) if not allow_fixed_points: pairs = list(range(2**n)) shuffle(pairs) else: """ Uniform? n elements a(k): number of involutions with k transpositions a(k) / a(k-1) = (n-2*k+2) * (n-2*k+1) / (2*k) approximate by floats to avoid bigints, should be ok """ ak = [1.0] for k in range(1, 2**(n - 1) + 1): ak.append(ak[-1] * (n - 2 * k + 2) * (n - 2 * k + 1) / (2 * k)) r = random() * sum(ak) acc = 0 for k in range(2**(n - 1) + 1): acc += ak[k] if acc >= r: break pairs = list(range(2**n)) shuffle(pairs) pairs = pairs[:2 * k] for i in range(0, len(pairs), 2): a, b = s[i:i + 2] s[a] = b s[b] = a return SBox2(s)
def test_properties(): s = SBox2([5, 6, 3, 2, 1, 7, 0, 4]) assert props(s) == {s.is_permutation, s.is_balanced} assert props(s.resize(4)) == set() s = SBox2((0, 13, 14, 3, 8, 5, 6, 11, 12, 1, 2, 15, 4, 9, 10, 7)) assert props(s) == { s.is_permutation, s.is_balanced, s.is_affine, s.is_linear } s = SBox2((14, 13, 6, 5, 0, 3, 8, 11, 15, 12, 7, 4, 1, 2, 9, 10)) assert props(s) == {s.is_permutation, s.is_balanced, s.is_affine} s = SBox2([1] * 16) assert props(s) == {s.is_affine, s.is_constant} s = SBox2([0] * 16) assert props(s) == { s.is_affine, s.is_constant, s.is_linear, s.is_zero, s.is_balanced } s = SBox2([0] * 15 + [1]) assert props(s) == set() s = SBox2(range(16)) assert props(s) == { s.is_identity, s.is_permutation, s.is_balanced, s.is_involution, s.is_affine, s.is_linear, } s = SBox2([0] * 8 + [1] * 8) assert props(s) == {s.is_balanced, s.is_affine, s.is_linear} s = SBox2([1] * 8 + [0] * 8) assert props(s) == {s.is_balanced, s.is_affine} s = SBox2(list(range(8, 16)) + list(range(8))) assert props(s) == { s.is_balanced, s.is_permutation, s.is_involution, s.is_affine, }
def make_transition(self, exp2, log2): large_to_double = [0, 1] for x in xrange(2, 2**self.N): l = self.log1[x] y = exp2[l] large_to_double.append(y) large_to_double = SBox2(large_to_double) return large_to_double
def parallel(funcs): input_sizes = [f.input_size() for f in funcs] output_sizes = [f.output_size() for f in funcs] s = [] for xs in ranges(list=[2**w for w in input_sizes]): fully = 0 for f, x, w in zip(funcs, xs, output_sizes): fully = (fully << w) | f(x) s.append(fully) return SBox2(s, m=sum(output_sizes))
def test_main(): from cry.sbox2 import SBox2 s = SBox2([3, 4, 7, 2, 1, 1, 6, 6], m=4) assert s.n == s.input_size() == 3 assert s.m == s.output_size() == 4 assert len(s) == 8 assert list(s.input_range()) == list(range(8)) assert list(s.output_range()) == list(range(16)) assert list(s.graph()) == [(0, 3), (1, 4), (2, 7), (3, 2), (4, 1), (5, 1), (6, 6), (7, 6)] assert s.as_hex(sep=":") == "3:4:7:2:1:1:6:6" assert s.as_hex(sep="") == "34721166" ss = SBox2([3, 4, 7, 2, 1, 1, 6, 6]) assert s != ss assert s == ss.resize(4) ss = SBox2([3, 4, 7, 2, 1, 1, 6, 6], 4) assert s == ss ss = SBox2([2, 4, 7, 2, 1, 1, 6, 6], 4) assert s != ss assert s == [3, 4, 7, 2, 1, 1, 6, 6] assert s == (3, 4, 7, 2, 1, 1, 6, 6) assert s != (2, 4, 7, 2, 1, 1, 6, 6) assert hash(s) != 0 assert s ^ 1 == s ^ 1 == s ^ Integer(1) == s ^ SBox2([1] * 8, m=4) \ == (2, 5, 6, 3, 0, 0, 7, 7) assert s ^ s == [0] * 8 assert s[0] == s(0) == s[0, 0, 0] == 3 assert s[3] == s(3) == s[0, 1, 1] == 2 assert s[7] == s(7) == s[1, 1, 1] == 6 assert tuple(s)[1:3] == (4, 7) assert tuple(s)[-3:] == (1, 6, 6)
def try_good(): A = SBox2.new.random_linear_permutation(N) B = SBox2.new.random_linear_permutation(N) s1 = gen() s2 = B * s1 * A At, Bt = SBox2.are_linear_equivalent(s1, s2) assert Bt * s1 * At == s2 assert At.is_linear() assert Bt.is_linear() assert At.is_permutation() assert Bt.is_permutation()
def feistel_round_xor(func, swap=False): func = SBox2(func) n = func.in_bits res = [] for al in range(2**n): for ar in range(2**n): l, r = al, ar l ^= func(r) if swap: l, r = r, l res.append((l << n) | r) return res
def random_function_of_degree( n, m, d, zero_zero=False, force_all_maxterms=False ): anf = [0] * m mindeg = 1 if zero_zero else 0 for deg in range(mindeg, d + 1): for mask in hamming_masks(m, deg): for out_bit in range(m): take = int(randint(0, 1) or (force_all_maxterms and deg == d)) anf[mask] = (anf[mask] << 1) | take return SBox2(anf, m=m).mobius()
def feistel_round_add(func, swap=False): func = SBox2.new(func) n = func.in_bits mask = (1 << n) - 1 res = [] for al in range(2**n): for ar in range(2**n): l, r = al, ar l = (l + func(r)) & mask if swap: l, r = r, l res.append((l << n) | r) return res
def from_matrix(mat): s = [] for x in range(2**mat.ncols()): s.append(matrix_mult_int(mat, x)) return SBox2(s, m=mat.nrows())
def power(e, n=None, field=None): assert (n is not None) ^ (field is not None) field = field or GF(2**n, name='a') x = PolynomialRing(field, names='x').gen() return SBox2(x**e)
def id(n): return SBox2(range(2**n))
def const(c, n): return SBox2([c] * 2**n)
def swap(h): s = [] for l, r in ranges(2**h, 2**h): s.append((r << h) | l) return SBox2(s)
def test_transform(): s = SBox2([5, 6, 3, 2, 1, 7, 0, 4]) assert s.xor(0, 3) == s ^ 3 assert s.mobius().mobius() == s
def try_bad(): s1 = gen() s2 = gen() res = SBox2.are_linear_equivalent(s1, s2) assert res is False
def random_affine_permutation(n): xor = randint(0, 2**n - 1) return SBox2(y ^ xor for y in from_matrix(random_invertible_matrix(n)))
def random_affine(*args): lin = random_linear(*args) xor = randint(0, max(lin)) return SBox2(y ^ xor for y in lin)
def random_function(n, m=None, zero_zero=False): m = m or n s = [randint(0, 2**m - 1) for i in range(2**n)] if zero_zero: s[0] = 0 return SBox2(s, m=m)