arxpy.smt.verification_differential module¶
Verify characteristics found by the SMT solver.
To this end, a characteristic is split into sub-characteristics
where each sub-ch has up to MAX_WEIGHT
weight.
-
arxpy.smt.verification_differential.
bv2ccode
(bv)[source]¶ Convert a bit-vector type to C code.
- Parameters
bv – the bit-vector
Term
to convert
>>> from arxpy.bitvector.core import Constant, Variable >>> from arxpy.bitvector.operation import RotateLeft >>> from arxpy.smt.verification_differential import bv2ccode >>> x, y = Variable("x", 8), Variable("y", 8) >>> bv2ccode(x | y) 'x | y' >>> bv2ccode(x + y) '(x + y) & 255' >>> bv2ccode(RotateLeft(x, 1)) '((x << 1) | (x >> 7)) & 255' >>> bv2ccode((~x) + y) Traceback (most recent call last): ... ValueError: nested bit-vector operations are not supported
-
arxpy.smt.verification_differential.
ssa2ccode
(ssa, diff_type)[source]¶ Return the C code to compute a differential probability over a function in ssa form.
>>> from arxpy.differential.difference import XorDiff, RXDiff >>> from arxpy.primitives.chaskey import ChaskeyPi >>> from arxpy.smt.verification_differential import ssa2ccode >>> ChaskeyPi.set_rounds(1) >>> ssa = ChaskeyPi.ssa(["v0", "v1", "v2", "v3"], "x") >>> header, source = ssa2ccode(ssa, XorDiff) >>> print(header) static unsigned long get_num_valid_pairs(uint32_t input_diff[], uint32_t output_diff[], unsigned long pair_samples, unsigned int seed); >>> print(source) void eval(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3, uint32_t* x7, uint32_t* x12, uint32_t* x13, uint32_t* x9){ uint32_t x0 = (v0 + v1) & 4294967295; uint32_t x1 = ((v1 << 5) | (v1 >> 27)) & 4294967295; uint32_t x2 = x0 ^ x1; uint32_t x3 = ((x0 << 16) | (x0 >> 16)) & 4294967295; uint32_t x4 = (v2 + v3) & 4294967295; uint32_t x5 = ((v3 << 8) | (v3 >> 24)) & 4294967295; uint32_t x6 = x4 ^ x5; *x7 = (x3 + x6) & 4294967295; uint32_t x8 = ((x6 << 13) | (x6 >> 19)) & 4294967295; *x9 = *x7 ^ x8; uint32_t x10 = (x2 + x4) & 4294967295; uint32_t x11 = ((x2 << 7) | (x2 >> 25)) & 4294967295; *x12 = x10 ^ x11; *x13 = ((x10 << 16) | (x10 >> 16)) & 4294967295; }; static unsigned long get_num_valid_pairs(uint32_t input_diff[], uint32_t output_diff[], unsigned long pair_samples, unsigned int seed){ if (seed == 0) srand((unsigned int) time (NULL)); else srand(seed); unsigned long num_valid_pairs = 0; unsigned long i = 0; unsigned int j = 0; uint32_t input1[4]; uint32_t input2[4]; uint32_t output1[4]; uint32_t output2[4]; for (; i < pair_samples; ++i) { for (j = 0; j < 4; ++j) { input1[j] = rand(); input2[j] = input1[j] ^ input_diff[j]; } eval(input1[0], input1[1], input1[2], input1[3], &output1[0], &output1[1], &output1[2], &output1[3]); eval(input2[0], input2[1], input2[2], input2[3], &output2[0], &output2[1], &output2[2], &output2[3]); for (j = 0; j < 4; ++j) { if ( (output1[j] ^ output2[j]) != output_diff[j] ) break; if (j == 4 - 1) num_valid_pairs += 1; } } return num_valid_pairs; } >>> header, source = ssa2ccode(ssa, RXDiff) >>> print(header) static unsigned long get_num_valid_pairs(uint32_t input_diff[], uint32_t output_diff[], unsigned long pair_samples, unsigned int seed); >>> print(source) void eval(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3, uint32_t* x7, uint32_t* x12, uint32_t* x13, uint32_t* x9){ uint32_t x0 = (v0 + v1) & 4294967295; uint32_t x1 = ((v1 << 5) | (v1 >> 27)) & 4294967295; uint32_t x2 = x0 ^ x1; uint32_t x3 = ((x0 << 16) | (x0 >> 16)) & 4294967295; uint32_t x4 = (v2 + v3) & 4294967295; uint32_t x5 = ((v3 << 8) | (v3 >> 24)) & 4294967295; uint32_t x6 = x4 ^ x5; *x7 = (x3 + x6) & 4294967295; uint32_t x8 = ((x6 << 13) | (x6 >> 19)) & 4294967295; *x9 = *x7 ^ x8; uint32_t x10 = (x2 + x4) & 4294967295; uint32_t x11 = ((x2 << 7) | (x2 >> 25)) & 4294967295; *x12 = x10 ^ x11; *x13 = ((x10 << 16) | (x10 >> 16)) & 4294967295; }; static unsigned long get_num_valid_pairs(uint32_t input_diff[], uint32_t output_diff[], unsigned long pair_samples, unsigned int seed){ if (seed == 0) srand((unsigned int) time (NULL)); else srand(seed); unsigned long num_valid_pairs = 0; unsigned long i = 0; unsigned int j = 0; uint32_t input1[4]; uint32_t input2[4]; uint32_t output1[4]; uint32_t output2[4]; for (; i < pair_samples; ++i) { for (j = 0; j < 4; ++j) { input1[j] = rand(); input2[j] = ( ((input1[j] << 1) | (input1[j] >> 31)) ^ input_diff[j] ) & 4294967295; } eval(input1[0], input1[1], input1[2], input1[3], &output1[0], &output1[1], &output1[2], &output1[3]); eval(input2[0], input2[1], input2[2], input2[3], &output2[0], &output2[1], &output2[2], &output2[3]); for (j = 0; j < 4; ++j) { if ( (( ((output1[j] << 1) | (output1[j] >> 31)) ^ output2[j] ) & 4294967295) != output_diff[j] ) break; if (j == 4 - 1) num_valid_pairs += 1; } } return num_valid_pairs; }
Return the C code to compute a differential probability over a (related) function in ssa form.
>>> from arxpy.differential.difference import XorDiff >>> from arxpy.primitives.chaskey import ChaskeyPi >>> from arxpy.smt.verification_differential import relatedssa2ccode >>> ChaskeyPi.set_rounds(1) >>> ssa1 = ChaskeyPi.ssa(["v0", "v1", "v2", "v3"], "x") >>> ssa2 = dict(ssa1) >>> ssa2["assignments"] = list(ssa2["assignments"]) >>> ssa2["assignments"].append([ssa2["output_vars"][0], ssa2["output_vars"][0]]) >>> header, source = relatedssa2ccode(ssa1, ssa2, XorDiff) >>> print(header) static unsigned long get_num_valid_pairs(uint32_t input_diff[], uint32_t output_diff[], unsigned long pair_samples, unsigned int seed); >>> print(source) void eval1(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3, uint32_t* x7, uint32_t* x12, uint32_t* x13, uint32_t* x9){ uint32_t x0 = (v0 + v1) & 4294967295; uint32_t x1 = ((v1 << 5) | (v1 >> 27)) & 4294967295; uint32_t x2 = x0 ^ x1; uint32_t x3 = ((x0 << 16) | (x0 >> 16)) & 4294967295; uint32_t x4 = (v2 + v3) & 4294967295; uint32_t x5 = ((v3 << 8) | (v3 >> 24)) & 4294967295; uint32_t x6 = x4 ^ x5; *x7 = (x3 + x6) & 4294967295; uint32_t x8 = ((x6 << 13) | (x6 >> 19)) & 4294967295; *x9 = *x7 ^ x8; uint32_t x10 = (x2 + x4) & 4294967295; uint32_t x11 = ((x2 << 7) | (x2 >> 25)) & 4294967295; *x12 = x10 ^ x11; *x13 = ((x10 << 16) | (x10 >> 16)) & 4294967295; }; void eval2(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3, uint32_t* x7, uint32_t* x12, uint32_t* x13, uint32_t* x9){ uint32_t x0 = (v0 + v1) & 4294967295; uint32_t x1 = ((v1 << 5) | (v1 >> 27)) & 4294967295; uint32_t x2 = x0 ^ x1; uint32_t x3 = ((x0 << 16) | (x0 >> 16)) & 4294967295; uint32_t x4 = (v2 + v3) & 4294967295; uint32_t x5 = ((v3 << 8) | (v3 >> 24)) & 4294967295; uint32_t x6 = x4 ^ x5; *x7 = (x3 + x6) & 4294967295; uint32_t x8 = ((x6 << 13) | (x6 >> 19)) & 4294967295; *x9 = *x7 ^ x8; uint32_t x10 = (x2 + x4) & 4294967295; uint32_t x11 = ((x2 << 7) | (x2 >> 25)) & 4294967295; *x12 = x10 ^ x11; *x13 = ((x10 << 16) | (x10 >> 16)) & 4294967295; *x7 = *x7; }; static unsigned long get_num_valid_pairs(uint32_t input_diff[], uint32_t output_diff[], unsigned long pair_samples, unsigned int seed){ if (seed == 0) srand((unsigned int) time (NULL)); else srand(seed); unsigned long num_valid_pairs = 0; unsigned long i = 0; unsigned int j = 0; uint32_t input1[4]; uint32_t input2[4]; uint32_t output1[4]; uint32_t output2[4]; for (; i < pair_samples; ++i) { for (j = 0; j < 4; ++j) { input1[j] = rand(); input2[j] = input1[j] ^ input_diff[j]; } eval1(input1[0], input1[1], input1[2], input1[3], &output1[0], &output1[1], &output1[2], &output1[3]); eval2(input2[0], input2[1], input2[2], input2[3], &output2[0], &output2[1], &output2[2], &output2[3]); for (j = 0; j < 4; ++j) { if ( (output1[j] ^ output2[j]) != output_diff[j] ) break; if (j == 4 - 1) num_valid_pairs += 1; } } return num_valid_pairs; }
-
arxpy.smt.verification_differential.
compile_run_empirical_weight
(ccode, module_name, input_diff, output_diff, target_weight, verbose=False)[source]¶ Compile and execute the C code to compute the empirical weight
>>> from arxpy.differential.difference import XorDiff, RXDiff >>> from arxpy.primitives.chaskey import ChaskeyPi >>> from arxpy.smt.verification_differential import ssa2ccode, compile_run_empirical_weight >>> ChaskeyPi.set_rounds(1) >>> ssa = ChaskeyPi.ssa(["v0", "v1", "v2", "v3"], "x") >>> header, source = ssa2ccode(ssa, XorDiff) >>> ind, outd, tw = [0, 0, 0, 0], [0, 0, 0, 0], 2 >>> compile_run_empirical_weight([header, source], "_libverChaskeyPi", ind, outd, tw) 0.0 >>> ind, outd, tw = [0, 0, 0, 0], [0, 0, 0, 1], 2 >>> compile_run_empirical_weight([header, source], "_libverChaskeyPi", ind, outd, tw) inf >>> header, source = ssa2ccode(ssa, RXDiff) >>> ind, outd, tw = [0, 0, 0, 0], [0, 0, 0, 0], 8 >>> 4 <= compile_run_empirical_weight([header, source], "_libverChaskeyPi", ind, outd, tw) <= 8 True >>> ind, outd, tw = [0, 0, 0, 0], [1, 1, 1, 1], 8 >>> compile_run_empirical_weight([header, source], "_libverChaskeyPi", ind, outd, tw) inf
-
arxpy.smt.verification_differential.
fast_empirical_weight
(ch_found, verbose_lvl=0, debug=False, filename=None)[source]¶ Computes the empirical weight of the model using C code.
If
filename
is notNone
, the output will be printed to the given file rather than the to stdout.The argument
verbose_lvl
can take an integer between0
(no verbose) and3
(full verbose).>>> from arxpy.differential.difference import XorDiff, RXDiff >>> from arxpy.differential.characteristic import BvCharacteristic >>> from arxpy.primitives.chaskey import ChaskeyPi >>> from arxpy.smt.search_differential import SearchCh >>> from arxpy.smt.verification_differential import fast_empirical_weight >>> ChaskeyPi.set_rounds(2) >>> ch = BvCharacteristic(ChaskeyPi, XorDiff, ["dv0", "dv1", "dv2", "dv3"]) >>> search_problem = SearchCh(ch) >>> ch_found = search_problem.solve(0) >>> ch_found.ch_weight 0x04 >>> 3 <= fast_empirical_weight(ch_found) <= 5 True >>> ChaskeyPi.set_rounds(1) >>> ch = BvCharacteristic(ChaskeyPi, RXDiff, ["dv0", "dv1", "dv2", "dv3"]) >>> ic = [operation.BvComp(0, d.val) for d in ch.input_diff] >>> ic += [operation.BvComp(0, d[1].val) for d in ch.output_diff] >>> ch_found = SearchCh(ch, allow_zero_input_diff=True, initial_constraints=ic).solve(5) >>> ch_found.ch_weight 0x05 >>> 4 - 1 <= fast_empirical_weight(ch_found) <= 8 True