cascada.linear.chmodel module
Manage bit-vector models of linear characteristics.
Represent bit-vector models of linear characteristics over bit-vector functions.  | 
|
Represent linear characteristic models of encryption functions.  | 
- class cascada.linear.chmodel.ChModel(func, mask_type, input_mask_names, prefix='mx', external_var2mask=None, op_model_class2options=None)[source]
 Bases:
cascada.abstractproperty.chmodel.ChModelRepresent bit-vector models of linear characteristics over bit-vector functions.
Internally, this class is a subclass of
abstractproperty.chmodel.ChModel, where thePropertyis aLinearMasktype and the probability of the characteristic here considered is the product of the absolute linear correlation of the linear approximations \((\Delta_{x_{i}} \mapsto \Delta_{x_{i+1}})\) composing the characteristic (seelinear.characteristic.Characteristic).To handle the propagation of masks through branching subroutines (i.e., \(x \mapsto (x, x)\)), the
SSAof theBvFunctionis computed with the initialization argumentreplace_multiuse_varsset toTrueand the new free masks are wrapped inLinearModelFreeBranchobjects (see alsoSSAandLinearModelFreeBranch).If the
SSAof theBvFunctioncontains externalVariableobjects and theirLinearMaskobjects are not provided in the initialization throughexternal_var2mask, these free external masks are wrapped inLinearMaskobjects.Linear characteristic models of functions with unused input vars is currently not supported.
>>> from cascada.bitvector.core import Variable >>> 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"]) >>> ch_model ChModel(func=SpeckKeySchedule_2R, input_mask=[LinearMask(mk0), LinearMask(mk1), LinearMask(mk2)], output_mask=[LinearMask(mk2_out), LinearMask(mx3_out), LinearMask(mx8_out)], assign_outmask2op_model=[(LinearMask(mk2__0), LinearModelFreeBranch(LinearMask(mk2))), (LinearMask(mk2__1), LinearModelFreeBranch(LinearMask(mk2))), (LinearMask(mx1), LinearModelBvAdd([LinearMask(mk1 >>> 7), LinearMask(mk2__0)])), (LinearMask(mx3), LinearModelBvXor([LinearMask(mk2__1 <<< 2), LinearMask(mx1)])), (LinearMask(mx3__0), LinearModelFreeBranch(LinearMask(mx3))), (LinearMask(mx3__1), LinearModelFreeBranch(LinearMask(mx3))), (LinearMask(mx5), LinearModelBvAdd([LinearMask(mk0 >>> 7), LinearMask(mx3__0)])), (LinearMask(mx8), LinearModelBvXor([LinearMask(mx3__1 <<< 2), LinearMask(mx5)])), (LinearMask(mk2_out), LinearModelId(LinearMask(mk2 ^ mk2__0 ^ mk2__1))), (LinearMask(mx3_out), LinearModelId(LinearMask(mx3 ^ mx3__0 ^ mx3__1))), (LinearMask(mx8_out), LinearModelId(LinearMask(mx8)))]) >>> ch_model.ssa SSA(input_vars=[mk0, mk1, mk2], output_vars=[mk2_out, mx3_out, mx8_out], assignments=[(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_type
 the mask type (currently only
LinearMaskis supported); alias ofabstractproperty.chmodel.ChModel.prop_type.
- input_mask
 a list of
LinearMaskobjects containing the (symbolic) input mask (alias ofabstractproperty.chmodel.ChModel.input_prop).
- output_mask
 a list of
LinearMaskobjects containing the (symbolic) output mask (alias ofabstractproperty.chmodel.ChModel.output_prop).
- external_var2mask
 a
collections.OrderedDictmapping the external variables ofabstractproperty.chmodel.ChModel.ssato their associated (symbolic or constant)LinearMaskobjects (alias ofabstractproperty.chmodel.ChModel.external_var2prop).
- assign_outmask2op_model
 a
