コード例 #1
0
ファイル: types.py プロジェクト: ranea/ArxPy
def pysmt2bv(ps):
    """Convert a pySMT type to a bit-vector type.

    Currently, only conversion from `pysmt.shortcuts.BV`
    and `pysmt.shortcuts.Symbol` is supported.

        >>> from pysmt import shortcuts, typing  # pySMT shortcuts and typing modules
        >>> from arxpy.smt.types import pysmt2bv
        >>> env = shortcuts.reset_env()
        >>> pysmt2bv(env.formula_manager.Symbol("x", env.type_manager.BVType(8))).vrepr()
        "Variable('x', width=8)"
        >>> pysmt2bv(env.formula_manager.BV(1, 8)).vrepr()
        'Constant(0b00000001, width=8)'

    """
    class_name = type(ps).__name__
    msg = "unknown conversion of {} ({} {}) to a bit-vector type".format(
        ps, ps.get_type(), class_name)

    if ps.is_symbol():
        if str(ps.get_type()) == "Bool":
            return core.Variable(ps.symbol_name(), 1)
        else:
            return core.Variable(ps.symbol_name(), ps.bv_width())
    elif ps.is_bv_constant():
        return core.Constant(int(ps.constant_value()), ps.bv_width())
    elif ps.is_false():
        return core.Constant(0, 1)
    elif ps.is_true():
        return core.Constant(1, 1)
    else:
        raise NotImplementedError(msg)
コード例 #2
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x, y):
        def doit(x, y, width):
            """Modular subtraction when both operands are integers."""
            return (x - y) % (2**width)

        if isinstance(x, core.Constant) and isinstance(y, core.Constant):
            return core.Constant(doit(int(x), int(y), x.width), x.width)

        zero = core.Constant(0, x.width)

        if x == zero:
            return BvNeg(y)
        elif y == zero:
            return x
        elif x == y:
            return zero
        elif isinstance(x, BvAdd):  # (x0 + x1) - y
            if x.args[0] == y:
                return x.args[1]
            elif x.args[1] == y:
                return x.args[0]
        elif isinstance(y, BvAdd):  # x - (y0 + y1)
            if y.args[0] == x:
                return BvNeg(y.args[1])
            elif y.args[1] == x:
                return BvNeg(y.args[0])
コード例 #3
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x, y):
        zero = core.Constant(0, 1)
        one = core.Constant(1, 1)

        if x is y:
            return one
        elif isinstance(x, core.Constant) and isinstance(y, core.Constant):
            return one if x.val == y.val else zero
コード例 #4
0
    def eval(cls, x, y, z):
        # Source: Hacker's Delight

        if x.width < 4:
            # the HW of a 1-bit/2-bit vector requires 1-bit/2-bit (HW(0b1)=0b1, HW(0b11)=0b10)
            # thus, the sum of three HW of these sizes require an extra bit (3*0b1=0b11, 3*0b10=0b110)
            # the HW of a 3-bit vector requires 2-bit (Hw(0b111)=0b11)
            # but the sum of three HW of 3-bit require two extra bit (3*0b11 = 0b1001)
            offset = 1
            if x.width == 3:
                offset = 2
            x = operation.ZeroExtend(PopCount(x), offset)
            y = operation.ZeroExtend(PopCount(y), offset)
            z = operation.ZeroExtend(PopCount(z), offset)
            return x + y + z
        elif x.width > 32:
            width = cls.output_width(x, y, z)
            x = PopCount(x)
            x = operation.ZeroExtend(x, width - x.width)
            y = PopCount(y)
            y = operation.ZeroExtend(y, width - y.width)
            z = PopCount(z)
            z = operation.ZeroExtend(z, width - z.width)
            return x + y + z

        orig_x, orig_y, orig_z = x, y, z
        while (x.width & (x.width - 1)) != 0:
            x = operation.ZeroExtend(x, 1)
        while (y.width & (y.width - 1)) != 0:
            y = operation.ZeroExtend(y, 1)
        while (z.width & (z.width - 1)) != 0:
            z = operation.ZeroExtend(z, 1)
        width_log2 = x.width.bit_length() - 1

        m_ctes = []
        for i in range(width_log2):
            m_ctes.append(repeat_pattern(pattern01(2 ** i), x.width))

        bv = core.Constant(0, x.width)
        for i, m in enumerate(m_ctes):
            if i == 0:
                x = x - ((x >> core.Constant(1, bv.width)) & m)
                y = y - ((y >> core.Constant(1, bv.width)) & m)
                z = z - ((z >> core.Constant(1, bv.width)) & m)
                bv = x + y + z
            elif i == 1:
                x = (x & m) + ((x >> core.Constant(2 ** i, bv.width)) & m)  # generic case
                y = (y & m) + ((y >> core.Constant(2 ** i, bv.width)) & m)
                z = (z & m) + ((z >> core.Constant(2 ** i, bv.width)) & m)
                bv = x + y + z
            elif i == 2:
                bv = (bv & m) + ((bv >> core.Constant(4, bv.width)) & m)
            elif i == 3:
                bv = bv + (bv >> core.Constant(8, bv.width))
            elif i == 4:
                bv = bv + (bv >> core.Constant(16, bv.width))

        return bv[cls.output_width(orig_x, orig_y, orig_z) - 1:]
