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.ChModel
Represent bit-vector models of linear characteristics over bit-vector functions.
Internally, this class is a subclass of
abstractproperty.chmodel.ChModel
, where theProperty
is aLinearMask
type 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
SSA
of theBvFunction
is computed with the initialization argumentreplace_multiuse_vars
set toTrue
and the new free masks are wrapped inLinearModelFreeBranch
objects (see alsoSSA
andLinearModelFreeBranch
).If the
SSA
of theBvFunction
contains externalVariable
objects and theirLinearMask
objects are not provided in the initialization throughexternal_var2mask
, these free external masks are wrapped inLinearMask
objects.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
LinearMask
is supported); alias ofabstractproperty.chmodel.ChModel.prop_type
.
- input_mask
a list of
LinearMask
objects containing the (symbolic) input mask (alias ofabstractproperty.chmodel.ChModel.input_prop
).
- output_mask
a list of
LinearMask
objects containing the (symbolic) output mask (alias ofabstractproperty.chmodel.ChModel.output_prop
).
- external_var2mask
a
collections.OrderedDict
mapping the external variables ofabstractproperty.chmodel.ChModel.ssa
to their associated (symbolic or constant)LinearMask
objects (alias ofabstractproperty.chmodel.ChModel.external_var2prop
).
- assign_outmask2op_model
a
collections.OrderedDict
mapping the outputLinearMask
\(\Delta_{x_{i+1}}\) of the non-trivial assignment \(x_{i+1} \leftarrow f_i(x_i)\) to thelinear.opmodel.OpModel
of this assignment (alias ofabstractproperty.chmodel.ChModel.assign_outprop2op_model
).
- var2mask
a
collections.OrderedDict
mapping each variable inabstractproperty.chmodel.ChModel.ssa
to its associatedLinearMask
object (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_assertions
and 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
ChModel
objects 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
func
is 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.ChModel
Represent linear characteristic models of encryption functions.
Given a
Cipher
, anEncryptionChModel
is a bit-vector model (seeChModel
) of a linear characteristic over theCipher.encryption
(where theCipher.key_schedule
is ignored and round key masks are set toLinearMask
objects containingVariable
objects).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)'