collections.OrderedDictmapping the outputLinearMask\(\Delta_{x_{i+1}}\) of the non-trivial assignment \(x_{i+1} \leftarrow f_i(x_i)\) to thelinear.opmodel.OpModelof this assignment (alias ofabstractproperty.chmodel.ChModel.assign_outprop2op_model).
- var2mask
 a
collections.OrderedDictmapping each variable inabstractproperty.chmodel.ChModel.ssato its associatedLinearMaskobject (alias ofabstractproperty.chmodel.ChModel.var2prop).
- vrepr()[source]
 Return an executable string representation.
See also
abstractproperty.chmodel.ChModel.vrepr.>>> from cascada.bitvector.core import Variable >>> 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"]) >>> ch_model.vrepr() "ChModel(func=SpeckKeySchedule.set_num_rounds_and_return(2), mask_type=LinearMask, input_mask_names=['mk0', 'mk1', 'mk2'], prefix='mx')"
- validity_assertions()[source]
 Return the validity constraint as a list of assertions.
See also
abstractproperty.chmodel.ChModel.validity_assertions.>>> from functools import reduce >>> from cascada.bitvector.core import Variable >>> from cascada.bitvector.operation import BvAnd >>> 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"]) >>> assertions = ch_model.validity_assertions() >>> for a in assertions: print(a) ((~((mx1 ^ (mk1 >>> 7)) | (mx1 ^ mk2__0)) | _tmp5b87dfbff36ecd792bff9b4a837080cc) == 0xffff) & ((_tmp5b87dfbff36ecd792bff9b4a837080cc ^ (_tmp5b87dfbff36ecd792bff9b4a837080cc >> 0x0001) ^ ((mx1 ^ (mk1 >>> 7) ^ mk2__0) >> 0x0001)) == 0x0000) ((mk2__1 <<< 2) == mx1) & ((mk2__1 <<< 2) == mx3) ((~((mx5 ^ (mk0 >>> 7)) | (mx5 ^ mx3__0)) | _tmp496354c626556f9b918d51527d988998) == 0xffff) & ((_tmp496354c626556f9b918d51527d988998 ^ (_tmp496354c626556f9b918d51527d988998 >> 0x0001) ^ ((mx5 ^ (mk0 >>> 7) ^ mx3__0) >> 0x0001)) == 0x0000) ((mx3__1 <<< 2) == mx5) & ((mx3__1 <<< 2) == mx8) (mk2 ^ mk2__0 ^ mk2__1) == mk2_out (mx3 ^ mx3__0 ^ mx3__1) == mx3_out mx8 == mx8_out >>> validity_constraint = reduce(BvAnd, assertions) >>> validity_constraint ((~((mx1 ^ (mk1 >>> 7)) | (mx1 ^ mk2__0)) | ...
- pr_one_assertions()[source]
 Return the probability-one constraint as a list of assertions.
See also
abstractproperty.chmodel.ChModel.pr_one_assertions.>>> from cascada.bitvector.core import Variable >>> 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"]) >>> for a in ch_model.pr_one_assertions(): print(a) (~((mx1 ^ (mk1 >>> 7)) | (mx1 ^ mk2__0)) == 0xffff) & (((mx1 ^ (mk1 >>> 7) ^ mk2__0)[:1]) == 0b000000000000000) ((mk2__1 <<< 2) == mx1) & ((mk2__1 <<< 2) == mx3) (~((mx5 ^ (mk0 >>> 7)) | (mx5 ^ mx3__0)) == 0xffff) & (((mx5 ^ (mk0 >>> 7) ^ mx3__0)[:1]) == 0b000000000000000) ((mx3__1 <<< 2) == mx5) & ((mx3__1 <<< 2) == mx8) (mk2 ^ mk2__0 ^ mk2__1) == mk2_out (mx3 ^ mx3__0 ^ mx3__1) == mx3_out mx8 == mx8_out
- weight_assertions(ch_weight_variable, assign_weight_variables, truncate=True)[source]
 Return the weight constraint as a list of assertions.