コード例 #5
0
    def is_possible(self, output_diff):
        """Return whether the given output `RXDiff` is possible.

            >>> from arxpy.bitvector.core import Constant, Variable
            >>> from arxpy.differential.difference import RXDiff
            >>> from arxpy.differential.derivative import RXDA
            >>> alpha = RXDiff(Constant(0, 4)), RXDiff(Constant(0, 4))
            >>> f = RXDA(alpha)
            >>> beta = RXDiff(Constant(0, 4))
            >>> f.is_possible(beta)
            0b1
            >>> a0, a1, b = Variable("a0", 4), Variable("a1", 4), Variable("b", 4)
            >>> alpha = RXDiff(a0), RXDiff(a1)
            >>> f = RXDA(alpha)
            >>> beta = RXDiff(b)
            >>> result = f.is_possible(beta)
            >>> result  # doctest:+NORMALIZE_WHITESPACE
            0b11 == (~(((((a0[:1]) ^ (a1[:1]) ^ (b[:1])) << 0b001) ^ (a0[:1]) ^ (a1[:1]) ^ (b[:1]))[:1]) |
            ((((a0[:1]) ^ (b[:1])) | ((a1[:1]) ^ (b[:1])))[1:]))
            >>> result.xreplace({a0: Constant(0, 4), a1: Constant(0, 4), b: Constant(0, 4)})
            0b1
            >>> a1 = Constant(0, 4)
            >>> alpha = RXDiff(a0), RXDiff(a1)
            >>> f = RXDA(alpha)
            >>> beta = RXDiff(b)
            >>> result = f.is_possible(beta)
            >>> result  # doctest:+NORMALIZE_WHITESPACE
            0b11 == (~(((((a0[:1]) ^ (b[:1])) << 0b001) ^ (a0[:1]) ^ (b[:1]))[:1])
            | ((((a0[:1]) ^ (b[:1])) | (b[:1]))[1:]))

        See `Derivative.is_possible` for more information.
        """
        # (I ^ SHL)(da ^ db ^ dc)[1:] <= SHL((da ^ dc) OR (db ^ dc))[1:]

        # one = core.Constant(1, self.input_diff[0].val.width)  # alt v1

        alpha, beta = [d.val for d in self.input_diff]
        gamma = output_diff.val
        # da, db, dc = alpha >> one, beta >> one, gamma >> one  # alt v1
        da, db, dc = alpha[:1], beta[:1], gamma[:1]  # ignore LSB

        one = core.Constant(1, da.width)

        # lhs = (da ^ db ^ dc) ^ ((da ^ db ^ dc) << one)  # alt v1
        # rhs = ((da ^ dc) | (db ^ dc)) << one
        lhs = ((da ^ db ^ dc) ^ ((da ^ db ^ dc) << one))[:1]
        rhs = (((da ^ dc) | (db ^ dc)) << one)[:1]

        def bitwise_implication(x, y):
            return (~x) | y

        # alt v1
        # n = lhs.width
        # return operation.BvComp(
        #     bitwise_implication(lhs[n - 2:1], rhs[n - 2:1]),  # ignore MSB, LSB
        #     ~ core.Constant(0, n - 2))
        return operation.BvComp(bitwise_implication(lhs, rhs), ~core.Constant(0, lhs.width))  # alt v1
