Beispiel #1
0
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)
    )
Beispiel #2
0
 def swap_halves(self, input=True, output=True):
     if input:
         fx = lambda x: Bin(x, self.input_size()).swap_halves().int
     else:
         fx = lambda x: x
     if output:
         fy = lambda y: Bin(y, self.output_size()).swap_halves().int
     else:
         fy = lambda y: y
     return self.transform_graph(lambda x, y: (fx(x), fy(y)))
Beispiel #3
0
def int_tuple_list_vector(v):
    if isinstance(v, int):
        return v
    if isinstance(v, Integer):
        return int(v)
    if isinstance(v, tuple):
        return Bin(v).int
    if isinstance(v, list):
        return Bin(v).int
    if is_Vector(v):
        return Bin(tuple(v)).int
    raise TypeError("%r is not tuple, list, vector or integer")
Beispiel #4
0
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), Bin(x, n).tuple[::-1])
    y = mat * x
    return Bin(y[::-1]).int
Beispiel #5
0
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), Bin(x, n).tuple)
    y = mat * x
    return Bin(y).int
Beispiel #6
0
    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)
Beispiel #7
0
    def propagate_single_permutation(self, pos):
        outs_by_consts = [defaultdict(dict) for _ in range(self.num_out)]
        for x, y in self.s.graph():
            xs = Bin(x, self.num_in * self.width_in).split(parts=self.num_in)
            ys = Bin(y,
                     self.num_out * self.width_out).split(parts=self.num_out)
            key = tuple(xs[i] for i in range(self.num_in) if i != pos)
            for j, y in enumerate(ys):
                d = outs_by_consts[j][key]
                d.setdefault(y, 0)
                d[y] += 1

        out_prop = []
        for j in range(self.num_out):
            has_const = False
            has_perm = False
            has_balanced = False
            has_unknown = False
            for key, d in outs_by_consts[j].items():
                if self.width_in == self.width_out and\
                   len(d) == 2**self.width_in:
                    has_perm = True
                    continue
                if len(d) == 1:
                    has_const = True
                    continue

                xorsum = 0
                for y, cnt in d.items():
                    if cnt & 1:
                        xorsum ^= y
                if xorsum == 0:
                    has_balanced = True
                else:
                    has_unknown = True
                    break

            if has_unknown:
                result = UNKNOWN
            elif has_balanced:
                result = BALANCED
            elif has_const and not has_perm:
                result = CONST
            elif has_perm and not has_const:
                result = PERM
            else:
                assert False
            out_prop.append(result)
        return "".join(out_prop)
Beispiel #8
0
    def as_matrix(self):
        assert self.is_linear()

        m = matrix(GF(2), self.output_size(), self.input_size())
        for e in range(self.input_size()):
            vec = Bin(self[2**e], self.output_size()).tuple
            m.set_column(self.input_size() - 1 - e, vec)
        return m
Beispiel #9
0
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 = res.integer_representation()
        m.set_column(i, Bin(res, d).tuple)
    return m
Beispiel #10
0
 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 range(self.in_bits):
         mask = (1 << self.in_bits) - 1
         mask ^= 1 << (self.in_bits - 1 - j)
         res.set_column(j, Bin(anf[mask], self.out_bits).tuple)
     if right_to_left:
         res = res[::-1, ::-1]
     return res
Beispiel #11
0
 def anfs(self):
     names = ["x%d" % e for e in range(self.input_size())]
     bpr = BooleanPolynomialRing(names=names)
     vs = list((bpr.gens()))
     res = []
     for f in self.mobius().coordinates():
         anf = bpr(0)
         for mask, take in f.graph():
             if not take:
                 continue
             clause = bpr(1)
             for b, v in zip(Bin(mask, self.input_size()).tuple, vs):
                 if b:
                     clause *= v
             anf += clause
         res.append(anf)
     return res
Beispiel #12
0
 def decrypt(self, msg):
     msg = Bin(msg).int
     msg = power_mod(msg, self.d, self.n)
     return Bin(msg).bytes
Beispiel #13
0
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
        mat.set_column(i, Bin(func(x), n).tuple)
    return mat
Beispiel #14
0
 def component(self, mask):
     mask = int_tuple_list_vector(mask)
     tt = [Bin(y & mask).parity() for y in self]
     yield type(self)(tt, m=1)
Beispiel #15
0
 def squeeze_by_mask(self, mask):
     mask = int_tuple_list_vector(mask)
     assert mask in self.output_range()
     m = self.output_size()
     return type(self)([Bin(y, m).squeeze_by_mask(mask).int for y in self],
                       m=Bin(mask).hw)
Beispiel #16
0
 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)