Пример #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 XDF
            >>> x, y = DiffVar("x", 16), DiffVar("y", 16)
            >>> d = XDF(x, y)
            >>> d.weight()  # doctest: +ELLIPSIS
            Ite(0xffff == x, 0b01111, ((0x00ff & ((0x0f0f & ((0x3333 ...
            >>> zero = Constant(0, 16)
            >>> d.weight().xreplace({x: zero, y: zero})
            0b00000

        """
        a, b = self.op.a, self.op.b
        n = self.input_diff[0].width

        alpha = self.input_diff[0]
        BvRol = RotateLeft
        varibits = BvRol(alpha, a) | BvRol(alpha, b)
        doublebits = BvRol(alpha, b) & (~BvRol(alpha, a)) & BvRol(
            alpha, 2 * a - b)

        hw = _HammingWeight(varibits ^ doublebits)
        width = max((n - 1).bit_length(), hw.width)

        value = Ite(BvComp(alpha, ~Constant(0, n)), Constant(n - 1, width),
                    ZeroExtend(hw, width - hw.width))

        return value
Пример #2
0
    def test(cls):
        old_rounds = cls.rounds

        cls.set_rounds(1)
        pt = [Constant(0x00000000, 16)] * (N * 4)
        ct = (0xe9f5, 0xcfab, 0x5198, 0x9eec,
              0xcb81, 0x7fb0, 0xd47a, 0x45b7,
              0xa5b5, 0xd8da, 0x2cc5, 0x0aa1,
              0x7bc9, 0x97f0, 0xc515, 0x7224)
        assert cls(*pt) == tuple(ct), "{}".format(cls(*pt))

        cls.set_rounds(2)
        pt = [Constant(0x00000000, 16)] * (N * 4)
        ct = (0x4d2f, 0x383a, 0xa84d, 0xe12c,
              0xee36, 0x2b82, 0xb624, 0x1e15,
              0x39f9, 0x2ded, 0x54c3, 0x15c9,
              0x58fe, 0xbff0, 0x44ad, 0x2b57)
        assert cls(*pt) == tuple(ct), "{}".format(cls(*pt))

        cls.set_rounds(6)
        pt = [Constant(0x00000000, 16)] * (N * 4)
        ct = (0x0274, 0x2a3d, 0x9d5e, 0x0319,
              0x32b4, 0x2751, 0x745b, 0xa328,
              0xd2d4, 0x1ae9, 0x8e70, 0x0fe6,
              0x9506, 0xe58d, 0x996b, 0x6075)
        assert cls(*pt) == tuple(ct), "{}".format(cls(*pt))

        cls.set_rounds(old_rounds)
Пример #3
0
    def eval(cls, *W):  # w0, w1, ...
        rk = list(W)

        for i in range(N, 16):
            rk.append(Constant(0, 32))

        sigma0 = lambda x: ROR(x, 7) ^ ROR(x, 18) ^ (x >> Constant(3, 32))
        sigma1 = lambda x: ROR(x, 17) ^ ROR(x, 19) ^ (x >> Constant(10, 32))

        for i in range(16, cls.rounds):
            rk.append(sigma1(rk[i-2]) + rk[i-7] + sigma0(rk[i-15]) + rk[i-16])

        if REFERENCE_VERSION:
            pass
        else:
            for i in range(cls.rounds):
                rk[i] += k_ctes[i]

        for i in range(cls.rounds):
            if hasattr(cls, "skip_rounds") and i in cls.skip_rounds:
                if i < N:
                    rk[i] = W[0]
                elif N <= i < 16:
                    pass  # rk[i] = 0
                else:
                    rk[i] = W[0]

        return rk[:N] + rk[16:cls.rounds]
Пример #4
0
    def test_bv_ch(self, x, y, x_, y_):
        input_diff_names = ["dx", "dy"]
        prefix = "d"

        x = Constant(x, 8)
        x_ = Constant(x_, 8)
        y = Constant(y, 8)
        y_ = Constant(y_, 8)

        for diff_type in [XorDiff, RXDiff]:
            ch = BvCharacteristic(MyFunction, diff_type, input_diff_names,
                                  prefix)
            input_diff = [
                diff_type.from_pair(x, x_),
                diff_type.from_pair(y, y_)
            ]
            # noinspection PyUnresolvedReferences
            output_diff = diff_type.from_pair(
                MyFunction(x, y)[0],
                MyFunction(x_, y_)[0])

            der = first_value(ch.nonlinear_diffs)
            der.input_diff[0].val = der.input_diff[0].val.xreplace(
                {diff_type(Variable("dx", 8)): input_diff[0]})
            der.input_diff[1].val = der.input_diff[1].val.xreplace(
                {diff_type(Variable("dx", 8)): input_diff[1]})
            self.assertTrue(der.is_possible(output_diff))
Пример #5
0
    def _count_preimages(cls, f, beta):
        width = f.input_diff[0].val.width

        if width == 8 and f.diff_type == XorDiff:
            foo = cls.libXDA.count_XOR_preimage_8bit
        elif width == 8 and f.diff_type == RXDiff:
            foo = cls.libRXDA.count_RX_preimage_8bit
        elif width == 16 and f.diff_type == RXDiff:
            foo = cls.libRXDA.count_RX_preimage_16bit
        else:
            foo = None

        if foo is not None:
            result = foo(f.input_diff[0].val, f.input_diff[1].val, beta.val)
            return int(result)
        else:
            num_preimages = 0
            # total_preimages = 0
            for i, j in itertools.product(range(2**width), range(2**width)):
                # total_preimages += 1
                output_diff = f.eval(Constant(i, width), Constant(j, width))
                assert isinstance(output_diff, Difference) and isinstance(
                    beta, Difference)
                if output_diff == beta:
                    num_preimages += 1
            return num_preimages
Пример #6
0
    def test_find_preimage(self, d1, d2, d3):
        assert DP_WIDTH == 8

        d1 = Constant(d1, DP_WIDTH)
        d2 = Constant(d2, DP_WIDTH)
        d3 = Constant(d3, DP_WIDTH)

        for diff_type, der_type in zip([XorDiff, RXDiff], [XDA, RXDA]):
            alpha = diff_type(d1), diff_type(d2)
            beta = diff_type(d3)
            f = der_type(alpha)

            msg = "{}({} -> {})\n".format(der_type.__name__, alpha, beta)

            if diff_type == XorDiff:
                foo = self.__class__.libXDA.find_XOR_preimage_8bit
            elif diff_type == RXDiff:
                foo = self.__class__.libRXDA.find_RX_preimage_8bit

            result_lib = foo(f.input_diff[0].val, f.input_diff[1].val,
                             beta.val)
            result_lib = result_lib.found

            result_loop = 0
            for i, j in itertools.product(range(2**DP_WIDTH),
                                          range(2**DP_WIDTH)):
                output_diff = f.eval(Constant(i, DP_WIDTH),
                                     Constant(j, DP_WIDTH))
                assert isinstance(output_diff, Difference) and isinstance(
                    beta, Difference)
                if output_diff == beta:
                    result_loop = 1
                    break

            self.assertEqual(result_lib, result_loop, msg=msg)
Пример #7
0
    def test_rx_linear_op(self, width, x1, y1, x2, y2):
        x1 = Constant(x1 % (2**width), width)
        y1 = Constant(y1 % (2**width), width)
        d1 = RXDiff.from_pair(x1, y1)
        x2 = Constant(x2 % (2**width), width)
        y2 = Constant(y2 % (2**width), width)
        d2 = RXDiff.from_pair(x2, y2)

        self.assertEqual(RXDiff.from_pair(~x1, ~y1),
                         RXDiff.derivative(BvNot, d1))

        self.assertEqual(RXDiff.from_pair(x1 ^ x2, y1 ^ y2),
                         RXDiff.derivative(BvXor, [d1, d2]))

        cte = x2
        BvXor_fix = make_partial_operation(BvXor, tuple([None, cte]))
        self.assertEqual(RXDiff.from_pair(x1 ^ cte, y1 ^ cte),
                         RXDiff.derivative(BvXor_fix, [d1]))

        cte = Variable("c", width)
        BvXor_fix = make_partial_operation(BvShl, tuple([None, cte]))
        with self.assertRaises(ValueError):
            XorDiff.derivative(BvXor_fix, d1)

        r = int(x2) % x1.width
        RotateLeft_fix = make_partial_operation(RotateLeft, tuple([None, r]))
        RotateRight_fix = make_partial_operation(RotateRight, tuple([None, r]))
        self.assertEqual(
            RXDiff.from_pair(RotateLeft(x1, r), RotateLeft(y1, r)),
            RXDiff.derivative(RotateLeft_fix, d1))
        self.assertEqual(
            RXDiff.from_pair(RotateRight(x1, r), RotateRight(y1, r)),
            RXDiff.derivative(RotateRight_fix, d1))
Пример #8
0
    def test_basic_simplify(self):
        x, y, z = Variable("x", 8), Variable("y", 8), Variable("z", 8)

        allones = Constant((2 ** 8) - 1, 8)
        notone = ~Constant(1, 8)

        # constants

        self.assertEqual(1 + (x + allones), x)
        self.assertEqual(1 ^ (x ^ 1), x)
        self.assertEqual(1 & (x & notone), 0)
        self.assertEqual(1 | (x | notone), allones)

        # compatible terms

        self.assertEqual(x + (y - x), y)
        self.assertEqual(x ^ (y ^ x), y)
        self.assertEqual(x & (y & x), x & y)
        self.assertEqual(x | (y | x), x | y)

        self.assertEqual((x ^ z) + (y - (x ^ z)), y)
        self.assertEqual((x + z) ^ (y ^ (x + z)), y)

        self.assertEqual((x + z) + (y - x), z + y)
        self.assertEqual((x ^ z) ^ (y ^ x), z ^ y)
        self.assertEqual((x & z) & (y & (~x)), 0)
        self.assertEqual((x | z) | (y | (~x)), allones)
Пример #9
0
    def _find_preimage(cls, f, beta):
        width = f.input_diff[0].val.width

        if width == 8 and f.diff_type == XorDiff:
            foo = cls.libXDA.find_XOR_preimage_8bit
        elif width == 8 and f.diff_type == RXDiff:
            foo = cls.libRXDA.find_RX_preimage_8bit
        elif width == 16 and f.diff_type == RXDiff:
            foo = cls.libRXDA.find_RX_preimage_16bit
        else:
            foo = None

        if foo is not None:
            result = foo(f.input_diff[0].val, f.input_diff[1].val, beta.val)
            if result.found:
                return result.i, result.j
            else:
                return None
        else:
            for i, j in itertools.product(range(2**width), range(2**width)):
                output_diff = f.eval(Constant(i, width), Constant(j, width))
                assert isinstance(output_diff, Difference) and isinstance(
                    beta, Difference)
                if output_diff == beta:
                    return i, j
            else:
                return None
Пример #10
0
    def has_probability_one(self, output_diff):
        """Return whether the input diff propagates to the output diff with probability one.

            >>> from arxpy.bitvector.core import Constant, Variable
            >>> from arxpy.differential.difference import XorDiff
            >>> alpha = XorDiff(Constant(0, 16))
            >>> f = XDSimonRF(alpha)
            >>> f.has_probability_one(XorDiff(Constant(0, 16)))
            0b1

        """
        a, b, c = self.op.a, self.op.b, self.op.c
        n = self.input_diff[0].val.width
        assert math.gcd(n, a - b) == 1 and a > b and n % 2 == 0

        alpha = self.input_diff[0].val
        Rol = RotateLeft
        varibits = Rol(alpha, a) | Rol(alpha, b)
        r = (2 * a - b) % n
        doublebits = (Rol(alpha, b) & (~Rol(alpha, a)) & Rol(alpha, r))

        beta = output_diff.val
        gamma = beta ^ Rol(alpha, c)

        case2 = BvComp(Constant(0, n), (gamma & (~varibits)) |
                       ((gamma ^ Rol(gamma, a - b)) & doublebits))

        hw = varibits ^ doublebits  # no need to PopCount

        condition = ~BvComp(alpha, ~Constant(0, n))
        condition &= case2
        condition &= BvComp(hw, Constant(0, hw.width))

        return condition
Пример #11
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}))
Пример #12
0
    def test_initialization(self):
        x = Constant(0, 8)

        self.assertTrue(x.is_Atom)
        self.assertEqual(x.atoms(), {x})

        with self.assertRaises(AttributeError):
            x.val = 0
Пример #13
0
    def eval(cls, x, y):
        v0 = x
        v1 = y
        k = cls.round_keys
        for i in range(cls.rounds):
            v0, v1 = v1, v0 + ((((v1 << Constant(4, 32)) ^ (v1 >> Constant(5, 32))) + v1) ^ k[i])

        return v0, v1
Пример #14
0
    def test_case(self, d1, d2, d3):
        # d1, d2 input differences; d3 output difference
        d1 = Constant(d1, DP_WIDTH)
        d2 = Constant(d2, DP_WIDTH)
        d3 = Constant(d3, DP_WIDTH)

        for diff_type, der_type in zip([XorDiff], [XDS]):
            alpha = diff_type(d1), diff_type(d2)
            beta = diff_type(d3)
            f = der_type(alpha)

            if VERBOSE:
                der_name = der_type.__name__
                print("{}({} -> {})".format(der_name, alpha, beta))

            is_valid = f.is_possible(beta)

            if VERBOSE:
                print("\tis_valid:", bool(is_valid))

            if is_valid:
                with Simplification(False):
                    num_preimages = self._count_preimages(f, beta)

                if VERBOSE:
                    print("\tpreimages found:", num_preimages)

                self.assertNotEqual(num_preimages, 0)

                total_preimages = 2**(2 * DP_WIDTH)

                emp_weight = -math.log(num_preimages / total_preimages, 2)

                theo_weight = f.weight(beta)  # .doit()
                self.assertLessEqual(theo_weight, f.max_weight())

                theo_weight = int(theo_weight)

                if VERBOSE:
                    print("\tempirical weight:\t", emp_weight)
                    print("\ttheoretical weight:\t", theo_weight)

                if diff_type == XorDiff:
                    error = 0
                else:
                    raise ValueError(
                        "invalid difference: {}".format(diff_type))

                self.assertGreaterEqual(emp_weight, theo_weight - error)
                self.assertLessEqual(emp_weight, theo_weight + error)
            else:
                with Simplification(False):
                    preimage = self._find_preimage(f, beta)

                if VERBOSE:
                    print("\tpreimage found:", preimage)

                self.assertIsNone(preimage)
Пример #15
0
    def test_xor_linear_op(self, width, x1, y1, x2, y2):
        x1 = Constant(x1 % (2**width), width)
        y1 = Constant(y1 % (2**width), width)
        d1 = XorDiff.from_pair(x1, y1)
        x2 = Constant(x2 % (2**width), width)
        y2 = Constant(y2 % (2**width), width)
        d2 = XorDiff.from_pair(x2, y2)

        self.assertEqual(XorDiff.from_pair(~x1, ~y1),
                         XorDiff.derivative(BvNot, d1))

        self.assertEqual(XorDiff.from_pair(x1 ^ x2, y1 ^ y2),
                         XorDiff.derivative(BvXor, [d1, d2]))

        cte = x2
        BvXor_fix = make_partial_operation(BvXor, tuple([None, cte]))
        self.assertEqual(XorDiff.from_pair(x1 ^ cte, y1 ^ cte),
                         XorDiff.derivative(BvXor_fix, [d1]))

        cte = Variable("c", width)
        BvXor_fix = make_partial_operation(BvXor, tuple([None, cte]))
        self.assertEqual(
            XorDiff.from_pair(x1 ^ cte, y1 ^ cte),
            XorDiff.derivative(BvXor, [d1, XorDiff.from_pair(cte, cte)]))
        self.assertEqual(XorDiff.from_pair(x1 ^ cte, y1 ^ cte),
                         XorDiff.derivative(BvXor_fix, [d1]))

        cte = x2
        BvAnd_fix = make_partial_operation(BvAnd, tuple([None, cte]))
        self.assertEqual(XorDiff.from_pair(x1 & cte, y1 & cte),
                         XorDiff.derivative(BvAnd_fix, [d1]))

        r = int(x2) % x1.width
        RotateLeft_fix = make_partial_operation(RotateLeft, tuple([None, r]))
        RotateRight_fix = make_partial_operation(RotateRight, tuple([None, r]))
        self.assertEqual(
            XorDiff.from_pair(RotateLeft(x1, r), RotateLeft(y1, r)),
            XorDiff.derivative(RotateLeft_fix, d1))
        self.assertEqual(
            XorDiff.from_pair(RotateRight(x1, r), RotateRight(y1, r)),
            XorDiff.derivative(RotateRight_fix, d1))

        r = Constant(int(x2) % x1.width, width)
        BvShl_fix = make_partial_operation(BvShl, tuple([None, r]))
        BvLshr_fix = make_partial_operation(BvLshr, tuple([None, r]))
        self.assertEqual(XorDiff.from_pair(x1 << r, y1 << r),
                         XorDiff.derivative(BvShl_fix, d1))
        self.assertEqual(XorDiff.from_pair(x1 >> r, y1 >> r),
                         XorDiff.derivative(BvLshr_fix, d1))

        i = int(x2) % x1.width
        j = int(y2) % (i + 1)
        Extract_fix = make_partial_operation(Extract, tuple([None, i, j]))
        self.assertEqual(XorDiff.from_pair(x1[i:j], y1[i:j]),
                         XorDiff.derivative(Extract_fix, d1))

        self.assertEqual(XorDiff.from_pair(Concat(x1, x2), Concat(y1, y2)),
                         XorDiff.derivative(Concat, [d1, d2]))
Пример #16
0
def get_constant(i):
    if i < 20:
        return Constant(0x5A827999, 32)
    elif i < 40:
        return Constant(0x6ED9EBA1, 32)
    elif i < 60:
        return Constant(0x8F1BBCDC, 32)
    else:
        return Constant(0xCA62C1D6, 32)
Пример #17
0
 def test_invalid_args(self):
     with self.assertRaises(AssertionError):
         Constant("1", 8)
     with self.assertRaises(AssertionError):
         Constant(0.5, 8)
     with self.assertRaises(AssertionError):
         Constant(-1, 8)
     with self.assertRaises(AssertionError):
         Constant(9, 2)
Пример #18
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)
Пример #19
0
 def eval(cls, *master_key):
     mk = list(master_key)
     s = Constant(0, 32)
     delta = Constant(0x9E3779B9, 32)
     k = []
     for i in range(cls.rounds):
         if i % 2 == 0:
             k.append(s + mk[int(s & Constant(3, 32))])
             s += delta
         else:
             k.append(s + mk[int((s >> Constant(11, 32)) & Constant(3, 32))])
     return k
Пример #20
0
    def _test_case(self, d1, d2, a, precision, version):
        d1 = Constant(d1, DP_WIDTH)
        d2 = Constant(d2, DP_WIDTH)
        a = Constant(a, DP_WIDTH)

        diff_type = XorDiff
        der_type = derivative.XDCA
        old_precision = der_type.precision
        der_type.precision = precision

        alpha = diff_type(d1)
        beta = diff_type(d2)
        f = der_type(alpha, a)

        der_repr = "{}_cte={}_prec={}_v={}({} -> {})\n".format(
            der_type.__name__, a, precision, version, alpha, beta)
        msg = der_repr

        is_valid = f.is_possible(beta)

        msg += "\tis_valid: {}\n".format(is_valid)

        real_weight = f.exact_weight(beta)

        msg += "\texact weight: {}\n".format(real_weight)

        self.assertEqual(is_valid, real_weight != math.inf, msg=msg)

        if is_valid:
            theo_weight = int(f.weight(beta, version=version))  # .doit())

            self.assertLessEqual(theo_weight, f.max_weight(), msg=msg)

            theo_weight /= 2**(f.num_frac_bits())

            msg += "\ttheo weight: {}\n".format(theo_weight)

            real_error = theo_weight - real_weight
            theo_error = f.error()

            if PRINT_MAX_ERROR and real_error > self.__class__.max_error[0]:
                self.__class__.max_error = [real_error, der_repr]

            msg += "\treal_error: {}\n".format(round(real_error, ERROR_DIGITS))
            msg += "\ttheo_error: {}\n".format(round(theo_error, ERROR_DIGITS))

            if PRINT_DISTR_ERROR:
                self.distr_error[round(real_error, ERROR_DIGITS)] += 1

            self.assertGreaterEqual(real_error, 0, msg=msg)
            self.assertLessEqual(real_error, theo_error, msg=msg)

        der_type.precision = old_precision
Пример #21
0
    def test_pysmt_operations(self, width, x, y):
        try:
            from pysmt import shortcuts as sc
        except ImportError:
            return

        modulus = 2 ** width
        x = x % modulus
        y = y % modulus
        bvx = Constant(x, width)
        bvy = Constant(y, width)
        psx = sc.BV(x, width)
        psy = sc.BV(y, width)

        def eval_pysmt(pysmt_var):
            return pysmt_var.simplify().constant_value()

        self.assertEqual(~bvx, eval_pysmt(sc.BVNot(psx)))
        self.assertEqual(bvx & bvy, eval_pysmt(sc.BVAnd(psx, psy)))
        self.assertEqual(bvx | bvy, eval_pysmt(sc.BVOr(psx, psy)))
        self.assertEqual(bvx ^ bvy, eval_pysmt(sc.BVXor(psx, psy)))

        self.assertEqual(BvComp(bvx, bvy), eval_pysmt(sc.BVComp(psx, psy)))
        self.assertEqual((bvx < bvy), eval_pysmt(sc.BVULT(psx, psy)))
        self.assertEqual((bvx <= bvy), eval_pysmt(sc.BVULE(psx, psy)))
        self.assertEqual((bvx > bvy), eval_pysmt(sc.BVUGT(psx, psy)))
        self.assertEqual((bvx >= bvy), eval_pysmt(sc.BVUGE(psx, psy)))

        r = y % bvx.width
        self.assertEqual(bvx << bvy, eval_pysmt(sc.BVLShl(psx, psy)))
        self.assertEqual(bvx >> bvy, eval_pysmt(sc.BVLShr(psx, psy)))
        self.assertEqual(RotateLeft(bvx, r), eval_pysmt(sc.BVRol(psx, r)))
        self.assertEqual(RotateRight(bvx, r), eval_pysmt(sc.BVRor(psx, r)))

        bvb = Constant(y % 2, 1)
        psb = sc.Bool(bool(bvb))
        self.assertEqual(Ite(bvb, bvx, bvy), eval_pysmt(sc.Ite(psb, psx, psy)))
        j = y % bvx.width
        self.assertEqual(bvx[:j], eval_pysmt(sc.BVExtract(psx, start=j)))
        self.assertEqual(bvx[j:], eval_pysmt(sc.BVExtract(psx, end=j)))
        self.assertEqual(Concat(bvx, bvy), eval_pysmt(sc.BVConcat(psx, psy)))
        self.assertEqual(ZeroExtend(bvx, j), eval_pysmt(sc.BVZExt(psx, j)))
        self.assertEqual(Repeat(bvx, 1 + j), eval_pysmt(psx.BVRepeat(1 + j)))

        self.assertEqual(-bvx, eval_pysmt(sc.BVNeg(psx)))
        self.assertEqual(bvx + bvy, eval_pysmt(sc.BVAdd(psx, psy)))
        self.assertEqual(bvx - bvy, eval_pysmt(sc.BVSub(psx, psy)))
        self.assertEqual(bvx * bvy, eval_pysmt(sc.BVMul(psx, psy)))
        if bvy > 0:
            self.assertEqual(bvx / bvy, eval_pysmt(sc.BVUDiv(psx, psy)))
            self.assertEqual(bvx % bvy, eval_pysmt(sc.BVURem(psx, psy)))
Пример #22
0
    def eval(cls, x, y):
        v0 = x
        v1 = y
        k = cls.round_keys
        cls.round_inputs = []
        for i in range(cls.rounds):
            cls.round_inputs.append([v0, v1])
            if hasattr(cls, "skip_rounds") and i in cls.skip_rounds:
                continue
            v0, v1 = v1, v0 + ((((v1 << Constant(4, 32)) ^
                                 (v1 >> Constant(5, 32))) + v1) ^ k[i])
        cls.round_inputs.append([v0, v1])

        return v0, v1
Пример #23
0
    def is_possible(self, output_diff):
        """Return whether the given output `XorDiff` is possible.

            >>> from arxpy.bitvector.core import Constant, Variable
            >>> from arxpy.bitvector.context import NotEvaluation
            >>> from arxpy.bitvector.printing import BvWrapPrinter
            >>> from arxpy.differential.difference import XorDiff
            >>> alpha = XorDiff(Constant(0, 16))
            >>> f = XDSimonRF(alpha)
            >>> f.is_possible(XorDiff(Constant(0, 16)))
            0b1
            >>> u, v = Variable("u", 16), Variable("v", 16)
            >>> f = XDSimonRF(XorDiff(u))
            >>> with NotEvaluation([PopCount]):
            ...     result = f.is_possible(XorDiff(v))
            >>> print(BvWrapPrinter().doprint(result))
            Ite(0xffff == u,
                0b0 == (PopCount(v ^ (u <<< 2))[0]),
                ==(0x0000,
                   |(~(u <<< 8) & (u <<< 1) & (u <<< 15) & (v ^ (u <<< 2) ^ ((v ^ (u <<< 2)) <<< 7)),
                     ~((u <<< 1) | (u <<< 8)) & (v ^ (u <<< 2))
            >>> result.xreplace({u: Constant(0, 16), v: Constant(0, 16)})
            0b1

        See `Derivative.is_possible` for more information.
        """
        a, b, c = self.op.a, self.op.b, self.op.c
        n = self.input_diff[0].val.width
        assert math.gcd(n, a - b) == 1 and a > b and n % 2 == 0

        alpha = self.input_diff[0].val
        Rol = RotateLeft
        varibits = Rol(alpha, a) | Rol(alpha, b)
        r = (2 * a - b) % n
        doublebits = (Rol(alpha, b) & (~Rol(alpha, a)) & Rol(alpha, r))

        beta = output_diff.val
        gamma = beta ^ Rol(alpha, c)

        def is_even(x):
            return BvComp(x[0], Constant(0, 1))

        case2 = BvComp(Constant(0, n), (gamma & (~varibits)) |
                       ((gamma ^ Rol(gamma, a - b)) & doublebits))

        condition = Ite(BvComp(alpha, ~Constant(0, n)),
                        is_even(PopCount(gamma)), case2)

        return condition
Пример #24
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)
Пример #25
0
    def round_function(cls, A, B, C, D, E, F, G, H, i):
        if i < N:
            W = cls.round_keys[i]
        elif N <= i < 16:
            if REFERENCE_VERSION:
                W = Constant(0, 32)
            else:
                W = k_ctes[i]
        else:
            W = cls.round_keys[i - (16 - N)]

        delta0 = lambda x: ROR(x, 2) ^ ROR(x, 13) ^ ROR(x, 22)
        delta1 = lambda x: ROR(x, 6) ^ ROR(x, 11) ^ ROR(x, 25)

        if REFERENCE_VERSION:
            T1 = H + delta1(E) + BvIf(E, F, G) + W + k_ctes[i]  # ref
        else:
            T1 = H + delta1(E) + BvIf(E, F, G) + W  # optimized
        T2 = delta0(A) + BvMaj(A, B, C)
        return [
            T1 + T2,
            A,
            B,
            C,
            D + T1,
            E,
            F,
            G
        ]
Пример #26
0
    def eval(cls, *W):  # w0, w1, ...
        rk = list(W)

        for i in range(N, 16):
            rk.append(Constant(0, 32))

        for i in range(16, cls.rounds):
            rk.append(ROL(rk[i - 3] ^ rk[i - 8] ^ rk[i - 14] ^ rk[i - 16], 1))

        if REFERENCE_VERSION:
            pass
        else:
            for i in range(cls.rounds):
                rk[i] += get_constant(i)

        for i in range(cls.rounds):
            if hasattr(cls, "skip_rounds") and i in cls.skip_rounds:
                if i < N:
                    rk[i] = W[0]
                elif N <= i < 16:
                    pass  # rk[i] = 0
                else:
                    rk[i] = W[0]

        return rk[:N] + rk[16:cls.rounds]
Пример #27
0
    def eval(cls, KL0, KL1, KL2, KL3, KL4, KL5, KL6, KL7, KR0, KR1, KR2, KR3,
             KR4, KR5, KR6, KR7):
        KL = [KL0, KL1, KL2, KL3, KL4, KL5, KL6, KL7]
        KR = [KR0, KR1, KR2, KR3, KR4, KR5, KR6, KR7]
        KR1, KR2 = KR[:4], KR[4:]
        Q = []
        for r in range(cls.rounds // 2 + 4):
            if (r + 1) % 3 == 1:
                Q.append(xor(KR1, KR2))
            elif (r + 1) % 3 == 2:
                Q.append(KR1)
            elif (r + 1) % 3 == 0:
                Q.append(KR2)

        A = KL[:4]
        B = KL[4:]
        D = [Constant(0, 8) for _ in range(4)]
        K = []
        for r in range(cls.rounds // 2 + 4):
            D, A, B = A, B, cls.fk(*A, *xor(B, xor(D, Q[r])))
            K.extend(B)

        if cls.rounds % 2 != 0:
            if cls.rounds % 3 == 1:
                Qr = xor(KR1, KR2)
            elif cls.rounds % 3 == 2:
                Qr = KR1
            else:
                assert cls.rounds % 3 == 0
                Qr = KR2
            D, A, B = A, B, cls.fk(*A, *xor(B, xor(D, Qr)))
            K.extend(B[:2])

        return K
Пример #28
0
def pi2(R, k_i):
    if REFERENCE_VERSION:
        x = RotateLeft(R + k_i, 1) + (R + k_i) + (-Constant(1, 32))
    else:
        assert isinstance(k_i, list)
        x = RotateLeft(R + k_i[0], 1) + (R + k_i[1])
    return RotateLeft(x, 4) ^ x
Пример #29
0
def pi4(R, k_i):
    if REFERENCE_VERSION:
        x = RotateLeft(R + k_i, 2) + (R + k_i) + Constant(1, 32)
    else:
        assert isinstance(k_i, list)
        x = RotateLeft(R + k_i[0], 2) + (R + k_i[1])
    return x
Пример #30
0
    def round_function(cls, A, B, C, D, E, i):
        if i < N:
            W = cls.round_keys[i]
        elif N <= i < 16:
            if REFERENCE_VERSION:
                W = Constant(0, 32)
            else:
                W = get_constant(i)
        else:
            W = cls.round_keys[i - (16 - N)]

        if i < 20:
            F = BvIf
        elif i < 40:
            F = lambda x, y, z: x ^ y ^ z
        elif i < 60:
            F = BvMaj
        else:
            F = lambda x, y, z: x ^ y ^ z
        return [
            W + ROL(A, 5) + F(B, C, D) + E +
            get_constant(i) if REFERENCE_VERSION else W + ROL(A, 5) +
            F(B, C, D) + E, A,
            ROL(B, 30), C, D
        ]