コード例 #6
0
    def is_possible(self, output_diff):
        """Return whether the given output `XorDiff` is possible.

            >>> from arxpy.bitvector.core import Constant, Variable
            >>> from arxpy.differential.difference import XorDiff
            >>> from arxpy.differential.derivative import XDA
            >>> alpha = XorDiff(Constant(0, 4)), XorDiff(Constant(0, 4))
            >>> f = XDA(alpha)
            >>> beta = XorDiff(Constant(0, 4))
            >>> f.is_possible(beta)
            0b1
            >>> a0, a1, b = Variable("a0", 4), Variable("a1", 4), Variable("b", 4)
            >>> alpha = XorDiff(a0), XorDiff(a1)
            >>> f = XDA(alpha)
            >>> beta = XorDiff(b)
            >>> result = f.is_possible(beta)
            >>> result
            0x0 == ((~(a0 << 0x1) ^ (a1 << 0x1)) & (~(a0 << 0x1) ^ (b << 0x1)) & ((a0 << 0x1) ^ b ^ a0 ^ a1))
            >>> result.xreplace({a0: Constant(0, 4), a1: Constant(0, 4), b: Constant(0, 4)})
            0b1
            >>> a1 = Constant(0, 4)
            >>> alpha = XorDiff(a0), XorDiff(a1)
            >>> f = XDA(alpha)
            >>> beta = XorDiff(b)
            >>> result = f.is_possible(beta)
            >>> result
            0x0 == (~(a0 << 0x1) & ~(b << 0x1) & (a0 ^ b))

        See `Derivative.is_possible` for more information.
        """
        a, b = [d.val for d in self.input_diff]
        c = output_diff.val

        one = core.Constant(1, a.width)

        def eq(x, y, z):
            if not isinstance(x, core.Constant):
                if isinstance(y, core.Constant):
                    return eq(y, x, z)
                elif isinstance(z, core.Constant):
                    return eq(z, x, y)

            return (~x ^ y) & (~x ^ z)

        def xor_shift(x, y, z):
            if not isinstance(x, core.Constant):
                if isinstance(y, core.Constant):
                    return xor_shift(y, x, z)
                elif isinstance(z, core.Constant):
                    return xor_shift(z, x, y)

            return (x ^ y ^ z ^ (x << one))

        return operation.BvComp(
            eq(a << one, b << one, c << one) & xor_shift(a, b, c),
            core.Constant(0, a.width))
コード例 #7
0
    def _is_possible(self, output_diff, debug=False):
        u = self.input_diff[0].val
        v = output_diff.val
        a = self.op.constant
        n = a.width

        one = core.Constant(1, n)

        assert self._effective_width == n - 1

        def carry(x, y):
            # carry[i] = Maj(x[i-1], y[i-1], carry[i-1])
            return (x + y) ^ x ^ y

        # # S_0 well defined
        case11_ = (u << one) & (v << one)  # i-bit is True if S_i = 11*
        case00_ = (~(u << one)) & (~(v << one))  # i-bit is True if S_i = 00*
        case__1 = u ^ v
        a = a << one  # i-bit holds a[i-1]

        local_eq_a = ~(a ^ (a << one))  # i-bit is True if a[i-1] == a[i-2]
        case00_prev = case00_ << one  # i-bit is True if S_{i-1} = 00*

        c = carry(local_eq_a & case00_, (~case00_prev))

        case001 = case00_ & case__1
        bad_case11_ = case11_ & ~(case__1 ^ local_eq_a) & (c | ~case00_prev)

        bad_events = (case001 | bad_case11_)
        is_valid = operation.BvComp(bad_events, core.Constant(0, bad_events.width))

        if debug:
            print("\n\n ~~ ")
            print("u:           ", u.bin())
            print("v:           ", v.bin())
            print("a:           ", a.bin())
            print("case11_:     ", case11_.bin())
            print("case00_:     ", case00_.bin())
            print("case__1:     ", case__1.bin())
            print("case001:     ", case001.bin())
            print("case00_prev: ", case00_prev.bin())
            print("local_eq_a:  ", local_eq_a.bin())
            print("c:           ", c.bin())
            print("bad_case11_: ", bad_case11_.bin())
            print("bad_events:  ", bad_events.bin())
            print("is_valid    :", is_valid.bin())
            print("\n\n")

        return is_valid
コード例 #8
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x, y):
        def doit(x, y):
            """Remainder operation when both operands are int."""
            assert y != 0
            return x % y

        zero = core.Constant(0, x.width)
        one = core.Constant(1, x.width)

        assert y != zero

        if isinstance(x, core.Constant) and isinstance(y, core.Constant):
            return core.Constant(doit(int(x), int(y)), x.width)
        elif x == y or x == zero or y == one:
            return zero
