Ejemplo n.º 1
0
    def weight(self):
        """Return the weight of the differential.

            >>> from arxpy.bitvector.core import Constant
            >>> from arxpy.diffcrypt.difference import DiffVar
            >>> from arxpy.ciphers.simon32_64 import RXDF
            >>> x, y = DiffVar("x", 16), DiffVar("y", 16)
            >>> d = RXDF(x, y)
            >>> d.weight()  # doctest: +ELLIPSIS
            Ite(0xffff == (x <<< 1), 0b01111, ((0x00ff & ((0x0f0f & ((0x3333 ...
            >>> zero = Constant(0, 16)
            >>> d.weight().xreplace({x: zero, y: zero})
            0b00000

        """
        width = self.input_diff[0].width
        x = DiffVar("x", width)
        y = DiffVar("y", width)

        return self.op.differential(XorDiff)(x, y).weight().xreplace({
            x:
            RotateLeft(self.input_diff[0], 1),
            y:
            RotateLeft(self.output_diff, 1)
        })
Ejemplo n.º 2
0
    def is_valid(self):
        """Return the bv expression for non-zero propagation probability.

            >>> from arxpy.bitvector.core import Constant
            >>> from arxpy.diffcrypt.difference import DiffVar
            >>> from arxpy.ciphers.simon32_64 import RXDF
            >>> x, y = DiffVar("x", 16), DiffVar("y", 16)
            >>> d = RXDF(x, y)
            >>> d.is_valid()  # doctest: +ELLIPSIS
            Ite(0xffff == (x <<< 1), 0b0 == (((0x00ff & ((0x0f0f & ((0x3333 ...
            >>> zero = Constant(0, 16)
            >>> d.is_valid().xreplace({x: zero, y: zero})
            0b1

        """
        width = self.input_diff[0].width
        x = DiffVar("x", width)
        y = DiffVar("y", width)

        return self.op.differential(XorDiff)(x, y).is_valid().xreplace({
            x:
            RotateLeft(self.input_diff[0], 1),
            y:
            RotateLeft(self.output_diff, 1)
        })
Ejemplo n.º 3
0
    def test_rx_deterministic_propagation(self, width, x1, y1, x2, y2):
        x1 = Constant(x1 % (2**width), width)
        y1 = Constant(y1 % (2**width), width)
        d1 = RXDiff.get_difference(x1, y1)
        x2 = Constant(x2 % (2**width), width)
        y2 = Constant(y2 % (2**width), width)
        d2 = RXDiff.get_difference(x2, y2)
        vd1 = DiffVar("in1", width)
        vd2 = DiffVar("in2", width)

        d3 = RXDiff.get_difference(~x1, ~y1)
        vd3 = RXDiff.propagate(BvNot, vd1)
        self.assertEqual(d3, vd3.xreplace({vd1: d1}))

        d3 = RXDiff.get_difference(x1 ^ x2, y1 ^ y2)
        vd3 = RXDiff.propagate(BvXor, [vd1, vd2])
        self.assertEqual(d3, vd3.xreplace({vd1: d1, vd2: d2}))

        d3 = RXDiff.get_difference(x1 ^ x2, y1 ^ x2)  # Xor with a constant
        vd3 = RXDiff.propagate(BvXor, [vd1, x2])
        self.assertEqual(d3, vd3.xreplace({vd1: d1}))

        r = int(x2) % x1.width
        d3 = RXDiff.get_difference(RotateLeft(x1, r), RotateLeft(y1, r))
        vd3 = RXDiff.propagate(RotateLeft, [vd1, r])
        self.assertEqual(d3, vd3.xreplace({vd1: d1}))

        d3 = RXDiff.get_difference(RotateRight(x1, r), RotateRight(y1, r))
        vd3 = RXDiff.propagate(RotateRight, [vd1, r])
        self.assertEqual(d3, vd3.xreplace({vd1: d1}))
Ejemplo n.º 4
0
    def test_f(self, din, dout):
        width = DP_WIDTH
        din, dout = Constant(din, width), Constant(dout, width)
        sin, sout = DiffVar("sin", width), DiffVar("sout", width)

        for differential_type in [
                ciphers.simon32_64.F.differential(XorDiff),
                ciphers.simon32_64.F.differential(RXDiff),
                ciphers.simeck32_64.F.differential(XorDiff),
                ciphers.simeck32_64.F.differential(RXDiff)
        ]:
            dbvadd = differential_type(sin, sout)
            is_valid = dbvadd.is_valid().xreplace({sin: din, sout: dout})

            print("{}({} -> {})".format(differential_type.__name__, din, dout))

            if is_valid:
                with Validation(False), Simplification(False):
                    correct, total = self._count_correct_pairs(
                        dbvadd, din, dout)

                msg = ("{}({} -> {}) is VALID but no correct pairs were found"
                       ).format(differential_type.__name__, din, dout)

                self.assertNotEqual(correct, 0, msg=msg)

                emp_weight = -math.log(correct / total, 2)
                emp_weight = dbvadd.weight_function(emp_weight)

                w = dbvadd.weight()
                theo_weight = int(w.xreplace({sin: din, sout: dout}))
                max_weight = 2**(w.width) - 1

                error = max_weight * 0.10

                msg = ("{}({} -> {})  has theoretical weight {} "
                       "but empirical weight {:.2f}").format(
                           differential_type.__name__, din, dout, theo_weight,
                           emp_weight)

                self.assertGreaterEqual(emp_weight,
                                        theo_weight - error,
                                        msg=msg)
                self.assertLessEqual(emp_weight, theo_weight + error, msg=msg)
            else:
                with Validation(False), Simplification(False):
                    pairs = self._find_correct_pair(dbvadd, din, dout)

                msg = (
                    "{}({} -> {}) is INVALID but the correct pair {} was found"
                ).format(differential_type.__name__, din, dout, pairs)

                self.assertIsNone(pairs, msg=msg)
