cascada.linear.characteristic module
Manipulate non-symbolic linear characteristics.
Represent linear characteristics over bit-vector functions. |
|
Represent linear characteristics over encryption functions. |
- class cascada.linear.characteristic.Characteristic(input_mask, output_mask, assign_outmask_list, ch_model, external_masks=None, free_masks=None, empirical_ch_weight=None, empirical_data_list=None, is_valid=True)[source]
Bases:
cascada.abstractproperty.characteristic.Characteristic
Represent linear characteristics over bit-vector functions.
Internally, this class is a subclass of
abstractproperty.characteristic.Characteristic
, where theProperty
is aLinearMask
type.As mentioned in
abstractproperty.characteristic.Characteristic
, the characteristic probability is defined as the product of the propagation probability (absolute correlation) of theLinearMask
pairs (linear approximations) \((\Delta_{x_{i}} \mapsto \Delta_{x_{i+1}})\) over \(f_i\). If \(f\) has external variables, the characteristic probability approximates the absolute correlation of the input-output mask pair of the characteristic averaged over the set of all values of the external variables.>>> from cascada.bitvector.core import Constant >>> from cascada.bitvector.operation import RotateLeft, RotateRight >>> from cascada.linear.mask import LinearMask, LinearMask >>> from cascada.linear.chmodel import ChModel >>> from cascada.linear.characteristic import Characteristic >>> from cascada.primitives import speck >>> Speck32_KS = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64).key_schedule >>> Speck32_KS.set_num_rounds(2) >>> ch_model = ChModel(Speck32_KS, LinearMask, ["mk0", "mk1", "mk2"]) >>> zm = core.Constant(0, width=16) >>> mk0 = RotateLeft(Constant(1, width=16), 8) # mk0 >>> 7 == 0b0···010 >>> mx5 = RotateRight(mk0, 7) # ~ mk0 >>> 7 == 0b0···010 >>> mx3__1 = RotateRight(Constant(1, width=16), 1) # mx3__1 <<< 2 == 0b0···010 >>> mx3_out = core.Constant(0x8002, 16) >>> assign_outmask_list = [zm, zm, zm, zm, mx5, mx3__1, mx5, mx5, zm, mx3_out, mx5] >>> ch = Characteristic([mk0, zm, zm], [zm, mx3_out, mx5], assign_outmask_list, ch_model) >>> ch Characteristic(ch_weight=1, assignment_weights=[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], input_mask=[0x0100, 0x0000, 0x0000], output_mask=[0x0000, 0x8002, 0x0002], assign_outmask_list=[0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x8000, 0x0002, 0x0002, 0x0000, 0x8002, 0x0002]) >>> list(zip(ch.assignment_weights, ch.tuple_assign_outmask2op_model)) [(Decimal('0'), (LinearMask(0x0000), LinearModelFreeBranch(LinearMask(0x0000)))), (Decimal('0'), (LinearMask(0x0000), LinearModelFreeBranch(LinearMask(0x0000)))), (Decimal('0'), (LinearMask(0x0000), LinearModelBvAdd([LinearMask(0x0000), LinearMask(0x0000)]))), (Decimal('0'), (LinearMask(0x0000), LinearModelBvXor([LinearMask(0x0000), LinearMask(0x0000)]))), (Decimal('0'), (LinearMask(0x0002), LinearModelFreeBranch(LinearMask(0x0000)))), (Decimal('0'), (LinearMask(0x8000), LinearModelFreeBranch(LinearMask(0x0000)))), (Decimal('1'), (LinearMask(0x0002), LinearModelBvAdd([LinearMask(0x0002), LinearMask(0x0002)]))), (Decimal('0'), (LinearMask(0x0002), LinearModelBvXor([LinearMask(0x0002), LinearMask(0x0002)]))), (Decimal('0'), (LinearMask(0x0000), LinearModelId(LinearMask(0x0000)))), (Decimal('0'), (LinearMask(0x8002), LinearModelId(LinearMask(0x8002)))), (Decimal('0'), (LinearMask(0x0002), LinearModelId(LinearMask(0x0002))))]
- input_mask
a list of
LinearMask
objects containing the (constant) input mask (alias ofabstractproperty.characteristic.Characteristic.input_prop
).
- output_mask
a list of
LinearMask
objects containing the (constant) output mask (alias ofabstractproperty.characteristic.Characteristic.output_prop
).
- external_masks
a list containing the (constant)
LinearMask
of the external variables of the function (alias ofabstractproperty.characteristic.Characteristic.external_props
).
- tuple_assign_outmask2op_model
a tuple where each element is a pair containing: (1) the output (constant)
LinearMask
\(\Delta_{x_{i+1}}\) of the non-trivial assignment \(x_{i+1} \leftarrow f_i(x_i)\) and (2) thelinear.opmodel.OpModel
of this assignment with a (constant) inputLinearMask
\(\Delta_{x_{i}}\) (alias ofabstractproperty.characteristic.Characteristic.tuple_assign_outprop2op_model
).
- free_masks
a list of (symbolic)
LinearMask
objects of theCharacteristic.ch_model
, whose values do not affect the characteristic, and were replaced by constant masks ininput_mask
,output_mask
,external_masks
ortuple_assign_outmask2op_model
(alias ofabstractproperty.characteristic.Characteristic.free_props
).
- var_mask2ct_mask
a
collections.OrderedDict
mapping each symbolicLinearMask
in the trail to its constant mask (alias ofabstractproperty.characteristic.Characteristic.var_prop2ct_prop
).
- vrepr(ignore_external_masks=False)[source]
Return an executable string representation.
See also
abstractproperty.characteristic.Characteristic.vrepr
.>>> from cascada.bitvector.core import Constant >>> from cascada.bitvector.operation import RotateLeft, RotateRight >>> from cascada.linear.mask import LinearMask >>> from cascada.linear.chmodel import ChModel >>> from cascada.primitives import speck >>> Speck32_KS = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64).key_schedule >>> Speck32_KS.set_num_rounds(2) >>> ch_model = ChModel(Speck32_KS, LinearMask, ["mk0", "mk1", "mk2"]) >>> zm = core.Constant(0, width=16) >>> mk0 = RotateLeft(Constant(1, width=16), 8) # mk0 >>> 7 == 0b0···010 >>> mx5 = RotateRight(mk0, 7) # ~ mk0 >>> 7 == 0b0···010 >>> mx3__1 = RotateRight(Constant(1, width=16), 1) # mx3__1 <<< 2 == 0b0···010 >>> mx3_out = core.Constant(0x8002, 16) >>> assign_outmask_list = [zm, zm, zm, zm, mx5, mx3__1, mx5, mx5, zm, mx3_out, mx5] >>> ch = Characteristic([mk0, zm, zm], [zm, mx3_out, mx5], assign_outmask_list, ch_model) >>> ch.vrepr() "Characteristic(input_mask=[Constant(0x0100, width=16), Constant(0x0000, width=16), Constant(0x0000, width=16)], output_mask=[Constant(0x0000, width=16), Constant(0x8002, width=16), Constant(0x0002, width=16)], assign_outmask_list=[Constant(0x0000, width=16), Constant(0x0000, width=16), Constant(0x0000, width=16), Constant(0x0000, width=16), Constant(0x0002, width=16), Constant(0x8000, width=16), Constant(0x0002, width=16), Constant(0x0002, width=16), Constant(0x0000, width=16), Constant(0x8002, width=16), Constant(0x0002, width=16)], ch_model=ChModel(func=SpeckKeySchedule.set_num_rounds_and_return(2), mask_type=LinearMask, input_mask_names=['mk0', 'mk1', 'mk2'], prefix='mx'))" >>> ch.srepr() 'Ch(w=1, id=0100 0000 0000, od=0000 8002 0002)'
- split(mask_separators)[source]
Split into multiple
Characteristic
objects given the list of mask separators.See also
abstractproperty.characteristic.Characteristic.split
.>>> from cascada.bitvector.core import Constant, Variable >>> from cascada.bitvector.operation import RotateLeft, RotateRight >>> from cascada.linear.mask import LinearMask >>> from cascada.linear.chmodel import ChModel >>> from cascada.linear.characteristic import Characteristic >>> from cascada.primitives import speck >>> Speck32_KS = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64).key_schedule >>> Speck32_KS.set_num_rounds(2) >>> ch_model = ChModel(Speck32_KS, LinearMask, ["mk0", "mk1", "mk2"]) >>> tuple(ch_model.ssa.assignments.items()) ((mx0, mk1 >>> 7), (mk2__0, Id(mk2)), (mk2__1, Id(mk2)), (mk2__2, Id(mk2)), (mx1, mx0 + mk2__0), (mx2, mk2__1 <<< 2), (mx3, mx2 ^ mx1), (mx4, mk0 >>> 7), (mx3__0, Id(mx3)), (mx3__1, Id(mx3)), (mx3__2, Id(mx3)), (mx5, mx4 + mx3__0), (mx6, mx5 ^ 0x0001), (mx7, mx3__1 <<< 2), (mx8, mx7 ^ mx6), (mk2_out, Id(mk2__2)), (mx3_out, Id(mx3__2)), (mx8_out, Id(mx8))) >>> mask_separators = [ (LinearMask(Variable("mx2", width=16)), LinearMask(Variable("mx3", width=16))), ] >>> zm = core.Constant(0, width=16) >>> mk0 = RotateLeft(Constant(1, width=16), 8) # mk0 >>> 7 == 0b0···010 >>> mx5 = RotateRight(mk0, 7) # ~ mk0 >>> 7 == 0b0···010 >>> mx3__1 = RotateRight(Constant(1, width=16), 1) # mx3__1 <<< 2 == 0b0···010 >>> mx3_out = core.Constant(0x8002, 16) >>> assign_outmask_list = [zm, zm, zm, zm, mx5, mx3__1, mx5, mx5, zm, mx3_out, mx5] >>> ch = Characteristic([mk0, zm, zm], [zm, mx3_out, mx5], assign_outmask_list, ch_model) >>> for ch in ch.split(mask_separators): print(ch) Characteristic(ch_weight=0, assignment_weights=[0, 0, 0, 0, 0, 0, 0], input_mask=[0x0100, 0x0000, 0x0000], output_mask=[0x0100, 0x0000, 0x0000], assign_outmask_list=[0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000]) Characteristic(ch_weight=1, assignment_weights=[0, 0, 1, 0, 0, 0, 0], input_mask=[0x0100, 0x0000, 0x0000], output_mask=[0x0000, 0x8002, 0x0002], assign_outmask_list=[0x0002, 0x8000, 0x0002, 0x0002, 0x0000, 0x8002, 0x0002])
- classmethod random(ch_model, seed, external_masks=None)[source]
Return a random
Characteristic
with givenlinear.chmodel.ChModel
.See also
abstractproperty.characteristic.Characteristic.random
.>>> from cascada.linear.mask import LinearMask >>> from cascada.linear.chmodel import ChModel >>> from cascada.linear.characteristic import Characteristic >>> from cascada.bitvector.ssa import BvFunction >>> class MyFoo(BvFunction): ... input_widths, output_widths = [4, 4], [4, 4] ... @classmethod ... def eval(cls, a, b): return a + b, a >>> ch_model = ChModel(MyFoo, LinearMask, ["ma", "mb"]) >>> Characteristic.random(ch_model, 0) Characteristic(ch_weight=2, assignment_weights=[0, 2, 0, 0], input_mask=[0x2, 0x6], output_mask=[0x4, 0x5], assign_outmask_list=[0x7, 0x4, 0x4, 0x5])
- compute_empirical_ch_weight(num_input_samples=None, num_external_samples=None, split_by_max_weight=None, split_by_rounds=False, seed=None, C_code=False, num_parallel_processes=None)[source]
Compute and store the empirical weight.
The main description of this method can be read from
abstractproperty.characteristic.Characteristic.compute_empirical_ch_weight
, simply by replacingProperty
byLinearMask
and input-output pair by hull.The basic subroutine in this case consists of computing the fraction of right inputs for
num_input_samples
sampled inputs. An input \(x\) is a right input if \(\langle \alpha, x \rangle = \langle \beta, f(x) \rangle\), where \(\alpha\) isinput_mask
, \(\beta\) isoutput_mask
and \(f\) is the underlying bit-vector function.>>> from cascada.bitvector.core import Constant >>> from cascada.bitvector.operation import RotateLeft, RotateRight >>> from cascada.linear.mask import LinearMask, LinearMask >>> from cascada.linear.chmodel import ChModel >>> from cascada.linear.characteristic import Characteristic >>> from cascada.primitives import speck >>> Speck32_KS = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64).key_schedule >>> Speck32_KS.set_num_rounds(2) >>> ch_model = ChModel(Speck32_KS, LinearMask, ["mk0", "mk1", "mk2"]) >>> zm = core.Constant(0, width=16) >>> mk0 = RotateLeft(Constant(1, width=16), 8) # mk0 >>> 7 == 0b0···010 >>> mx5 = RotateRight(mk0, 7) # ~ mk0 >>> 7 == 0b0···010 >>> mx3__1 = RotateRight(Constant(1, width=16), 1) # mx3__1 <<< 2 == 0b0···010 >>> mx3_out = core.Constant(0x8002, 16) >>> assign_outmask_list = [zm, zm, zm, zm, mx5, mx3__1, mx5, mx5, zm, mx3_out, mx5] >>> ch = Characteristic([mk0, zm, zm], [zm, mx3_out, mx5], assign_outmask_list, ch_model) >>> ch.compute_empirical_ch_weight(seed=0) >>> ch.empirical_ch_weight Decimal('1.093109404391481470675941626') >>> for data in ch.empirical_data_list: print(data) EmpiricalWeightData(weight_avg_aux_prs=1.093109404391481470675941626, num_aux_weights=1, num_inf_aux_weights=0, num_input_samples=192, seed=0, C_code=False) >>> ch.compute_empirical_ch_weight(seed=0, C_code=True) >>> ch.empirical_ch_weight Decimal('1.061400544664143309159590699')
- class cascada.linear.characteristic.EncryptionCharacteristic(input_mask, output_mask, assign_outmask_list, ch_model, external_masks=None, free_masks=None, empirical_ch_weight=None, empirical_data_list=None, is_valid=True)[source]
Bases:
cascada.abstractproperty.characteristic.EncryptionCharacteristic
,cascada.linear.characteristic.Characteristic
Represent linear characteristics over encryption functions.
Given a
Cipher
, anEncryptionCharacteristic
is a linear characteristic (seeCharacteristic
) over theCipher.encryption
(where theCipher.key_schedule
is ignored and round key masks are given as constantLinearMask
).The propagation probability of an
EncryptionCharacteristic
is similar to the expected linear probability (ELP), but instead of multiplying the absolute correlations, the ELP multiplies the square of the correlations (see https://eprint.iacr.org/2005/212).>>> from cascada.bitvector.core import Constant >>> from cascada.bitvector.operation import RotateRight, RotateLeft >>> from cascada.linear.mask import LinearMask >>> from cascada.linear.chmodel import EncryptionChModel >>> from cascada.linear.characteristic import EncryptionCharacteristic >>> from cascada.primitives import speck >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> Speck32.set_num_rounds(2) >>> ch_model = EncryptionChModel(Speck32, LinearMask) >>> zm = core.Constant(0, width=16) >>> p1 = core.Constant(0x0600, width=16) >>> c0 = core.Constant(0x60f0, width=16) >>> c1 = core.Constant(0x60c0, width=16) >>> k1 = core.Constant(0x0030, width=16) >>> bv_1800 = core.Constant(0x1800, width=16) >>> assign_outmask_list = [zm, zm, zm, bv_1800, bv_1800, k1, k1, k1, c1, c1, c0, c1] >>> ch = EncryptionCharacteristic([zm, p1], [c0, c1], assign_outmask_list, ch_model, [zm, k1]) >>> ch EncryptionCharacteristic(ch_weight=1, assignment_weights=[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], input_mask=[0x0000, 0x0600], output_mask=[0x60f0, 0x60c0], external_masks=[0x0000, 0x0030], assign_outmask_list=[0x0000, 0x0000, 0x0000, 0x1800, 0x1800, 0x0030, 0x0030, 0x0030, 0x60c0, 0x60c0, 0x60f0, 0x60c0]) >>> list(zip(ch.assignment_weights, ch.tuple_assign_outmask2op_model)) [(Decimal('0'), (LinearMask(0x0000), LinearModelFreeBranch(LinearMask(0x0600)))), (Decimal('0'), (LinearMask(0x0000), LinearModelBvAdd([LinearMask(0x0000), LinearMask(0x0000)]))), (Decimal('0'), (LinearMask(0x0000), LinearModelBvXor([LinearMask(0x0000), LinearMask(0x0000)]))), (Decimal('0'), (LinearMask(0x1800), LinearModelFreeBranch(LinearMask(0x0000)))), (Decimal('0'), (LinearMask(0x1800), LinearModelBvXor([LinearMask(0x1800), LinearMask(0x1800)]))), (Decimal('0'), (LinearMask(0x0030), LinearModelFreeBranch(LinearMask(0x1800)))), (Decimal('1'), (LinearMask(0x0030), LinearModelBvAdd([LinearMask(0x0030), LinearMask(0x0030)]))), (Decimal('0'), (LinearMask(0x0030), LinearModelBvXor([LinearMask(0x0030), LinearMask(0x0030)]))), (Decimal('0'), (LinearMask(0x60c0), LinearModelFreeBranch(LinearMask(0x0030)))), (Decimal('0'), (LinearMask(0x60c0), LinearModelBvXor([LinearMask(0x60c0), LinearMask(0x60c0)]))), (Decimal('0'), (LinearMask(0x60f0), LinearModelId(LinearMask(0x60f0)))), (Decimal('0'), (LinearMask(0x60c0), LinearModelId(LinearMask(0x60c0))))]