コード例 #9
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
            >>> from arxpy.differential.derivative import XDA
            >>> alpha = XorDiff(Constant(0, 4)), XorDiff(Constant(0, 4))
            >>> f = XDA(alpha)
            >>> f.has_probability_one(XorDiff(Constant(0, 4)))
            0b1

        """
        is_possible = self.is_possible(output_diff)

        a, b = [d.val for d in self.input_diff]
        c = output_diff.val
        n = a.width

        def eq(x, y, z):
            if not isinstance(x, core.Constant):
                if isinstance(y, core.Constant):
                    return eq(y, x, z)
                elif isinstance(z, core.Constant):
                    return eq(z, x, y)

            return (~x ^ y) & (~x ^ z)

        # not optimized

        return is_possible & operation.BvComp(
            (~eq(a, b, c))[n-2:],
            core.Constant(0, n - 1)
        )
コード例 #10
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x, i, j):
        def doit(x, i, j):
            """Extract from x[i] down x[j] from a constant x."""
            bin_repr = x.bin()
            prefix, value = bin_repr[:2], bin_repr[2:]
            n = x.width
            value = value[n - 1 - i:n - j]  # e.g.: i=n-1, j=0
            return int(prefix + value, 2)

        if isinstance(x, core.Constant):
            return core.Constant(doit(x, i, j), cls.output_width(x, i, j))
        elif i == x.width - 1 and j == 0:
            return x
        elif isinstance(x, Extract):
            # x[3:1][2] = (x3 x2 x1)[2] = x3 = x[3]
            offset = x.args[2]
            return Extract(x.args[0], i + offset, j + offset)
        elif isinstance(x, Concat):
            if i <= x.args[1].width - 1:
                # 4-bit x, y: concat(x, y)[3:] = y[3:]
                return Extract(x.args[1], i, j)
            elif j >= x.args[1].width:
                # 4-bit x, y: concat(x, y)[:5] = x[:1]
                offset = x.args[1].width
                return Extract(x.args[0], i - offset, j - offset)
        elif isinstance(x, (BvShl, RotateLeft)) and \
                isinstance(x.args[1], (int, core.Constant)) and x.args[1] <= j:
            # (x << 1)[:2] = x[n-2: 1]
            offset = int(x.args[1])
            return Extract(x.args[0], i - offset, j - offset)
        elif isinstance(x, (BvLshr, RotateRight)) and \
                isinstance(x.args[1], (int, core.Constant)) and i < x.width - x.args[1]:
            # (x >> 1)[n-3:] = x[n-2: 1]
            offset = int(x.args[1])
            return Extract(x.args[0], i + offset, j + offset)
コード例 #11
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.diffcrypt.differential import RXDBvAdd
            >>> a, b, c = DiffVar("a", 8), DiffVar("b", 8), DiffVar("c", 8)
            >>> rxda = RXDBvAdd([a, b], c)
            >>> rxda.is_valid()  # doctest: +ELLIPSIS
            0b111111 == (~(((((c >> 0x01) ^ ((a >> 0x01) ^ (b >> 0x01))) ...
            >>> zero = Constant(0, 8)
            >>> rxda.is_valid().xreplace({a: zero, b: zero, c: zero})
            0b1

        """
        # (I ^ SHL)(da ^ db ^ dc)[1:] <= SHL((da ^ dc) OR (db ^ dc))[1:]

        alpha, beta = self.input_diff
        gamma = self.output_diff
        # da, db, dc = alpha[:1], beta[:1], gamma[:1]  # boolector error
        da, db, dc = alpha >> 1, beta >> 1, gamma >> 1  # ignore LSB

        lhs = (da ^ db ^ dc) ^ ((da ^ db ^ dc) << 1)
        rhs = ((da ^ dc) | (db ^ dc)) << 1

        def bitwise_implication(x, y):
            return (~x) | y

        n = lhs.width
        return operation.BvComp(
            bitwise_implication(lhs[n - 2:1], rhs[n - 2:1]),  # ignore MSB, LSB
            ~core.Constant(0, n - 2))
コード例 #12
0
    def eval(cls, x, y):
        def doit(x, y, width):
            """Modular addition when both operands are integers."""
            return (x + y) % (2 ** width)

        if isinstance(x, core.Constant) and isinstance(y, core.Constant):
            return core.Constant(doit(int(x), int(y), x.width), x.width)

        zero = core.Constant(0, x.width)

        if x == zero:
            return y
        elif y == zero:
            return x
        elif x == BvNeg(y):
            return zero
コード例 #13
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x, y):
        def doit(x, y, width):
            """Modular multiplication when both operands are int."""
            return (x * y) % (2**width)

        if isinstance(x, core.Constant) and isinstance(y, core.Constant):
            return core.Constant(doit(int(x), int(y), x.width), x.width)

        zero = core.Constant(0, x.width)
        one = core.Constant(1, x.width)

        if x == zero or y == zero:
            return zero
        elif x == one:
            return y
        elif y == one:
            return x
コード例 #14
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x, y):
        def doit(x, y):
            """Logical right shift operation when both operands are int."""
            return x >> y

        zero = core.Constant(0, x.width)

        if isinstance(x, core.Constant) and isinstance(y, core.Constant):
            return core.Constant(doit(int(x), int(y)), x.width)
        elif isinstance(y, core.Constant) and y >= x.width:
            return zero
        elif x == zero or y == zero:
            return x
        elif isinstance(x, BvLshr) and isinstance(x.args[1], core.Constant) \
                and isinstance(y, core.Constant):
            r = min(x.args[0].width, int(x.args[1]) + int(y))
            return BvLshr(x.args[0], r)
