cascada.smt.invalidpropsearch module
Search for zero-probability (invalid) properties (e.g., impossible differentials or zero-correlation hulls) by modeling the search as a sequence of SMT problems.
Represent the subsets of bit-vectors available depending on which bits are activated (set to 1) for |
|
Search for zero-probability (invalid) property pairs by modeling the search as a sequence of SMT problems. |
|
Search for invalid properties of ciphers by modeling the search as a sequence of SMT problems. |
|
Search for zero-probability (invalid) property pairs of round-based functions over multiple number of rounds. |
|
Search for zero-probability (invalid) properties of iterated ciphers over multiple number of rounds. |
- class cascada.smt.invalidpropsearch.ActiveBitMode(value)[source]
Bases:
enum.Enum
Represent the subsets of bit-vectors available depending on which bits are activated (set to 1) for
find_next_invalidprop_activebitmode
.- Default
all bit-vectors
- SingleBit
bit-vectors with up to one bit activated (zero included)
- MSBbit
bit-vectors with up to the most significant bit activated (zero included)
- Zero
the zero bit-vector
- class cascada.smt.invalidpropsearch.InvalidPropFinder(ch_model, solver_name, check_universally_invalid_ch_found=True, printing_mode=PrintingMode.Silent, filename=None, solver_seed=None, env=None)[source]
Bases:
cascada.smt.chsearch.ChFinder
Search for zero-probability (invalid) property pairs by modeling the search as a sequence of SMT problems.
Given a characteristic model defined for a particular
Property
(e.g.,XorDiff
orLinearMask
), this class finds universally-invalid characteristics following the characteristic model by modelling the search as a sequence of SMT problems in the bit-vector theory.A universally-invalid characteristic is a characteristic where the characteristic input property \(\alpha\) propagates to the characteristic output property \(\beta\) with probability zero regardless of the intermediate properties (i.e., for all assignments of the intermediate properties). In other words, the input-output property pair \((\alpha, \beta)\) has zero propagation probability.
Note
For the
Difference
(resp.LinearMask
) property, a universally-invalid characteristic is actually an impossible differential (resp. a zero-correlation hull).Search for universally-invalid algebraic characteristic is not supported.
Consider the SMT problem \(\Omega\) of whether there exists a valid characteristic with constant input property \(\alpha\) and constant output property \(\beta\) (and where the intermediate properties are not specified). The main idea of the SMT-based search is that one can check whether \(\alpha\) propagates to \(\beta\) with probability zero by checking whether \(\Omega\) is unsatisfiable (UNSAT). Note that only the validity constraints are needed to build \(\Omega\); the weight constraints are ignored when searching for universally-invalid characteristics.
The initialization argument
ch_model
must be a subclass ofabstractproperty.chmodel.ChModel
with up to one non-trivial transitions (abstractproperty.opmodel.OpModel
excludingModelIdentity
), since a zero-probability characteristic with up to one non-trivial transitions is a universally-invalid characteristic. For a characteristic model with more than one non-trivial transitions, the functionget_wrapped_chmodel
can be used to wrap the characteristic model into an equivalent characteristic model with one non-trivial transition.An
InvalidPropFinder
object is also an instance ofChFinder
whereassert_type
isValidity
and with the given initialization argumentsch_model
,solver_name
,printing_mode
,filename
,solver_seed
andenv=env
. See alsoChFinder
.Similar as
ChFinder
, the methods ofInvalidPropFinder
that search for universally-invalid characteristics are Pythongenerator
functions, returning aniterator
that yields the universally-invalid characteristics found in the search. If initialization argumentch_model
is aabstractproperty.chmodel.ChModel
(resp.abstractproperty.chmodel.EncryptionChModel
), then these methods yieldabstractproperty.characteristic.Characteristic
(resp.abstractproperty.characteristic.EncryptionCharacteristic
) objects.If the initialization argument
check_universally_invalid_ch_found
isTrue
, all universally-invalid characteristics found in the search are checked by searching for a valid characteristic with the same input and output property withChFinder.find_next_ch
.>>> # example of SMT problem of universally-invalid LinearMask-EncryptionCharacteristic of (wrapped) Speck32 >>> from cascada.linear.mask import LinearMask >>> from cascada.linear.chmodel import EncryptionChModel >>> from cascada.smt.invalidpropsearch import InvalidPropFinder >>> from cascada.primitives import speck >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> Speck32.set_num_rounds(2) >>> wrapped_ch_model = get_wrapped_chmodel(EncryptionChModel(Speck32, LinearMask)) >>> invalid_prop_finder = InvalidPropFinder(wrapped_ch_model, "z3", solver_seed=0) >>> invalid_prop_finder.formula_size() 133 >>> print(invalid_prop_finder.hrepr(full_repr=True)) ; characteristic model assertions assert (_mx0 == (mx9_out :: mx7_out)) & ((~((mx1 ^ (_mp0 >>> 7)) | (mx1 ^ mp1__0)) | _tmp20affb7ca27930ce775156bcc0ecaf20) == 0xffff) & ((_tmp20affb7ca27930ce775156bcc0ecaf20 ^ (_tmp20affb7ca27930ce775156bcc0ecaf20 >> 0x0001) ^ ((mx1 ^ (_mp0 >>> 7) ^ mp1__0) >> 0x0001)) == 0x0000) & (mx1 == _mk0) & (mx1 == mx2) & (((_mp1 ^ mp1__0) <<< 2) == mx2__0) & (((_mp1 ^ mp1__0) <<< 2) == mx4) & ((~((mx6 ^ ((mx2 ^ mx2__0) >>> 7)) | (mx6 ^ mx4__0)) | _tmp824d7e7c80d9889507eb4e5d5c7be280) == 0xffff) & ((_tmp824d7e7c80d9889507eb4e5d5c7be280 ^ (_tmp824d7e7c80d9889507eb4e5d5c7be280 >> 0x0001) ^ ((mx6 ^ ((mx2 ^ mx2__0) >>> 7) ^ mx4__0) >> 0x0001)) == 0x0000) & (mx6 == _mk1) & (mx6 == mx7) & (((mx4 ^ mx4__0) <<< 2) == mx7__0) & (((mx4 ^ mx4__0) <<< 2) == mx9) & ((mx7 ^ mx7__0) == mx7_out) & (mx9 == mx9_out) assert PropExtract_{·, 15, 0}(_mx0) == _mx1_out assert PropExtract_{·, 31, 16}(_mx0) == _mx2_out
>>> # example of SMT problem of universally-invalid XorDiff-Characteristic of Speck32-KeySchedule >>> from cascada.differential.difference import XorDiff >>> from cascada.differential.chmodel import ChModel >>> from cascada.smt.invalidpropsearch import InvalidPropFinder >>> from cascada.primitives import speck >>> Speck32_KS = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64).key_schedule >>> Speck32_KS.set_num_rounds(1) >>> ch_model = ChModel(Speck32_KS, XorDiff, ["mk0", "mk1"]) >>> invalid_prop_finder = InvalidPropFinder(ch_model, "z3", solver_seed=0) >>> invalid_prop_finder.formula_size() 42 >>> print(invalid_prop_finder.hrepr(full_repr=True)) ; characteristic model assertions assert ((~((mk0 >>> 7) << 0x0001) ^ (mk1 << 0x0001)) & (~((mk0 >>> 7) << 0x0001) ^ (dx1 << 0x0001)) & ((mk0 >>> 7) ^ mk1 ^ dx1 ^ ((mk0 >>> 7) << 0x0001))) == 0x0000 assert mk1 == mk1_out assert ((mk1 <<< 2) ^ dx1) == dx3_out
- find_next_invalidprop_activebitmode(initial_num_active_bits, input_prop_activebitmode, output_prop_activebitmode)[source]
Return an iterator that yields the universally-invalid characteristics found in the SMT-based search with given
ActiveBitMode
.This method searches for universally-invalid characteristic using SMT solvers by checking one-by-one all input and output properties with given
ActiveBitMode
.Given a particular input and output properties \((\alpha, \beta)\), the main subroutine of this method (herein call the check subroutine) checks whether \(\alpha\) propagates to \(\beta\) with probability zero by checking with an SMT solver whether the SMT problem, of whether there exists a valid characteristic with input property \(\alpha\) and output property \(\beta\), is unsatisfiable (UNSAT). If the problem is UNSAT, the universally-invalid
abstractproperty.characteristic.Characteristic
object with input and output properties \((\alpha, \beta)\) is created and yielded.The check subroutine is repeated for all input and output properties where the
ActiveBitMode
of each word in the input (resp. output) property isinput_prop_activebitmode
(resp.output_prop_activebitmode
). The search starts considering input and output properties where the total number of active bits isinitial_num_active_bits
, and the total number of active bits is incremented when all the input and output properties are checked.>>> # example of search for universally-invalid LinearMask-EncryptionCharacteristic of (wrapped) Speck32 >>> from cascada.linear.mask import LinearMask >>> from cascada.linear.chmodel import EncryptionChModel >>> from cascada.smt.invalidpropsearch import InvalidPropFinder, ActiveBitMode >>> from cascada.primitives import speck >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> Speck32.set_num_rounds(2) >>> wrapped_ch_model = get_wrapped_chmodel(EncryptionChModel(Speck32, LinearMask)) >>> invalid_prop_finder = InvalidPropFinder(wrapped_ch_model, "btor", solver_seed=0) >>> inab, ipabm, opabm = 1, ActiveBitMode.MSBit, ActiveBitMode.MSBit >>> for ch in invalid_prop_finder.find_next_invalidprop_activebitmode(inab, ipabm, opabm): ... print(ch.srepr()) Ch(w=Infinity, id=8000 0000, od=8000 0000) Ch(w=Infinity, id=8000 0000, od=0000 8000) Ch(w=Infinity, id=0000 8000, od=8000 0000) Ch(w=Infinity, id=0000 8000, od=0000 8000) Ch(w=Infinity, id=8000 0000, od=8000 8000) Ch(w=Infinity, id=0000 8000, od=8000 8000) Ch(w=Infinity, id=8000 8000, od=8000 0000) Ch(w=Infinity, id=8000 8000, od=0000 8000) Ch(w=Infinity, id=8000 8000, od=8000 8000) >>> # example of SMT problem of universally-invalid XorDiff-Characteristic of Speck32-KeySchedule >>> from cascada.differential.difference import XorDiff >>> from cascada.differential.chmodel import ChModel >>> Speck32_KS = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64).key_schedule >>> Speck32_KS.set_num_rounds(1) >>> ch_model = ChModel(Speck32_KS, XorDiff, ["mk0", "mk1"]) >>> invalid_prop_finder = InvalidPropFinder(ch_model, "btor", solver_seed=0) >>> inab, ipabm, opabm = 1, ActiveBitMode.SingleBit, ActiveBitMode.SingleBit >>> ch = next(invalid_prop_finder.find_next_invalidprop_activebitmode(inab, ipabm, opabm)) >>> print(ch) Characteristic(ch_weight=inf, assignment_weights=[inf, inf, 0], input_diff=[0x0001, 0x0000], output_diff=[0x0001, 0x0000], assign_outdiff_list=[0x0000, 0x0001, 0x0000])
- find_next_invalidprop_miss_in_the_middle(ch_model_E0, ch_model_E2, ch_model_E=None, ch_model_external_E=None, exclude_zero_input_prop_E0=True, exclude_zero_input_prop_E2=True, exclude_zero_input_prop_external_E=None)[source]
Return an iterator that yields the universally-invalid characteristics found in the SMT+MitM-based search.
This method searches for universally-invalid characteristic using SMT problems and the miss-in-the-middle approach.
Let \(E\) be a function split into three functions \(E = E_2 \circ E_1 \circ E_0\). Let \(((p_0, p_1), (p_2, p_3))\) denote a partial characteristic over \(E\), that is, a characteristic over \(E\) where:
\((p_0, p_1)\) are the non-zero input and output properties of a characteristic with probability 1 over \(E_0\)
\((p_2, p_3)\) are the non-zero input and output properties of a characteristic with probability 1 over \(E_2\)
no relation is imposed between \((p_1, p_2)\), the input and output properties of \(E_1\).
The underlying function of
self.ch_model
corresponds to \(E_1\), the underlying function of theabstractproperty.chmodel.ChModel
ch_model_E0
corresponds to \(E_0\), and the underlying function of theabstractproperty.chmodel.ChModel
ch_model_E2
corresponds to \(E_2\). The underlying function of theabstractproperty.chmodel.ChModel
ch_model_E
corresponds to \(E\), but this argument is optional (more on that later).By default the input properties of
ch_model_E0
andch_model_E2
are excluded to be zero, but this can be changed with the optional argumentsexclude_zero_input_prop_*
.Note
This method requires that for any probability-one characteristic over \(E_0\) with input-output property \((p_0, p_1)\), there is no other probability-one characteristic over \(E_0\) with input property \(p_0\) but output property \(\neq p_1\).
Similarly, for any probability-one characteristic over \(E_2\) with input-output property \((p_2, p_3)\), there is no other probability-one characteristic over \(E_2\) with output property \(p3\) but input property \(\neq p_2\).
If \(E_0\) and \(E_2\) are permutations, then these two requirements are satisfied for
Difference
andLinearMask
properties.If the optional argument
ch_model_external_E
is given as aabstractproperty.chmodel.ChModel
with input and output properties \((q_0, q_1)\), the definition of a partial characteristic is extended to \(((p_0, p_1), (p_2, p_3), (q_0, q_1)\) such that \((q_0, q_1)\) are the input and output properties of a characteristic with probability 1 where \(q_1\) is the list of external variables of \(E\) (seeSSA
). Ifch_model_external_E
is given, the argumentexclude_zero_input_prop_external_E
that determines whether to exclude non-zero \(q_0\) must also be given.Note
The functions \((E_0, E_1, E_2)\) can be easily obtained from a
RoundBasedFunction
\(E\) that includesadd_round_outputs
calls in itseval
.For example, obtaining \(E_0\) from the round
ns
tons+ne0
(ns
denoting the initial number of skipped rounds), \(E_1\) as the nextne1
rounds, and \(E_2\) as the nextne2
rounds can be done as follows:[...] ns, ne0, ne1, ne2 = ... MyRoundBasedFunction.set_num_rounds(ns+ne0+ne1+ne2) ch_model_E = ChModel(MyRoundBasedFunction, ...) rs = ch_model.get_round_separators() # the end of the i-th round (i=1,2,...) is rs[i-1] e0_rs, e1_rs = rs[ns+ne0-1], rs[ns+ne0+ne1-1] ch_model_E0, ch_model_E1, ch_model_E2 = ch_model_E.split([e0_rs, e1_rs]) ch_model_E1 = get_wrapped_chmodel(ch_model_E1) # in case ch_model_E1 2+ non-trivial transitions invalid_prop_finder = InvalidPropFinder(ch_model_E1, ...) invalid_prop_finder.find_next_invalidprop_miss_in_the_middle( ch_model_E0=ch_model_E0, ch_model_E2=ch_model_E2, ch_model_E=ch_model_E)
Alternatively, one can use the function
round_based_invalidprop_search
which automates the generation of \((E_0, E_1, E_2)\) and applies this method iteratively on the number of rounds.This method finds universally-invalid characteristics by searching for all partial characteristics over \(E\) using
ChFinder.find_next_ch
, and for each partial characteristic we apply the check subroutine to check whether \(p_1\) propagates to \(p_2\) with zero probability over \(E_1\). The check subroutine is explained infind_next_invalidprop_activebitmode
.For each partial characteristic \(((p_0, p_1), (p_2, p_3))\) found, if the check subroutine finds that \(p_1\) propagates to \(p_2\) with zero probability, a tuple of 3
abstractproperty.characteristic.Characteristic
is yielded:the first characteristic corresponds to the characteristic with probability 1 over \(E_0\) with input and output properties \((p_0, p_1)\)
the second characteristic corresponds to the universally-invalid characteristic over \(E_1\) with input and output properties \((p_1, p_2)\)
the third characteristic corresponds to the characteristic with probability 1 over \(E_2\) with input and output properties \((p_2, p_3)\)
Since the first and third characteristics have probability one, the concatenation of these three characteristics is a universally-invalid characteristic over \(E\) (regardless of the external variables of \(E\))
If the optional argument
ch_model_external_E
is given, instead a tuple of 4 characteristic is yieled; the 4-th characteristic corresponds to the characteristic with probability 1 with input and output properties \((q_0, q_1)\). In this case, the concatenation of the first 3 characteristics is a universally-invalid characteristic over \(E\) for the external properties given by the outputs of the 4-th characteristic.If the initialization argument
check_universally_invalid_ch_found
isTrue
, all universally-invalid characteristics found over \(E_1\) in the search are checked by searching for a valid characteristic with the same input and output property withChFinder.find_next_ch
. In addition, if the optional argumentch_model_E
is given, then the universally-invalid characteristic over \(E\) (the concatenation of the characteristic founds over \(E_0\), \(E_1\) and \(E_2\)) is also checked in a similar way.>>> # example of search for universally-invalid LinearMask-EncryptionCharacteristic of (wrapped) Speck32 >>> from cascada.linear.mask import LinearMask >>> from cascada.linear.chmodel import EncryptionChModel >>> from cascada.smt.invalidpropsearch import InvalidPropFinder >>> from cascada.primitives import speck >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> Speck32.set_num_rounds(3) >>> ch_model_E = EncryptionChModel(Speck32, LinearMask) >>> ch_model_E0, ch_model_E1, ch_model_E2 = ch_model_E.split(ch_model_E.get_round_separators()) >>> ch_model_E1 = get_wrapped_chmodel(ch_model_E1) >>> invalid_prop_finder = InvalidPropFinder(ch_model_E1, "btor", solver_seed=0) >>> tuple_iterator = invalid_prop_finder.find_next_invalidprop_miss_in_the_middle(ch_model_E0, ch_model_E2) >>> for i, (pr1_ch_E0, uni_inv_ch_E1, pr1_ch_E2) in enumerate(tuple_iterator): ... print(pr1_ch_E0.srepr(), uni_inv_ch_E1.srepr(), pr1_ch_E2.srepr()) ... if i == 2: break Ch(w=0, id=0000 0001, od=0004 0004) Ch(w=Infinity, id=0004 0004, od=0000 0001) Ch(w=0, id=0000 0001, od=0004 0004) Ch(w=0, id=0000 0001, od=0004 0004) Ch(w=Infinity, id=0004 0004, od=0080 e001) Ch(w=0, id=0080 e001, od=8002 8003) Ch(w=0, id=0000 0001, od=0004 0004) Ch(w=Infinity, id=0004 0004, od=0080 f001) Ch(w=0, id=0080 f001, od=c002 c003) >>> # example of SMT problem of universally-invalid XorDiff-Characteristic of Speck32-KeySchedule >>> from cascada.differential.difference import XorDiff >>> from cascada.differential.chmodel import ChModel >>> Speck32_KS = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64).key_schedule >>> Speck32_KS.set_num_rounds(3) >>> ch_model_E = ChModel(Speck32_KS, XorDiff, ["mk0", "mk1", "mk2", "mk3"]) >>> ch_model_E0, ch_model_E1, ch_model_E2 = ch_model_E.split(ch_model_E.get_round_separators()) >>> invalid_prop_finder = InvalidPropFinder(ch_model_E1, "btor", solver_seed=0) >>> ti = invalid_prop_finder.find_next_invalidprop_miss_in_the_middle(ch_model_E0, ch_model_E2, ch_model_E=ch_model_E) >>> pr1_ch_E0, uni_inv_ch_E1, pr1_ch_E2 = next(ti) >>> print(pr1_ch_E0) Characteristic(ch_weight=0, assignment_weights=[0, 0, 0, 0, 0], input_diff=[0x0001, 0x0001, 0x0000, 0x0000], output_diff=[0x0001, 0x0000, 0x0001, 0x0000], assign_outdiff_list=[0x0000, 0x0001, 0x0000, 0x0001, 0x0000]) >>> print(uni_inv_ch_E1) Characteristic(ch_weight=inf, assignment_weights=[inf, inf, 0, inf, inf], input_diff=[0x0001, 0x0000, 0x0001, 0x0000], output_diff=[0x0000, 0x8000, 0x0001, 0x0001], assign_outdiff_list=[0x8000, 0x0000, 0x8000, 0x0001, 0x0001]) >>> print(pr1_ch_E2) Characteristic(ch_weight=0, assignment_weights=[0, 0, 0, 0, 0], input_diff=[0x0000, 0x8000, 0x0001, 0x0001], output_diff=[0x0001, 0x0001, 0x8000, 0x8002], assign_outdiff_list=[0x8000, 0x0001, 0x0001, 0x8000, 0x8002])
- find_next_invalidprop_quantified_logic()[source]
Return an iterator that yields the universally-invalid characteristics found in the quantified SMT-based search.
This method searches for universally-invalid characteristic using SMT problems in the quantified bit-vector logic (with the ForAll quantifier).
Let \(P(\alpha, \gamma_1, \dots, \gamma_t, \beta)\) be the underlying bit-vector formula of the decision problem of whether there exists a characteristic following the characteristic model
ch_model
with non-zero probability, where \((\alpha, \beta)\) is the input and output properties and \((\gamma_1, \dots, \gamma_t)\) are the intermediate properties.First, this method creates the decision problem of whether there exists an assignment of the input and output properties \((\alpha, \beta)\) such that for all intermediate properties \((\gamma_1, \dots, \gamma_t)\) the negation of \(P\) is True; in other words, the decision problem given by the underlying quantified formula \(\exists \alpha, \beta, \forall \gamma_1, \dots, \gamma_t : \ \neg P(\alpha, \gamma_1, \dots, \gamma_t, \beta)\)
If the SMT solver finds the first problem satisfiable, an assignment of the input and output properties \((\alpha, \beta)\) that makes \(\neg P(\alpha, \gamma_1, \dots, \gamma_t, \beta) = True\) is obtained, and a universally-invalid
abstractproperty.characteristic.Characteristic
object is created and yielded.Afterwards, an additional constraint is added to the SMT problem to exclude the characteristic yielded and this procedure is repeated until all characteristics are found.
This method requires that the SMT solver given in
solver_name
supports the bit-vector logic with quantifiers. Although the recent version of boolector supports the bit-vector logic with quantifiers, pySMT does not support yet this recent feature of boolector.>>> # example of search for universally-invalid XorDiff-EncryptionCharacteristic of (wrapped) Speck32 >>> from cascada.differential.difference import XorDiff >>> from cascada.differential.chmodel import EncryptionChModel >>> from cascada.smt.invalidpropsearch import InvalidPropFinder >>> from cascada.primitives import speck >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> Speck32.set_num_rounds(2) >>> wrapped_ch_model = get_wrapped_chmodel(EncryptionChModel(Speck32, XorDiff)) >>> invalid_prop_finder = InvalidPropFinder(wrapped_ch_model, "z3", solver_seed=0) >>> for i, ch in enumerate(invalid_prop_finder.find_next_invalidprop_quantified_logic()): ... print(ch.srepr()) ... if i == 2: break Ch(w=Infinity, id=..., od=...) Ch(w=Infinity, id=..., od=...) Ch(w=Infinity, id=..., od=...) >>> # example of SMT problem of universally-invalid RXDiff-Characteristic of Speck32-KeySchedule >>> from cascada.differential.difference import RXDiff >>> from cascada.differential.chmodel import ChModel >>> Speck32_KS = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64).key_schedule >>> Speck32_KS.set_num_rounds(1) >>> ch_model = ChModel(Speck32_KS, RXDiff, ["mk0", "mk1"]) >>> invalid_prop_finder = InvalidPropFinder(ch_model, "z3", solver_seed=0) >>> for i, ch in enumerate(invalid_prop_finder.find_next_invalidprop_quantified_logic()): ... print(ch.srepr()) ... if i == 2: break Ch(w=Infinity, id=..., od=...) Ch(w=Infinity, id=..., od=...) Ch(w=Infinity, id=..., od=...)
- hrepr(full_repr=False)[source]
Return a human-readable representation of the base SMT problem.
The base SMT problem is the decision problem of whether there exists a valid characteristic for an input-output property pair. In other words, it contains the validity assertions of the underlying characteristic model.
The methods
InvalidPropFinder.find_next_invalidprop_activebitmode
andInvalidPropFinder.find_next_invalidprop_miss_in_the_middle
check for the unsatisfiability of this base SMT problem (with some additional constraints), whileInvalidPropFinder.find_next_invalidprop_quantified_logic
uses this base SMT problem to create a quantified bit-vector formula.If
full_repr
is False, the short string representation srepr is used.
- class cascada.smt.invalidpropsearch.InvalidCipherPropFinder(ch_model, solver_name, check_universally_invalid_ch_found=True, printing_mode=PrintingMode.Silent, filename=None, solver_seed=None, env=None)[source]
Bases:
cascada.smt.invalidpropsearch.InvalidPropFinder
Search for invalid properties of ciphers by modeling the search as a sequence of SMT problems.
Given a characteristic model of a
Cipher
(abstractproperty.chmodel.CipherChModel
) defined for a particularProperty
(e.g.,XorDiff
orRXDiff
), this class finds universally-invalid cipher characteristics (abstractproperty.characteristic.CipherCharacteristic
) following the characteristic model by modelling the search as a sequence of SMT problems in the bit-vector theory.Given a cipher characteristic, let \(\alpha_{KS}\) be the input property of the underlying key-schedule characteristic and \((\alpha_{ENC}, \beta_{ENC})\) be the input and output properties of the underlying encryption characteristic. A universally-invalid characteristic over a cipher is a characteristic where \((\alpha_{KS}, \alpha_{ENC})\) propagates to \(\beta_{ENC}\) with probability zero regardless of the intermediate properties. In other words, the input-output property pair \(((\alpha_{KS}, \alpha_{ENC}), \beta_{ENC})\) has zero propagation probability.
Note
For the
Difference
property, a universally-invalid characteristic over a cipher is actually a related-key impossible differential.To initialize an
InvalidCipherPropFinder
object, first two auxiliary instances ofInvalidPropFinder
are created:ks_finder
anInvalidPropFinder
with characteristic modelch_model.ks_ch_model
enc_finder
anInvalidPropFinder
with characteristic modelch_model.enc_ch_model
Both
ks_finder
andenc_finder
(together with theInvalidCipherPropFinder
object) share the argumentssolver_name
,printing_mode
,filename
,solver_seed
andenv
.Then, these two auxiliary
InvalidPropFinder
objects are merged into anInvalidCipherPropFinder
(which is also an instance ofInvalidPropFinder
) as follows:solver_name
,printing_mode
,filename
,solver_seed
env
are the same as the ones fromks_finder
andenc_finder
ch_model
is set to the characteristic model of the cipher (a subclass ofabstractproperty.chmodel.CipherChModel
)chmodel_asserts
is the union ofchmodel_asserts
ofks_finder
andenc_finder
See also
ChFinder
.>>> from cascada.differential.difference import XorDiff >>> from cascada.differential.chmodel import CipherChModel >>> from cascada.smt.invalidpropsearch import InvalidCipherPropFinder, get_wrapped_cipher_chmodel >>> from cascada.primitives import speck >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> Speck32.set_num_rounds(2) >>> ch_model = get_wrapped_cipher_chmodel(CipherChModel(Speck32, XorDiff)) >>> invalid_prop_finder = InvalidCipherPropFinder(ch_model, "btor", solver_seed=0) >>> invalid_prop_finder.formula_size() 177 >>> print(invalid_prop_finder.hrepr(full_repr=False)) ; characteristic model assertions assert (_dk0 == (dk3_out :: dmk1_out)) & ((... & ... & (... ^ ...)) == 0x0000) & (_dmk1 == dmk1_out) & (((_dmk1 <<< 2) ^ dk1) == dk3_out) assert PropExtract_{·, 15, 0}(_dk0) == _dk1_out assert PropExtract_{·, 31, 16}(_dk0) == _dk2_out assert (_dx0 == (dx9_out :: dx7_out)) & ((... & ...) == 0x0000) & ((... & ...) == 0x0000) & ((dx6 ^ _dk2_out) == dx7_out) & ((((... ^ ...) <<< 2) ^ dx6 ^ _dk2_out) == dx9_out) assert PropExtract_{·, 15, 0}(_dx0) == _dx1_out assert PropExtract_{·, 31, 16}(_dx0) == _dx2_out
- find_next_invalidprop_activebitmode(initial_num_active_bits, input_prop_activebitmode, output_prop_activebitmode)[source]
Return an iterator that yields the universally-invalid characteristics found in the SMT-based search with given
ActiveBitMode
.This method is similar to
InvalidPropFinder.find_next_invalidprop_activebitmode
; the only difference is that the input property considered by this method is the concatenation of the input property of the underlying key-schedule characteristic and the input property of the underlying encryption characteristic, and the output property considered by this method is the output property of the encryption characteristic. In other words,output_prop_activebitmode
only affects to the output property of the encryption characteristic and not to the output property of the key-schedule characteristic.>>> from cascada.differential.difference import XorDiff >>> from cascada.differential.chmodel import CipherChModel >>> from cascada.smt.invalidpropsearch import InvalidCipherPropFinder, ActiveBitMode, get_wrapped_cipher_chmodel >>> from cascada.primitives import speck >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> Speck32.set_num_rounds(2) >>> ch_model = get_wrapped_cipher_chmodel(CipherChModel(Speck32, XorDiff)) >>> invalid_prop_finder = InvalidCipherPropFinder(ch_model, "btor", solver_seed=0) >>> inab, ipabm, opabm = 1, ActiveBitMode.MSBit, ActiveBitMode.Zero >>> for ch in invalid_prop_finder.find_next_invalidprop_activebitmode(inab, ipabm, opabm): ... print(ch.srepr()) Ch(ks_ch=Ch(w=Infinity, id=8000 0000, od=0000 0000), enc_ch=Ch(w=0, id=0000 0000, od=0000 0000)) Ch(ks_ch=Ch(w=Infinity, id=0000 8000, od=0000 0000), enc_ch=Ch(w=0, id=0000 0000, od=0000 0000)) Ch(ks_ch=Ch(w=0, id=0000 0000, od=0000 0000), enc_ch=Ch(w=Infinity, id=8000 0000, od=0000 0000)) Ch(ks_ch=Ch(w=0, id=0000 0000, od=0000 0000), enc_ch=Ch(w=Infinity, id=0000 8000, od=0000 0000)) Ch(ks_ch=Ch(w=Infinity, id=8000 8000, od=0000 0000), enc_ch=Ch(w=0, id=0000 0000, od=0000 0000)) Ch(ks_ch=Ch(w=Infinity, id=8000 0000, od=0000 0000), enc_ch=Ch(w=Infinity, id=8000 0000, od=0000 0000)) Ch(ks_ch=Ch(w=Infinity, id=8000 0000, od=0000 0000), enc_ch=Ch(w=Infinity, id=0000 8000, od=0000 0000)) Ch(ks_ch=Ch(w=0, id=0000 8000, od=8000 8002), enc_ch=Ch(w=Infinity, id=8000 0000, od=0000 0000)) Ch(ks_ch=Ch(w=0, id=0000 8000, od=8000 8002), enc_ch=Ch(w=Infinity, id=0000 8000, od=0000 0000)) Ch(ks_ch=Ch(w=0, id=0000 0000, od=0000 0000), enc_ch=Ch(w=Infinity, id=8000 8000, od=0000 0000)) Ch(ks_ch=Ch(w=Infinity, id=8000 8000, od=0000 0000), enc_ch=Ch(w=Infinity, id=8000 0000, od=0000 0000)) Ch(ks_ch=Ch(w=Infinity, id=8000 8000, od=0000 0000), enc_ch=Ch(w=Infinity, id=0000 8000, od=0000 0000)) Ch(ks_ch=Ch(w=Infinity, id=8000 0000, od=0000 0000), enc_ch=Ch(w=Infinity, id=8000 8000, od=0000 0000)) Ch(ks_ch=Ch(w=0, id=0000 8000, od=8000 8002), enc_ch=Ch(w=Infinity, id=8000 8000, od=0000 0000)) Ch(ks_ch=Ch(w=Infinity, id=8000 8000, od=0000 0000), enc_ch=Ch(w=Infinity, id=8000 8000, od=0000 0000))
- find_next_invalidprop_miss_in_the_middle(*args, **kargs)[source]
This method is disabled, see
round_based_invalidcipherprop_search
for an alternative.
- find_next_invalidprop_quantified_logic()[source]
Return an iterator that yields the universally-invalid characteristics found in the quantified SMT-based search.
See also
InvalidPropFinder.find_next_invalidprop_quantified_logic
.>>> from cascada.differential.difference import RXDiff >>> from cascada.differential.chmodel import CipherChModel >>> from cascada.smt.invalidpropsearch import InvalidCipherPropFinder, get_wrapped_cipher_chmodel >>> from cascada.primitives import speck >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> Speck32.set_num_rounds(2) >>> ch_model = get_wrapped_cipher_chmodel(CipherChModel(Speck32, RXDiff)) >>> invalid_prop_finder = InvalidCipherPropFinder(ch_model, "z3", solver_seed=0) >>> uni_inv_ch = next(invalid_prop_finder.find_next_invalidprop_quantified_logic()) >>> print(uni_inv_ch) CipherCharacteristic(ks_characteristic=Characteristic(ch_weight=..., assignment_weights=[..., ..., ...], input_diff=[..., ...], output_diff=[..., ...], assign_outdiff_list=[..., ..., ...]), enc_characteristic=Characteristic(ch_weight=..., assignment_weights=[..., ..., ...], input_diff=[..., ...], output_diff=[..., ...], external_diffs=[..., ...], assign_outdiff_list=[..., ..., ...]))
- cascada.smt.invalidpropsearch.round_based_invalidprop_search(func, initial_num_rounds, final_num_rounds, prop_type, solver_name, max_num_skipped_rounds=0, min_num_E0_rounds=1, min_num_E2_rounds=1, extra_chmodel_args=None, extra_invalidpropfinder_args=None, exclude_zero_input_prop_E0=True, exclude_zero_input_prop_E2=True, **kwargs)[source]
Search for zero-probability (invalid) property pairs of round-based functions over multiple number of rounds.
This function searches for universally-invalid characteristics (leading to invalid properties, see
InvalidPropFinder
) of aRoundBasedFunction
func
by modelling the search as a sequence of SMT problems (usingInvalidPropFinder.find_next_invalidprop_miss_in_the_middle
), but the search is perfomed iteratively over the number of rounds offunc
. That is, first universally-invalid characteristics coveringinitial_num_rounds
rounds are searched, theninitial_num_rounds + 1
, untilfinal_num_rounds
. See alsoround_based_ch_search
.Note
The
RoundBasedFunction
func
must includeadd_round_outputs
calls in itseval
.While
InvalidPropFinder
requires wrapping the characteristic model if it has more than one non-trivial transition, this method does require the functionfunc
to be not wrapped.This method also requires that for all the round functions \(f_i\) of
func
(generated throughSSA.split
withSSA.get_round_separators
), given any probability-one characteristic over \(f\) with input-output property \((\alpha, \beta)\), then there is no other probability-one characteristic with input property \(\alpha\) (resp. output property \(\beta\)) but output property \(\neq \beta\) (resp. input property \(\neq \alpha\)). If all the round functions are permutations, then this is satisfied forDifference
andLinearMask
properties. See alsoInvalidPropFinder.find_next_invalidprop_miss_in_the_middle
.This function proceed as follows:
Set the current number of rounds of the universally-invalid characteristics to search for to
initial_num_rounds
.Set the current number of initial rounds to skip to
0
.Set the number of rounds of
func
to the sum of the number of rounds of step 1 and step 2, and splitfunc
into \(E \circ S\) (\(S\) denotes the skipped rounds and \(E\) the target function of the universally-invalid characteristics to search for).Create a
abstractproperty.chmodel.ChModel
(resp.abstractproperty.chmodel.EncryptionChModel
) object of \(E\) using as argumentsprop_type
andextra_chmodel_args
.Split \(E\) into \(E = E_2 \circ E_1 \circ E_0\) taking into account
min_num_E0_rounds, min_num_E2_rounds
and generate the characteristic models of \((E_0, E_1, E_2)\) usingabstractproperty.chmodel.ChModel.get_round_separators
andabstractproperty.chmodel.ChModel.split
. SeeInvalidPropFinder.find_next_invalidprop_miss_in_the_middle
for more details about \((E_0, E_1, E_2)\).Create an
InvalidPropFinder
object with arguments the characteristic model over \(E_1\),solver_name
andextra_invalidpropfinder_args
.Loop over the generator
InvalidPropFinder.find_next_invalidprop_miss_in_the_middle
(with argumentsexclude_zero_input_prop_E0
andexclude_zero_input_prop_E2
) and yield all the 3-length tuples of characteristics from the generator (together with the current number of rounds).After the generator is exhausted, go to step 5 but splitting \(E\) into antoher another partition \((E_0, E_1, E_2)\).
If all partitions has been exhausted, instead increase the current number of initial rounds to skip (up to
max_num_skipped_rounds
) and go to step 3.If the current number of skipped rounds was
max_num_skipped_rounds
, instead increase the current number of rounds of the universally-invalid characteristics to search for and go to step 2.If this number was
final_num_rounds
, instead the search is finished.
This function is a Python
generator
function (seeInvalidPropFinder
), returning aniterator
that yields 2-length tuples:The first element in the tuple is a 4-length tuple containing the number of initial skipped rounds, the number of rounds of \(E_0\), the number of rounds of \(E_1\) and the number of rounds of \(E_2\).
The second element in the tuple is a 3-length tuple containing the characteristics over \(E_0\), \(E_1\) and \(E_2\) respectively (i.e., the outputs of
InvalidPropFinder.find_next_invalidprop_miss_in_the_middle
). Note that these characteristics areabstractproperty.characteristic.Characteristic
objects iffunc
is aRoundBasedFunction
object, orabstractproperty.characteristic.EncryptionCharacteristic
objects iffunc
is aRoundBasedFunction
-encryption function of aCipher
.
The argument
prop_type
is a particularProperty
such asXorDiff
orLinearMask
. Forsolver_name
, seeInvalidPropFinder
. The optional argumentsextra_chmodel_args
andextra_invalidpropfinder_args
can be given as dictionaries (in the form of**kwargs
) containing additional arguments forChModel/EncryptionChModel
andInvalidPropFinder
respectively.It is possible to abort the current search for the current number of rounds and start the search with one more round by passing the value
INCREMENT_NUM_ROUNDS
to the generator iterator withgenerator.send
(seeround_based_ch_search
).This function reuses information from previous partitions \((E_0', E_1', E_2')\) to directly avoid some new partitions \((E_0, E_1, E_2)\) that don’t contain universally-invalid characteristics. Assume that no universally-invalid characteristic was found for the partition \((E_0', E_1', E_2')\), where \(E_0'\) covers from the \(a'\)-th round to the \(b'\)-th round (i.e.,
a'-›b'
) and \(E_2'\) coversc'-›d'
. Then it holds that no universally-invalid characteristic can be found usingInvalidPropFinder.find_next_invalidprop_miss_in_the_middle
from any partition \((E_0, E_1, E_2)\) where \(E_0\) coversa-›a'-›b'-›b
and \(E_2\) coversc-›c'-›d'-›d
, that is, from any partition \((E_0, E_1, E_2)\) where \(E_0\) coversa-›b
and \(E_2\) coversc-›d
such that \(a \le a', b' \le b, c \le c\) and \(d' \le d\).Note
Note that
InvalidPropFinder
contains other methods to search for universally-invalid characteristics (e.g.,InvalidPropFinder.find_next_invalidprop_activebitmode
orInvalidPropFinder.find_next_invalidprop_quantified_logic
) which might find universally-invalid characteristics faster.>>> # example of searching for XorDiff universally-invalid Characteristic over a BvFunction >>> from cascada.differential.difference import XorDiff >>> from cascada.smt.invalidpropsearch import round_based_invalidprop_search, INCREMENT_NUM_ROUNDS >>> from cascada.primitives import speck >>> Speck32_ks = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64).key_schedule >>> iterator = round_based_invalidprop_search(Speck32_ks, 3, 3, XorDiff, "btor", ... extra_invalidpropfinder_args={"solver_seed":0}) >>> for i, (tuple_rounds, tuple_chs) in enumerate(iterator): ... print(tuple_rounds, ":", ', '.join([ch.srepr() for ch in tuple_chs])) ... if i == 2: break (0, 1, 1, 1) : Ch(w=0, id=..., od=...), Ch(w=Infinity, id=..., od=...), Ch(w=0, id=..., od=...) (0, 1, 1, 1) : Ch(w=0, id=..., od=...), Ch(w=Infinity, id=..., od=...), Ch(w=0, id=..., od=...) (0, 1, 1, 1) : Ch(w=0, id=..., od=...), Ch(w=Infinity, id=..., od=...), Ch(w=0, id=..., od=...) >>> # example of searching for LinearMask universally-invalid EncryptionCharacteristic over a Cipher >>> from cascada.linear.mask import LinearMask >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> iterator = round_based_invalidprop_search(Speck32, 4, 5, LinearMask, "btor", ... min_num_E0_rounds=2, extra_invalidpropfinder_args={"solver_seed":0}) >>> tuple_rounds, tuple_chs = next(iterator) >>> print(tuple_rounds, ":", ', '.join([ch.srepr() for ch in tuple_chs])) (0, 2, 1, 1) : Ch(w=0, id=0080 4021, od=0201 0200), Ch(w=Infinity, id=0201 0200, od=0000 0001), Ch(w=0, id=0000 0001, od=0004 0004) >>> tuple_rounds, tuple_chs = next(iterator) >>> print(tuple_rounds, ":", ', '.join([ch.srepr() for ch in tuple_chs])) (0, 2, 1, 1) : Ch(w=0, id=0080 4021, od=0201 0200), Ch(w=Infinity, id=0201 0200, od=0080 e001), Ch(w=0, id=0080 e001, od=8002 8003) >>> iterator.send(INCREMENT_NUM_ROUNDS) # stop current num_rounds and increment by 1 >>> tuple_rounds, tuple_chs = next(iterator) >>> print(tuple_rounds, ":", ', '.join([ch.srepr() for ch in tuple_chs])) (0, 2, 1, 2) : Ch(w=0, id=0080 4021, od=0201 0200), Ch(w=Infinity, id=0201 0200, od=0080 4021), Ch(w=0, id=0080 4021, od=0201 0200)
- cascada.smt.invalidpropsearch.round_based_invalidcipherprop_search(cipher, initial_num_rounds, final_num_rounds, prop_type, solver_name, max_num_skipped_rounds=0, min_num_E0_rounds=1, min_num_E2_rounds=1, extra_cipherchmodel_args=None, extra_invalidcipherpropfinder_args=None, exclude_zero_input_prop_E0=True, exclude_zero_input_prop_E2=True, exclude_zero_input_prop_external_E=True)[source]
Search for zero-probability (invalid) properties of iterated ciphers over multiple number of rounds.
Note
The
Cipher.encryption
ofcipher
must be aRoundBasedFunction
includingadd_round_outputs
calls in itseval
.This function is similar to
round_based_invalidprop_search
. The only differences are:The function
func
(i.e., \(E \circ S\)) is theCipher.encryption
of the givencipher
. Thus, \(S\) denote the skipped rounds of the encryption function.Let \(K\) denote the
Cipher.key_schedule
ofcipher
, that is, the function whose outputs are the round keys used in \(E \circ S\). The generatorInvalidPropFinder.find_next_invalidprop_miss_in_the_middle
is called with the argumentch_model_external_E
given as the characteristic model over \(K\) and with the argumentexclude_zero_input_prop_external_E
.This function yields 2-length tuples where the 2nd element is a 4-length tuple; the last characteristic is the characteristic with probability 1 over \(K\). Thus, the concatenation of the first 3 characteristics is a universally-invalid characteristic over \(E\) where the round key properties are given by the outputs of the probability-one characteristic over \(K\).
Note that initial rounds are only skipped in the encryption function and not in the key-schedule function.
Note
Let
(tuple_nr, tuple_ch)
be an element yielded byround_based_invalidcipherprop_search
.Let \(\alpha_{K}\) be the input property of the 4-th characteristic in
tuple_ch
, and let \((\alpha_{E}, \beta_{E})\) be the input-output property pair of the concatenation of the first three characteristic intuple_ch
.If
tuple_nr[0]
is 0, no initial rounds are skipped, and \((\alpha_{K}, \alpha_{E}) \mapsto \beta_{E}\) is a universally-invalid cipher characteristic (as defined inInvalidCipherPropFinder
) ofcipher.set_num_rounds_and_return(tuple_nr[1]+tuple_nr[2]+tuple_nr[3])
, that is, thecipher
with number of roundstuple_nr[1]+tuple_nr[2]+tuple_nr[3]
.If
tuple_nr[0]
is not zero then a universally-invalid cipher characteristic is also obtained but the underlying cipher is more difficult to generate due to the skipped initial rounds.>>> from cascada.differential.difference import XorDiff >>> from cascada.smt.invalidpropsearch import round_based_invalidcipherprop_search >>> from cascada.primitives import speck >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> iterator = round_based_invalidcipherprop_search(Speck32, 3, 3, XorDiff, "btor", ... extra_invalidcipherpropfinder_args={"solver_seed":0}) >>> for i, (tuple_rounds, tuple_chs) in enumerate(iterator): ... print(tuple_rounds, ":", ', '.join([ch.srepr() for ch in tuple_chs])) ... if i == 1: break (0, 1, 1, 1) : Ch(w=0, id=0000 8000, od=8000 8002), Ch(w=Infinity, id=8000 8002, od=0000 8000), Ch(w=0, id=0000 8000, od=0002 0000), Ch(w=0, id=0000 0040 0000, od=0000 8000 8002) (0, 1, 1, 1) : Ch(w=0, id=0000 8000, od=8000 8002), Ch(w=Infinity, id=8000 8002, od=0040 8000), Ch(w=0, id=0040 8000, od=8002 8000), Ch(w=0, id=0000 0040 0000, od=0000 8000 8002)