def symbolic_execution(cls, *args, id_prefix="x", st=None): """Evaluate symbolically the function. It evalutes the composite function in the "stateful execution mode" (see symbolic_execution of Function). It returns two pairs (inner_output, inner_st), (outer_outer, outer_st) where each pair is the result of calling symbolic_execution on inner and outer respectively. >>> from arxpy.bitvector.core import Variable >>> from arxpy.bitvector.function import Function, CompositeFunction >>> class MyInner(Function): ... input_widths = [8, 8] ... output_widths = [8] ... @classmethod ... def eval(cls, a, b): return (a ^ b) >>> MyInner(1, 1) 0x00 >>> class MyOuter(Function): ... input_widths = [8, 8] ... output_widths = [8] ... @classmethod ... def eval(cls, c, d): return (c + d) >>> MyOuter(1, 1) 0x02 >>> class MyComposite(CompositeFunction): ... input_widths = [8, 8, 8] ... output_widths = [8] ... inner_func = MyInner ... outer_func = MyOuter >>> MyComposite(1, 1, 1) 0x01 >>> a, b, cd = Variable("a", 8), Variable("b", 8), Variable("cd", 8) >>> MyComposite.symbolic_execution(a, b, cd) # doctest: +NORMALIZE_WHITESPACE ((x0, ExecutionState([(x0, b ^ cd), (x1, a + x0)])), (x1, ExecutionState([(x0, b ^ cd), (x1, a + x0)]))) """ if st is None: st = context.ExecutionState(id_prefix=id_prefix) inner_ninputs = len(cls.inner_func.input_widths) inner_args = args[-inner_ninputs:] inner_exec = cls.inner_func.symbolic_execution(*inner_args, st=st) new_args = args[:-inner_ninputs] + core.tuplify(inner_exec[0]) self_exec = cls.outer_func.symbolic_execution(*new_args, st=st) return inner_exec, self_exec
def __init__(self, func, diff_type, input_diff, prefix="d"): """Create a characteristic.""" assert issubclass(func, function.Function) assert issubclass(diff_type, difference.Difference) input_diff = core.tuplify(input_diff) assert len(input_diff) == len(func.input_widths) assert all(isinstance(d, difference.DiffVar) for d in input_diff) assert all(not d.name.startswith(prefix) for d in input_diff) self.func = func self.diff_type = diff_type self.input_diff = input_diff self.prefix = prefix self.output_diff = None self.propagations = collections.OrderedDict() self._generate()
def __new__(cls, *args, **options): assert len(cls.input_widths) == len(args) newargs = [] for arg, width in zip(args, cls.input_widths): newargs.append(core.bitvectify(arg, width)) args = newargs if all(isinstance(arg, core.Constant) for arg in args) or \ options.pop("symbolic_inputs", False): result = cls.eval(*args) else: raise TypeError("expected bit-vector constant arguments") output = list(core.tuplify(result)) assert len(cls.output_widths) == len(output) for i in range(len(output)): output[i] = core.bitvectify(output[i], cls.output_widths[i]) if isinstance(result, collections.Sequence): return tuple(output) else: return output[0]
def __init__(self, func, diff_type, input_diff, inner_prefix="i", outer_prefix="o"): """Create a composite characteristic.""" assert issubclass(func, function.CompositeFunction) self.func = func self.diff_type = diff_type input_diff = core.tuplify(input_diff) inner_ninputs = len(func.inner_func.input_widths) inner_input_diff = input_diff[-inner_ninputs:] self.inner_ch = Characteristic(func.inner_func, diff_type, inner_input_diff, inner_prefix) outer_input_diff = input_diff[:-inner_ninputs] + self.inner_ch.output_diff self.outer_ch = Characteristic(func.outer_func, diff_type, outer_input_diff, outer_prefix)
def eval(cls, *args): inner_ninputs = len(cls.inner_func.input_widths) evaluated_inner = cls.inner_func(*args[-inner_ninputs:]) evaluated_inner = core.tuplify(evaluated_inner) return cls.outer_func(*args[:-inner_ninputs], *evaluated_inner)
def __init__(self, input_diff, output_diff): """Initialize the differential.""" assert all(isinstance(d, DiffVar) for d in tuplify(input_diff)) assert isinstance(output_diff, DiffVar) super().__init__(input_diff, output_diff)
def __init__(self, input_diff, output_diff): """Initialize the Differential with given input/output differences.""" input_diff = core.tuplify(input_diff) assert len(input_diff) == sum(self.op.arity) self.input_diff = input_diff self.output_diff = output_diff
def propagate(cls, op, input_diff, output_diff=None): """Propagate an input difference variable through a bit-vector op. >>> from arxpy.bitvector.core import Variable, Constant >>> from arxpy.bitvector.operation import BvAdd, BvXor >>> from arxpy.diffcrypt.difference import XorDiff, DiffVar >>> d1, d2 = DiffVar("d1", 8), DiffVar("d2", 8) >>> XorDiff.propagate(BvXor, [d1, d2]) d1 ^ d2 >>> d3 = DiffVar("d3", 8) >>> XorDiff.propagate(BvAdd, [d1, d2], d3) xdp+((d1, d2), d3) Deterministic propagations return bit-vector terms while probabilistic propagations return Differential objects. """ input_diff = core.tuplify(input_diff) assert len(input_diff) == sum(op.arity) msg = "unknown XOR propagation of {}({})".format( type(op).__name__, [d.vrepr() if isinstance(d, core.Term) else d for d in input_diff]) if op == operation.BvNot: x = input_diff[0] if isinstance(x, DiffVar): return x else: raise NotImplementedError(msg) if op == operation.BvXor: newdiffs = [] for d in input_diff: if isinstance(d, DiffVar): newdiffs.append(d) elif isinstance(d, (core.Constant, core.Variable)): newdiffs.append(core.Constant(0, d.width)) else: raise NotImplementedError(msg) return op(*newdiffs) if op in [operation.RotateLeft, operation.RotateRight]: x, r = input_diff if isinstance(x, DiffVar): return op(x, r) else: raise NotImplementedError(msg) if op == operation.Extract: x, i, j = input_diff if isinstance(x, DiffVar): return op(x, i, j) else: raise NotImplementedError(msg) if op == operation.Concat: if all(isinstance(d, DiffVar) for d in input_diff): return op(*input_diff) else: raise NotImplementedError(msg) if op == operation.BvAdd: if all(isinstance(d, DiffVar) for d in input_diff): from arxpy.diffcrypt import differential return differential.XDBvAdd(input_diff, output_diff) else: raise NotImplementedError(msg) if hasattr(op, "differential"): return op.differential(cls)(input_diff, output_diff) raise NotImplementedError(msg)
def propagate(cls, op, input_diff, output_diff=None): """Propagate an input difference variable through a bit-vector op. >>> from arxpy.bitvector.core import Variable, Constant >>> from arxpy.bitvector.operation import BvAdd, BvXor >>> from arxpy.diffcrypt.difference import RXDiff, DiffVar >>> d1, d2 = DiffVar("d1", 8), DiffVar("d2", 8) >>> RXDiff.propagate(BvXor, [d1, d2]) d1 ^ d2 >>> d3 = DiffVar("d3", 8) >>> RXDiff.propagate(BvAdd, [d1, d2], d3) rxdp+((d1, d2), d3) Deterministic propagations return bit-vector terms while probabilistic propagations return Differential objects. """ input_diff = core.tuplify(input_diff) assert len(input_diff) == sum(op.arity) msg = "unknown RX propagation of {}({})".format( type(op).__name__, [d.vrepr() if isinstance(d, core.Term) else d for d in input_diff]) if op == operation.BvNot: x = input_diff[0] if isinstance(x, DiffVar): return x else: raise NotImplementedError(msg) if op == operation.BvXor: if all(isinstance(d, DiffVar) for d in input_diff): return op(*input_diff) else: x, y = input_diff if isinstance(x, core.Constant) and isinstance(y, DiffVar): cte, var = x, y elif isinstance(y, core.Constant) and isinstance(x, DiffVar): cte, var = y, x else: raise NotImplementedError(msg) cte = operation.BvXor(cte, operation.RotateLeft(cte, 1)) return operation.BvXor(var, cte) if op in [operation.RotateLeft, operation.RotateRight]: x, r = input_diff if isinstance(x, DiffVar): return op(x, r) else: raise NotImplementedError(msg) if op == operation.BvAdd: if all(isinstance(d, DiffVar) for d in input_diff): from arxpy.diffcrypt import differential return differential.RXDBvAdd(input_diff, output_diff) else: raise NotImplementedError(msg) if hasattr(op, "differential"): return op.differential(cls)(input_diff, output_diff) raise NotImplementedError(msg)