コード例 #15
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x):
        def doit(x, width):
            """Unary minus operation when the operand is int."""
            return ((2**width) - x) % (2**width)

        if isinstance(x, core.Constant):
            return core.Constant(doit(int(x), x.width), x.width)
        elif isinstance(x, BvNeg):
            return x.args[0]
コード例 #16
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x):
        def doit(x, width):
            """NOT operation when the operand is int."""
            return ~x % (2**width)

        if isinstance(x, core.Constant):
            return core.Constant(doit(int(x), x.width), x.width)
        elif isinstance(x, BvNot):
            return x.args[0]
コード例 #17
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x, y):
        def doit(x, y, width):
            """Shift left operation when both operands are int."""
            return (x << y) % (2**width)

        zero = core.Constant(0, x.width)

        if isinstance(x, core.Constant) and isinstance(y, core.Constant):
            return core.Constant(doit(int(x), int(y), x.width), x.width)
        elif isinstance(y, core.Constant) and y >= x.width:
            return zero
        elif x == zero or y == zero:
            return x
        elif isinstance(x, BvShl) and isinstance(x.args[1], core.Constant) \
                and isinstance(y, core.Constant):
            # prevent out of bound
            r = min(x.args[0].width, int(x.args[1]) + int(y))
            return BvShl(x.args[0], r)
コード例 #18
0
    def exact_weight(self, output_diff):
        """Return the weight without rounding to the closest integer.

        When the input/output differences have width smaller than 16,
        the exact weight does not coincide with the actual real weight.
        For example, for width=8, the error can be as high as 1.2.
        Moreover, in this case the exact weight is not always smaller
        than the weight.
        """
        alpha, beta = [d.val for d in self.input_diff]
        gamma = output_diff.val
        da, db, dc = alpha[:1], beta[:1], gamma[:1]

        one = core.Constant(1, da.width)

        rhs = ((da ^ dc) | (db ^ dc)) << one
        # rhs = ((da ^ dc) | (db ^ dc))[da.width-2:]  # alt v1
        hw = extraop.PopCount(rhs)

        result = int(hw)

        def bitwise_implication(x, y):
            return (~x) | y

        n = alpha.width
        w_rotational_pair = -(math.log2((1 + 2**(1 - n) + 0.5 + 2**(-n))) - 2)

        if bitwise_implication(da[0] ^ db[0] ^ dc[0], core.Constant(0, 1)) == core.Constant(1, 1):
            result += w_rotational_pair
        else:
            result += 3

        # if debug:
        #     print("\n\n ~~ ")
        #     print("da:           ", da.bin())
        #     print("db:           ", db.bin())
        #     print("dc:           ", dc.bin())
        #     print("rhs:          ", rhs.bin())
        #     print("hw:           ", int(hw))
        #     print("bw_implies:   ", bitwise_implication(da[0] ^ db[0] ^ dc[0], core.Constant(0, 1)).bin())
        #     print("result:       ", result)
        #     print("\n\n")

        return result
コード例 #19
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x, y):
        def doit(x, y):
            """Division operation (truncated) when both operands are int."""
            assert y != 0
            return x // y

        zero = core.Constant(0, x.width)
        one = core.Constant(1, x.width)

        assert y != zero

        if isinstance(x, core.Constant) and isinstance(y, core.Constant):
            return core.Constant(doit(int(x), int(y)), x.width)
        elif x == y:
            return one
        elif x == zero:
            return zero
        elif y == one:
            return x
