arxpy.differential.characteristic module¶
Manage characteristics.
-
class
arxpy.differential.characteristic.
ChSignatureType
[source]¶ Bases:
enum.Enum
Represent the different types of signatures available for a characteristic.
-
Full
¶ the signature includes the input and all output differences of each non-linear operation.
-
InputOutput
¶ the signature only includes the input and output differences
-
-
class
arxpy.differential.characteristic.
BvCharacteristic
(func, diff_type, input_diff_names, prefix='d', initial_var2diff=None)[source]¶ Bases:
object
Represent characteristics of bit-vector functions.
Given a bit-vector function
BvFunction
\(f\), a characteristic is a trail of differences obtained by propagating an input difference over \(f\).In particular, a characteristic is composed of the input difference and the output difference of each non-linear operation.
This class manages symbolic characteristics, where the input difference is given symbolically and the intermediate differences are
Term
that depend on the input difference.>>> from arxpy.bitvector.core import Variable >>> from arxpy.differential.difference import XorDiff, RXDiff >>> from arxpy.differential.characteristic import BvCharacteristic >>> from arxpy.primitives.primitives import BvFunction >>> from arxpy.primitives.chaskey import ChaskeyPi >>> issubclass(ChaskeyPi, BvFunction) True >>> ChaskeyPi.set_rounds(1) >>> ch = BvCharacteristic(ChaskeyPi, XorDiff, ["dv0", "dv1", "dv2", "dv3"]) >>> ch.ssa {'input_vars': (dv0, dv1, dv2, dv3), 'output_vars': (d7, d12, d13, d9), 'assignments': ((d0, dv0 + dv1), (d1, dv1 <<< 5), (d2, d0 ^ d1), (d3, d0 <<< 16), (d4, dv2 + dv3), (d5, dv3 <<< 8), (d6, d4 ^ d5), (d7, d3 + d6), (d8, d6 <<< 13), (d9, d7 ^ d8), (d10, d2 + d4), (d11, d2 <<< 7), (d12, d10 ^ d11), (d13, d10 <<< 16))} >>> ch.input_diff (XorDiff(dv0), XorDiff(dv1), XorDiff(dv2), XorDiff(dv3)) >>> ch.nonlinear_diffs OrderedDict([(XorDiff(d0), XDA(XorDiff(dv0), XorDiff(dv1))), (XorDiff(d4), XDA(XorDiff(dv2), XorDiff(dv3))), (XorDiff(d7), XDA(XorDiff(d0 <<< 16), XorDiff(d4 ^ (dv3 <<< 8)))), (XorDiff(d10), XDA(XorDiff(d0 ^ (dv1 <<< 5)), XorDiff(d4)))]) >>> ch.output_diff [[XorDiff(d7), XorDiff(d7)], [XorDiff(d12), XorDiff(d10 ^ ((d0 ^ (dv1 <<< 5)) <<< 7))], [XorDiff(d13), XorDiff(d10 <<< 16)], [XorDiff(d9), XorDiff(d7 ^ ((d4 ^ (dv3 <<< 8)) <<< 13))]] >>> ch = BvCharacteristic(ChaskeyPi, RXDiff, ["dv0", "dv1", "dv2", "dv3"]) >>> ch.input_diff (RXDiff(dv0), RXDiff(dv1), RXDiff(dv2), RXDiff(dv3)) >>> ch.nonlinear_diffs OrderedDict([(RXDiff(d0), RXDA(RXDiff(dv0), RXDiff(dv1))), (RXDiff(d4), RXDA(RXDiff(dv2), RXDiff(dv3))), (RXDiff(d7), RXDA(RXDiff(d0 <<< 16), RXDiff(d4 ^ (dv3 <<< 8)))), (RXDiff(d10), RXDA(RXDiff(d0 ^ (dv1 <<< 5)), RXDiff(d4)))]) >>> ch.output_diff [[RXDiff(d7), RXDiff(d7)], [RXDiff(d12), RXDiff(d10 ^ ((d0 ^ (dv1 <<< 5)) <<< 7))], [RXDiff(d13), RXDiff(d10 <<< 16)], [RXDiff(d9), RXDiff(d7 ^ ((d4 ^ (dv3 <<< 8)) <<< 13))]]
-
func
¶ the
BvFunction
-
diff_type
¶ the
Difference
of the characteristic
-
input_diff
¶ a list containing the input symbolic differences
-
nonlinear_diffs
¶ an
collections.OrderedDict
mapping non-linear symbolic differences to their correspondingDerivative
-
output_diff
¶ a list, where the i-th element is a pair containing the i-th output symbolic difference and its value
-
empirical_weight
(input_diff, output_diff, pair_samples)[source]¶ Return the empirical weight of a given differential.
Given a differential (a pair of input and output differences), the differential probability is the fraction of input pairs with the given input difference leading to output pairs with the given output difference.
This method returns an approximation of the weight of the differential probability by sampling a given number of input pairs.
If no correct output pairs are found,
math.inf
is returned.>>> from arxpy.bitvector.core import Constant >>> from arxpy.differential.difference import XorDiff, RXDiff >>> from arxpy.differential.characteristic import BvCharacteristic >>> from arxpy.primitives.chaskey import ChaskeyPi >>> ChaskeyPi.set_rounds(1) >>> ch = BvCharacteristic(ChaskeyPi, XorDiff, ["dv" + str(i) for i in range(4)]) >>> zero, one = XorDiff(Constant(0, 32)), XorDiff(Constant(1, 32)) >>> ch.empirical_weight([zero, zero, zero, zero], [zero, zero, zero, zero], 100) 0.0 >>> ch.empirical_weight([zero, zero, zero, zero], [one, one, one, one], 100) inf >>> ch = BvCharacteristic(ChaskeyPi, RXDiff, ["dv" + str(i) for i in range(4)]) >>> zero, one = RXDiff(Constant(0, 32)), RXDiff(Constant(1, 32)) >>> 4 - 1 <= ch.empirical_weight([zero]*4, [zero]*4, 3 * 2**6) <= 8 True >>> ch.empirical_weight([zero]*4, [one]*4, 3 * 2**6) inf
-
signature
(ch_signature_type)[source]¶ Return the signature of the characteristic.
The signature is a “hash” of the characteristic used for comparing.
For the type of the signature, see
ChSignatureType
.>>> from arxpy.bitvector.core import Variable >>> from arxpy.differential.difference import XorDiff >>> from arxpy.differential.characteristic import BvCharacteristic, ChSignatureType >>> from arxpy.primitives.primitives import BvFunction >>> from arxpy.primitives.chaskey import ChaskeyPi >>> issubclass(ChaskeyPi, BvFunction) True >>> ChaskeyPi.set_rounds(1) >>> ch = BvCharacteristic(ChaskeyPi, XorDiff, ["dv0", "dv1", "dv2", "dv3"]) >>> ch.signature(ChSignatureType.Full) [dv0, dv1, dv2, dv3, d0, d4, d7, d10] >>> ch.signature(ChSignatureType.InputOutput) [dv0, dv1, dv2, dv3, d7, d12, d13, d9]
-
-
class
arxpy.differential.characteristic.
SingleKeyCh
(bv_cipher, diff_type)[source]¶ Bases:
arxpy.differential.characteristic.BvCharacteristic
Represent single-key characteristics of block ciphers.
A single-key characteristic of a
Cipher
is aBvCharacteristic
over theEncryption
function of the cipher.The plaintext differences start with the prefix
"dp"
and the non-linear differences start with the prefix"dx"
.>>> from arxpy.bitvector.core import Variable >>> from arxpy.differential.difference import XorDiff >>> from arxpy.differential.characteristic import SingleKeyCh >>> from arxpy.primitives.primitives import Cipher >>> from arxpy.primitives import speck >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> issubclass(Speck32, Cipher) True >>> Speck32.set_rounds(1) >>> ch = SingleKeyCh(Speck32, XorDiff) >>> ch .ssa {'input_vars': (dp0, dp1), 'output_vars': (dx2, dx4), 'assignments': ((dx0, dp0 >>> 7), (dx1, dp1 + dx0), (dx2, dx1 ^ k0), (dx3, dp1 <<< 2), (dx4, dx2 ^ dx3))} >>> ch.input_diff (XorDiff(dp0), XorDiff(dp1)) >>> ch.nonlinear_diffs OrderedDict([(XorDiff(dx1), XDA(XorDiff(dp1), XorDiff(dp0 >>> 7)))]) >>> ch.output_diff [[XorDiff(dx2), XorDiff(dx1)], [XorDiff(dx4), XorDiff(dx1 ^ (dp1 <<< 2))]]
-
empirical_weight
(input_diff, output_diff, pair_samples, key_samples, precision=1, rk_diffs=None)[source]¶ Return the empirical weight distribution of a given differential.
This method returns a
collections.Counter
storing the distribution of differential probability weights over the given number of keys.The weights are rounded to the given number of precision digits after the decimal point.
See also
BvCharacteristic.empirical_weight
.>>> from arxpy.bitvector.core import Constant >>> from arxpy.differential.difference import XorDiff >>> from arxpy.differential.characteristic import SingleKeyCh >>> from arxpy.primitives import speck >>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64) >>> Speck32.set_rounds(1) >>> ch = SingleKeyCh(Speck32, XorDiff) >>> zero, one = XorDiff(Constant(0, 16)), XorDiff(Constant(1, 16)) >>> ch.empirical_weight([zero, zero], [zero, zero], 100, 10) Counter({0.0: 10}) >>> ch.empirical_weight([zero, zero], [one, one], 100, 10) Counter({inf: 10})
-
-
class
arxpy.differential.characteristic.
RelatedKeyCh
(bv_cipher, diff_type)[source]¶ Bases:
object
Represent related-key characteristics of block ciphers.
A related-key characteristic of a
Cipher
is a pairBvCharacteristic
, one over theKeySchedule
of the cipher, and another one over the theEncryption
function of the cipher, where the output differences of the key schedule characteristic are used as round key differences in the encryption characteristic.The master key differences start with the prefix
"dmk"
, the round key differences start with the prefix"dk"
, the plaintext differences start with the prefix"dp"
and the non-linear differences start with the prefix"dx"
.>>> from arxpy.bitvector.core import Variable >>> from arxpy.differential.difference import XorDiff >>> from arxpy.differential.characteristic import RelatedKeyCh >>> from arxpy.primitives.primitives import Cipher >>> from arxpy.primitives.lea import LeaCipher >>> issubclass(LeaCipher, Cipher) True >>> LeaCipher.set_rounds(1) >>> rkch = RelatedKeyCh(LeaCipher, XorDiff) >>> rkch .key_schedule_ch.ssa {'input_vars': (dmk0, dmk1, dmk2, dmk3), 'output_vars': (dk1, dk3, dk5, dk3, dk7, dk3), 'assignments': ((dk0, 0xc3efe9db + dmk0), (dk1, dk0 <<< 1), (dk2, 0x87dfd3b7 + dmk1), (dk3, dk2 <<< 3), (dk4, 0x0fbfa76f + dmk2), (dk5, dk4 <<< 6), (dk6, 0x1f7f4ede + dmk3), (dk7, dk6 <<< 11))} >>> rkch.key_schedule_ch.input_diff (XorDiff(dmk0), XorDiff(dmk1), XorDiff(dmk2), XorDiff(dmk3)) >>> rkch.key_schedule_ch.output_diff [[XorDiff(dk1), XorDiff(dk0 <<< 1)], [XorDiff(dk3), XorDiff(dk2 <<< 3)], [XorDiff(dk5), XorDiff(dk4 <<< 6)], [XorDiff(dk3), XorDiff(dk2 <<< 3)], [XorDiff(dk7), XorDiff(dk6 <<< 11)], [XorDiff(dk3), XorDiff(dk2 <<< 3)]] >>> rkch.key_schedule_ch.nonlinear_diffs OrderedDict([(XorDiff(dk0), XDCA_0xc3efe9db(XorDiff(dmk0))), (XorDiff(dk2), XDCA_0x87dfd3b7(XorDiff(dmk1))), (XorDiff(dk4), XDCA_0x0fbfa76f(XorDiff(dmk2))), (XorDiff(dk6), XDCA_0x1f7f4ede(XorDiff(dmk3)))]) >>> rkch.encryption_ch.ssa {'input_vars': (dp0, dp1, dp2, dp3), 'output_vars': (dx3, dx7, dx11, dp0), 'assignments': ((dx0, dk1 ^ dp0), (dx1, dk3 ^ dp1), (dx2, dx0 + dx1), (dx3, dx2 <<< 9), (dx4, dk5 ^ dp1), (dx5, dk3 ^ dp2), (dx6, dx4 + dx5), (dx7, dx6 >>> 5), (dx8, dk7 ^ dp2), (dx9, dk3 ^ dp3), (dx10, dx8 + dx9), (dx11, dx10 >>> 3))} >>> rkch.encryption_ch.input_diff (XorDiff(dp0), XorDiff(dp1), XorDiff(dp2), XorDiff(dp3)) >>> rkch.encryption_ch.output_diff [[XorDiff(dx3), XorDiff(dx2 <<< 9)], [XorDiff(dx7), XorDiff(dx6 >>> 5)], [XorDiff(dx11), XorDiff(dx10 >>> 3)], [XorDiff(dp0), XorDiff(dp0)]] >>> rkch.encryption_ch.nonlinear_diffs OrderedDict([(XorDiff(dx2), XDA(XorDiff(dp0 ^ (dk0 <<< 1)), XorDiff(dp1 ^ (dk2 <<< 3)))), (XorDiff(dx6), XDA(XorDiff(dp1 ^ (dk4 <<< 6)), XorDiff(dp2 ^ (dk2 <<< 3)))), (XorDiff(dx10), XDA(XorDiff(dp2 ^ (dk6 <<< 11)), XorDiff(dp3 ^ (dk2 <<< 3))))])
-
key_schedule_ch
¶ the
BvCharacteristic
over the key schedule
-
encryption_ch
¶ the
BvCharacteristic
over the encryption function
-
empirical_weight
(key_input_diff, key_output_diff, key_samples, enc_input_diff, enc_output_diff, enc_samples, precision=1)[source]¶ Return the empirical weight of a given differential for multiple keys.
This method returns the differential probability weight for the key schedule characteristic (see
BvCharacteristic.empirical_weight
) and thecollections.Counter
storing the distribution of weights for the encryption characteristic (seeSingleKeyCh.empirical_weight
).>>> from arxpy.bitvector.core import Variable, Constant >>> from arxpy.differential.difference import XorDiff >>> from arxpy.differential.characteristic import RelatedKeyCh >>> from arxpy.primitives.lea import LeaCipher >>> LeaCipher.set_rounds(1) >>> rkch = RelatedKeyCh(LeaCipher, XorDiff) >>> zero, one = XorDiff(Constant(0, 32)), XorDiff(Constant(1, 32)) >>> kid, kod = [zero]*4, [zero]*6 >>> eid, eod = [zero]*4, [zero]*4 >>> rkch.empirical_weight(kid, kod, 10, eid, eod, 100) (0.0, Counter({0.0: 10})) >>> kid, kod = [zero]*4, [one]*6 >>> eid, eod = [zero]*4, [one]*4 >>> rkch.empirical_weight(kid, kod, 10, eid, eod, 100) (inf, Counter({inf: 10}))
-
signature
(ch_signature_type)[source]¶ Return the signature of the related-key characteristic.
The signature of a related-key characteristic is the concatenation of the key schedule and encryption signatures.
See also
BvCharacteristic.signature
.>>> from arxpy.bitvector.core import Variable >>> from arxpy.differential.difference import XorDiff >>> from arxpy.differential.characteristic import RelatedKeyCh, ChSignatureType >>> from arxpy.primitives.primitives import Cipher >>> from arxpy.primitives.lea import LeaCipher >>> LeaCipher.set_rounds(1) >>> rkch = RelatedKeyCh(LeaCipher, XorDiff) >>> rkch.signature(ChSignatureType.Full) [dmk0, dmk1, dmk2, dmk3, dk0, dk2, dk4, dk6, dp0, dp1, dp2, dp3, dx2, dx6, dx10] >>> rkch.signature(ChSignatureType.InputOutput) [dmk0, dmk1, dmk2, dmk3, dk1, dk3, dk5, dk3, dk7, dk3, dp0, dp1, dp2, dp3, dx3, dx7, dx11]
-