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.Term
Represent 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
Simplification
context 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
,Validation
orMemoization
.This class is not meant to be instantiated but to provide a base class for the two types of operations:
PrimaryOperation
andSecondaryOperation
.Note
New bit-vector operations can be defined by subclassing
SecondaryOperation
(seeBvMaj
as 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
args
has 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
Operation
object \(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 theMemoization
context.The argument
id_prefix
is the string prefix used to name intermediate variables and the argumentdecompose_sec_ops
determines whether to use the contextSecondaryOperationEvaluation
. In other words, ifdecompose_sec_ops
isTrue
,SecondaryOperation
objects are not allowed in the list of assignments and they are replaced by their decomposition intoPrimaryOperation
objects.>>> 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.Operation
Represent 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
,Ite
andBvIdentity
.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.Operation
Represent 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.eval
is used) if all the operands are scalar orConstant
objects (see alsocontext.SecondaryOperationEvaluation
). On the other hand,pre_eval
is 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
args
has been parsed.
- class cascada.bitvector.operation.PartialOperation[source]
Bases:
object
Represent 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
.PartialOperation
subclasses generated bymake_partial_operation
are also subclasses ofPrimaryOperation
orSecondaryOperation
depending on the type of the base operator.
- cascada.bitvector.operation.make_partial_operation(base_op, fixed_args)[source]
Return a new
PartialOperation
subclass with the given base operator and fixed arguments.The argument
fixed_args
is atuple
, with the same length as the number of operands of the base operator, containingNone
, scalar orConstant
elements. 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
PrimaryOperation
orSecondaryOperation
, 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.PrimaryOperation
Bitwise negation operation.
It overrides the operator ~. See
PrimaryOperation
for 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.PrimaryOperation
Bitwise AND (logical conjunction) operation.
It overrides the operator & and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Bitwise OR (logical disjunction) operation.
It overrides the operator | and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Bitwise XOR (exclusive-or) operation.
It overrides the operator ^ and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Equality operator.
Provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Unsigned less than operator.
It overrides < and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Unsigned less than or equal operator.
It overrides <= and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Unsigned greater than operator.
It overrides > and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Unsigned greater than or equal operator.
It overrides >= and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Shift left operation.
It overrides << and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Logical right shift operation.
It overrides >> and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Circular 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.PrimaryOperation
Circular right rotation operation.
It provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
If-then-else operator.
Ite(b, x, y)
returnsx
ifb == 0b1
andy
otherwise.>>> 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.PrimaryOperation
Extraction of bits.
Extract(t, i, j)
extracts the bits from positioni
down 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
t
is 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 positioni
up 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
l
and 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.PrimaryOperation
Concatenation 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.PrimaryOperation
Unary minus operation.
It overrides the unary operator -. See
PrimaryOperation
for 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.PrimaryOperation
Modular addition operation.
It overrides the operator + and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Modular subtraction operation.
It overrides the operator - and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Modular multiplication operation.
It overrides the operator * and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Unsigned and truncated division operation.
It overrides the operator / and provides Automatic Constant Conversion. See
PrimaryOperation
for 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.PrimaryOperation
Unsigned 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.PrimaryOperation
The identity operation.
Return the same value when the input is constant and a
BvIdentity
object 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