コード例 #20
0
    def weight(self, output_diff, prefix=None, debug=False, version=2):
        """Return the weight of a possible output `XorDiff`.

        If the output difference is symbolic, a pair
        ``(weight, assertions)`` is returned, where ``assertions`` is
        a tuple of equalities fixing some temporary variables.
        If the output difference is a constant value,
        only the value of the weight is returned.

            >>> from arxpy.bitvector.core import Constant, Variable
            >>> from arxpy.bitvector.context import NotEvaluation
            >>> from arxpy.bitvector.printing import BvWrapPrinter
            >>> from arxpy.bitvector.extraop import PopCount, PopCountSum2, PopCountSum3, PopCountDiff, Reverse, LeadingZeros
            >>> from arxpy.differential.difference import XorDiff
            >>> from arxpy.differential.derivative import XDCA
            >>> alpha, cte = XorDiff(Constant(0, 4)), Constant(1, 4)
            >>> f = XDCA(alpha, cte)
            >>> f.weight(XorDiff(Constant(0, 4)))
            0x0
            >>> alpha = XorDiff(Variable("u", 4))
            >>> f = XDCA(alpha, cte)
            >>> beta = XorDiff(Variable("v", 4))
            >>> with NotEvaluation([Reverse, PopCount, PopCountDiff, PopCountSum2, PopCountSum3, LeadingZeros]):
            ...     weight_value, assertions = f.weight(beta, prefix="")
            >>> print(BvWrapPrinter().doprint(weight_value))
            -(::(PopCountDiff((~_0lz & ((~u & ~v) << 0x1)) | ((u ^ v) << 0x1),
                              (_1rev & _4rev) ^ (0x1 + _1rev) ^ (0x1 + _1rev + (_1rev & _4rev)),
                 0b0,
              ::(0b0,
                 PopCount(&(_4rev & ((_1rev & _4rev) ^ (0x1 + _1rev) ^ (0x1 + _1rev + (_1rev & _4rev))),
                            ~(((_1rev & _4rev) ^ (0x1 + _1rev) ^ (0x1 + _1rev + (_1rev & _4rev))) << 0x1)
            >>> assertions  # doctest: +NORMALIZE_WHITESPACE
            [_0lz == LeadingZeros(~((~u & ~v) << 0x1)),
            _1rev == Reverse((~u & ~v) << 0x1),
            _2rev == Reverse(~(((~u & ~v) << 0x1) >> 0x1) & ((~u & ~v) << 0x1) & (~(0x2 ^ u ^ v) >> 0x1)),
            _3rev == Reverse(_2rev ^ _1rev ^ (_1rev + _2rev)),
            _4rev == Reverse((((0x1 & (((~u & ~v) << 0x1) >> 0x1)) + (0x2 & (((~u & ~v) << 0x1) >> 0x1) & ~((~u & ~v) << 0x1))) & ~(_3rev | (~(((~u & ~v) << 0x1) >> 0x1) & ((~u & ~v) << 0x1) & (~(0x2 ^ u ^ v) >> 0x1)))) | ((~(((~u & ~v) << 0x1) >> 0x1) & ((~u & ~v) << 0x1) & (~(0x2 ^ u ^ v) >> 0x1)) - (((0x1 & (((~u & ~v) << 0x1) >> 0x1)) + (0x2 & (((~u & ~v) << 0x1) >> 0x1) & ~((~u & ~v) << 0x1))) & (_3rev | (~(((~u & ~v) << 0x1) >> 0x1) & ((~u & ~v) << 0x1) & (~(0x2 ^ u ^ v) >> 0x1))))))]


        See `Derivative.weight` for more information.
        """
        u = self.input_diff[0].val
        v = output_diff.val
        a = self.op.constant

        effective_width = self._effective_width
        index_one = self._index_first_one

        if effective_width <= 1:
            return core.Constant(0, 1)
        else:
            u = difference.XorDiff(u[:index_one])
            v = difference.XorDiff(v[:index_one])
            der = type(self)([u], a[:index_one])
            return der._weight(v, prefix, debug, version)
コード例 #21
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x, y):
        def doit(x, y):
            """OR operation when both operands are int."""
            return x | y

        zero = core.Constant(0, x.width)
        allones = BvNot(zero)

        if isinstance(x, core.Constant) and isinstance(y, core.Constant):
            return core.Constant(doit(int(x), int(y)), x.width)
        elif x == allones or y == allones:
            return allones
        elif x == zero:
            return y
        elif y == zero:
            return x
        elif x == y:
            return x
        elif x == BvNot(y):
            return allones
コード例 #22
0
    def weight(self):
        """Return the weight of the differential.

            >>> from arxpy.bitvector.core import Constant
            >>> from arxpy.diffcrypt.difference import DiffVar
            >>> from arxpy.diffcrypt.differential import RXDBvAdd
            >>> a, b, c = DiffVar("a", 8), DiffVar("b", 8), DiffVar("c", 8)
            >>> rxda = RXDBvAdd([a, b], c)
            >>> rxda.weight()  # doctest: +ELLIPSIS
            (0b00010 * (0b00 ∘ (((0x0f & ((0x33 & ((0x55 & ((0b00 ...
            >>> zero = Constant(0, 8)
            >>> rxda.weight().xreplace({a: zero, b: zero, c: zero})
            0b00011

        """
        alpha, beta = self.input_diff
        gamma = self.output_diff
        da, db, dc = alpha[:1], beta[:1], gamma[:1]
        # da, db, dc = alpha >> 1, beta >> 1, gamma >> 1

        rhs = ((da ^ dc) | (db ^ dc)) << 1
        hw = _HammingWeight(rhs[:1])  # ignore LSB

        max_hw = rhs.width - 1
        weight_width = max((2 * max_hw + 6).bit_length(), hw.width, 3)  # 0b110

        # let lhs = LSB(lhs) = da ^ db ^ dc
        #     rhs = LSB(rhs) = 0
        # case A (2 * 1.415): lhs => rhs
        # case B (2 * 3):     lhs ^ 1 => rhs

        def bitwise_implication(x, y):
            return (~x) | y

        cte_part = operation.Ite(
            bitwise_implication(da[0] ^ db[0] ^ dc[0], core.Constant(0, 1)),
            core.Constant(3, weight_width), core.Constant(6, weight_width))

        hw_extend = operation.ZeroExtend(hw, weight_width - hw.width)

        return 2 * hw_extend + cte_part
