cascada.bitvector.operation module
Provide the common bit-vector operators.
Represent bit-vector operations. |
|
Represent the primary bit-vector operations. |
|
Represent secondary bit-vector operations. |
|
Represent bit-vector operations with fixed operands. |
|
Return a new |
|
Bitwise negation operation. |
|
Bitwise AND (logical conjunction) operation. |
|
Bitwise OR (logical disjunction) operation. |
|
Bitwise XOR (exclusive-or) operation. |
|
Equality operator. |
|
Unsigned less than operator. |
|
Unsigned less than or equal operator. |
|
Unsigned greater than operator. |
|
Unsigned greater than or equal operator. |
|
Shift left operation. |
|
Logical right shift operation. |
|
Circular left rotation operation. |
|
Circular right rotation operation. |
|
If-then-else operator. |
|
Extraction of bits. |
|
Concatenation operation. |
|
Unary minus operation. |
|
Modular addition operation. |
|
Modular subtraction operation. |
|
Modular multiplication operation. |
|
Unsigned and truncated division operation. |
|
Unsigned remainder (modulus) operation. |
|
The identity operation. |
|
Extend with zeroes preserving the unsigned value. |
|
Concatenate a bit-vector with itself a given number of times. |
- class cascada.bitvector.operation.Operation(**kwargs)[source]
Bases:
cascada.bitvector.core.TermRepresent bit-vector operations.
A bit-vector operation is a mathematical function that takes some bit-vector operands (i.e.
Term) and some scalar operands (i.e.int), and returns a single bit-vector term. Often, operator is used to denote the Python class representing the mathematical function (without operands) and operation is used to denote the application of an operator to some operands.A particular operator (a subclass of
Operation) can be evaluated by instantiating an object with the operands as the object arguments. The instantiation internally calls the methodeval, containing the logic of the operator. This behaviour is similar as those of the SymPy classes Add or Mul.Unless the
Simplificationcontext is disabled (enabled by default), many of the operations automatically simplify complex expressions by applying basic rules from Boolean algebra. Moreoever, operations are also affected by other context managers such asCache,PrimaryOperationEvaluation,SecondaryOperationEvaluation,ValidationorMemoization.This class is not meant to be instantiated but to provide a base class for the two types of operations:
PrimaryOperationandSecondaryOperation.Note
New bit-vector operations can be defined by subclassing
SecondaryOperation(seeBvMajas example). It is also possible to define new bit-vector operations by subclassingPrimaryOperation, but this is not recommended.- arity
a pair of number specifying the number of bit-vector operands (at least one) and scalar operands, respectively.
- is_symmetric
True if the operator is symmetric with respect to its operands (a permutation of the inputs does not change the output). Operators with scalar operands cannot be symmetric.
- is_simple
True if the operator is simple, that is, all its operands are bit-vector of the same width. Simple operators allow Automatic Constant Conversion, that is, instead of passing all arguments as bit-vector types, it is possible to pass arguments as plain integers.
>>> from cascada.bitvector.core import Constant >>> (Constant(1, 8) + 1).vrepr() 'Constant(0b00000010, width=8)'
- operand_types
a list specifying the types of the operands (optional if all operands are bit-vectors)
- alt_name
an alternative name used when printing (optional)
- unary_symbol
a symbol used when printing (optional)
- infix_symbol
a symbol used when printing (optional)
- classmethod condition(*args)[source]
Check if the operands verify the restrictions of the operator.
- classmethod eval(*args)[source]
Evaluate the operator with given operands.
This is an internal method that assumes the list
argshas been parsed. To evaluate a bit-vector operation, instantiate a new object with the operands as the object arguments (i.e., use the Python operator()).
- memoization_table(id_prefix='x', decompose_sec_ops=True)[source]
Return a decomposition of the current operation into simple assignments.
Given an
Operationobject \(F(a_1, a_2, \dots)\), this method decomposes it into a list of simple assignments \(x_{i+1} \leftarrow f_i(x_i)\) such that the last output variable \(x_{n}\) represents the output of \(F(a_1, a_2, \dots)\). The i-th assignment is given by:The list of assignments is given as a
MemoizationTable, and it is obtained by re-evaluating the current operation under theMemoizationcontext.The argument
id_prefixis the string prefix used to name intermediate variables and the argumentdecompose_sec_opsdetermines whether to use the contextSecondaryOperationEvaluation. In other words, ifdecompose_sec_opsisTrue,SecondaryOperationobjects are not allowed in the list of assignments and they are replaced by their decomposition intoPrimaryOperationobjects.>>> from cascada.bitvector.core import Variable >>> from cascada.bitvector.secondaryop import BvMaj >>> expr = 1 + BvMaj(2, Variable("a_1", 8), 3 | Variable("a_2", 8)) >>> expr.memoization_table() MemoizationTable([(x0, a_2 | 0x03), (x1, 0x02 & a_1), (x2, 0x02 & x0), (x3, x1 | x2), (x4, a_1 & x0), (x5, x3 | x4), (x6, x5 + 0x01), (x7, Id(x6))]) >>> expr.memoization_table(decompose_sec_ops=False) MemoizationTable([(x0, a_2 | 0x03), (x1, BvMaj(0x02, a_1, x0)), (x2, x1 + 0x01), (x3, Id(x2))])
- class cascada.bitvector.operation.PrimaryOperation(**kwargs)[source]
Bases:
cascada.bitvector.operation.OperationRepresent the primary bit-vector operations.
The primary bit-vector operations are those basic operations that are included in the bit-vector theory of the SMT_LIBv2 format.
The primary operations are
BvAnd,BvOr,BvXor,BvComp,BvUlt,BvUle,BvUgt,BvUge,BvShl,BvLshr,RotateLeft,RotateRight,Concat,BvAdd,BvSub,BvMul,BvUdiv,BvUrem,BvNeg,BvNot,Extract,IteandBvIdentity.This class is not meant to be instantiated but to provide a base class to define primary operators.
- class cascada.bitvector.operation.SecondaryOperation(**kwargs)[source]
Bases:
cascada.bitvector.operation.OperationRepresent secondary bit-vector operations.
Secondary bit-vector operations are those bit-vector operations that are not primary operations (see
PrimaryOperation). Secondary operations must be defined in terms of primary operations.By default, secondary operations are fully evaluated (
Operation.evalis used) if all the operands are scalar orConstantobjects (see alsocontext.SecondaryOperationEvaluation). On the other hand,pre_evalis always called in the evaluation (even with symbolic inputs).This class is not meant to be instantiated but to provide a base class to define secondary operators.
- classmethod pre_eval(*args)[source]
Evaluate the operator before
Operation.eval.This is an internal method that assumes the list
argshas been parsed.
- class cascada.bitvector.operation.PartialOperation[source]
Bases:
objectRepresent bit-vector operations with fixed operands.
Given a base operator \((x, y) \mapsto f(x, y)\), a partial operator is a function obtained by fixing some of the inputs to constants, e.g., \(x \mapsto f(x, y=0)\).
This class is not meant to be instantiated but to provide a base class for bit-vector operations with fixed operands generated through
make_partial_operation.PartialOperationsubclasses generated bymake_partial_operationare also subclasses ofPrimaryOperationorSecondaryOperationdepending on the type of the base operator.
- cascada.bitvector.operation.make_partial_operation(base_op, fixed_args)[source]
Return a new
PartialOperationsubclass with the given base operator and fixed arguments.The argument
fixed_argsis atuple, with the same length as the number of operands of the base operator, containingNone, scalar orConstantelements. Iffixed_args[i]isNone, the i-th operand is not fixed; otherwise, the i-th operand is replaced withfixed_args[i].The resulting class is also a subclass of
PrimaryOperationorSecondaryOperation, depending on the type of the base operator.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvAdd, Extract, make_partial_operation >>> from cascada.bitvector.secondaryop import BvMaj >>> BvAddCte = make_partial_operation(BvAdd, tuple([None, Constant(1, 4)])) >>> BvAddCte.__name__ 'BvAdd_{·, 0x1}' >>> expr = BvAddCte(Variable("a", 4)) >>> expr a + 0x1 >>> expr.vrepr() "make_partial_operation(BvAdd, (None, Constant(0b0001, width=4)))(Variable('a', width=4))" >>> ExtractLSB = make_partial_operation(Extract, tuple([None, 0, 0])) >>> ExtractLSB.__name__ 'Extract_{·, 0, 0}' >>> ExtractLSB(Extract(Variable("a", 4), 2, 0)) # result is simplified a[0] >>> BvCteMaj = make_partial_operation(BvMaj, tuple([None, None, Constant(1, 4)])) >>> BvCteMaj.__name__ 'BvMaj_{·, ·, 0x1}' >>> BvCteMaj(Variable("a", 4), Variable("a", 4)) a >>> expr = BvCteMaj(Variable("a", 4), Variable("b", 4)) >>> expr BvMaj_{·, ·, 0x1}(a, b) >>> expr.doit() (a & b) | (a & 0x1) | (b & 0x1) >>> expr.memoization_table() MemoizationTable([(x0, a & b), (x1, a & 0x1), (x2, x0 | x1), (x3, b & 0x1), (x4, x2 | x3), (x5, Id(x4))]) >>> BvCteMaj_v2 = make_partial_operation(BvCteMaj, tuple([Constant(2, 4), None])) >>> BvCteMaj_v2.__name__ 'BvMaj_{0x2, ·, 0x1}' >>> BvCteMaj_v2(Variable("a", 4)) BvMaj_{0x2, ·, 0x1}(a)
- class cascada.bitvector.operation.BvNot(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationBitwise negation operation.
It overrides the operator ~. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvNot >>> BvNot(Constant(0b1010101, 7)) 0b0101010 >>> ~Constant(0b1010101, 7) 0b0101010 >>> ~Variable("x", 8) ~x
- class cascada.bitvector.operation.BvAnd(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationBitwise AND (logical conjunction) operation.
It overrides the operator & and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvAnd >>> BvAnd(Constant(5, 8), Constant(3, 8)) 0x01 >>> BvAnd(Constant(5, 8), 3) 0x01 >>> Constant(5, 8) & 3 0x01 >>> Variable("x", 8) & Variable("y", 8) x & y
- class cascada.bitvector.operation.BvOr(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationBitwise OR (logical disjunction) operation.
It overrides the operator | and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvOr >>> BvOr(Constant(5, 8), Constant(3, 8)) 0x07 >>> BvOr(Constant(5, 8), 3) 0x07 >>> Constant(5, 8) | 3 0x07 >>> Variable("x", 8) | Variable("y", 8) x | y
- class cascada.bitvector.operation.BvXor(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationBitwise XOR (exclusive-or) operation.
It overrides the operator ^ and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvXor >>> BvXor(Constant(5, 8), Constant(3, 8)) 0x06 >>> BvXor(Constant(5, 8), 3) 0x06 >>> Constant(5, 8) ^ 3 0x06 >>> Variable("x", 8) ^ Variable("y", 8) x ^ y
- class cascada.bitvector.operation.BvComp(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationEquality operator.
Provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvComp >>> BvComp(Constant(1, 8), Constant(2, 8)) 0b0 >>> BvComp(Constant(1, 8), 2) 0b0 >>> x, y = Variable("x", 8), Variable("y", 8) >>> BvComp(Constant(1, 8), Variable("y", 8)) 0x01 == y >>> bool(BvComp(x + y, y + x)) True
The operator == is used for exact structural equality testing and it returns either True or False. On the other hand, BvComp performs symbolic equality testing and it leaves the relation unevaluated if it cannot prove the objects are equal (or unequal).
>>> x == y False >>> BvComp(x, y) # symbolic equality x == y
- class cascada.bitvector.operation.BvUlt(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationUnsigned less than operator.
It overrides < and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvUlt >>> BvUlt(Constant(1, 8), Constant(2, 8)) 0b1 >>> BvUlt(Constant(1, 8), 2) 0b1 >>> Constant(1, 8) < 2 0b1 >>> Constant(1, 8) < Variable("y", 8) 0x01 < y
- class cascada.bitvector.operation.BvUle(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationUnsigned less than or equal operator.
It overrides <= and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvUle >>> BvUle(Constant(2, 8), Constant(2, 8)) 0b1 >>> BvUle(Constant(2, 8), 2) 0b1 >>> Constant(2, 8) <= 2 0b1 >>> Constant(2, 8) <= Variable("y", 8) 0x02 <= y
- class cascada.bitvector.operation.BvUgt(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationUnsigned greater than operator.
It overrides > and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvUgt >>> BvUgt(Constant(1, 8), Constant(2, 8)) 0b0 >>> BvUgt(Constant(1, 8), 2) 0b0 >>> Constant(1, 8) > 2 0b0 >>> Constant(1, 8) > Variable("y", 8) 0x01 > y
- class cascada.bitvector.operation.BvUge(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationUnsigned greater than or equal operator.
It overrides >= and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvUgt >>> BvUge(Constant(2, 8), Constant(2, 8)) 0b1 >>> BvUge(Constant(2, 8), 2) 0b1 >>> Constant(2, 8) >= 2 0b1 >>> Constant(2, 8) >= Variable("y", 8) 0x02 >= y
- class cascada.bitvector.operation.BvShl(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationShift left operation.
It overrides << and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvShl >>> BvShl(Constant(0b10001, 5), Constant(1, 5)) 0b00010 >>> BvShl(Constant(0b10001, 5), 1) 0b00010 >>> Constant(0b10001, 5) << 1 0b00010 >>> Variable("x", 8) << Variable("y", 8) x << y
- class cascada.bitvector.operation.BvLshr(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationLogical right shift operation.
It overrides >> and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvLshr >>> BvLshr(Constant(0b10001, 5), Constant(1, 5)) 0b01000 >>> BvLshr(Constant(0b10001, 5), 1) 0b01000 >>> Constant(0b10001, 5) >> 1 0b01000 >>> Variable("x", 8) >> Variable("y", 8) x >> y
- class cascada.bitvector.operation.RotateLeft(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationCircular left rotation operation.
>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import RotateLeft >>> RotateLeft(Constant(150, 8), 2) 0x5a >>> RotateLeft(Variable("x", 8), 2) x <<< 2
- class cascada.bitvector.operation.RotateRight(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationCircular right rotation operation.
It provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import RotateRight >>> RotateRight(Constant(150, 8), 3) 0xd2 >>> RotateRight(Variable("x", 8), 3) x >>> 3
- class cascada.bitvector.operation.Ite(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationIf-then-else operator.
Ite(b, x, y)returnsxifb == 0b1andyotherwise.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import Ite >>> Ite(Constant(0, 1), Constant(0b11, 2), Constant(0b00, 2)) 0b00 >>> Ite(Constant(1, 1), Constant(0x1, 4), Constant(0x0, 4)) 0x1
- class cascada.bitvector.operation.Extract(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationExtraction of bits.
Extract(t, i, j)extracts the bits from positionidown positionj(end points included, position 0 corresponding to the least significant bit).It overrides the operation [], that is,
Extract(t, i, j)is equivalent tot[i:j].Note that the indices can be omitted when they point the most significant bit or the least significant bit. For example, if
tis a bit-vector of lengthn, thent[n-1:j] = t[:j]andt[i:0] = t[i:]Warning
In python, given a list
l,l[i:j]denotes the elements from positioniup to (but not included) positionj. Note that with bit-vectors, the order of the arguments is swapped and both end points are included.For example, for a given list
land bit-vectort,l[0:1] == l[0]andt[1:0] == (t[0], t[1]).>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import Extract >>> Extract(Constant(0b11100, 5), 4, 2,) 0b111 >>> Constant(0b11100, 5)[4:2] 0b111 >>> Variable("x", 8)[4:2] x[4:2] >>> Variable("x", 8)[7:0] x
- class cascada.bitvector.operation.Concat(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationConcatenation operation.
Given the bit-vectors \((x_{n-1}, \dots, x_0)\) and \((y_{m-1}, \dots, y_0)\),
Concat(x, y)returns the bit-vector \((x_{n-1}, \dots, x_0, y_{m-1}, \dots, y_0)\).>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import Concat >>> Concat(Constant(0x12, 8), Constant(0x345, 12)) 0x12345 >>> Concat(Variable("x", 8), Variable("y", 8)) x :: y
- class cascada.bitvector.operation.BvNeg(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationUnary minus operation.
It overrides the unary operator -. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvNeg >>> BvNeg(Constant(1, 8)) 0xff >>> -Constant(1, 8) 0xff >>> BvNeg(Variable("x", 8)) -x
- class cascada.bitvector.operation.BvAdd(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationModular addition operation.
It overrides the operator + and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvAdd >>> BvAdd(Constant(1, 8), Constant(2, 8)) 0x03 >>> BvAdd(Constant(1, 8), 2) 0x03 >>> Constant(1, 8) + 2 0x03 >>> Variable("x", 8) + Variable("y", 8) x + y
- class cascada.bitvector.operation.BvSub(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationModular subtraction operation.
It overrides the operator - and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvSub >>> BvSub(Constant(1, 8), Constant(2, 8)) 0xff >>> BvSub(Constant(1, 8), 2) 0xff >>> Constant(1, 8) - 2 0xff >>> Variable("x", 8) - Variable("y", 8) x - y
- class cascada.bitvector.operation.BvMul(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationModular multiplication operation.
It overrides the operator * and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvMul >>> BvMul(Constant(4, 8), Constant(3, 8)) 0x0c >>> BvMul(Constant(4, 8), 3) 0x0c >>> Constant(4, 8) * 3 0x0c >>> Variable("x", 8) * Variable("y", 8) x * y
- class cascada.bitvector.operation.BvUdiv(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationUnsigned and truncated division operation.
It overrides the operator / and provides Automatic Constant Conversion. See
PrimaryOperationfor more information.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvUdiv >>> BvUdiv(Constant(0x0c, 8), Constant(3, 8)) 0x04 >>> BvUdiv(Constant(0x0c, 8), 3) 0x04 >>> Constant(0x0c, 8) / 3 0x04 >>> Variable("x", 8) / Variable("y", 8) x / y
- class cascada.bitvector.operation.BvUrem(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationUnsigned remainder (modulus) operation.
Usage:
>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvUrem >>> BvUrem(Constant(0x0d, 8), Constant(3, 8)) 0x01 >>> BvUrem(Constant(0x0d, 8), 3) 0x01 >>> Constant(0x0d, 8) % 3 0x01 >>> Variable("x", 8) % Variable("y", 8) x % y
- class cascada.bitvector.operation.BvIdentity(**kwargs)[source]
Bases:
cascada.bitvector.operation.PrimaryOperationThe identity operation.
Return the same value when the input is constant and a
BvIdentityobject when the input is symbolic:>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import BvIdentity >>> BvIdentity(Constant(0x1, 4)) 0x1 >>> BvIdentity(Variable("x", 8)) Id(x)
- cascada.bitvector.operation.zero_extend(x, i)[source]
Extend with zeroes preserving the unsigned value.
>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import zero_extend >>> zero_extend(Constant(0x12, 8), 4) 0x012 >>> zero_extend(Variable("x", 8), 4) 0x0 :: x
- cascada.bitvector.operation.repeat(x, i)[source]
Concatenate a bit-vector with itself a given number of times.
>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import repeat >>> repeat(Constant(0x1, 4), 4) 0x1111 >>> repeat(Variable("x", 8), 4) x :: x :: x :: x