See also
abstractproperty.chmodel.ChModel.weight_assertions.>>> from cascada.bitvector.core import Variable >>> 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) >>> cm = ChModel(Speck32_KS, LinearMask, ["mk0", "mk1", "mk2"]) >>> cwv = Variable("w", cm.weight_width()) >>> omvs = [Variable(f"w{i}", om.weight_width()) for i, om in enumerate(cm.assign_outmask2op_model.values())] >>> for a in cm.weight_assertions(cwv, omvs): print(a) w0 == 0b0 w1 == 0b0 (PopCount(_tmp5b87dfbff36ecd792bff9b4a837080cc[14:]) == w2) & ((_tmp5b87dfbff36ecd792bff9b4a837080cc ^ (_tmp5b87dfbff36ecd792bff9b4a837080cc >> 0x0001) ^ ((mx1 ^ (mk1 >>> 7) ^ mk2__0) >> 0x0001)) == 0x0000) w3 == 0b0 w4 == 0b0 w5 == 0b0 (PopCount(_tmp496354c626556f9b918d51527d988998[14:]) == w6) & ((_tmp496354c626556f9b918d51527d988998 ^ (_tmp496354c626556f9b918d51527d988998 >> 0x0001) ^ ((mx5 ^ (mk0 >>> 7) ^ mx3__0) >> 0x0001)) == 0x0000) w7 == 0b0 w8 == 0b0 w9 == 0b0 w10 == 0b0 w == ((0b0 :: w2) + (0b0 :: w6))
- max_weight(truncate=True)[source]
 Return the maximum value the ch. weight variable can achieve in
weight_assertions.See also
abstractproperty.chmodel.ChModel.max_weight.>>> from cascada.bitvector.core import Variable >>> 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) >>> cm = ChModel(Speck32_KS, LinearMask, ["mk0", "mk1", "mk2"]) >>> cm.max_weight(), cm.weight_width(), cm.num_frac_bits() (30, 5, 0)
- error()[source]
 Return the maximum difference between
weight_assertionsand the exact weight.See also
abstractproperty.chmodel.ChModel.error.>>> from cascada.bitvector.core import Variable >>> 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) >>> ChModel(Speck32_KS, LinearMask, ["mk0", "mk1", "mk2"]).error() 0
- signature(sig_type)[source]
 Return the signature of the characteristic model.
See also
abstractproperty.chmodel.ChModel.signature.>>> from cascada.bitvector.core import Variable >>> from cascada.linear.mask import LinearMask >>> from cascada.linear.chmodel import ChModel, ChModelSigType >>> 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"]) >>> ch_model.signature(ChModelSigType.Unique) [mk2, mk1, mk2__0, mx3, mk0, mx3__0, mk2_out, mx3_out, mx8_out] >>> ch_model.signature(ChModelSigType.InputOutput) [mk0, mk1, mk2, mk2_out, mx3_out, mx8_out]
- split(mask_separators)[source]
 Split into multiple