コード例 #23
0
    def eval(cls, bv):
        # Source: Hacker's Delight

        if bv.width < 4:
            w = cls.output_width(bv)
            return sum([operation.ZeroExtend(bv[i], w-1) for i in range(bv.width)])

        # extend the bv until power of 2 length
        original_width = bv.width
        while (bv.width & (bv.width - 1)) != 0:
            bv = operation.ZeroExtend(bv, 1)
        width_log2 = bv.width.bit_length() - 1

        m_ctes = []
        for i in range(width_log2):
            m_ctes.append(repeat_pattern(pattern01(2 ** i), bv.width))

        if bv.width > 32:
            for i, m in enumerate(m_ctes):
                bv = (bv & m) + ((bv >> core.Constant(2 ** i, bv.width)) & m)
            return bv[original_width.bit_length() - 1:]

        for i, m in enumerate(m_ctes):
            if i == 0:
                bv = bv - ((bv >> core.Constant(1, bv.width)) & m)
            elif i == 1:
                bv = (bv & m) + ((bv >> core.Constant(2 ** i, bv.width)) & m)  # generic case
            elif i == 2:
                bv = (bv + (bv >> core.Constant(4, bv.width))) & m
            elif i == 3:
                bv = bv + (bv >> core.Constant(8, bv.width))
            elif i == 4:
                bv = bv + (bv >> core.Constant(16, bv.width))

        return bv[original_width.bit_length() - 1:]
コード例 #24
0
    def eval(cls, bv):
        # Source: Hacker's Delight

        if bv.width == 1:
            return bv
        elif bv.width == 2:
            return operation.RotateLeft(bv, 1)
        elif bv.width == 3:
            return operation.Concat(operation.Concat(bv[0], bv[1]), bv[2])

        original_width = bv.width
        while (bv.width & (bv.width - 1)) != 0:
            bv = operation.ZeroExtend(bv, 1)
        width_log2 = bv.width.bit_length() - 1

        m_ctes = []
        for i in range(width_log2):
            m_ctes.append(repeat_pattern(pattern01(2 ** i), bv.width))

        if bv.width > 32:
            for i, m in list(enumerate(m_ctes)):
                bv = ((bv & m) << core.Constant(2 ** i, bv.width)) | ((bv >> core.Constant(2 ** i, bv.width)) & m)
            return bv[:bv.width - original_width]

        for i, m in list(enumerate(m_ctes))[:3]:
            bv = ((bv & m) << core.Constant(2 ** i, bv.width)) | ((bv >> core.Constant(2 ** i, bv.width)) & m)  # generic case

        if len(m_ctes) == 4:
            bv = ((bv & m_ctes[3]) << core.Constant(8, bv.width)) | ((bv >> core.Constant(8, bv.width)) & m_ctes[3])
        elif len(m_ctes) == 5:
            rol = operation.RotateLeft
            ror = operation.RotateRight
            bv = ror(bv & m_ctes[3], 8) | (rol(bv, 8) & m_ctes[3])

        return bv[:bv.width - original_width]
コード例 #25
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x, y):
        def doit(x, y, width):
            """Modular addition when both operands are integers."""
            return (x + y) % (2**width)

        if isinstance(x, core.Constant) and isinstance(y, core.Constant):
            return core.Constant(doit(int(x), int(y), x.width), x.width)

        zero = core.Constant(0, x.width)

        if x == zero:
            return y
        elif y == zero:
            return x
        elif x == BvNeg(y):
            return zero
        elif isinstance(x, BvSub):  # (x0 - x1) + y
            if x.args[1] == y:
                return x.args[0]
        elif isinstance(y, BvSub):  # x + (y0 - y1)
            if y.args[1] == x:
                return y.args[0]