Ejemplo n.º 5
0
    def test_bvadd(self, d1, d2, d3):
        width = DP_WIDTH
        d1, d2, d3 = Constant(d1, width), Constant(d2, width), Constant(d3, width)
        s1, s2, s3 = DiffVar("s1", width), DiffVar("s2", width), DiffVar("s3", width)

        # TODO: perform exhaustive test
        for differential_type in [RXDBvAdd]:  # XDBvAdd
            dbvadd = differential_type([s1, s2], s3)
            is_valid = dbvadd.is_valid().xreplace({s1: d1, s2: d2, s3: d3})

            print("{}({},{} -> {})".format(differential_type.__name__, d1, d2, d3))

            if is_valid:
                with Validation(False), Simplification(False):
                    correct, total = self._count_correct_pairs(dbvadd, d1, d2, d3)

                msg = (
                    "{}({},{} -> {}) is VALID but no correct pairs were found"
                ).format(differential_type.__name__, d1, d2, d3)

                self.assertNotEqual(correct, 0, msg=msg)

                emp_weight = - math.log(correct / total, 2)
                emp_weight = dbvadd.weight_function(emp_weight)

                w = dbvadd.weight()
                theo_weight = int(w.xreplace({s1: d1, s2: d2, s3: d3}))
                max_weight = 2 ** (w.width) - 1

                error = max_weight * 0.10

                msg = (
                    "{}({},{} -> {})  has theoretical weight {} "
                    "but empirical weight {:.2f}"
                ).format(differential_type.__name__, d1, d2, d3,
                         theo_weight, emp_weight)

                self.assertGreaterEqual(emp_weight, theo_weight - error, msg=msg)
                self.assertLessEqual(emp_weight, theo_weight + error, msg=msg)
            else:
                with Validation(False), Simplification(False):
                    pairs = self._find_correct_pair(dbvadd, d1, d2, d3)

                msg = (
                    "{}({},{} -> {}) is INVALID but the correct pair {} was found"
                ).format(differential_type.__name__, d1, d2, d3, pairs)

                self.assertIsNone(pairs, msg=msg)
Ejemplo n.º 6
0
    def test_manual_search(self):
        for bc, default_rounds in zip(block_ciphers, self.default_rounds):
            for diff_type in [XorDiff, RXDiff]:
                for rounds in range(1, MAX_ROUNDS):
                    bc.set_rounds(rounds)

                    input_diff = bc._symbolic_input("p", "k")
                    input_diff = [DiffVar.from_Variable(d) for d in input_diff]

                    ch = CompositeCh(bc, diff_type, input_diff)

                    for outer_target_weight in range(0, MAX_INNER_WEIGHT):
                        target_weight = [MAX_INNER_WEIGHT, outer_target_weight]

                        smt_problem = CompositeSmtProblem(ch, target_weight)

                        msg = (
                            "\nSearching optimal {} characteristic of "
                            "{}-round {} with target weight {}"
                            "\nFormula sizes: {}, {} \n{} \n{} \n{}").format(
                                diff_type.__name__, rounds, bc.__name__,
                                target_weight, smt_problem.formula_size,
                                smt_problem.pysmt_formula_size, ch.inner_ch,
                                ch.outer_ch, smt_problem)
                        if EXTRA_VERBOSE:
                            print(msg)

                        if not smt_problem.solve():
                            continue

                        inner_assig, outer_assig = smt_problem.solve(
                            get_assignment=True)

                        for assig, iter_ch in zip(
                            [inner_assig, outer_assig],
                            [ch.inner_ch, ch.outer_ch],
                        ):
                            tw = assig["weight"]
                            iter_func = iter_ch.func
                            error = sum(iter_func.input_widths) * 0.10
                            ew = iter_ch.empirical_weight(
                                list(assig["differences"].values()), False, tw)

                            msg = (
                                "{}-round {}-{} {} ch. with target weight {} "
                                "has (emp_weight, theo_weight) = ({:.2f}, {}) "
                            ).format(iter_func.rounds, iter_func.__name__,
                                     bc.__name__, diff_type.__name__,
                                     target_weight, ew, tw)

                            if VERBOSE:
                                print(msg)

                            if EXTRA_VERBOSE:
                                print(assig)

                            self.assertGreaterEqual(ew, tw - error, msg=msg)
                            self.assertLessEqual(ew, tw + error, msg=msg)

                        break

            bc.set_rounds(default_rounds)