ChModelobjects given the list of mask separators.See also
abstractproperty.chmodel.ChModel.split.>>> from cascada.bitvector.core import Variable >>> from cascada.linear.mask import LinearMask >>> from cascada.linear.chmodel import ChModel, ChModelSigType >>> 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))), ] >>> for cm in ch_model.split(mask_separators): print(cm) ChModel(func=SpeckKeySchedule_2R_0S, input_mask=[LinearMask(mk0), LinearMask(mk1), LinearMask(mk2)], output_mask=[LinearMask(mk0_out), LinearMask(mx3_out), LinearMask(mk2__2_out)], assign_outmask2op_model=[(LinearMask(mk2__0), LinearModelFreeBranch(LinearMask(mk2))), (LinearMask(mk2__1), LinearModelFreeBranch(LinearMask(mk2))), (LinearMask(mx1), LinearModelBvAdd([LinearMask(mk1 >>> 7), LinearMask(mk2__0)])), (LinearMask(mx3), LinearModelBvXor([LinearMask(mk2__1 <<< 2), LinearMask(mx1)])), (LinearMask(mk0_out), LinearModelId(LinearMask(mk0))), (LinearMask(mx3_out), LinearModelId(LinearMask(mx3))), (LinearMask(mk2__2_out), LinearModelId(LinearMask(mk2 ^ mk2__0 ^ mk2__1)))]) ChModel(func=SpeckKeySchedule_2R_1S, input_mask=[LinearMask(mk0), LinearMask(mx3), LinearMask(mk2__2)], output_mask=[LinearMask(mk2_out), LinearMask(mx3_out), LinearMask(mx8_out)], assign_outmask2op_model=[(LinearMask(mx3__0), LinearModelFreeBranch(LinearMask(mx3))), (LinearMask(mx3__1), LinearModelFreeBranch(LinearMask(mx3))), (LinearMask(mx5), LinearModelBvAdd([LinearMask(mk0 >>> 7), LinearMask(mx3__0)])), (LinearMask(mx8), LinearModelBvXor([LinearMask(mx3__1 <<< 2), LinearMask(mx5)])), (LinearMask(mk2_out), LinearModelId(LinearMask(mk2__2))), (LinearMask(mx3_out), LinearModelId(LinearMask(mx3 ^ mx3__0 ^ mx3__1))), (LinearMask(mx8_out), LinearModelId(LinearMask(mx8)))])
- get_round_separators()[source]
 Return the round separators if
funcis aRoundBasedFunction.See also
abstractproperty.chmodel.ChModel.get_round_separators.>>> 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"]) >>> sub_cms = ch_model.split(ch_model.get_round_separators()) >>> for cm in sub_cms: print(cm) ChModel(func=SpeckKeySchedule_2R_0S, input_mask=[LinearMask(mk0), LinearMask(mk1), LinearMask(mk2)], output_mask=[LinearMask(mk0_out), LinearMask(mx3_out), LinearMask(mk2__2_out)], assign_outmask2op_model=[(LinearMask(mk2__0), LinearModelFreeBranch(LinearMask(mk2))), (LinearMask(mk2__1), LinearModelFreeBranch(LinearMask(mk2))), (LinearMask(mx1), LinearModelBvAdd([LinearMask(mk1 >>> 7), LinearMask(mk2__0)])), (LinearMask(mx3), LinearModelBvXor([LinearMask(mk2__1 <<< 2), LinearMask(mx1)])), (LinearMask(mk0_out), LinearModelId(LinearMask(mk0))), (LinearMask(mx3_out), LinearModelId(LinearMask(mx3))), (LinearMask(mk2__2_out), LinearModelId(LinearMask(mk2 ^ mk2__0 ^ mk2__1)))]) ChModel(func=SpeckKeySchedule_2R_1S, input_mask=[LinearMask(mk0), LinearMask(mx3), LinearMask(mk2__2)], output_mask=[LinearMask(mk2_out), LinearMask(mx3_out), LinearMask(mx8_out)], assign_outmask2op_model=[(LinearMask(mx3__0), LinearModelFreeBranch(LinearMask(mx3))), (LinearMask(mx3__1), LinearModelFreeBranch(LinearMask(mx3))), (LinearMask(mx5), LinearModelBvAdd([LinearMask(mk0 >>> 7), LinearMask(mx3__0)])), (LinearMask(mx8), LinearModelBvXor([LinearMask(mx3__1 <<< 2), LinearMask(mx5)])), (LinearMask(mk2_out), LinearModelId(LinearMask(mk2__2))), (LinearMask(mx3_out), LinearModelId(LinearMask(mx3 ^ mx3__0 ^ mx3__1))), (LinearMask(mx8_out), LinearModelId(LinearMask(mx8)))])
- class cascada.linear.chmodel.EncryptionChModel(cipher, mask_type, op_model_class2options=None)[source]
 Bases:
cascada.abstractproperty.chmodel.EncryptionChModel,cascada.linear.chmodel.ChModelRepresent linear characteristic models of encryption functions.
Given a
Cipher, anEncryptionChModelis a bit-vector model (seeChModel) of a linear characteristic over theCipher.encryption(where theCipher.key_scheduleis ignored and round key masks are set toLinearMaskobjects containingVariableobjects).See also
linear.characteristic.EncryptionCharacteristic.In an
EncryptionChModel, the plaintext masks start with the prefix"mp", the intermediate and output masks start with the prefix"mx", and the round key masks (the masks of the external variables of the encryptionSSA) start with the prefix"mk".>>> from cascada.bitvector.core import Variable >>> from cascada.linear.mask import LinearMask >>> from cascada.linear.chmodel import EncryptionChModel >>> 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) >>> ch_model EncryptionChModel(cipher=SpeckCipher_2R, input_mask=[LinearMask(mp0), LinearMask(mp1)], output_mask=[LinearMask(mx7_out), LinearMask(mx9_out)], external_var2mask=[(mk0, LinearMask(mk0)), (mk1, LinearMask(mk1))], assign_outmask2op_model=[(LinearMask(mp1__0), LinearModelFreeBranch(LinearMask(mp1))), (LinearMask(mx1), LinearModelBvAdd([LinearMask(mp0 >>> 7), LinearMask(mp1__0)])), (LinearMask(mx2), LinearModelBvXor([LinearMask(mx1), LinearMask(mk0)])), (LinearMask(mx2__0), LinearModelFreeBranch(LinearMask(mx2))), (LinearMask(mx4), LinearModelBvXor([LinearMask((mp1 ^ mp1__0) <<< 2), LinearMask(mx2__0)])), (LinearMask(mx4__0), LinearModelFreeBranch(LinearMask(mx4))), (LinearMask(mx6), LinearModelBvAdd([LinearMask((mx2 ^ mx2__0) >>> 7), LinearMask(mx4__0)])), (LinearMask(mx7), LinearModelBvXor([LinearMask(mx6), LinearMask(mk1)])), (LinearMask(mx7__0), LinearModelFreeBranch(LinearMask(mx7))), (LinearMask(mx9), LinearModelBvXor([LinearMask((mx4 ^ mx4__0) <<< 2), LinearMask(mx7__0)])), (LinearMask(mx7_out), LinearModelId(LinearMask(mx7 ^ mx7__0))), (LinearMask(mx9_out), LinearModelId(LinearMask(mx9)))]) >>> ch_model.ssa SSA(input_vars=[mp0, mp1], output_vars=[mx7_out, mx9_out], external_vars=[mk0, mk1], assignments=[(mx0, mp0 >>> 7), (mp1__0, Id(mp1)), (mp1__1, Id(mp1)), (mx1, mx0 + mp1__0), (mx2, mx1 ^ mk0), (mx3, mp1__1 <<< 2), (mx2__0, Id(mx2)), (mx2__1, Id(mx2)), (mx4, mx3 ^ mx2__0), (mx5, mx2__1 >>> 7), (mx4__0, Id(mx4)), (mx4__1, Id(mx4)), (mx6, mx5 + mx4__0), (mx7, mx6 ^ mk1), (mx8, mx4__1 <<< 2), (mx7__0, Id(mx7)), (mx7__1, Id(mx7)), (mx9, mx8 ^ mx7__0), (mx7_out, Id(mx7__1)), (mx9_out, Id(mx9))])
- vrepr()[source]
 Return an executable string representation.
See also
abstractproperty.chmodel.EncryptionChModel.vrepr.>>> from cascada.bitvector.core import Variable >>> from cascada.linear.mask import LinearMask >>> from cascada.linear.chmodel import EncryptionChModel >>> from cascada.primitives import speck >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> Speck32.set_num_rounds(2) >>> EncryptionChModel(Speck32, LinearMask).vrepr() 'EncryptionChModel(cipher=SpeckCipher.set_num_rounds_and_return(2), mask_type=LinearMask)'