コード例 #26
0
    def eval(cls, bv):
        # Source: Hacker's Delight

        if bv.width == 1:
            return ~bv

        original_width = bv.width
        while (bv.width & (bv.width - 1)) != 0:
            bv = operation.ZeroExtend(bv, 1)
        width_log2 = bv.width.bit_length() - 1

        for i in range(width_log2):
            bv = bv | (bv >> core.Constant(2 ** i, bv.width))
        return ~bv[original_width - 1:]
コード例 #27
0
    def eval(cls, x, y):
        # Source: Hacker's Delight

        if x.width < 4:
            # the HW of a 1-bit/2-bit vector requires 1-bit/2-bit (HW(0b1)=0b1, HW(0b11)=0b10)
            # thus, the sum of two HW of these sizes require an extra bit
            # the HW of a 3-bit vector requires 2-bit (Hw(0b111)=0b11)
            # and the sum of two HW of 3-bit also require an extra bit
            return operation.ZeroExtend(PopCount(x), 1) + operation.ZeroExtend(PopCount(y), 1)
        elif x.width > 32:
            width = cls.output_width(x, y)
            x = PopCount(x)
            x = operation.ZeroExtend(x, width - x.width)
            y = PopCount(y)
            y = operation.ZeroExtend(y, width - y.width)
            return x + y

        orig_x, orig_y = x, y
        while (x.width & (x.width - 1)) != 0:
            x = operation.ZeroExtend(x, 1)
        while (y.width & (y.width - 1)) != 0:
            y = operation.ZeroExtend(y, 1)
        width_log2 = x.width.bit_length() - 1

        m_ctes = []
        for i in range(width_log2):
            m_ctes.append(repeat_pattern(pattern01(2 ** i), x.width))

        bv = core.Constant(0, x.width)
        for i, m in enumerate(m_ctes):
            if i == 0:
                x = x - ((x >> core.Constant(1, bv.width)) & m)
                y = y - ((y >> core.Constant(1, bv.width)) & m)
                bv = x + y
            elif i == 1:
                x = (x & m) + ((x >> core.Constant(2 ** i, bv.width)) & m)  # generic case
                y = (y & m) + ((y >> core.Constant(2 ** i, bv.width)) & m)
                bv = x + y
            elif i == 2:
                bv = (bv & m) + ((bv >> core.Constant(4, bv.width)) & m)
            elif i == 3:
                bv = bv + (bv >> core.Constant(8, bv.width))
            elif i == 4:
                bv = bv + (bv >> core.Constant(16, bv.width))

        return bv[cls.output_width(orig_x, orig_y) - 1:]
コード例 #28
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x, r):
        def doit(val, r, width):
            """Right cyclic rotation operation when both operands are int."""
            mask = 2**width - 1
            r = r % width
            return ((val & mask) >> r) | (val << (width - r) & mask)

        if isinstance(x, core.Constant):
            return core.Constant(doit(int(x), r, x.width), x.width)
        elif r == 0:
            return x
        elif isinstance(x, RotateRight):
            return RotateRight(x.args[0], (x.args[1] + r) % x.args[0].width)
        elif isinstance(x, RotateLeft):
            return RotateLeft(x.args[0], (x.args[1] - r) % x.args[0].width)
コード例 #29
0
ファイル: operation.py プロジェクト: nc26676027/ArxPy
    def eval(cls, x, y):
        def doit(x, y):
            """Concatenation when both operands are int."""
            return int(x.bin() + y.bin()[2:], 2)

        if isinstance(x, core.Constant) and isinstance(y, core.Constant):
            return core.Constant(doit(x, y), cls.output_width(x, y))
        elif isinstance(x, core.Constant) and isinstance(y, Concat) and \
                isinstance(y.args[0], core.Constant):
            return Concat(Concat(x, y.args[0]), y.args[1])
        elif isinstance(y, core.Constant) and isinstance(x, Concat) and \
                isinstance(x.args[1], core.Constant):
            return Concat(x.args[0], Concat(x.args[1], y))
        elif isinstance(x, Extract) and isinstance(y, Extract):
            # x[5:4] concat x[3:2] = x[5:2]
            if x.args[0] == y.args[0] and x.args[2] == y.args[1] + 1:
                return Extract(x.args[0], x.args[1], y.args[2])
コード例 #30
0
    def _has_probability_one(self, output_diff):
        u = self.input_diff[0].val
        v = output_diff.val
        a = self.op.constant
        n = a.width

        assert self._effective_width == n - 1

        one = core.Constant(1, n)

        def all_ones(width):
            return ~ core.Constant(0, width)

        case00_ = (~(u << one)) & (~(v << one))  # i-bit is True if S_i = 00*
        case__1 = u ^ v
        case000 = case00_ & (~case__1)

        return operation.BvComp(case000, all_ones(n))