boolcrypt.utilities module
Basic utilities of boolcrypt.
- boolcrypt.utilities.get_rijndael_field(name='a')[source]
Return the finite field used in AES
>>> get_rijndael_field().modulus() x^8 + x^4 + x^3 + x + 1
- boolcrypt.utilities.matrix2poly(bin_matrix, field=None, poly_ring=None)[source]
Return the linearized polynomial given by the binary matrix.
>>> matrix2poly(sage.all.identity_matrix(GF(2), 4), GF(2**4)) x >>> # See In How Many Ways Can You Write Rijndael? >>> entries = [ ... [1, 0, 0, 0, 1, 1, 1, 1], [1, 1, 0, 0, 0, 1, 1, 1], [1, 1, 1, 0, 0, 0, 1, 1], [1, 1, 1, 1, 0, 0, 0, 1], ... [1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1]] >>> bin_matrix = sage.all.matrix(GF(2), 8, 8, entries) >>> ct = get_rijndael_field().fetch_int(vector2int([1, 1, 0 ,0, 0, 1, 1, 0])) >>> poly = matrix2poly(bin_matrix, get_rijndael_field()) + ct >>> poly 143*x^128 + 181*x^64 + x^32 + 244*x^16 + 37*x^8 + 249*x^4 + 9*x^2 + 5*x + 99 >>> [hex(c.integer_representation()) for c in poly.coefficients()] # [ct term, ..., leading coeff] ['0x63', '0x5', '0x9', '0xf9', '0x25', '0xf4', '0x1', '0xb5', '0x8f']
- boolcrypt.utilities.matrix2anf(bin_matrix, bool_poly_ring=None, input_vars=None, bin_vector=None)[source]
Return the ANF (the canonical components) of a given matrix.
If bool_poly_ring is given, the list input_vars can be given as a list of Boolean variables, strings or input variable indices. Otherwise, input_vars is given as a a list of Boolean variables.
>>> anf = matrix2anf(sage.all.identity_matrix(GF(2), 4, 4), bin_vector=[0, 1, 0, 1]) >>> for p in anf: print(p) x0 x1 + 1 x2 x3 + 1 >>> bool_poly_ring = BooleanPolynomialRing(names=('a','b','c','d','y0','y1','y2','y3')) >>> a, b, c, d, y0, y1, y2, y3 = bool_poly_ring.gens() >>> symbolic_matrix = sage.all.matrix(2, 2, [[a, b], [c, d]]) >>> symbolic_matrix [a b] [c d] >>> anf = matrix2anf(symbolic_matrix, bool_poly_ring, input_vars=[y0, y1, y2, y3]) >>> for p in anf: print(p) a*y0 + b*y1 c*y0 + d*y1
- boolcrypt.utilities.matrix2lut(bin_matrix, bin_vector=None)[source]
Return the LUT of a given matrix.
>>> matrix2lut(sage.all.identity_matrix(GF(2), 4, 4), bin_vector=sage.all.vector(GF(2), [1, 0, 0, 0])) [1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14]
- boolcrypt.utilities.poly2matrix(lin_poly)[source]
Return the binary matrix given by the linearized polynomial.
>>> x = PolynomialRing(GF(2**4), 'x').gen() >>> poly2matrix(x) [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] >>> x = PolynomialRing(get_rijndael_field(), 'x').gen() >>> # See In How Many Ways Can You Write Rijndael >>> poly2matrix(x**2) [1 0 0 0 1 0 1 0] [0 0 0 0 1 0 1 1] [0 1 0 0 0 1 0 0] [0 0 0 0 1 1 1 1] [0 0 1 0 1 0 0 1] [0 0 0 0 0 1 1 0] [0 0 0 1 0 1 0 0] [0 0 0 0 0 0 1 1]
- boolcrypt.utilities.lut2matrix(lut, return_ct=False)[source]
Return the binary matrix given by the LUT
>>> x = PolynomialRing(GF(2**4), 'x').gen() >>> lut2matrix(poly2lut(x)) [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] >>> lut2matrix(poly2lut(x + 1), return_ct=True) [[0 1 1 1] [0 1 0 0] [0 0 1 0] [0 0 0 1], (1, 0, 0, 0)] >>> x = PolynomialRing(get_rijndael_field(), 'x').gen() >>> lut2matrix(poly2lut(x**2)) # See In How Many Ways Can You Write Rijndael [1 0 0 0 1 0 1 0] [0 0 0 0 1 0 1 1] [0 1 0 0 0 1 0 0] [0 0 0 0 1 1 1 1] [0 0 1 0 1 0 0 1] [0 0 0 0 0 1 1 0] [0 0 0 1 0 1 0 0] [0 0 0 0 0 0 1 1]
- boolcrypt.utilities.hex_string2lut(s, num_char_per_elem)[source]
Return the LUT given as a compact hex string.
>>> s = "6512304789ABCDEF" >>> lut = hex_string2lut(s, 1) >>> lut [6, 5, 1, 2, 3, 0, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15] >>> [hex(x) for x in lut] ['0x6', '0x5', '0x1', '0x2', '0x3', '0x0', '0x4', '0x7', '0x8', '0x9', '0xa', '0xb', '0xc', '0xd', '0xe', '0xf'] >>> assert lut == hex_string2lut("0x6512304789ABCDEF", 1) >>> assert lut == hex_string2lut("0x060501020300040708090a0b0c0d0e0f", 2)
- boolcrypt.utilities.lut2hex_string(lut, num_char_per_elem, prefix0x=False)[source]
Return the hex string representation.
>>> lut = [6, 5, 1, 2, 3, 0, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15] >>> lut2hex_string(lut, 1) '6512304789abcdef' >>> assert lut2hex_string(lut, 2, True) == "0x060501020300040708090a0b0c0d0e0f"
- boolcrypt.utilities.lut2poly(lut, field_var=None)[source]
Return the polynomial representation of a given LUT.
>>> lut2poly(get_lut_inversion(4)) x^14 >>> field_var = PolynomialRing(get_rijndael_field(), 'y').gen() >>> lut2poly(get_lut_inversion(8, field_var.base_ring()), field_var) y^254
- boolcrypt.utilities.lut2anf(lut, bool_poly_ring=None, num_inputs=None, num_outputs=None)[source]
Return the ANF (the canonical components) of a function given as a LUT.
>>> for p in lut2anf(get_lut_inversion(4)): print(p) x0*x1*x2 + x0*x2 + x0 + x1*x2*x3 + x1*x2 + x1 + x2 + x3 x0*x1*x3 + x0*x1 + x0*x2 + x1*x2 + x1*x3 + x3 x0*x1 + x0*x2*x3 + x0*x2 + x0*x3 + x2 + x3 x0*x3 + x1*x2*x3 + x1*x3 + x1 + x2*x3 + x2 + x3 >>> bpr = BooleanPolynomialRing(3, 'x') >>> for p in lut2anf([0] * (2**3), bool_poly_ring=bpr): print(p) 0 0 0 >>> # more inputs that outputs >>> lut = [[bpr("x0*x1 + x0 + x1")(*v), bpr("x0")(*v)] for v in sage.all.VectorSpace(GF(2), 3)] >>> for p in lut2anf([vector2int(v) for v in lut]): print(p) x0*x1 + x0 + x1 x0 0 >>> for p in lut2anf([vector2int(v) for v in lut], num_outputs=2): print(p) x0*x1 + x0 + x1 x0 >>> # more outputs than inputs >>> lut = [[bpr("x0")(*v), bpr("x1")(*v), bpr("x2")(*v), bpr("x0*x1 + x2")(*v), ] for v in sage.all.VectorSpace(GF(2), 3)] >>> # for p in lut2anf([vector2int(v) for v in lut]): print(p) # AssertionError >>> for p in lut2anf([vector2int(v) for v in lut], num_outputs=4): print(p) x0 x1 x2 x0*x1 + x2
- boolcrypt.utilities.poly2lut(polynomial)[source]
Return the LUT representation of a permutation polynomial.
>>> x = PolynomialRing(GF(2**4, repr="int"), 'x').gen() >>> poly2lut(x) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] >>> from sage.crypto.sboxes import AES >>> poly = AES.interpolation_polynomial() >>> poly2lut(poly) == list(AES) True
- boolcrypt.utilities.anf2lut(anf)[source]
Return the LUT representation of a permutation given by its ANF.
>>> x0, x1, x2, x3 = BooleanPolynomialRing(4, 'x').gens() >>> anf2lut([x0, x1, x2, x3]) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] >>> anf2lut(lut2anf(get_lut_inversion(4))) == get_lut_inversion(4) True
- boolcrypt.utilities.anf2matrix(anf, input_vars=None)[source]
Return the binary index_input_vars of the vectorial Boolean function given in ANF.
If the anf is symbolic, index_input_vars must be given. The list input_vars can be given as a list of Boolean variables, strings or input variable indices.
>>> x, y = BooleanPolynomialRing(names="x, y").gens() >>> anf2matrix([x + y, x]) [1 1] [1 0] >>> x, y, a, b, c = BooleanPolynomialRing(names="x, y, a, b, c").gens() >>> anf = [0*x + (a + b)*y, c*x + y] >>> anf2matrix(anf, (0, 1)) [ 0 a + b] [ c 1]
- boolcrypt.utilities.get_ct_coeff(anf, input_vars=None)[source]
Return the binary constant of the vectorial Boolean function given in ANF.
If the anf is symbolic, index_input_vars must be given. The list input_vars can be given as a list of Boolean variables, strings or input variable indices.
>>> from sage.crypto.sboxes import AES >>> hex(vector2int(get_ct_coeff(lut2anf(list(AES))))) '0x63' >>> x, y, a, b, c = BooleanPolynomialRing(names="x, y, a, b, c").gens() >>> anf = [x + x*a + x*b + x*y*(a*b + c) + (a*b*c), y + 1 + a + b + c] >>> get_ct_coeff(anf, [x, y]) (a*b*c, a + b + c + 1)
- boolcrypt.utilities.int2vector(x, size)[source]
Return the integer associated to the given binary vector.
>>> pprint.pprint([int2vector(i, 3) for i in range(2**3)]) [(0, 0, 0), (1, 0, 0), (0, 1, 0), (1, 1, 0), (0, 0, 1), (1, 0, 1), (0, 1, 1), (1, 1, 1)]
- boolcrypt.utilities.vector2int(v)[source]
Return the binary vector associated to the given integer.
>>> vectors = sage.all.VectorSpace(GF(2), 3).list() >>> vectors [(0, 0, 0), (1, 0, 0), (0, 1, 0), (1, 1, 0), (0, 0, 1), (1, 0, 1), (0, 1, 1), (1, 1, 1)] >>> [vector2int(v) for v in vectors] [0, 1, 2, 3, 4, 5, 6, 7] >>> assert all([i == vector2int(int2vector(i, 4)) for i in range(2**4)])
- boolcrypt.utilities.test_conversion(iterations=100)[source]
Test the conversion functions
>>> test_conversion(100) True
- boolcrypt.utilities.get_lut_inversion(n, field=None)[source]
Return the LUT representing the inversion of GF(2**n).
>>> lut = get_lut_inversion(4) >>> lut [0, 1, 9, 14, 13, 11, 7, 6, 15, 2, 12, 5, 10, 4, 3, 8] >>> lut2poly(lut) x^14
- boolcrypt.utilities.invert_lut(lut)[source]
Return the inverse of a LUT
>>> invert_lut([0, 1, 2, 3]) [0, 1, 2, 3] >>> invert_lut(get_lut_inversion(4)) == get_lut_inversion(4) True >>> invert_lut(get_lut_inversion(9)) == get_lut_inversion(9) True
- boolcrypt.utilities.get_bitsize(lut)[source]
Return the bitsize of the given permutation.
>>> get_bitsize(get_lut_inversion(4)) 4
- boolcrypt.utilities.is_invertible(lut)[source]
Return whether the function is a permutation.
>>> is_invertible(get_lut_inversion(3)) True >>> is_invertible([0, 1, 2, 0]) False >>> is_invertible(get_lut_inversion(9)) True >>> is_invertible([0 for i in range(2**9)]) False >>> is_invertible([0, 1, 2, 4]) False
- boolcrypt.utilities.str2bp(my_str, bpr_gens_dict)[source]
Fast conversion of a string to a Boolean polynomial given the gens of a BooleanPolynomialRing.
>>> bpr = BooleanPolynomialRing(names="x, y") >>> str2bp("x + y", bpr.gens_dict()) x + y
- boolcrypt.utilities.get_num_inputs_anf(anf)[source]
Return the number of inputs of the given vectorial anf
- boolcrypt.utilities.is_balanced(anf)[source]
Return whether the anf is balanced.
>>> is_balanced(lut2anf(get_lut_inversion(4))) True >>> bpr = BooleanPolynomialRing(n=4, names="x") >>> is_balanced([bpr("x0*x1 + x0*x2 + x1*x2")]) # only 3-var 2-deg-homo balanced True >>> is_balanced([bpr("x0*x1 + x0*x2 + x0*x3 + x1*x2 + x1*x3")]) True >>> is_balanced([bpr("x0*x1")]) False >>> is_balanced([bpr("x0*x1 + x0*x2")]) False
- boolcrypt.utilities.get_anf_coeffmatrix_str(anf, input_vars=None, full_repr=None)[source]
Return the coefficient matrix of a (symbolic) anf as a string.
If the anf is symbolic, input_vars must be given. The list input_vars can be given as a list of Boolean variables, strings or input variable indices.
If the anf is symbolic and the number of symbolic coefficients is greater than 32, then instead of the coefficient matrix, a short string representation of the ANF is returned (unless
full_repr
is True).>>> x, y, z = BooleanPolynomialRing(names="x, y, z").gens() >>> f0 = x*y*z + x*y + x*z + y*z + x + y + z + 1 >>> f1 = x*y + + y*z + x + + z + 1 >>> f2 = 0*x >>> [f0, f1, f2] [x*y*z + x*y + x*z + x + y*z + y + z + 1, x*y + x + y*z + z + 1, 0] >>> get_anf_coeffmatrix_str([f0, f1, f2]) [x*y*z| x*y x*z y*z| x y z| 1] [-----+-----------------+-----------------+-----] [ 1| 1 1 1| 1 1 1| 1] [ 0| 1 0 1| 1 0 1| 1] [ 0| 0 0 0| 0 0 0| 0] >>> names = "x, y, z, ax, ay, az, a" >>> x, y, z, ax, ay, az, a = BooleanPolynomialRing(names=names).gens() >>> f0 = ax*x + ay*y + az*z >>> f1 = x + + z >>> f2 = 0*x >>> get_anf_coeffmatrix_str([f0, f1, f2], input_vars=[x, y, z]) [ x y z] [--------] [ax ay az] [ 1 0 1] [ 0 0 0] >>> vars = BooleanPolynomialRing(names=["x0", "x1"] + ["a" + str(i) for i in range(32)]).gens() >>> anf = [vars[0]*sage.all.prod(vars[2:2+32]), vars[1]*vars[-2] + vars[-1]] >>> print(get_anf_coeffmatrix_str(anf, input_vars=["x0", "x1"])) [ BooleanPolynomial(x0, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31) x1*a30 + a31 ]
- boolcrypt.utilities.pretty_poly(polynomial, ignore_coefficients=False)[source]
Return a string representation of a finite field polynomial where the coefficients are represented as integers.
>>> F = GF(2**8, 'z') >>> x = PolynomialRing(F, 'x').gen() >>> polynomial = F.fetch_int(1) + F.fetch_int(2) * x + F.fetch_int(4) * x**2 >>> polynomial z^2*x^2 + z*x + 1 >>> pretty_poly(polynomial) '4*x^2 + 2*x + 1'
- boolcrypt.utilities.normalize_poly(polynomial)[source]
Return the normalized representation of a polynomial.
Given f(x) = sum_{i=0}_{n} a_i x^i, return g(x) = c f(x + b) + d, such that g(0) = 0, g is monic, and g doesn’t have x^{n-1} term (if n != 0 mod p for n = deg(f) and GF(p**r)).
>>> F = GF(2**4, 'z') >>> x = PolynomialRing(F, 'x').gen() >>> normalize_poly(F.fetch_int(2) * x**2 + 1) x^2 >>> normalize_poly(F.fetch_int(2) * x**3 + x**2 + 1) x^3 + (z^3 + z^2 + 1)*x
See also Section 1.5 of arXiv:1211.6044 [math.NT]
- boolcrypt.utilities.pretty_container_with_matrices(matrices)[source]
Print a sequence of matrices each one in a different line, similar to IPython.
- boolcrypt.utilities.get_canonical_matrix(rank, nrows, ncols=None)[source]
Return the canonical matrix with given rank over GF(2).
The square canonical matrix of rank r is the following matrix
( I_r 0 ) ( 0 O_n-r )
Note that any matrix of dimension (n,m) and rank r is matrix equivalent to the canonical matrix of same dimension and rank k.
>>> get_canonical_matrix(1, nrows=2, ncols=2) [1|0] [-+-] [0|0] >>> get_canonical_matrix(2, nrows=4, ncols=5) [1 0|0 0 0] [0 1|0 0 0] [---+-----] [0 0|0 0 0] [0 0|0 0 0]
- boolcrypt.utilities.find_monomial_matrices(n, field=None, condition=None, verbose=False)[source]
Find the binary matrices corresponding to the polynomials a*x^(2^i) verifying some condition.
>>> n = 4 >>> condition = lambda m: m.column(0)[1:].is_zero() and m.submatrix(1, 1, n-1, n-1).is_invertible() >>> matrices = find_monomial_matrices(4, condition=condition) >>> print(pretty_container_with_matrices(matrices)) # not necessary in IPython [ [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1], [1 0 1 0] [0 0 1 0] [0 1 0 1] [0 0 0 1], [1 1 1 1] [0 1 0 1] [0 0 1 1] [0 0 0 1], [1 1 0 0] [0 0 1 1] [0 1 0 0] [0 0 0 1] ]
- boolcrypt.utilities.lin_poly2pseudocirc_matrix(polynomial)[source]
Return the pseudo-circulant matrix associated to a linearized polynomial.
A linearized polynomial is invertible iff its associated matrix is non-singular.
>>> n = 4 >>> z0 = GF(2**n).gen() >>> R = PolynomialRing(GF(2**n), 'x') >>> x = R.gen() >>> lin_poly2pseudocirc_matrix(x + z0*x**2 + (z0 + 1)*x**4) [ 1 0 z4 z4^2 + 1] [ z4 1 0 z4^2] [ z4 + 1 z4^2 1 0] [ 0 z4^2 + 1 z4 + 1 1] >>> for _ in range(100): ... poly = R.random_element() ... poly -= poly.constant_coefficient() ... assert lin_poly2pseudocirc_matrix(poly).is_invertible() == poly2matrix(poly).is_invertible()
- boolcrypt.utilities.compose_lut(left, right)[source]
Return the LUT representing F(G(x)).
F and G can be given as LUTs, matrices or affine functions, but one of them should be given as a LUT.
>>> compose_lut(get_lut_inversion(4), get_lut_inversion(4)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] >>> rm = sage.all.random_matrix(GF(2), 4, 4, algorithm="unimodular") >>> compose_lut(matrix2lut(rm), rm.inverse()) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] >>> compose_lut([rm.inverse(), rm.inverse() * sage.all.vector([1, 0, 0, 0])], [x.__xor__(1) for x in matrix2lut(rm)]) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] >>> lut = get_lut_inversion(4) >>> field = GF(2**4, repr="int") >>> right_self = field.fetch_int(3) * PolynomialRing(field, 'x').gen() >>> left_self = right_self >>> left_self(lut2poly(lut)(right_self)) # checking is a self_equivalence x^14 >>> right_self, left_self = poly2matrix(right_self), poly2matrix(left_self) >>> lut2poly(compose_lut(left_self, compose_lut(lut, right_self))) x^14
- boolcrypt.utilities.compose_affine(left_matrix, left_ct, right_matrix, right_ct)[source]
Return the composition of two affine functions as a (matrix, vector) pair.
>>> left_rot = sage.all.matrix.circulant(sage.all.vector(GF(2), [0,0,0,1])) >>> compose_affine(left_rot.inverse(), 1, left_rot, 1) [[1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1], (1, 0, 0, 1)]
- boolcrypt.utilities.compose_lut_matrix(lut, bin_matrix, bin_ct=0)[source]
Return the LUT representing F A, F given as a lut and A given as a pair of a binary matrix and a binary constant
- boolcrypt.utilities.compose_matrix_lut(bin_matrix, lut, bin_ct=0)[source]
Return the LUT representing A F, F given as a lut and A given as a pair of a binary matrix and a binary constant
- boolcrypt.utilities.substitute_anf(anf, replacement, output_bool_poly_ring)[source]
Substitute variables from the given anf according to the given dictionary.
>>> B = BooleanPolynomialRing(4, "x") >>> x0, x1, x2, x3 = B.gens() >>> identity = [x0, x1, x2, x3] >>> for p in substitute_anf(identity, {x0:x0, x3:x3}, B): print(p) x0 x1 x2 x3 >>> inv_anf = lut2anf(get_lut_inversion(4)) >>> B = inv_anf[0].parent() >>> for p in substitute_anf(inv_anf, {B.gens()[0]: B(0)}, B): print(p) x1*x2*x3 + x1*x2 + x1 + x2 + x3 x1*x2 + x1*x3 + x3 x2 + x3 x1*x2*x3 + x1*x3 + x1 + x2*x3 + x2 + x3
- boolcrypt.utilities.compose_anf_fast(left_anf, right_anf)[source]
Compose two functions compatible given by their anf.
The output size of right_anf must be the same as the input size of left_anf.
>>> x0, x1, x2, x3 = BooleanPolynomialRing(4, "x").gens() >>> identity = BooleanPolynomialVector([x0, x1, x2, x3]) >>> for p in compose_anf_fast(identity, identity): print(p) x0 x1 x2 x3 >>> inversion = lut2anf(get_lut_inversion(4)) >>> for p in compose_anf_fast(inversion, inversion): print(p) x0 x1 x2 x3
- boolcrypt.utilities.concatenate_lut(left_lut, right_lut)[source]
Return the concatenation of two permutations F || G given by their lut.
>>> n = 3 >>> identity = [i for i in range(2**n)] >>> for p in lut2anf(concatenate_lut(identity, identity)): print(p) x0 x1 x2 x3 x4 x5 >>> inversion = get_lut_inversion(n) >>> for p in lut2anf(inversion): print(p) x0 + x1*x2 + x1 + x2 x0*x1 + x2 x0*x2 + x1 + x2 >>> for p in lut2anf(concatenate_lut(inversion, inversion)): print(p) x0 + x1*x2 + x1 + x2 x0*x1 + x2 x0*x2 + x1 + x2 x3 + x4*x5 + x4 + x5 x3*x4 + x5 x3*x5 + x4 + x5
- boolcrypt.utilities.concatenate_anf(left_anf, right_anf, prefix='x', input_vars_left=None, input_vars_right=None)[source]
Return the concatenation of two functions given by their anf
By default, the input variables of the concatenation are set to x0, x1, … If prefix=None, the input variables are set to the input variables of left concatenated to the input variables of right (assuming they don’t collide).
If left/right are symbolic anf, input_vars_left/right must be given.
The lists input_vars_* can be given as a list of Boolean variables or strings.
>>> x, = BooleanPolynomialRing(1, "x").gens() >>> concatenation = concatenate_anf([x], [x]) >>> list(concatenation) [x0, x1] >>> concatenation[0].parent() Boolean PolynomialRing in x0, x1 >>> left_anf, right_anf = [BooleanPolynomialRing(1, "x")("x")], [BooleanPolynomialRing(1, "y")("y")] >>> concatenation = concatenate_anf(left_anf, right_anf, prefix=None) >>> list(concatenation) [x, y] >>> concatenation[0].parent() Boolean PolynomialRing in x, y >>> x, a, b = BooleanPolynomialRing(3, "x, a, b").gens() >>> concatenation = concatenate_anf([x + a], [x + a*b], input_vars_left=[x], input_vars_right=["x"]) >>> list(concatenation) [x0 + a, x1 + a*b] >>> concatenation[0].parent() Boolean PolynomialRing in x0, x1, a, b
- boolcrypt.utilities.concatenate_anf_fast(*list_anfs)[source]
Return the concatenation of several non-symbolic functions given by their anf-
The inputs of each function must be x0, x1, …
>>> x0, = BooleanPolynomialRing(1, "x0").gens() >>> list(concatenate_anf_fast([x0], [x0], [x0], [x0])) [x0, x1, x2, x3]
- boolcrypt.utilities.get_upper_bound_monomials(alg_deg, domain, int2log2=False)[source]
Return the maximum number of monomials a function can have with given algebraic degree.
If the domain is GF(2)**n, return the maximum number of GF(2) monomials of a component. If the domain is GF(2**n), return the maximum number of GF(2**n) monomials of the univariate representation.
>>> get_upper_bound_monomials(7, GF(2)**8) 255 >>> get_upper_bound_monomials(7, GF(2**8), int2log2=True) 7 >>> n, d = 4, 2 >>> p = sage.all.BooleanPolynomialRing(4, 'x').random_element(d, terms=sage.all.Infinity) >>> len(p) <= get_upper_bound_monomials(d, GF(2)**n) True
- boolcrypt.utilities.get_upper_bound_gf2_splitdegree_monomials(nx, ny, dx, dy, dxy, int2log2=False)[source]
Return the maximum number of monomials a bit-function with split degree.
Return the maximum number of monomoials of a (nx,ny)-bit function f(x, y) with x-degree dx and y-degree dy and mixed degree dxy.
>>> get_upper_bound_monomials(4, GF(2)**8) 163 >>> get_upper_bound_gf2_splitdegree_monomials(4, 4, 2, 2, 4) 121 >>> get_upper_bound_gf2_splitdegree_monomials(4, 4, 4, 1, 4) 76
- boolcrypt.utilities.get_megabyte_size_anf(n, d, m=None)[source]
Return the maximum megabytes size of a system of m Boolean functions, where each n-bit Boolean function is of degree d.
This is assuming we represent the coefficient of a monomial of each Boolean function with a unique n-bit integer.
- boolcrypt.utilities.get_megabyte_size_splitdegree_anf(nx, ny, dx, dy, dxy, m=None)[source]
Return the maximum megabytes size of a system of m Boolean functions, where each (nx, ny)-bit Boolean function is of x-degree dx and y-degree dy and mixed degree dxy.
This is assuming we represent the coefficient of a monomial of each Boolean function with a unique n-bit integer.
- boolcrypt.utilities.get_algebraic_degree(lut, only_maximum=True)[source]
Return the maximum and minumum algebraic degree of the canonical components of a permutation.
>>> get_algebraic_degree(get_lut_inversion(4)) 3 >>> get_algebraic_degree(get_lut_inversion(8), only_maximum=False) (7, 7) >>> get_algebraic_degree(get_lut_inversion(9), only_maximum=False) (8, 8)
- boolcrypt.utilities.get_all_algebraic_degrees(lut)[source]
Return the algebraic degree of all components of a permutation.
>>> lut = get_lut_inversion(4) >>> get_all_algebraic_degrees(lut) [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] >>> import collections >>> print(collections.Counter(get_all_algebraic_degrees(lut))) Counter({3: 15})
- boolcrypt.utilities.get_differential_uniformity(lut)[source]
See sage.crypto.sbox.Sbox.maximal_difference_probability_absolute
In other words, the biggest entry in the DDT table for a non-zero differential.
>>> get_differential_uniformity(get_lut_inversion(4)) 4 >>> get_differential_uniformity(get_lut_inversion(8)) 4
- boolcrypt.utilities.get_linearity(lut)[source]
See sage.crypto.sbox.Sbox.maximal_linear_bias_absolute
In other words, the biggest entry in the LAT table for a non-zero input mask.
>>> get_linearity(get_lut_inversion(4)) 4 >>> get_linearity(get_lut_inversion(8)) 16
- boolcrypt.utilities.has_linear_structures(lut)[source]
See sage.crypto.sbox.Sbox.has_linear_structures
>>> from sage.crypto.sboxes import AES, PRESENT >>> has_linear_structures(list(AES)) False >>> has_linear_structures(list(PRESENT)) True
- boolcrypt.utilities.get_all_components(lut)[source]
Return all components (in ANF) of a permutation.
>>> pprint.pprint(get_all_components(get_lut_inversion(4))) {1: x0*x1*x2 + x0*x2 + x0 + x1*x2*x3 + x1*x2 + x1 + x2 + x3, 2: x0*x1*x3 + x0*x1 + x0*x2 + x1*x2 + x1*x3 + x3, 3: x0*x1*x2 + x0*x1*x3 + x0*x1 + x0 + x1*x2*x3 + x1*x3 + x1 + x2, 4: x0*x1 + x0*x2*x3 + x0*x2 + x0*x3 + x2 + x3, 5: x0*x1*x2 + x0*x1 + x0*x2*x3 + x0*x3 + x0 + x1*x2*x3 + x1*x2 + x1, 6: x0*x1*x3 + x0*x2*x3 + x0*x3 + x1*x2 + x1*x3 + x2, 7: x0*x1*x2 + x0*x1*x3 + x0*x2*x3 + x0*x2 + x0*x3 + x0 + x1*x2*x3 + x1*x3 + x1 + x3, 8: x0*x3 + x1*x2*x3 + x1*x3 + x1 + x2*x3 + x2 + x3, 9: x0*x1*x2 + x0*x2 + x0*x3 + x0 + x1*x2 + x1*x3 + x2*x3, 10: x0*x1*x3 + x0*x1 + x0*x2 + x0*x3 + x1*x2*x3 + x1*x2 + x1 + x2*x3 + x2, 11: x0*x1*x2 + x0*x1*x3 + x0*x1 + x0*x3 + x0 + x2*x3 + x3, 12: x0*x1 + x0*x2*x3 + x0*x2 + x1*x2*x3 + x1*x3 + x1 + x2*x3, 13: x0*x1*x2 + x0*x1 + x0*x2*x3 + x0 + x1*x2 + x1*x3 + x2*x3 + x2 + x3, 14: x0*x1*x3 + x0*x2*x3 + x1*x2*x3 + x1*x2 + x1 + x2*x3 + x3, 15: x0*x1*x2 + x0*x1*x3 + x0*x2*x3 + x0*x2 + x0 + x2*x3 + x2}
- boolcrypt.utilities.get_symbolic_anf(degree, num_inputs, num_outputs, ct_terms=True, prefix_inputs='x', prefix_coeffs='a', coeff2ct=None, coeff2expr=None, bpr=None, return_varnames=False)[source]
Return an ANF with symbolic coefficients given as Boolean variables.
- Parameters
prefix_inputs (-) – the prefix string to label the input variables of the ANF.
prefix_coeffs (-) – the prefix string to label the coefficients of the ANF.
degree (-) – the algebraic degree of the ANF.
ct_terms (-) – whether to consider constant terms
num_inputs (-) – the dimension of the ANF
num_outputs – the dimension of the ANF
coeff2ct (-) – a dictionary mapping string/Boolean coefficient labels to constants to replace those coefficients to fixed values.
coeff2expr (-) – a dictionary mapping string/Boolean coefficient labels to Boolean to replace those coefficients to Boolean expressions (bpr must be given)
bpr (-) – if given, each ANF component is an element of given Boolean poly ring
return_varnames (-) – if True, return the varnames of the parent BooleanPolynomialRing of the symbolic anf.
>>> get_anf_coeffmatrix_str(get_symbolic_anf(1, 3, 3), input_vars=[0, 1, 2]) [ x0 x1 x2| 1] [--------------+----] [a0_0 a0_1 a0_2| a0] [a1_0 a1_1 a1_2| a1] [a2_0 a2_1 a2_2| a2] >>> anf = get_symbolic_anf(2, 3, 1, ct_terms=False, prefix_inputs="y", ... prefix_coeffs="b", coeff2ct={"b0_0": 1}) >>> get_anf_coeffmatrix_str(anf, input_vars=[0, 1, 2]) [ y0*y1 y0*y2 y1*y2| y0 y1 y2] [--------------------+--------------------] [b0_0_1 b0_0_2 b0_1_2| 1 b0_1 b0_2] >>> bpr = BooleanPolynomialRing(names=["x0", "a0_0", "b"]) >>> anf = get_symbolic_anf(1, 1, 1, ct_terms=False, prefix_inputs="x", ... prefix_coeffs="a", coeff2expr={"a0_0": "b"}, bpr=bpr) >>> get_anf_coeffmatrix_str(anf, input_vars=["x0"]) [x0] [--] [ b] >>> get_symbolic_anf(1, 3, 3, return_varnames=True) ['x0', 'x1', 'x2', 'a0_0', 'a0_1', 'a0_2', 'a0', 'a1_0', 'a1_1', 'a1_2', 'a1', 'a2_0', 'a2_1', 'a2_2', 'a2']
- boolcrypt.utilities.get_symbolic_coeff(bool_poly, input_vars, monomial)[source]
Return the symbolic coefficient of a symbolic Boolean polynomial.
A symbolic Boolean function is a Boolean function of the form f(x1, dots, xn-1, a1, dots,), where xi are the inputs and ai are parameters.
Given a monomial x_i1 * dots * x_ir, it returns the symbolic coefficient (in terms of ai) of the monomial x_i1 * dots * x_ir.
It is assumed the given monomial only contains input_vars variables.
The list input_vars can be given as a list of Boolean variables, strings or input variable indices.
>>> x, y, a, b, c = BooleanPolynomialRing(names="x, y, a, b, c").gens() >>> poly = x + x*a + x*b + x*y*(a*b + c) + (a*b*c) >>> get_symbolic_coeff(poly, ("x", "y"), "x") a + b + 1 >>> get_symbolic_coeff(poly, (x, y, a, b, c), x) 1 >>> poly.monomial_coefficient(x) 1 >>> get_symbolic_coeff(poly, [0, 1], 1) a*b*c
- boolcrypt.utilities.get_all_symbolic_coeff(bool_poly, input_vars, ignore_terms_of_deg_strictly_less=0)[source]
Return all the symbolic coefficients of a symbolic Boolean polynomial.
A symbolic Boolean function is a Boolean function of the form f(x1, dots, xn-1, a1, dots,), where xi are the inputs and ai are parameters.
It returns a dictionary with entries (X, A), where X is a monomial with input vars and A is a polynomial of symbolic variables corresponding to the monomial X. For example, the entry (x_0*x_1, a_0a_1+_a2), means the symbolic polynomial contains the monomial (a_0a_1+_a2) * x_0_x1 (after grouping).
By default, the ct terms are always returned in the dictionary mapping the monomial to the coefficients.
The list input_vars can be given as a list of Boolean variables, strings or input variable indices.
>>> x, y, a, b, c = BooleanPolynomialRing(names="x, y, a, b, c").gens() >>> poly = x + x*a + x*b + x*y*(a*b + c) + (a*b*c) >>> poly x*y*a*b + x*y*c + x*a + x*b + x + a*b*c >>> get_all_symbolic_coeff(poly, (0, 1)) {x*y: a*b + c, x: a + b + 1, 1: a*b*c} >>> get_all_symbolic_coeff(poly, (x, y)) {x*y: a*b + c, x: a + b + 1, 1: a*b*c} >>> get_all_symbolic_coeff(poly, ("x", "y"), ignore_terms_of_deg_strictly_less=1) {x*y: a*b + c, x: a + b + 1} >>> get_all_symbolic_coeff(poly, (0, 1, 2, 3, 4)) {x*y*a*b: 1, x*y*c: 1, x*a: 1, x*b: 1, x: 1, a*b*c: 1}
- boolcrypt.utilities.get_symbolic_alg_deg(bool_poly, input_vars)[source]
“Return the algebraic degree of a symbolic Boolean function.
A symbolic Boolean function is a Boolean function of the form f(x1, dots, xn-1, a1, dots,), where xi are the inputs and ai are parameters (not necessarily ordered).
The list input_vars can be given as a list of Boolean variables, strings or input variable indices.
>>> x, a, b = BooleanPolynomialRing(names="x, a, b").gens() >>> get_symbolic_alg_deg(x + a * b, [0]) 1 >>> get_symbolic_alg_deg(x + a * b, [x]) 1 >>> (x + a * b).degree() 2
- boolcrypt.utilities.simplify_symbolic_matrix(matrix, prefix='x')[source]
Return a symbolic matrix where each symbolic coeff is replaced by a symbolic var.
>>> a, b, c, d = BooleanPolynomialRing(names=('a','b','c','d')).gens() >>> matrix = sage.all.matrix(2, 3, [[a*b, a*b + c, 0], [a*b, d, 1]]) >>> simplify_symbolic_matrix(matrix) [x0 x1 0] [x0 x2 1]
- boolcrypt.utilities.simplify_symbolic_anf(anf, input_vars, prefix='a', order='lex')[source]
Return a symbolic anf where each symbolic coeff is replaced by a symbolic var.
The list input_vars can be given as a list of Boolean variables, strings or input variable indices.
>>> x, y, z, a, b, c = BooleanPolynomialRing(names="x, y, z, a, b, c").gens() >>> f0 = a*x*y*z + b*x*y + c*y*z + (a+b)*x + (b+c)*z + a*b*c >>> f1 = a*b*c*x*y*z + x*y + y*z + (b+c)*x + (a+b)*z + 1 >>> simplify_symbolic_anf([f0, f1], [x, y, z]) [x*y*z*a0 + x*y*a1 + x*a2 + y*z*a3 + z*a4 + a5, x*y*z*a5 + x*y + x*a4 + y*z + z*a2 + 1] >>> simplify_symbolic_anf([f0, f1], ["x", "y", "z"], order="deglex") [x*y*z*a0 + x*y*a1 + x*a3 + y*z*a2 + z*a4 + a5, x*y*z*a5 + x*y + x*a4 + y*z + z*a3 + 1]