From c01499286683f0d3856879b25661dd36a5d3752c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 5 Mar 2023 21:38:40 -0800 Subject: [PATCH 01/15] Add # optional - numpy etc. --- src/sage/crypto/lwe.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/crypto/lwe.py b/src/sage/crypto/lwe.py index e6928d00213..577f8b6eb08 100644 --- a/src/sage/crypto/lwe.py +++ b/src/sage/crypto/lwe.py @@ -296,8 +296,8 @@ def __init__(self, n, q, D, secret_dist='uniform', m=None): fix the representation and recover the correct standard deviation of the noise:: - sage: from numpy import std - sage: while abs(std([e if e <= 200 else e-401 for e in S()]) - 3.0) > 0.01: + sage: from numpy import std # optional - numpy + sage: while abs(std([e if e <= 200 else e-401 for e in S()]) - 3.0) > 0.01: # optional - numpy ....: L = [] # reset L to avoid quadratic behaviour ....: add_samples() From 94ea10ecd1f7d1c40a9ee49bea95fad4fbd5f018 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 May 2023 13:20:30 -0700 Subject: [PATCH 02/15] Massive modularization fixes --- src/sage/crypto/boolean_function.pyx | 14 ++++++-------- src/sage/crypto/lattice.py | 10 +++++----- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index 13d0a043ff8..ebe6d9bbf2d 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -179,10 +179,9 @@ cdef class BooleanFunction(SageObject): note that elements can be of different types:: - sage: B = BooleanFunction([False, sqrt(2)]) - sage: B + sage: B = BooleanFunction([False, sqrt(2)]); B # optional - sage.symbolic Boolean function with 1 variable - sage: [b for b in B] + sage: [b for b in B] # optional - sage.symbolic [False, True] from a string:: @@ -206,7 +205,7 @@ cdef class BooleanFunction(SageObject): two failure cases:: - sage: BooleanFunction(sqrt(2)) + sage: BooleanFunction(sqrt(2)) # optional - sage.symbolic Traceback (most recent call last): ... TypeError: unable to init the Boolean function @@ -255,10 +254,9 @@ cdef class BooleanFunction(SageObject): note that elements can be of different types:: - sage: B = BooleanFunction([False, sqrt(2)]) - sage: B + sage: B = BooleanFunction([False, sqrt(2)]); B # optional - sage.symbolic Boolean function with 1 variable - sage: [b for b in B] + sage: [b for b in B] # optional - sage.symbolic [False, True] from a :class:`sage.rings.polynomial.pbori.BooleanPolynomial`:: @@ -277,7 +275,7 @@ cdef class BooleanFunction(SageObject): two failure cases:: - sage: BooleanFunction(sqrt(2)) + sage: BooleanFunction(sqrt(2)) # optional - sage.symbolic Traceback (most recent call last): ... TypeError: unable to init the Boolean function diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index d7ee358b9a9..e68461628a5 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -95,9 +95,9 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, [ 3082 0 0 0 0 0 0 0 1 0] [-4580 0 0 0 0 0 0 0 0 1] - Ideal bases with quotient x^n-1, m=2*n are NTRU bases:: + Ideal bases with quotient `x^n-1`, `m=2*n` are NTRU bases:: - sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4-1) + sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4 - 1) # optional - sage.symbolic [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] @@ -110,7 +110,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, Ideal bases also work with polynomials:: sage: R. = PolynomialRing(ZZ) - sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=t^4-1) + sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=t^4 - 1) [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] @@ -159,11 +159,11 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, Test some bad quotient polynomials:: - sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=cos(x)) + sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=cos(x)) # optional - sage.symbolic Traceback (most recent call last): ... TypeError: self must be a numeric expression - sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=x^23-1) + sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=x^23-1) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: ideal basis requires n = quotient.degree() From 280acb2ff398d1c39eb6556d63b28c470d6cc560 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 7 Jun 2023 18:04:11 -0700 Subject: [PATCH 03/15] sage.crypto: Modularization fixes for imports, # optional --- src/sage/crypto/block_cipher/des.py | 1 + src/sage/crypto/block_cipher/miniaes.py | 1 + src/sage/crypto/block_cipher/present.py | 5 +- src/sage/crypto/block_cipher/sdes.py | 1 + src/sage/crypto/boolean_function.pyx | 203 ++++++++------- src/sage/crypto/cipher.py | 1 + src/sage/crypto/classical.py | 231 +++++++++--------- src/sage/crypto/classical_cipher.py | 65 ++--- src/sage/crypto/cryptosystem.py | 1 + src/sage/crypto/lattice.py | 31 +-- src/sage/crypto/lfsr.py | 1 + src/sage/crypto/mq/rijndael_gf.py | 1 + src/sage/crypto/mq/sr.py | 1 + src/sage/crypto/public_key/blum_goldwasser.py | 1 + src/sage/crypto/sbox.pyx | 10 +- src/sage/crypto/sboxes.py | 1 + src/sage/crypto/stream.py | 1 + src/sage/crypto/stream_cipher.py | 1 + src/sage/crypto/util.py | 3 +- 19 files changed, 286 insertions(+), 274 deletions(-) diff --git a/src/sage/crypto/block_cipher/des.py b/src/sage/crypto/block_cipher/des.py index e0d7f8b0471..a6d3108076b 100644 --- a/src/sage/crypto/block_cipher/des.py +++ b/src/sage/crypto/block_cipher/des.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" DES diff --git a/src/sage/crypto/block_cipher/miniaes.py b/src/sage/crypto/block_cipher/miniaes.py index 95fcf1a258c..b0dd068b683 100644 --- a/src/sage/crypto/block_cipher/miniaes.py +++ b/src/sage/crypto/block_cipher/miniaes.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Mini-AES diff --git a/src/sage/crypto/block_cipher/present.py b/src/sage/crypto/block_cipher/present.py index 1774e6d5977..3f5bddcefec 100644 --- a/src/sage/crypto/block_cipher/present.py +++ b/src/sage/crypto/block_cipher/present.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" PRESENT @@ -61,10 +62,12 @@ from sage.structure.sage_object import SageObject from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer +from sage.misc.lazy_import import lazy_import from sage.modules.free_module_element import vector from sage.rings.finite_rings.finite_field_constructor import GF from sage.crypto.sboxes import PRESENT as PRESENTSBOX -from sage.modules.vector_mod2_dense import Vector_mod2_dense + +lazy_import('sage.modules.vector_mod2_dense', 'Vector_mod2_dense') def _smallscale_present_linearlayer(nsboxes=16): diff --git a/src/sage/crypto/block_cipher/sdes.py b/src/sage/crypto/block_cipher/sdes.py index 02a7a14772c..accda2d3d15 100644 --- a/src/sage/crypto/block_cipher/sdes.py +++ b/src/sage/crypto/block_cipher/sdes.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.rings.finite_rings r""" Simplified DES diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index ebe6d9bbf2d..bc035c17732 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -10,14 +10,13 @@ and also algebraic immunity. EXAMPLES:: - sage: R. = GF(2^8,'a')[] + sage: R. = GF(2^8,'a')[] # optional - sage.rings.finite_rings sage: from sage.crypto.boolean_function import BooleanFunction - sage: B = BooleanFunction( x^254 ) # the Boolean function Tr(x^254) - sage: B + sage: B = BooleanFunction(x^254); B # the Boolean function Tr(x^254) # optional - sage.rings.finite_rings Boolean function with 8 variables - sage: B.nonlinearity() + sage: B.nonlinearity() # optional - sage.rings.finite_rings 112 - sage: B.algebraic_immunity() + sage: B.algebraic_immunity() # optional - sage.rings.finite_rings 4 AUTHOR: @@ -32,18 +31,19 @@ AUTHOR: from cysignals.signals cimport sig_check from libc.string cimport memcpy -from sage.structure.sage_object cimport SageObject -from sage.structure.richcmp cimport rich_to_bool -from sage.rings.integer_ring import ZZ -from sage.rings.integer cimport Integer -from sage.rings.finite_rings.finite_field_constructor import GF -from sage.rings.polynomial.pbori.pbori import BooleanPolynomial +from sage.misc.superseded import deprecated_function_alias from sage.rings.finite_rings.finite_field_base import FiniteField +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.integer cimport Integer +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_element import Polynomial +from sage.structure.richcmp cimport rich_to_bool +from sage.structure.sage_object cimport SageObject -from sage.misc.superseded import deprecated_function_alias - -from sage.data_structures.bitset_base cimport * +try: + from sage.rings.polynomial.pbori.pbori import BooleanPolynomial +except ImportError: + BooleanPolynomial = () # for details about the implementation of hamming_weight (in .pxd), # walsh_hadamard transform, reed_muller transform, and a lot @@ -90,10 +90,10 @@ cdef long yellow_code(unsigned long a): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: R. = BooleanPolynomialRing(3) - sage: P = x*y - sage: B = BooleanFunction( P ) - sage: B.truth_table() # indirect doctest + sage: R. = BooleanPolynomialRing(3) # optional - sage.rings.polynomial.pbori + sage: P = x*y # optional - sage.rings.polynomial.pbori + sage: B = BooleanFunction(P) # optional - sage.rings.polynomial.pbori + sage: B.truth_table() # indirect doctest # optional - sage.rings.polynomial.pbori (False, False, False, True, False, False, False, True) """ cdef unsigned long s = (8*sizeof(unsigned long)) >> 1 @@ -123,10 +123,10 @@ cdef reed_muller(mp_limb_t* f, int ldn): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: R. = BooleanPolynomialRing(3) - sage: P = x*y - sage: B = BooleanFunction( P ) - sage: B.truth_table() # indirect doctest + sage: R. = BooleanPolynomialRing(3) # optional - sage.rings.polynomial.pbori + sage: P = x*y # optional - sage.rings.polynomial.pbori + sage: B = BooleanFunction(P) # optional - sage.rings.polynomial.pbori + sage: B.truth_table() # indirect doctest # optional - sage.rings.polynomial.pbori (False, False, False, True, False, False, False, True) """ cdef long n, ldm, m, mh, t1, t2, r, j @@ -154,15 +154,15 @@ cdef class BooleanFunction(SageObject): We can construct a Boolean Function from either: - - an integer - the result is the zero function with ``x`` variables; - - a list - it is expected to be the truth table of the + - an integer -- the result is the zero function with ``x`` variables; + - a list -- it is expected to be the truth table of the result. Therefore it must be of length a power of 2, and its elements are interpreted as Booleans; - - a string - representing the truth table in hexadecimal; - - a Boolean polynomial - the result is the corresponding Boolean function; - - a polynomial P over an extension of GF(2) - the result is - the Boolean function with truth table ``( Tr(P(x)) for x in - GF(2^k) )`` + - a string -- representing the truth table in hexadecimal; + - a Boolean polynomial -- the result is the corresponding Boolean function; + - a polynomial `P` over an extension of `\GF{2}` -- the result is + the Boolean function with truth table ``(Tr(P(x)) for x in + GF(2^k))`` EXAMPLES: @@ -191,16 +191,15 @@ cdef class BooleanFunction(SageObject): from a :class:`sage.rings.polynomial.pbori.BooleanPolynomial`:: - sage: R. = BooleanPolynomialRing(3) - sage: P = x*y - sage: BooleanFunction( P ) + sage: R. = BooleanPolynomialRing(3) # optional - sage.rings.polynomial.pbori + sage: P = x*y # optional - sage.rings.polynomial.pbori + sage: BooleanFunction(P) # optional - sage.rings.polynomial.pbori Boolean function with 3 variables from a polynomial over a binary field:: - sage: R. = GF(2^8,'a')[] - sage: B = BooleanFunction( x^7 ) - sage: B + sage: R. = GF(2^8,'a')[] # optional - sage.rings.finite_rings + sage: B = BooleanFunction(x^7); B # optional - sage.rings.finite_rings Boolean function with 8 variables two failure cases:: @@ -261,16 +260,15 @@ cdef class BooleanFunction(SageObject): from a :class:`sage.rings.polynomial.pbori.BooleanPolynomial`:: - sage: R. = BooleanPolynomialRing(3) - sage: P = x*y - sage: BooleanFunction( P ) + sage: R. = BooleanPolynomialRing(3) # optional - sage.rings.polynomial.pbori + sage: P = x*y # optional - sage.rings.polynomial.pbori + sage: BooleanFunction(P) # optional - sage.rings.polynomial.pbori Boolean function with 3 variables from a polynomial over a binary field:: - sage: R. = GF(2^8,'a')[] - sage: B = BooleanFunction( x^7 ) - sage: B + sage: R. = GF(2^8,'a')[] # optional - sage.rings.finite_rings + sage: B = BooleanFunction(x^7); B # optional - sage.rings.finite_rings Boolean function with 8 variables two failure cases:: @@ -394,8 +392,8 @@ cdef class BooleanFunction(SageObject): it also corresponds to the addition of algebraic normal forms:: - sage: S = A.algebraic_normal_form() + B.algebraic_normal_form() - sage: (A+B).algebraic_normal_form() == S + sage: S = A.algebraic_normal_form() + B.algebraic_normal_form() # optional - sage.rings.polynomial.pbori + sage: (A+B).algebraic_normal_form() == S # optional - sage.rings.polynomial.pbori True TESTS:: @@ -426,8 +424,8 @@ cdef class BooleanFunction(SageObject): it also corresponds to the multiplication of algebraic normal forms:: - sage: P = A.algebraic_normal_form() * B.algebraic_normal_form() - sage: (A*B).algebraic_normal_form() == P + sage: P = A.algebraic_normal_form() * B.algebraic_normal_form() # optional - sage.rings.polynomial.pbori + sage: (A*B).algebraic_normal_form() == P # optional - sage.rings.polynomial.pbori True TESTS:: @@ -497,10 +495,9 @@ cdef class BooleanFunction(SageObject): sage: from sage.crypto.boolean_function import BooleanFunction sage: B = BooleanFunction([0,1,1,0,1,0,1,1]) - sage: P = B.algebraic_normal_form() - sage: P + sage: P = B.algebraic_normal_form(); P # optional - sage.rings.polynomial.pbori x0*x1*x2 + x0 + x1*x2 + x1 + x2 - sage: [ P(*ZZ(i).digits(base=2,padto=3)) for i in range(8) ] + sage: [P(*ZZ(i).digits(base=2, padto=3)) for i in range(8)] # optional - sage.rings.polynomial.pbori [0, 1, 1, 0, 1, 0, 1, 1] """ cdef bitset_t anf @@ -546,20 +543,20 @@ cdef class BooleanFunction(SageObject): INPUT: a string representing the desired format, can be either - - 'bin' (default) : we return a tuple of Boolean values - - 'int' : we return a tuple of 0 or 1 values - - 'hex' : we return a string representing the truth_table in hexadecimal + - ``'bin'`` (default): we return a tuple of Boolean values + - ``'int'``: we return a tuple of 0 or 1 values + - ``'hex'``: we return a string representing the truth table in hexadecimal EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: R. = BooleanPolynomialRing(3) - sage: B = BooleanFunction( x*y*z + z + y + 1 ) - sage: B.truth_table() + sage: R. = BooleanPolynomialRing(3) # optional - sage.rings.polynomial.pbori + sage: B = BooleanFunction(x*y*z + z + y + 1) # optional - sage.rings.polynomial.pbori + sage: B.truth_table() # optional - sage.rings.polynomial.pbori (True, True, False, False, False, False, True, False) - sage: B.truth_table(format='int') + sage: B.truth_table(format='int') # optional - sage.rings.polynomial.pbori (1, 1, 0, 0, 0, 0, 1, 0) - sage: B.truth_table(format='hex') + sage: B.truth_table(format='hex') # optional - sage.rings.polynomial.pbori '43' sage: BooleanFunction('00ab').truth_table(format='hex') @@ -581,7 +578,7 @@ cdef class BooleanFunction(SageObject): True sage: len(T) 256 - sage: B.truth_table(format='oct') + sage: B.truth_table(format='oct') # optional - sage.rings.polynomial.pbori Traceback (most recent call last): ... ValueError: unknown output format @@ -701,9 +698,9 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: R. = GF(2^3,'a')[] - sage: B = BooleanFunction( x^3 ) - sage: B.walsh_hadamard_transform() + sage: R. = GF(2^3,'a')[] # optional - sage.rings.finite_rings + sage: B = BooleanFunction(x^3) # optional - sage.rings.finite_rings + sage: B.walsh_hadamard_transform() # optional - sage.rings.finite_rings (0, -4, 0, 4, 0, 4, 0, 4) """ cdef long *temp @@ -835,8 +832,8 @@ cdef class BooleanFunction(SageObject): correlation immune of order `m`. A Boolean function is said to be correlation immune of order - `m`, if the output of the function is statistically - independent of the combination of any m of its inputs. + `m` if the output of the function is statistically + independent of the combination of any `m` of its inputs. EXAMPLES:: @@ -864,7 +861,7 @@ cdef class BooleanFunction(SageObject): A Boolean function is said to be resilient of order `m` if it is balanced and correlation immune of order `m`. - If the function is not balanced, we return -1. + If the function is not balanced, we return `-1`. EXAMPLES:: @@ -989,17 +986,17 @@ cdef class BooleanFunction(SageObject): INPUT: - ``d`` -- an integer; - - ``dim`` -- a Boolean (default: False), if True, return also + - ``dim`` -- a Boolean (default: ``False``), if ``True``, return also the dimension of the annihilator vector space. EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction sage: f = BooleanFunction("7969817CC5893BA6AC326E47619F5AD0") - sage: f.annihilator(1) is None + sage: f.annihilator(1) is None # optional - sage.rings.polynomial.pbori True - sage: g = BooleanFunction( f.annihilator(3) ) - sage: set([ fi*g(i) for i,fi in enumerate(f) ]) + sage: g = BooleanFunction(f.annihilator(3)) # optional - sage.rings.polynomial.pbori + sage: set(fi*g(i) for i,fi in enumerate(f)) # optional - sage.rings.polynomial.pbori {0} """ # NOTE: this is a toy implementation @@ -1052,8 +1049,8 @@ cdef class BooleanFunction(SageObject): """ Return the algebraic immunity of the Boolean function. - This is the smallest integer `i` such that there exists a non - trivial annihilator for `self` or `~self`. + This is the smallest integer `i` such that there exists a + nontrivial annihilator for ``self`` or ``~self``. INPUT: @@ -1063,17 +1060,17 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: R. = BooleanPolynomialRing(6) - sage: B = BooleanFunction(x0*x1 + x1*x2 + x2*x3 + x3*x4 + x4*x5) - sage: B.algebraic_immunity(annihilator=True) + sage: R. = BooleanPolynomialRing(6) # optional - sage.rings.polynomial.pbori + sage: B = BooleanFunction(x0*x1 + x1*x2 + x2*x3 + x3*x4 + x4*x5) # optional - sage.rings.polynomial.pbori + sage: B.algebraic_immunity(annihilator=True) # optional - sage.rings.polynomial.pbori (2, x0*x1 + x1*x2 + x2*x3 + x3*x4 + x4*x5 + 1) - sage: B[0] +=1 - sage: B.algebraic_immunity() + sage: B[0] += 1 # optional - sage.rings.polynomial.pbori + sage: B.algebraic_immunity() # optional - sage.rings.polynomial.pbori 2 - sage: R. = GF(2^8,'a')[] - sage: B = BooleanFunction(x^31) - sage: B.algebraic_immunity() + sage: R. = GF(2^8,'a')[] # optional - sage.rings.finite_rings + sage: B = BooleanFunction(x^31) # optional - sage.rings.finite_rings + sage: B.algebraic_immunity() # optional - sage.rings.finite_rings 4 """ f = self @@ -1095,17 +1092,17 @@ cdef class BooleanFunction(SageObject): The algebraic degree of a Boolean function is defined as the degree of its algebraic normal form. Note that the degree of the constant - zero function is defined to be equal to -1. + zero function is defined to be equal to `-1`. EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: B. = BooleanPolynomialRing() - sage: f = BooleanFunction(x1*x2 + x1*x2*x3 + x1) - sage: f.algebraic_degree() + sage: B. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori + sage: f = BooleanFunction(x1*x2 + x1*x2*x3 + x1) # optional - sage.rings.polynomial.pbori + sage: f.algebraic_degree() # optional - sage.rings.polynomial.pbori 3 sage: g = BooleanFunction([0, 0]) - sage: g.algebraic_degree() + sage: g.algebraic_degree() # optional - sage.rings.polynomial.pbori -1 """ return self.algebraic_normal_form().degree() @@ -1119,11 +1116,11 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: R. = BooleanPolynomialRing() - sage: f = BooleanFunction(x0*x1 + x2 + x3) - sage: f.walsh_hadamard_transform() + sage: R. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori + sage: f = BooleanFunction(x0*x1 + x2 + x3) # optional - sage.rings.polynomial.pbori + sage: f.walsh_hadamard_transform() # optional - sage.rings.polynomial.pbori (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, -8) - sage: f.is_plateaued() + sage: f.is_plateaued() # optional - sage.rings.polynomial.pbori True """ W = self.absolute_walsh_spectrum() @@ -1153,26 +1150,26 @@ cdef class BooleanFunction(SageObject): sage: l = [1, 0, 0, 1] sage: f.is_linear_structure(l) True - sage: v = vector(GF(2), l) - sage: f.is_linear_structure(v) + sage: v = vector(GF(2), l) # optional - sage.rings.finite_rings + sage: f.is_linear_structure(v) # optional - sage.rings.finite_rings True sage: f.is_linear_structure(7) False - sage: f.is_linear_structure(20) #parameter is out of range + sage: f.is_linear_structure(20) # parameter is out of range Traceback (most recent call last): ... IndexError: index out of range - sage: v = vector(GF(3), [1, 0, 1, 1]) - sage: f.is_linear_structure(v) + sage: v = vector(GF(3), [1, 0, 1, 1]) # optional - sage.rings.finite_rings + sage: f.is_linear_structure(v) # optional - sage.rings.finite_rings Traceback (most recent call last): ... TypeError: base ring of input vector must be GF(2) - sage: v = vector(GF(2), [1, 0, 1, 1, 1]) - sage: f.is_linear_structure(v) + sage: v = vector(GF(2), [1, 0, 1, 1, 1]) # optional - sage.rings.finite_rings + sage: f.is_linear_structure(v) # optional - sage.rings.finite_rings Traceback (most recent call last): ... TypeError: input vector must be an element of a vector space with dimension 4 - sage: f.is_linear_structure('X') #failure case + sage: f.is_linear_structure('X') # failure case Traceback (most recent call last): ... TypeError: cannot compute is_linear_structure() using parameter X @@ -1246,13 +1243,13 @@ cdef class BooleanFunction(SageObject): sage: from sage.crypto.boolean_function import BooleanFunction sage: f = BooleanFunction([0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0]) - sage: LS = f.linear_structures() - sage: LS.dimension() + sage: LS = f.linear_structures() # optional - sage.modules sage.rings.finite_rings + sage: LS.dimension() # optional - sage.modules sage.rings.finite_rings 2 - sage: LS.basis_matrix() + sage: LS.basis_matrix() # optional - sage.modules sage.rings.finite_rings [1 0 0 0] [0 0 0 1] - sage: LS.list() + sage: LS.list() # optional - sage.modules sage.rings.finite_rings [(0, 0, 0, 0), (1, 0, 0, 0), (0, 0, 0, 1), (1, 0, 0, 1)] """ from sage.modules.free_module import VectorSpace @@ -1281,15 +1278,15 @@ cdef class BooleanFunction(SageObject): sage: from sage.crypto.boolean_function import BooleanFunction sage: f = BooleanFunction([0,1,0,1,0,1,0,1]) - sage: f.derivative(1).algebraic_normal_form() + sage: f.derivative(1).algebraic_normal_form() # optional - sage.rings.polynomial.pbori 1 sage: u = [1,0,0] - sage: f.derivative(u).algebraic_normal_form() + sage: f.derivative(u).algebraic_normal_form() # optional - sage.rings.polynomial.pbori 1 - sage: v = vector(GF(2), u) - sage: f.derivative(u).algebraic_normal_form() + sage: v = vector(GF(2), u) # optional - sage.modules sage.rings.finite_rings + sage: f.derivative(v).algebraic_normal_form() # optional - sage.modules sage.rings.finite_rings sage.rings.polynomial.pbori 1 - sage: f.derivative(8).algebraic_normal_form() + sage: f.derivative(8).algebraic_normal_form() # optional - sage.rings.polynomial.pbori Traceback (most recent call last): ... IndexError: index out of bound diff --git a/src/sage/crypto/cipher.py b/src/sage/crypto/cipher.py index 6d6ed6dd2b3..f0f9d4eedcc 100644 --- a/src/sage/crypto/cipher.py +++ b/src/sage/crypto/cipher.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat """ Ciphers """ diff --git a/src/sage/crypto/classical.py b/src/sage/crypto/classical.py index 132a18cdee0..9cb9c92f5cb 100644 --- a/src/sage/crypto/classical.py +++ b/src/sage/crypto/classical.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat r""" Classical Cryptosystems @@ -45,19 +46,22 @@ # - methods to cryptanalyze the Hill, substitution, transposition, and # Vigenere ciphers +from random import randint + +from sage.arith.misc import inverse_mod, xgcd +from sage.misc.lazy_import import lazy_import from sage.monoids.string_monoid import ( StringMonoid_class, AlphabeticStringMonoid) from sage.monoids.string_monoid_element import StringMonoidElement from sage.monoids.string_ops import strip_encoding -from sage.groups.perm_gps.permgroup_named import SymmetricGroup -from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing -from sage.arith.misc import inverse_mod, xgcd -from random import randint -from sage.matrix.matrix_space import MatrixSpace + +lazy_import('sage.groups.perm_gps.permgroup_named', 'SymmetricGroup') +lazy_import('sage.groups.perm_gps.permgroup_element', 'PermutationGroupElement') +lazy_import('sage.matrix.matrix_space', 'MatrixSpace') from .cryptosystem import SymmetricKeyCryptosystem from .classical_cipher import ( @@ -1285,7 +1289,7 @@ def random_key(self): class HillCryptosystem(SymmetricKeyCryptosystem): r""" - Create a Hill cryptosystem defined by the `m` x `m` matrix space + Create a Hill cryptosystem defined by the `m \times m` matrix space over `\ZZ / N \ZZ`, where `N` is the alphabet size of the string monoid ``S``. @@ -1303,27 +1307,24 @@ class HillCryptosystem(SymmetricKeyCryptosystem): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: E + sage: E = HillCryptosystem(S, 3); E # optional - sage.modules Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 sage: R = IntegerModRing(26) - sage: M = MatrixSpace(R,3,3) - sage: A = M([[1,0,1],[0,1,1],[2,2,3]]) - sage: A + sage: M = MatrixSpace(R,3,3) # optional - sage.modules + sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A # optional - sage.modules [1 0 1] [0 1 1] [2 2 3] - sage: e = E(A) - sage: e + sage: e = E(A); e # optional - sage.modules Hill cipher on Free alphabetic string monoid on A-Z of block length 3 - sage: e(S("LAMAISONBLANCHE")) + sage: e(S("LAMAISONBLANCHE")) # optional - sage.modules JYVKSKQPELAYKPV TESTS:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: E == loads(dumps(E)) + sage: E = HillCryptosystem(S, 3) # optional - sage.modules + sage: E == loads(dumps(E)) # optional - sage.modules True """ @@ -1331,7 +1332,7 @@ def __init__(self, S, m): r""" See ``HillCryptosystem`` for full documentation. - Create a Hill cryptosystem defined by the `m` x `m` matrix space + Create a Hill cryptosystem defined by the `m \times m` matrix space over `\ZZ / N \ZZ`, where `N` is the alphabet size of the string monoid ``S``. @@ -1349,8 +1350,7 @@ def __init__(self, S, m): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: E + sage: E = HillCryptosystem(S, 3); E # optional - sage.modules Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 """ if not isinstance(S, StringMonoid_class): @@ -1370,23 +1370,20 @@ def __call__(self, A): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: E + sage: E = HillCryptosystem(S,3); E # optional - sage.modules Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 - sage: M = E.key_space() - sage: A = M([[1,0,1],[0,1,1],[2,2,3]]) - sage: A + sage: M = E.key_space() # optional - sage.modules + sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A # optional - sage.modules [1 0 1] [0 1 1] [2 2 3] - sage: e = E(A) - sage: e + sage: e = E(A); e # optional - sage.modules Hill cipher on Free alphabetic string monoid on A-Z of block length 3 - sage: m = S("LAMAISONBLANCHE") - sage: e(m) + sage: m = S("LAMAISONBLANCHE") # optional - sage.modules + sage: e(m) # optional - sage.modules JYVKSKQPELAYKPV - sage: c = e.inverse() - sage: c(e(m)) + sage: c = e.inverse() # optional - sage.modules + sage: c(e(m)) # optional - sage.modules LAMAISONBLANCHE """ M = self.key_space() @@ -1405,10 +1402,9 @@ def _repr_(self): EXAMPLES:: sage: A = AlphabeticStrings() - sage: H = HillCryptosystem(A, 3) - sage: H + sage: H = HillCryptosystem(A, 3); H # optional - sage.modules Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 - sage: H._repr_() + sage: H._repr_() # optional - sage.modules 'Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3' """ return "Hill cryptosystem on %s of block length %s" % ( @@ -1430,8 +1426,8 @@ def block_length(self): sage: A = AlphabeticStrings() sage: n = randint(1, A.ngens() - 1) - sage: H = HillCryptosystem(A, n) - sage: H.block_length() == n + sage: H = HillCryptosystem(A, n) # optional - sage.modules + sage: H.block_length() == n # optional - sage.modules True """ return self.key_space().nrows() @@ -1439,11 +1435,11 @@ def block_length(self): def random_key(self): """ A random key within the key space of this Hill cipher. That is, - generate a random `m` x `m` matrix to be used as a block + generate a random `m \times m` matrix to be used as a block permutation, where `m` is the block length of this Hill cipher. If `n` is the size of the cryptosystem alphabet, then there are `n^{m^2}` possible keys. However the number of valid keys, - i.e. invertible `m` x `m` square matrices, is smaller than + i.e. invertible `m \times m` square matrices, is smaller than `n^{m^2}`. OUTPUT: @@ -1454,13 +1450,13 @@ def random_key(self): sage: A = AlphabeticStrings() sage: n = 3 - sage: H = HillCryptosystem(A, n) - sage: K = H.random_key() - sage: Ki = H.inverse_key(K) - sage: M = "LAMAISONBLANCHE" - sage: e = H(K) - sage: d = H(Ki) - sage: d(e(A(M))) == A(M) + sage: H = HillCryptosystem(A, n) # optional - sage.modules + sage: K = H.random_key() # optional - sage.modules + sage: Ki = H.inverse_key(K) # optional - sage.modules + sage: M = "LAMAISONBLANCHE" # optional - sage.modules + sage: e = H(K) # optional - sage.modules + sage: d = H(Ki) # optional - sage.modules + sage: d(e(A(M))) == A(M) # optional - sage.modules True """ M = self.key_space() @@ -1478,7 +1474,7 @@ def inverse_key(self, A): INPUT: - - ``A`` - an invertible matrix of the key space of this Hill cipher + - ``A`` -- an invertible matrix of the key space of this Hill cipher OUTPUT: @@ -1487,13 +1483,13 @@ def inverse_key(self, A): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: A = E.random_key() - sage: B = E.inverse_key(A) - sage: M = S("LAMAISONBLANCHE") - sage: e = E(A) - sage: c = E(B) - sage: c(e(M)) + sage: E = HillCryptosystem(S, 3) # optional - sage.modules + sage: A = E.random_key() # optional - sage.modules + sage: B = E.inverse_key(A) # optional - sage.modules + sage: M = S("LAMAISONBLANCHE") # optional - sage.modules + sage: e = E(A) # optional - sage.modules + sage: c = E(B) # optional - sage.modules + sage: c(e(M)) # optional - sage.modules LAMAISONBLANCHE """ S = self.plaintext_space() @@ -1519,7 +1515,7 @@ def encoding(self, M): INPUT: - - ``M`` - a string, possibly empty + - ``M`` -- a string, possibly empty OUTPUT: @@ -1529,8 +1525,8 @@ def encoding(self, M): sage: M = "The matrix cipher by Lester S. Hill." sage: A = AlphabeticStrings() - sage: H = HillCryptosystem(A, 7) - sage: H.encoding(M) == A.encoding(M) + sage: H = HillCryptosystem(A, 7) # optional - sage.modules + sage: H.encoding(M) == A.encoding(M) # optional - sage.modules True """ S = self.cipher_domain() @@ -1547,9 +1543,9 @@ def deciphering(self, A, C): INPUT: - - ``A`` - a key within the key space of this Hill cipher + - ``A`` -- a key within the key space of this Hill cipher - - ``C`` - a string (possibly empty) over the string monoid of this + - ``C`` -- a string (possibly empty) over the string monoid of this Hill cipher OUTPUT: @@ -1558,10 +1554,10 @@ def deciphering(self, A, C): EXAMPLES:: - sage: H = HillCryptosystem(AlphabeticStrings(), 3) - sage: K = H.random_key() - sage: M = H.encoding("Good day, mate! How ya going?") - sage: H.deciphering(K, H.enciphering(K, M)) == M + sage: H = HillCryptosystem(AlphabeticStrings(), 3) # optional - sage.modules + sage: K = H.random_key() # optional - sage.modules + sage: M = H.encoding("Good day, mate! How ya going?") # optional - sage.modules + sage: H.deciphering(K, H.enciphering(K, M)) == M # optional - sage.modules True """ # TODO: some type checking that A is invertible hence a valid key @@ -1585,16 +1581,17 @@ def enciphering(self, A, M): EXAMPLES:: - sage: H = HillCryptosystem(AlphabeticStrings(), 3) - sage: K = H.random_key() - sage: M = H.encoding("Good day, mate! How ya going?") - sage: H.deciphering(K, H.enciphering(K, M)) == M + sage: H = HillCryptosystem(AlphabeticStrings(), 3) # optional - sage.modules + sage: K = H.random_key() # optional - sage.modules + sage: M = H.encoding("Good day, mate! How ya going?") # optional - sage.modules + sage: H.deciphering(K, H.enciphering(K, M)) == M # optional - sage.modules True """ # TODO: some type checking that A is invertible hence a valid key e = self(A) return e(M) + class ShiftCryptosystem(SymmetricKeyCryptosystem): r""" Create a shift cryptosystem. @@ -3258,21 +3255,20 @@ class TranspositionCryptosystem(SymmetricKeyCryptosystem): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14) - sage: E - Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 - sage: K = [ 14-i for i in range(14) ] - sage: K + sage: E = TranspositionCryptosystem(S,14); E # optional - sage.groups + Transposition cryptosystem on + Free alphabetic string monoid on A-Z of block length 14 + sage: K = [14 - i for i in range(14)]; K [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] - sage: e = E(K) - sage: e(S("THECATINTHEHAT")) + sage: e = E(K) # optional - sage.groups + sage: e(S("THECATINTHEHAT")) # optional - sage.groups TAHEHTNITACEHT TESTS:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14) - sage: E == loads(dumps(E)) + sage: E = TranspositionCryptosystem(S,14) # optional - sage.groups + sage: E == loads(dumps(E)) # optional - sage.groups True """ @@ -3283,8 +3279,7 @@ def __init__(self, S, n): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14) - sage: E + sage: E = TranspositionCryptosystem(S,14); E # optional - sage.groups Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 """ if not isinstance(S, StringMonoid_class): @@ -3303,15 +3298,14 @@ def __call__(self, K): EXAMPLES:: sage: M = AlphabeticStrings() - sage: E = TranspositionCryptosystem(M,14) - sage: E + sage: E = TranspositionCryptosystem(M,14); E # optional - sage.groups Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 sage: K = [ 14-i for i in range(14) ] sage: K [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] - sage: e = E(K) + sage: e = E(K) # optional - sage.groups sage: m = M("THECATINTHEHAT") - sage: e(m) + sage: e(m) # optional - sage.groups TAHEHTNITACEHT """ G = self.key_space() @@ -3353,14 +3347,14 @@ def random_key(self): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S, 14) - sage: K = E.random_key() - sage: Ki = E.inverse_key(K) - sage: e = E(K) - sage: d = E(Ki) + sage: E = TranspositionCryptosystem(S, 14) # optional - sage.groups + sage: K = E.random_key() # optional - sage.groups + sage: Ki = E.inverse_key(K) # optional - sage.groups + sage: e = E(K) # optional - sage.groups + sage: d = E(Ki) # optional - sage.groups sage: M = "THECATINTHEHAT" - sage: C = e(S(M)) - sage: d(S(C)) == S(M) + sage: C = e(S(M)) # optional - sage.groups + sage: d(S(C)) == S(M) # optional - sage.groups True """ n = self.block_length() @@ -3372,10 +3366,10 @@ def inverse_key(self, K, check=True): INPUT: - - ``K`` - a key belonging to the key space of this transposition + - ``K`` -- a key belonging to the key space of this transposition cipher - - ``check`` - bool (default: ``True``); check that ``K`` belongs to + - ``check`` -- bool (default: ``True``); check that ``K`` belongs to the key space of this cryptosystem. OUTPUT: @@ -3385,14 +3379,14 @@ def inverse_key(self, K, check=True): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S, 14) - sage: K = E.random_key() - sage: Ki = E.inverse_key(K) - sage: e = E(K) - sage: d = E(Ki) + sage: E = TranspositionCryptosystem(S, 14) # optional - sage.groups + sage: K = E.random_key() # optional - sage.groups + sage: Ki = E.inverse_key(K) # optional - sage.groups + sage: e = E(K) # optional - sage.groups + sage: d = E(Ki) # optional - sage.groups sage: M = "THECATINTHEHAT" - sage: C = e(S(M)) - sage: d(S(C)) == S(M) + sage: C = e(S(M)) # optional - sage.groups + sage: d(S(C)) == S(M) # optional - sage.groups True """ if check: @@ -3410,7 +3404,7 @@ def encoding(self, M): INPUT: - - ``M`` - a string, possibly empty + - ``M`` -- a string, possibly empty OUTPUT: @@ -3420,8 +3414,8 @@ def encoding(self, M): sage: M = "Transposition cipher is not about matrix transpose." sage: A = AlphabeticStrings() - sage: T = TranspositionCryptosystem(A, 11) - sage: T.encoding(M) == A.encoding(M) + sage: T = TranspositionCryptosystem(A, 11) # optional - sage.groups + sage: T.encoding(M) == A.encoding(M) # optional - sage.groups True """ S = self.cipher_domain() @@ -3438,10 +3432,10 @@ def deciphering(self, K, C): INPUT: - - ``K`` - a key belonging to the key space of this transposition + - ``K`` -- a key belonging to the key space of this transposition cipher - - ``C`` - a string (possibly empty) over the string monoid of this + - ``C`` -- a string (possibly empty) over the string monoid of this cryptosystem. OUTPUT: @@ -3450,10 +3444,10 @@ def deciphering(self, K, C): EXAMPLES:: - sage: T = TranspositionCryptosystem(AlphabeticStrings(), 14) - sage: K = T.random_key() - sage: M = T.encoding("The cat in the hat.") - sage: T.deciphering(K, T.enciphering(K, M)) == M + sage: T = TranspositionCryptosystem(AlphabeticStrings(), 14) # optional - sage.groups + sage: K = T.random_key() # optional - sage.groups + sage: M = T.encoding("The cat in the hat.") # optional - sage.groups + sage: T.deciphering(K, T.enciphering(K, M)) == M # optional - sage.groups True """ i = self(self.inverse_key(K)) @@ -3465,10 +3459,10 @@ def enciphering(self, K, M): INPUT: - - ``K`` - a key belonging to the key space of this transposition + - ``K`` -- a key belonging to the key space of this transposition cipher - - ``M`` - a string (possibly empty) over the string monoid of this + - ``M`` -- a string (possibly empty) over the string monoid of this cryptosystem OUTPUT: @@ -3477,15 +3471,16 @@ def enciphering(self, K, M): EXAMPLES:: - sage: T = TranspositionCryptosystem(AlphabeticStrings(), 14) - sage: K = T.random_key() - sage: M = T.encoding("The cat in the hat.") - sage: T.deciphering(K, T.enciphering(K, M)) == M + sage: T = TranspositionCryptosystem(AlphabeticStrings(), 14) # optional - sage.groups + sage: K = T.random_key() # optional - sage.groups + sage: M = T.encoding("The cat in the hat.") # optional - sage.groups + sage: T.deciphering(K, T.enciphering(K, M)) == M # optional - sage.groups True """ e = self(K) return e(M) + class VigenereCryptosystem(SymmetricKeyCryptosystem): """ Create a Vigenere cryptosystem of block length ``n``. @@ -3494,7 +3489,7 @@ class VigenereCryptosystem(SymmetricKeyCryptosystem): - ``S``-- a string monoid over some alphabet - - ``n`` - integer `> 0`; block length of an encryption/decryption key + - ``n`` -- integer `> 0`; block length of an encryption/decryption key OUTPUT: @@ -3621,7 +3616,7 @@ def inverse_key(self, K): INPUT: - - ``K`` - a key within the key space of this Vigenere cryptosystem + - ``K`` -- a key within the key space of this Vigenere cryptosystem OUTPUT: @@ -3653,7 +3648,7 @@ def encoding(self, M): INPUT: - - ``M`` - a string, possibly empty + - ``M`` -- a string, possibly empty OUTPUT: @@ -3681,9 +3676,9 @@ def deciphering(self, K, C): INPUT: - - ``K`` - a key belonging to the key space of this Vigenere cipher + - ``K`` -- a key belonging to the key space of this Vigenere cipher - - ``C`` - a string (possibly empty) over the string monoid of this + - ``C`` -- a string (possibly empty) over the string monoid of this cryptosystem OUTPUT: @@ -3707,9 +3702,9 @@ def enciphering(self, K, M): INPUT: - - ``K`` - a key belonging to the key space of this Vigenere cipher + - ``K`` -- a key belonging to the key space of this Vigenere cipher - - ``M`` - a string (possibly empty) over the string monoid of this + - ``M`` -- a string (possibly empty) over the string monoid of this cryptosystem OUTPUT: diff --git a/src/sage/crypto/classical_cipher.py b/src/sage/crypto/classical_cipher.py index 2d5722b04df..7d9e15a4d7f 100644 --- a/src/sage/crypto/classical_cipher.py +++ b/src/sage/crypto/classical_cipher.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat """ Classical Ciphers """ @@ -8,9 +9,12 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from .cipher import SymmetricKeyCipher +from sage.misc.lazy_import import lazy_import from sage.monoids.string_monoid_element import StringMonoidElement -from sage.modules.free_module import FreeModule + +lazy_import('sage.modules.free_module', 'FreeModule') + +from .cipher import SymmetricKeyCipher class AffineCipher(SymmetricKeyCipher): @@ -152,6 +156,7 @@ def _repr_(self): # as the alphabet used for the plaintext and ciphertext spaces. return "Affine cipher on %s" % self.parent().cipher_domain() + class HillCipher(SymmetricKeyCipher): """ Hill cipher class @@ -165,25 +170,23 @@ def __init__(self, parent, key): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: E + sage: E = HillCryptosystem(S,3); E # optional - sage.modules Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 - sage: M = E.key_space() - sage: A = M([[1,0,1],[0,1,1],[2,2,3]]) - sage: A + sage: M = E.key_space() # optional - sage.modules + sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A # optional - sage.modules [1 0 1] [0 1 1] [2 2 3] - sage: e = E(A); e + sage: e = E(A); e # optional - sage.modules Hill cipher on Free alphabetic string monoid on A-Z of block length 3 - sage: e(S("LAMAISONBLANCHE")) + sage: e(S("LAMAISONBLANCHE")) # optional - sage.modules JYVKSKQPELAYKPV TESTS:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) - sage: E == loads(dumps(E)) + sage: E = HillCryptosystem(S,3) # optional - sage.modules + sage: E == loads(dumps(E)) # optional - sage.modules True """ # TODO: some type checking that the key is an invertible matrix? @@ -216,10 +219,10 @@ def _repr_(self): EXAMPLES:: - sage: H = HillCryptosystem(AlphabeticStrings(), 3) - sage: M = MatrixSpace(IntegerModRing(26), 3, 3) - sage: A = M([[1,0,1], [0,1,1], [2,2,3]]) - sage: e = H(A); e + sage: H = HillCryptosystem(AlphabeticStrings(), 3) # optional - sage.modules + sage: M = MatrixSpace(IntegerModRing(26), 3, 3) # optional - sage.modules + sage: A = M([[1,0,1], [0,1,1], [2,2,3]]) # optional - sage.modules + sage: e = H(A); e # optional - sage.modules Hill cipher on Free alphabetic string monoid on A-Z of block length 3 """ return "Hill cipher on %s of block length %s" % ( @@ -467,35 +470,33 @@ def __init__(self, parent, key): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14) - sage: E - Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 - sage: K = [ 14-i for i in range(14) ] - sage: K + sage: E = TranspositionCryptosystem(S,14); E # optional - sage.groups + Transposition cryptosystem on + Free alphabetic string monoid on A-Z of block length 14 + sage: K = [ 14-i for i in range(14) ]; K # optional - sage.groups [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] - sage: e = E(K) - sage: m = S("THECATINTHEHAT") - sage: e(m) + sage: e = E(K) # optional - sage.groups + sage: m = S("THECATINTHEHAT") # optional - sage.groups + sage: e(m) # optional - sage.groups TAHEHTNITACEHT EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,15) - sage: m = S("THECATANDTHEHAT") - sage: G = E.key_space() - sage: G + sage: E = TranspositionCryptosystem(S,15) # optional - sage.groups + sage: m = S("THECATANDTHEHAT") # optional - sage.groups + sage: G = E.key_space(); G # optional - sage.groups Symmetric group of order 15! as a permutation group - sage: g = G([ 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13 ]) - sage: e = E(g) - sage: e(m) + sage: g = G([ 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13 ]) # optional - sage.groups + sage: e = E(g) # optional - sage.groups + sage: e(m) # optional - sage.groups EHTTACDNAEHTTAH TESTS:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14) - sage: E == loads(dumps(E)) + sage: E = TranspositionCryptosystem(S,14) # optional - sage.groups + sage: E == loads(dumps(E)) # optional - sage.groups True """ n = parent.block_length() diff --git a/src/sage/crypto/cryptosystem.py b/src/sage/crypto/cryptosystem.py index 7ea7884a834..8c6eb5bb12e 100644 --- a/src/sage/crypto/cryptosystem.py +++ b/src/sage/crypto/cryptosystem.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat r""" Cryptosystems diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index e68461628a5..48b9429516d 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules """ Hard Lattice Generator @@ -35,22 +36,22 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, INPUT: - ``type`` -- one of the following strings - - ``'modular'`` (default) -- A class of lattices for which - asymptotic worst-case to average-case connections hold. For - more refer to [Aj1996]_. - - ``'random'`` -- Special case of modular (n=1). A dense class - of lattice used for testing basis reduction algorithms - proposed by Goldstein and Mayer [GM2002]_. - - ``'ideal'`` -- Special case of modular. Allows for a more - compact representation proposed by [LM2006]_. - - ``'cyclotomic'`` -- Special case of ideal. Allows for - efficient processing proposed by [LM2006]_. - - ``n`` -- Determinant size, primal:`det(L) = q^n`, dual:`det(L) = q^{m-n}`. + - ``'modular'`` (default) -- A class of lattices for which + asymptotic worst-case to average-case connections hold. For + more refer to [Aj1996]_. + - ``'random'`` -- Special case of modular (n=1). A dense class + of lattice used for testing basis reduction algorithms + proposed by Goldstein and Mayer [GM2002]_. + - ``'ideal'`` -- Special case of modular. Allows for a more + compact representation proposed by [LM2006]_. + - ``'cyclotomic'`` -- Special case of ideal. Allows for + efficient processing proposed by [LM2006]_. + - ``n`` -- Determinant size, primal: `det(L) = q^n`, dual: `det(L) = q^{m-n}`. For ideal lattices this is also the degree of the quotient polynomial. - ``m`` -- Lattice dimension, `L \subseteq Z^m`. - ``q`` -- Coefficient size, `q-Z^m \subseteq L`. - ``seed`` -- Randomness seed. - - ``quotient`` -- For the type ideal, this determines the quotient + - ``quotient`` -- For the type ``'ideal'``, this determines the quotient polynomial. Ignored for all other types. - ``dual`` -- Set this flag if you want a basis for `q-dual(L)`, for example for Regev's LWE bases [Reg2005]_. @@ -149,9 +150,9 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, Relation of primal and dual bases:: - sage: B_primal=sage.crypto.gen_lattice(m=10, q=11, seed=42) - sage: B_dual=sage.crypto.gen_lattice(m=10, q=11, seed=42, dual=True) - sage: B_dual_alt=transpose(11*B_primal.inverse()).change_ring(ZZ) + sage: B_primal = sage.crypto.gen_lattice(m=10, q=11, seed=42) + sage: B_dual = sage.crypto.gen_lattice(m=10, q=11, seed=42, dual=True) + sage: B_dual_alt = transpose(11*B_primal.inverse()).change_ring(ZZ) sage: B_dual_alt.hermite_form() == B_dual.hermite_form() True diff --git a/src/sage/crypto/lfsr.py b/src/sage/crypto/lfsr.py index b8aad014e27..faf39a3b5d1 100644 --- a/src/sage/crypto/lfsr.py +++ b/src/sage/crypto/lfsr.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.rings.finite_rings r""" Linear feedback shift register (LFSR) sequence commands diff --git a/src/sage/crypto/mq/rijndael_gf.py b/src/sage/crypto/mq/rijndael_gf.py index dbf2e0dd5a0..3281b8361b5 100644 --- a/src/sage/crypto/mq/rijndael_gf.py +++ b/src/sage/crypto/mq/rijndael_gf.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Rijndael-GF diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index ee3fce334a4..d30ce46256c 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" Small Scale Variants of the AES (SR) Polynomial System Generator diff --git a/src/sage/crypto/public_key/blum_goldwasser.py b/src/sage/crypto/public_key/blum_goldwasser.py index 8f076a4f70d..386cbf03a35 100644 --- a/src/sage/crypto/public_key/blum_goldwasser.py +++ b/src/sage/crypto/public_key/blum_goldwasser.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat r""" Blum-Goldwasser Probabilistic Encryption diff --git a/src/sage/crypto/sbox.pyx b/src/sage/crypto/sbox.pyx index 453ac488a88..a38d27de492 100644 --- a/src/sage/crypto/sbox.pyx +++ b/src/sage/crypto/sbox.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" S-Boxes and Their Algebraic Representations """ @@ -58,9 +59,9 @@ cdef Py_ssize_t _nterms(Py_ssize_t nvars, Py_ssize_t deg): cdef class SBox(SageObject): r""" A substitution box or S-box is one of the basic components of - symmetric key cryptography. In general, an S-box takes ``m`` input - bits and transforms them into ``n`` output bits. This is called an - ``mxn`` S-box and is often implemented as a lookup table. These + symmetric key cryptography. In general, an S-box takes `m` input + bits and transforms them into `n` output bits. This is called an + `m \times n` S-box and is often implemented as a lookup table. These S-boxes are carefully chosen to resist linear and differential cryptanalysis [He2002]_. @@ -839,7 +840,8 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox(7,6,0,4,2,5,1,3) sage: S.ring() - Multivariate Polynomial Ring in x0, x1, x2, y0, y1, y2 over Finite Field of size 2 + Multivariate Polynomial Ring in x0, x1, x2, y0, y1, y2 over + Finite Field of size 2 """ return self._ring diff --git a/src/sage/crypto/sboxes.py b/src/sage/crypto/sboxes.py index 056ce082b50..7c3722b5402 100644 --- a/src/sage/crypto/sboxes.py +++ b/src/sage/crypto/sboxes.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules sage.rings.finite_rings r""" S-Boxes used in cryptographic schemes diff --git a/src/sage/crypto/stream.py b/src/sage/crypto/stream.py index 71d8ffb9a21..92648a36404 100644 --- a/src/sage/crypto/stream.py +++ b/src/sage/crypto/stream.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.rings.finite_rings """ Stream Cryptosystems """ diff --git a/src/sage/crypto/stream_cipher.py b/src/sage/crypto/stream_cipher.py index 198e93d9216..21f913abee4 100644 --- a/src/sage/crypto/stream_cipher.py +++ b/src/sage/crypto/stream_cipher.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.rings.finite_rings """ Stream Ciphers """ diff --git a/src/sage/crypto/util.py b/src/sage/crypto/util.py index 637738e45d0..0e0e9c1ed1a 100644 --- a/src/sage/crypto/util.py +++ b/src/sage/crypto/util.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat """ Utility Functions for Cryptography @@ -23,11 +24,11 @@ from sage.arith.functions import lcm from sage.arith.misc import is_prime, primes, random_prime from sage.misc.lazy_import import lazy_import -from sage.monoids.string_monoid import BinaryStrings from sage.rings.finite_rings.integer_mod import Mod as mod from sage.rings.integer import Integer lazy_import('sage.arith.misc', ('carmichael_lambda'), deprecation=34719) +lazy_import('sage.monoids.string_monoid', 'BinaryStrings') def ascii_integer(B): From f030dec6095a6a7c2927e3289b22bce20ea91fd1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Jun 2023 23:42:13 -0700 Subject: [PATCH 04/15] src/sage/crypto/lattice.py: Fix markup --- src/sage/crypto/lattice.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index 48b9429516d..c86ca9b4e8b 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -36,6 +36,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, INPUT: - ``type`` -- one of the following strings + - ``'modular'`` (default) -- A class of lattices for which asymptotic worst-case to average-case connections hold. For more refer to [Aj1996]_. @@ -46,6 +47,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, compact representation proposed by [LM2006]_. - ``'cyclotomic'`` -- Special case of ideal. Allows for efficient processing proposed by [LM2006]_. + - ``n`` -- Determinant size, primal: `det(L) = q^n`, dual: `det(L) = q^{m-n}`. For ideal lattices this is also the degree of the quotient polynomial. - ``m`` -- Lattice dimension, `L \subseteq Z^m`. From 1a6738e666c916d1a7b9cab8d290e43420e85011 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 11 Jun 2023 23:47:37 -0700 Subject: [PATCH 05/15] More # optional --- src/sage/crypto/lwe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/crypto/lwe.py b/src/sage/crypto/lwe.py index 577f8b6eb08..7d036312aab 100644 --- a/src/sage/crypto/lwe.py +++ b/src/sage/crypto/lwe.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - scipy """ (Ring-)LWE oracle generators From 381f3f64f77835660ea04dfa272e6e34c6562d2b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 13 Jul 2023 23:31:48 -0700 Subject: [PATCH 06/15] sage.crypto: Update # needs --- src/sage/crypto/boolean_function.pyx | 160 +++++++++-------- src/sage/crypto/classical.py | 164 ++++++++++-------- src/sage/crypto/classical_cipher.py | 49 +++--- src/sage/crypto/lattice.py | 10 +- .../crypto/mq/mpolynomialsystemgenerator.py | 2 +- 5 files changed, 201 insertions(+), 184 deletions(-) diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index bc035c17732..bb51d7f5c89 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -10,13 +10,14 @@ and also algebraic immunity. EXAMPLES:: - sage: R. = GF(2^8,'a')[] # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: R. = GF(2^8,'a')[] sage: from sage.crypto.boolean_function import BooleanFunction - sage: B = BooleanFunction(x^254); B # the Boolean function Tr(x^254) # optional - sage.rings.finite_rings + sage: B = BooleanFunction(x^254); B # the Boolean function Tr(x^254) Boolean function with 8 variables - sage: B.nonlinearity() # optional - sage.rings.finite_rings + sage: B.nonlinearity() 112 - sage: B.algebraic_immunity() # optional - sage.rings.finite_rings + sage: B.algebraic_immunity() 4 AUTHOR: @@ -89,11 +90,12 @@ cdef long yellow_code(unsigned long a): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction - sage: R. = BooleanPolynomialRing(3) # optional - sage.rings.polynomial.pbori - sage: P = x*y # optional - sage.rings.polynomial.pbori - sage: B = BooleanFunction(P) # optional - sage.rings.polynomial.pbori - sage: B.truth_table() # indirect doctest # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing(3) + sage: P = x*y + sage: B = BooleanFunction(P) + sage: B.truth_table() # indirect doctest (False, False, False, True, False, False, False, True) """ cdef unsigned long s = (8*sizeof(unsigned long)) >> 1 @@ -122,11 +124,12 @@ cdef reed_muller(mp_limb_t* f, int ldn): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction - sage: R. = BooleanPolynomialRing(3) # optional - sage.rings.polynomial.pbori - sage: P = x*y # optional - sage.rings.polynomial.pbori - sage: B = BooleanFunction(P) # optional - sage.rings.polynomial.pbori - sage: B.truth_table() # indirect doctest # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing(3) + sage: P = x*y + sage: B = BooleanFunction(P) + sage: B.truth_table() # indirect doctest (False, False, False, True, False, False, False, True) """ cdef long n, ldm, m, mh, t1, t2, r, j @@ -179,9 +182,9 @@ cdef class BooleanFunction(SageObject): note that elements can be of different types:: - sage: B = BooleanFunction([False, sqrt(2)]); B # optional - sage.symbolic + sage: B = BooleanFunction([False, sqrt(2)]); B # needs sage.symbolic Boolean function with 1 variable - sage: [b for b in B] # optional - sage.symbolic + sage: [b for b in B] # needs sage.symbolic [False, True] from a string:: @@ -191,20 +194,20 @@ cdef class BooleanFunction(SageObject): from a :class:`sage.rings.polynomial.pbori.BooleanPolynomial`:: - sage: R. = BooleanPolynomialRing(3) # optional - sage.rings.polynomial.pbori - sage: P = x*y # optional - sage.rings.polynomial.pbori - sage: BooleanFunction(P) # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing(3) # needs sage.rings.polynomial.pbori + sage: P = x*y # needs sage.rings.polynomial.pbori + sage: BooleanFunction(P) # needs sage.rings.polynomial.pbori Boolean function with 3 variables from a polynomial over a binary field:: - sage: R. = GF(2^8,'a')[] # optional - sage.rings.finite_rings - sage: B = BooleanFunction(x^7); B # optional - sage.rings.finite_rings + sage: R. = GF(2^8,'a')[] # needs sage.rings.finite_rings + sage: B = BooleanFunction(x^7); B # needs sage.rings.finite_rings Boolean function with 8 variables two failure cases:: - sage: BooleanFunction(sqrt(2)) # optional - sage.symbolic + sage: BooleanFunction(sqrt(2)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to init the Boolean function @@ -253,27 +256,27 @@ cdef class BooleanFunction(SageObject): note that elements can be of different types:: - sage: B = BooleanFunction([False, sqrt(2)]); B # optional - sage.symbolic + sage: B = BooleanFunction([False, sqrt(2)]); B # needs sage.symbolic Boolean function with 1 variable - sage: [b for b in B] # optional - sage.symbolic + sage: [b for b in B] # needs sage.symbolic [False, True] from a :class:`sage.rings.polynomial.pbori.BooleanPolynomial`:: - sage: R. = BooleanPolynomialRing(3) # optional - sage.rings.polynomial.pbori - sage: P = x*y # optional - sage.rings.polynomial.pbori - sage: BooleanFunction(P) # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing(3) # needs sage.rings.polynomial.pbori + sage: P = x*y # needs sage.rings.polynomial.pbori + sage: BooleanFunction(P) # needs sage.rings.polynomial.pbori Boolean function with 3 variables from a polynomial over a binary field:: - sage: R. = GF(2^8,'a')[] # optional - sage.rings.finite_rings - sage: B = BooleanFunction(x^7); B # optional - sage.rings.finite_rings + sage: R. = GF(2^8,'a')[] # needs sage.rings.finite_rings + sage: B = BooleanFunction(x^7); B # needs sage.rings.finite_rings Boolean function with 8 variables two failure cases:: - sage: BooleanFunction(sqrt(2)) # optional - sage.symbolic + sage: BooleanFunction(sqrt(2)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: unable to init the Boolean function @@ -392,8 +395,8 @@ cdef class BooleanFunction(SageObject): it also corresponds to the addition of algebraic normal forms:: - sage: S = A.algebraic_normal_form() + B.algebraic_normal_form() # optional - sage.rings.polynomial.pbori - sage: (A+B).algebraic_normal_form() == S # optional - sage.rings.polynomial.pbori + sage: S = A.algebraic_normal_form() + B.algebraic_normal_form() # needs sage.rings.polynomial.pbori + sage: (A+B).algebraic_normal_form() == S # needs sage.rings.polynomial.pbori True TESTS:: @@ -424,8 +427,8 @@ cdef class BooleanFunction(SageObject): it also corresponds to the multiplication of algebraic normal forms:: - sage: P = A.algebraic_normal_form() * B.algebraic_normal_form() # optional - sage.rings.polynomial.pbori - sage: (A*B).algebraic_normal_form() == P # optional - sage.rings.polynomial.pbori + sage: P = A.algebraic_normal_form() * B.algebraic_normal_form() # needs sage.rings.polynomial.pbori + sage: (A*B).algebraic_normal_form() == P # needs sage.rings.polynomial.pbori True TESTS:: @@ -495,9 +498,9 @@ cdef class BooleanFunction(SageObject): sage: from sage.crypto.boolean_function import BooleanFunction sage: B = BooleanFunction([0,1,1,0,1,0,1,1]) - sage: P = B.algebraic_normal_form(); P # optional - sage.rings.polynomial.pbori + sage: P = B.algebraic_normal_form(); P # needs sage.rings.polynomial.pbori x0*x1*x2 + x0 + x1*x2 + x1 + x2 - sage: [P(*ZZ(i).digits(base=2, padto=3)) for i in range(8)] # optional - sage.rings.polynomial.pbori + sage: [P(*ZZ(i).digits(base=2, padto=3)) for i in range(8)] # needs sage.rings.polynomial.pbori [0, 1, 1, 0, 1, 0, 1, 1] """ cdef bitset_t anf @@ -549,14 +552,15 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction - sage: R. = BooleanPolynomialRing(3) # optional - sage.rings.polynomial.pbori - sage: B = BooleanFunction(x*y*z + z + y + 1) # optional - sage.rings.polynomial.pbori - sage: B.truth_table() # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing(3) + sage: B = BooleanFunction(x*y*z + z + y + 1) + sage: B.truth_table() (True, True, False, False, False, False, True, False) - sage: B.truth_table(format='int') # optional - sage.rings.polynomial.pbori + sage: B.truth_table(format='int') (1, 1, 0, 0, 0, 0, 1, 0) - sage: B.truth_table(format='hex') # optional - sage.rings.polynomial.pbori + sage: B.truth_table(format='hex') '43' sage: BooleanFunction('00ab').truth_table(format='hex') @@ -578,7 +582,7 @@ cdef class BooleanFunction(SageObject): True sage: len(T) 256 - sage: B.truth_table(format='oct') # optional - sage.rings.polynomial.pbori + sage: B.truth_table(format='oct') # needs sage.rings.polynomial.pbori Traceback (most recent call last): ... ValueError: unknown output format @@ -698,9 +702,9 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: R. = GF(2^3,'a')[] # optional - sage.rings.finite_rings - sage: B = BooleanFunction(x^3) # optional - sage.rings.finite_rings - sage: B.walsh_hadamard_transform() # optional - sage.rings.finite_rings + sage: R. = GF(2^3,'a')[] # needs sage.rings.finite_rings + sage: B = BooleanFunction(x^3) # needs sage.rings.finite_rings + sage: B.walsh_hadamard_transform() # needs sage.rings.finite_rings (0, -4, 0, 4, 0, 4, 0, 4) """ cdef long *temp @@ -993,10 +997,10 @@ cdef class BooleanFunction(SageObject): sage: from sage.crypto.boolean_function import BooleanFunction sage: f = BooleanFunction("7969817CC5893BA6AC326E47619F5AD0") - sage: f.annihilator(1) is None # optional - sage.rings.polynomial.pbori + sage: f.annihilator(1) is None # needs sage.rings.polynomial.pbori True - sage: g = BooleanFunction(f.annihilator(3)) # optional - sage.rings.polynomial.pbori - sage: set(fi*g(i) for i,fi in enumerate(f)) # optional - sage.rings.polynomial.pbori + sage: g = BooleanFunction(f.annihilator(3)) # needs sage.rings.polynomial.pbori + sage: set(fi*g(i) for i,fi in enumerate(f)) # needs sage.rings.polynomial.pbori {0} """ # NOTE: this is a toy implementation @@ -1059,18 +1063,19 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction - sage: R. = BooleanPolynomialRing(6) # optional - sage.rings.polynomial.pbori - sage: B = BooleanFunction(x0*x1 + x1*x2 + x2*x3 + x3*x4 + x4*x5) # optional - sage.rings.polynomial.pbori - sage: B.algebraic_immunity(annihilator=True) # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing(6) + sage: B = BooleanFunction(x0*x1 + x1*x2 + x2*x3 + x3*x4 + x4*x5) + sage: B.algebraic_immunity(annihilator=True) (2, x0*x1 + x1*x2 + x2*x3 + x3*x4 + x4*x5 + 1) - sage: B[0] += 1 # optional - sage.rings.polynomial.pbori - sage: B.algebraic_immunity() # optional - sage.rings.polynomial.pbori + sage: B[0] += 1 + sage: B.algebraic_immunity() 2 - sage: R. = GF(2^8,'a')[] # optional - sage.rings.finite_rings - sage: B = BooleanFunction(x^31) # optional - sage.rings.finite_rings - sage: B.algebraic_immunity() # optional - sage.rings.finite_rings + sage: R. = GF(2^8,'a')[] # needs sage.rings.finite_rings + sage: B = BooleanFunction(x^31) # needs sage.rings.finite_rings + sage: B.algebraic_immunity() # needs sage.rings.finite_rings 4 """ f = self @@ -1097,12 +1102,12 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: sage: from sage.crypto.boolean_function import BooleanFunction - sage: B. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: f = BooleanFunction(x1*x2 + x1*x2*x3 + x1) # optional - sage.rings.polynomial.pbori - sage: f.algebraic_degree() # optional - sage.rings.polynomial.pbori + sage: B. = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori + sage: f = BooleanFunction(x1*x2 + x1*x2*x3 + x1) # needs sage.rings.polynomial.pbori + sage: f.algebraic_degree() # needs sage.rings.polynomial.pbori 3 sage: g = BooleanFunction([0, 0]) - sage: g.algebraic_degree() # optional - sage.rings.polynomial.pbori + sage: g.algebraic_degree() # needs sage.rings.polynomial.pbori -1 """ return self.algebraic_normal_form().degree() @@ -1115,12 +1120,13 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction - sage: R. = BooleanPolynomialRing() # optional - sage.rings.polynomial.pbori - sage: f = BooleanFunction(x0*x1 + x2 + x3) # optional - sage.rings.polynomial.pbori - sage: f.walsh_hadamard_transform() # optional - sage.rings.polynomial.pbori + sage: R. = BooleanPolynomialRing() + sage: f = BooleanFunction(x0*x1 + x2 + x3) + sage: f.walsh_hadamard_transform() (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, -8) - sage: f.is_plateaued() # optional - sage.rings.polynomial.pbori + sage: f.is_plateaued() True """ W = self.absolute_walsh_spectrum() @@ -1150,8 +1156,8 @@ cdef class BooleanFunction(SageObject): sage: l = [1, 0, 0, 1] sage: f.is_linear_structure(l) True - sage: v = vector(GF(2), l) # optional - sage.rings.finite_rings - sage: f.is_linear_structure(v) # optional - sage.rings.finite_rings + sage: v = vector(GF(2), l) + sage: f.is_linear_structure(v) True sage: f.is_linear_structure(7) False @@ -1159,13 +1165,13 @@ cdef class BooleanFunction(SageObject): Traceback (most recent call last): ... IndexError: index out of range - sage: v = vector(GF(3), [1, 0, 1, 1]) # optional - sage.rings.finite_rings - sage: f.is_linear_structure(v) # optional - sage.rings.finite_rings + sage: v = vector(GF(3), [1, 0, 1, 1]) + sage: f.is_linear_structure(v) Traceback (most recent call last): ... TypeError: base ring of input vector must be GF(2) - sage: v = vector(GF(2), [1, 0, 1, 1, 1]) # optional - sage.rings.finite_rings - sage: f.is_linear_structure(v) # optional - sage.rings.finite_rings + sage: v = vector(GF(2), [1, 0, 1, 1, 1]) + sage: f.is_linear_structure(v) Traceback (most recent call last): ... TypeError: input vector must be an element of a vector space with dimension 4 @@ -1243,13 +1249,13 @@ cdef class BooleanFunction(SageObject): sage: from sage.crypto.boolean_function import BooleanFunction sage: f = BooleanFunction([0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0]) - sage: LS = f.linear_structures() # optional - sage.modules sage.rings.finite_rings - sage: LS.dimension() # optional - sage.modules sage.rings.finite_rings + sage: LS = f.linear_structures() # needs sage.modules + sage: LS.dimension() # needs sage.modules 2 - sage: LS.basis_matrix() # optional - sage.modules sage.rings.finite_rings + sage: LS.basis_matrix() # needs sage.modules [1 0 0 0] [0 0 0 1] - sage: LS.list() # optional - sage.modules sage.rings.finite_rings + sage: LS.list() # needs sage.modules [(0, 0, 0, 0), (1, 0, 0, 0), (0, 0, 0, 1), (1, 0, 0, 1)] """ from sage.modules.free_module import VectorSpace @@ -1278,15 +1284,15 @@ cdef class BooleanFunction(SageObject): sage: from sage.crypto.boolean_function import BooleanFunction sage: f = BooleanFunction([0,1,0,1,0,1,0,1]) - sage: f.derivative(1).algebraic_normal_form() # optional - sage.rings.polynomial.pbori + sage: f.derivative(1).algebraic_normal_form() # needs sage.rings.polynomial.pbori 1 sage: u = [1,0,0] - sage: f.derivative(u).algebraic_normal_form() # optional - sage.rings.polynomial.pbori + sage: f.derivative(u).algebraic_normal_form() # needs sage.rings.polynomial.pbori 1 - sage: v = vector(GF(2), u) # optional - sage.modules sage.rings.finite_rings - sage: f.derivative(v).algebraic_normal_form() # optional - sage.modules sage.rings.finite_rings sage.rings.polynomial.pbori + sage: v = vector(GF(2), u) # needs sage.modules + sage: f.derivative(v).algebraic_normal_form() # needs sage.modules sage.rings.finite_rings sage.rings.polynomial.pbori 1 - sage: f.derivative(8).algebraic_normal_form() # optional - sage.rings.polynomial.pbori + sage: f.derivative(8).algebraic_normal_form() Traceback (most recent call last): ... IndexError: index out of bound diff --git a/src/sage/crypto/classical.py b/src/sage/crypto/classical.py index 9cb9c92f5cb..aa012e758e7 100644 --- a/src/sage/crypto/classical.py +++ b/src/sage/crypto/classical.py @@ -1306,25 +1306,26 @@ class HillCryptosystem(SymmetricKeyCryptosystem): EXAMPLES:: + sage: # needs sage.modules sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S, 3); E # optional - sage.modules + sage: E = HillCryptosystem(S, 3); E Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 sage: R = IntegerModRing(26) - sage: M = MatrixSpace(R,3,3) # optional - sage.modules - sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A # optional - sage.modules + sage: M = MatrixSpace(R,3,3) + sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A [1 0 1] [0 1 1] [2 2 3] - sage: e = E(A); e # optional - sage.modules + sage: e = E(A); e Hill cipher on Free alphabetic string monoid on A-Z of block length 3 - sage: e(S("LAMAISONBLANCHE")) # optional - sage.modules + sage: e(S("LAMAISONBLANCHE")) JYVKSKQPELAYKPV TESTS:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S, 3) # optional - sage.modules - sage: E == loads(dumps(E)) # optional - sage.modules + sage: E = HillCryptosystem(S, 3) # needs sage.modules + sage: E == loads(dumps(E)) # needs sage.modules True """ @@ -1350,7 +1351,7 @@ def __init__(self, S, m): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S, 3); E # optional - sage.modules + sage: E = HillCryptosystem(S, 3); E # needs sage.modules Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 """ if not isinstance(S, StringMonoid_class): @@ -1369,21 +1370,22 @@ def __call__(self, A): EXAMPLES:: + sage: # needs sage.modules sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3); E # optional - sage.modules + sage: E = HillCryptosystem(S,3); E Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 - sage: M = E.key_space() # optional - sage.modules - sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A # optional - sage.modules + sage: M = E.key_space() + sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A [1 0 1] [0 1 1] [2 2 3] - sage: e = E(A); e # optional - sage.modules + sage: e = E(A); e Hill cipher on Free alphabetic string monoid on A-Z of block length 3 - sage: m = S("LAMAISONBLANCHE") # optional - sage.modules - sage: e(m) # optional - sage.modules + sage: m = S("LAMAISONBLANCHE") + sage: e(m) JYVKSKQPELAYKPV - sage: c = e.inverse() # optional - sage.modules - sage: c(e(m)) # optional - sage.modules + sage: c = e.inverse() + sage: c(e(m)) LAMAISONBLANCHE """ M = self.key_space() @@ -1402,9 +1404,9 @@ def _repr_(self): EXAMPLES:: sage: A = AlphabeticStrings() - sage: H = HillCryptosystem(A, 3); H # optional - sage.modules + sage: H = HillCryptosystem(A, 3); H # needs sage.modules Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 - sage: H._repr_() # optional - sage.modules + sage: H._repr_() # needs sage.modules 'Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3' """ return "Hill cryptosystem on %s of block length %s" % ( @@ -1426,8 +1428,8 @@ def block_length(self): sage: A = AlphabeticStrings() sage: n = randint(1, A.ngens() - 1) - sage: H = HillCryptosystem(A, n) # optional - sage.modules - sage: H.block_length() == n # optional - sage.modules + sage: H = HillCryptosystem(A, n) # needs sage.modules + sage: H.block_length() == n # needs sage.modules True """ return self.key_space().nrows() @@ -1448,15 +1450,16 @@ def random_key(self): EXAMPLES:: + sage: # needs sage.modules sage: A = AlphabeticStrings() sage: n = 3 - sage: H = HillCryptosystem(A, n) # optional - sage.modules - sage: K = H.random_key() # optional - sage.modules - sage: Ki = H.inverse_key(K) # optional - sage.modules - sage: M = "LAMAISONBLANCHE" # optional - sage.modules - sage: e = H(K) # optional - sage.modules - sage: d = H(Ki) # optional - sage.modules - sage: d(e(A(M))) == A(M) # optional - sage.modules + sage: H = HillCryptosystem(A, n) + sage: K = H.random_key() + sage: Ki = H.inverse_key(K) + sage: M = "LAMAISONBLANCHE" + sage: e = H(K) + sage: d = H(Ki) + sage: d(e(A(M))) == A(M) True """ M = self.key_space() @@ -1482,14 +1485,15 @@ def inverse_key(self, A): EXAMPLES:: + sage: # needs sage.modules sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S, 3) # optional - sage.modules - sage: A = E.random_key() # optional - sage.modules - sage: B = E.inverse_key(A) # optional - sage.modules - sage: M = S("LAMAISONBLANCHE") # optional - sage.modules - sage: e = E(A) # optional - sage.modules - sage: c = E(B) # optional - sage.modules - sage: c(e(M)) # optional - sage.modules + sage: E = HillCryptosystem(S, 3) + sage: A = E.random_key() + sage: B = E.inverse_key(A) + sage: M = S("LAMAISONBLANCHE") + sage: e = E(A) + sage: c = E(B) + sage: c(e(M)) LAMAISONBLANCHE """ S = self.plaintext_space() @@ -1525,8 +1529,8 @@ def encoding(self, M): sage: M = "The matrix cipher by Lester S. Hill." sage: A = AlphabeticStrings() - sage: H = HillCryptosystem(A, 7) # optional - sage.modules - sage: H.encoding(M) == A.encoding(M) # optional - sage.modules + sage: H = HillCryptosystem(A, 7) # needs sage.modules + sage: H.encoding(M) == A.encoding(M) # needs sage.modules True """ S = self.cipher_domain() @@ -1554,10 +1558,11 @@ def deciphering(self, A, C): EXAMPLES:: - sage: H = HillCryptosystem(AlphabeticStrings(), 3) # optional - sage.modules - sage: K = H.random_key() # optional - sage.modules - sage: M = H.encoding("Good day, mate! How ya going?") # optional - sage.modules - sage: H.deciphering(K, H.enciphering(K, M)) == M # optional - sage.modules + sage: # needs sage.modules + sage: H = HillCryptosystem(AlphabeticStrings(), 3) + sage: K = H.random_key() + sage: M = H.encoding("Good day, mate! How ya going?") + sage: H.deciphering(K, H.enciphering(K, M)) == M True """ # TODO: some type checking that A is invertible hence a valid key @@ -1581,10 +1586,11 @@ def enciphering(self, A, M): EXAMPLES:: - sage: H = HillCryptosystem(AlphabeticStrings(), 3) # optional - sage.modules - sage: K = H.random_key() # optional - sage.modules - sage: M = H.encoding("Good day, mate! How ya going?") # optional - sage.modules - sage: H.deciphering(K, H.enciphering(K, M)) == M # optional - sage.modules + sage: # needs sage.modules + sage: H = HillCryptosystem(AlphabeticStrings(), 3) + sage: K = H.random_key() + sage: M = H.encoding("Good day, mate! How ya going?") + sage: H.deciphering(K, H.enciphering(K, M)) == M True """ # TODO: some type checking that A is invertible hence a valid key @@ -3255,20 +3261,20 @@ class TranspositionCryptosystem(SymmetricKeyCryptosystem): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14); E # optional - sage.groups + sage: E = TranspositionCryptosystem(S,14); E # needs sage.groups Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 sage: K = [14 - i for i in range(14)]; K [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] - sage: e = E(K) # optional - sage.groups - sage: e(S("THECATINTHEHAT")) # optional - sage.groups + sage: e = E(K) # needs sage.groups + sage: e(S("THECATINTHEHAT")) # needs sage.groups TAHEHTNITACEHT TESTS:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14) # optional - sage.groups - sage: E == loads(dumps(E)) # optional - sage.groups + sage: E = TranspositionCryptosystem(S,14) # needs sage.groups + sage: E == loads(dumps(E)) # needs sage.groups True """ @@ -3279,7 +3285,7 @@ def __init__(self, S, n): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14); E # optional - sage.groups + sage: E = TranspositionCryptosystem(S,14); E # needs sage.groups Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 """ if not isinstance(S, StringMonoid_class): @@ -3298,14 +3304,14 @@ def __call__(self, K): EXAMPLES:: sage: M = AlphabeticStrings() - sage: E = TranspositionCryptosystem(M,14); E # optional - sage.groups + sage: E = TranspositionCryptosystem(M,14); E # needs sage.groups Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 sage: K = [ 14-i for i in range(14) ] sage: K [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] - sage: e = E(K) # optional - sage.groups + sage: e = E(K) # needs sage.groups sage: m = M("THECATINTHEHAT") - sage: e(m) # optional - sage.groups + sage: e(m) # needs sage.groups TAHEHTNITACEHT """ G = self.key_space() @@ -3346,15 +3352,16 @@ def random_key(self): EXAMPLES:: + sage: # needs sage.groups sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S, 14) # optional - sage.groups - sage: K = E.random_key() # optional - sage.groups - sage: Ki = E.inverse_key(K) # optional - sage.groups - sage: e = E(K) # optional - sage.groups - sage: d = E(Ki) # optional - sage.groups + sage: E = TranspositionCryptosystem(S, 14) + sage: K = E.random_key() + sage: Ki = E.inverse_key(K) + sage: e = E(K) + sage: d = E(Ki) sage: M = "THECATINTHEHAT" - sage: C = e(S(M)) # optional - sage.groups - sage: d(S(C)) == S(M) # optional - sage.groups + sage: C = e(S(M)) + sage: d(S(C)) == S(M) True """ n = self.block_length() @@ -3378,15 +3385,16 @@ def inverse_key(self, K, check=True): EXAMPLES:: + sage: # needs sage.groups sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S, 14) # optional - sage.groups - sage: K = E.random_key() # optional - sage.groups - sage: Ki = E.inverse_key(K) # optional - sage.groups - sage: e = E(K) # optional - sage.groups - sage: d = E(Ki) # optional - sage.groups + sage: E = TranspositionCryptosystem(S, 14) + sage: K = E.random_key() + sage: Ki = E.inverse_key(K) + sage: e = E(K) + sage: d = E(Ki) sage: M = "THECATINTHEHAT" - sage: C = e(S(M)) # optional - sage.groups - sage: d(S(C)) == S(M) # optional - sage.groups + sage: C = e(S(M)) + sage: d(S(C)) == S(M) True """ if check: @@ -3414,8 +3422,8 @@ def encoding(self, M): sage: M = "Transposition cipher is not about matrix transpose." sage: A = AlphabeticStrings() - sage: T = TranspositionCryptosystem(A, 11) # optional - sage.groups - sage: T.encoding(M) == A.encoding(M) # optional - sage.groups + sage: T = TranspositionCryptosystem(A, 11) # needs sage.groups + sage: T.encoding(M) == A.encoding(M) # needs sage.groups True """ S = self.cipher_domain() @@ -3444,10 +3452,11 @@ def deciphering(self, K, C): EXAMPLES:: - sage: T = TranspositionCryptosystem(AlphabeticStrings(), 14) # optional - sage.groups - sage: K = T.random_key() # optional - sage.groups - sage: M = T.encoding("The cat in the hat.") # optional - sage.groups - sage: T.deciphering(K, T.enciphering(K, M)) == M # optional - sage.groups + sage: # needs sage.groups + sage: T = TranspositionCryptosystem(AlphabeticStrings(), 14) + sage: K = T.random_key() + sage: M = T.encoding("The cat in the hat.") + sage: T.deciphering(K, T.enciphering(K, M)) == M True """ i = self(self.inverse_key(K)) @@ -3471,10 +3480,11 @@ def enciphering(self, K, M): EXAMPLES:: - sage: T = TranspositionCryptosystem(AlphabeticStrings(), 14) # optional - sage.groups - sage: K = T.random_key() # optional - sage.groups - sage: M = T.encoding("The cat in the hat.") # optional - sage.groups - sage: T.deciphering(K, T.enciphering(K, M)) == M # optional - sage.groups + sage: # needs sage.groups + sage: T = TranspositionCryptosystem(AlphabeticStrings(), 14) + sage: K = T.random_key() + sage: M = T.encoding("The cat in the hat.") + sage: T.deciphering(K, T.enciphering(K, M)) == M True """ e = self(K) diff --git a/src/sage/crypto/classical_cipher.py b/src/sage/crypto/classical_cipher.py index 7d9e15a4d7f..a686bdf89d6 100644 --- a/src/sage/crypto/classical_cipher.py +++ b/src/sage/crypto/classical_cipher.py @@ -170,23 +170,23 @@ def __init__(self, parent, key): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3); E # optional - sage.modules + sage: E = HillCryptosystem(S,3); E # needs sage.modules Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 - sage: M = E.key_space() # optional - sage.modules - sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A # optional - sage.modules + sage: M = E.key_space() # needs sage.modules + sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A # needs sage.modules [1 0 1] [0 1 1] [2 2 3] - sage: e = E(A); e # optional - sage.modules + sage: e = E(A); e # needs sage.modules Hill cipher on Free alphabetic string monoid on A-Z of block length 3 - sage: e(S("LAMAISONBLANCHE")) # optional - sage.modules + sage: e(S("LAMAISONBLANCHE")) # needs sage.modules JYVKSKQPELAYKPV TESTS:: sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3) # optional - sage.modules - sage: E == loads(dumps(E)) # optional - sage.modules + sage: E = HillCryptosystem(S,3) # needs sage.modules + sage: E == loads(dumps(E)) # needs sage.modules True """ # TODO: some type checking that the key is an invertible matrix? @@ -219,10 +219,11 @@ def _repr_(self): EXAMPLES:: - sage: H = HillCryptosystem(AlphabeticStrings(), 3) # optional - sage.modules - sage: M = MatrixSpace(IntegerModRing(26), 3, 3) # optional - sage.modules - sage: A = M([[1,0,1], [0,1,1], [2,2,3]]) # optional - sage.modules - sage: e = H(A); e # optional - sage.modules + sage: # needs sage.modules + sage: H = HillCryptosystem(AlphabeticStrings(), 3) + sage: M = MatrixSpace(IntegerModRing(26), 3, 3) + sage: A = M([[1,0,1], [0,1,1], [2,2,3]]) + sage: e = H(A); e Hill cipher on Free alphabetic string monoid on A-Z of block length 3 """ return "Hill cipher on %s of block length %s" % ( @@ -470,33 +471,33 @@ def __init__(self, parent, key): EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14); E # optional - sage.groups + sage: E = TranspositionCryptosystem(S,14); E # needs sage.groups Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 - sage: K = [ 14-i for i in range(14) ]; K # optional - sage.groups + sage: K = [ 14-i for i in range(14) ]; K [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] - sage: e = E(K) # optional - sage.groups - sage: m = S("THECATINTHEHAT") # optional - sage.groups - sage: e(m) # optional - sage.groups + sage: e = E(K) # needs sage.groups + sage: m = S("THECATINTHEHAT") # needs sage.groups + sage: e(m) # needs sage.groups TAHEHTNITACEHT EXAMPLES:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,15) # optional - sage.groups - sage: m = S("THECATANDTHEHAT") # optional - sage.groups - sage: G = E.key_space(); G # optional - sage.groups + sage: E = TranspositionCryptosystem(S,15) # needs sage.groups + sage: m = S("THECATANDTHEHAT") # needs sage.groups + sage: G = E.key_space(); G # needs sage.groups Symmetric group of order 15! as a permutation group - sage: g = G([ 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13 ]) # optional - sage.groups - sage: e = E(g) # optional - sage.groups - sage: e(m) # optional - sage.groups + sage: g = G([ 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13 ]) # needs sage.groups + sage: e = E(g) # needs sage.groups + sage: e(m) # needs sage.groups EHTTACDNAEHTTAH TESTS:: sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14) # optional - sage.groups - sage: E == loads(dumps(E)) # optional - sage.groups + sage: E = TranspositionCryptosystem(S,14) # needs sage.groups + sage: E == loads(dumps(E)) # needs sage.groups True """ n = parent.block_length() diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index c86ca9b4e8b..309adf15acb 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -100,7 +100,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, Ideal bases with quotient `x^n-1`, `m=2*n` are NTRU bases:: - sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4 - 1) # optional - sage.symbolic + sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4 - 1) # needs sage.symbolic [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] @@ -113,7 +113,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, Ideal bases also work with polynomials:: sage: R. = PolynomialRing(ZZ) - sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=t^4 - 1) + sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=t^4 - 1) # needs sage.libs.pari [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] @@ -125,7 +125,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, Cyclotomic bases with n=2^k are SWIFFT bases:: - sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42) + sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42) # needs sage.libs.pari [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] @@ -162,11 +162,11 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, Test some bad quotient polynomials:: - sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=cos(x)) # optional - sage.symbolic + sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=cos(x)) # needs sage.symbolic Traceback (most recent call last): ... TypeError: self must be a numeric expression - sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=x^23-1) # optional - sage.symbolic + sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=x^23-1) # needs sage.symbolic Traceback (most recent call last): ... ValueError: ideal basis requires n = quotient.degree() diff --git a/src/sage/crypto/mq/mpolynomialsystemgenerator.py b/src/sage/crypto/mq/mpolynomialsystemgenerator.py index 3c0bb6b349c..9028dab1d98 100644 --- a/src/sage/crypto/mq/mpolynomialsystemgenerator.py +++ b/src/sage/crypto/mq/mpolynomialsystemgenerator.py @@ -68,7 +68,7 @@ def varstrs(self, name, round): sage: from sage.crypto.mq.mpolynomialsystemgenerator import MPolynomialSystemGenerator sage: msg = MPolynomialSystemGenerator() - sage: msg.varstrs('K', i) + sage: msg.varstrs('K', i) # needs sage.all Traceback (most recent call last): ... NotImplementedError From 998958b8b97aa04edf0a9d7036a0587703667047 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 6 Aug 2023 20:45:04 -0700 Subject: [PATCH 07/15] src/sage/crypto: Update file-level doctest tag --- src/sage/crypto/block_cipher/des.py | 2 +- src/sage/crypto/block_cipher/miniaes.py | 2 +- src/sage/crypto/block_cipher/present.py | 2 +- src/sage/crypto/block_cipher/sdes.py | 2 +- src/sage/crypto/cipher.py | 2 +- src/sage/crypto/classical.py | 2 +- src/sage/crypto/classical_cipher.py | 2 +- src/sage/crypto/cryptosystem.py | 2 +- src/sage/crypto/lattice.py | 2 +- src/sage/crypto/lfsr.py | 2 +- src/sage/crypto/mq/rijndael_gf.py | 2 +- src/sage/crypto/mq/sr.py | 2 +- src/sage/crypto/public_key/blum_goldwasser.py | 2 +- src/sage/crypto/sbox.pyx | 2 +- src/sage/crypto/sboxes.py | 2 +- src/sage/crypto/stream.py | 2 +- src/sage/crypto/stream_cipher.py | 2 +- src/sage/crypto/util.py | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/crypto/block_cipher/des.py b/src/sage/crypto/block_cipher/des.py index a6d3108076b..04d35430924 100644 --- a/src/sage/crypto/block_cipher/des.py +++ b/src/sage/crypto/block_cipher/des.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules sage.rings.finite_rings +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" DES diff --git a/src/sage/crypto/block_cipher/miniaes.py b/src/sage/crypto/block_cipher/miniaes.py index b0dd068b683..0c7bc5ae979 100644 --- a/src/sage/crypto/block_cipher/miniaes.py +++ b/src/sage/crypto/block_cipher/miniaes.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules sage.rings.finite_rings +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" Mini-AES diff --git a/src/sage/crypto/block_cipher/present.py b/src/sage/crypto/block_cipher/present.py index 3f5bddcefec..5a7cda2d998 100644 --- a/src/sage/crypto/block_cipher/present.py +++ b/src/sage/crypto/block_cipher/present.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules sage.rings.finite_rings +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" PRESENT diff --git a/src/sage/crypto/block_cipher/sdes.py b/src/sage/crypto/block_cipher/sdes.py index accda2d3d15..30b8cf2516c 100644 --- a/src/sage/crypto/block_cipher/sdes.py +++ b/src/sage/crypto/block_cipher/sdes.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.rings.finite_rings +# sage.doctest: needs sage.combinat sage.rings.finite_rings r""" Simplified DES diff --git a/src/sage/crypto/cipher.py b/src/sage/crypto/cipher.py index f0f9d4eedcc..14e9df6a504 100644 --- a/src/sage/crypto/cipher.py +++ b/src/sage/crypto/cipher.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat +# sage.doctest: needs sage.combinat """ Ciphers """ diff --git a/src/sage/crypto/classical.py b/src/sage/crypto/classical.py index aa012e758e7..00512513916 100644 --- a/src/sage/crypto/classical.py +++ b/src/sage/crypto/classical.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat +# sage.doctest: needs sage.combinat r""" Classical Cryptosystems diff --git a/src/sage/crypto/classical_cipher.py b/src/sage/crypto/classical_cipher.py index a686bdf89d6..44bc1460685 100644 --- a/src/sage/crypto/classical_cipher.py +++ b/src/sage/crypto/classical_cipher.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat +# sage.doctest: needs sage.combinat """ Classical Ciphers """ diff --git a/src/sage/crypto/cryptosystem.py b/src/sage/crypto/cryptosystem.py index 8c6eb5bb12e..7973dff7ef4 100644 --- a/src/sage/crypto/cryptosystem.py +++ b/src/sage/crypto/cryptosystem.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat +# sage.doctest: needs sage.combinat r""" Cryptosystems diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index 309adf15acb..e36ec122ae3 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules """ Hard Lattice Generator diff --git a/src/sage/crypto/lfsr.py b/src/sage/crypto/lfsr.py index faf39a3b5d1..869bdcf5990 100644 --- a/src/sage/crypto/lfsr.py +++ b/src/sage/crypto/lfsr.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.rings.finite_rings +# sage.doctest: needs sage.rings.finite_rings r""" Linear feedback shift register (LFSR) sequence commands diff --git a/src/sage/crypto/mq/rijndael_gf.py b/src/sage/crypto/mq/rijndael_gf.py index 3281b8361b5..45e17cda4b6 100644 --- a/src/sage/crypto/mq/rijndael_gf.py +++ b/src/sage/crypto/mq/rijndael_gf.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules sage.rings.finite_rings +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" Rijndael-GF diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index d30ce46256c..9390359300e 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules sage.rings.finite_rings +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" Small Scale Variants of the AES (SR) Polynomial System Generator diff --git a/src/sage/crypto/public_key/blum_goldwasser.py b/src/sage/crypto/public_key/blum_goldwasser.py index 386cbf03a35..b3382974b15 100644 --- a/src/sage/crypto/public_key/blum_goldwasser.py +++ b/src/sage/crypto/public_key/blum_goldwasser.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat +# sage.doctest: needs sage.combinat r""" Blum-Goldwasser Probabilistic Encryption diff --git a/src/sage/crypto/sbox.pyx b/src/sage/crypto/sbox.pyx index a38d27de492..7ca51c45934 100644 --- a/src/sage/crypto/sbox.pyx +++ b/src/sage/crypto/sbox.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules sage.rings.finite_rings +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" S-Boxes and Their Algebraic Representations """ diff --git a/src/sage/crypto/sboxes.py b/src/sage/crypto/sboxes.py index 7c3722b5402..bfb3834d5aa 100644 --- a/src/sage/crypto/sboxes.py +++ b/src/sage/crypto/sboxes.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules sage.rings.finite_rings +# sage.doctest: needs sage.modules sage.rings.finite_rings r""" S-Boxes used in cryptographic schemes diff --git a/src/sage/crypto/stream.py b/src/sage/crypto/stream.py index 92648a36404..636f588ad97 100644 --- a/src/sage/crypto/stream.py +++ b/src/sage/crypto/stream.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.rings.finite_rings +# sage.doctest: needs sage.combinat sage.rings.finite_rings """ Stream Cryptosystems """ diff --git a/src/sage/crypto/stream_cipher.py b/src/sage/crypto/stream_cipher.py index 21f913abee4..c6f46c8cef0 100644 --- a/src/sage/crypto/stream_cipher.py +++ b/src/sage/crypto/stream_cipher.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.rings.finite_rings +# sage.doctest: needs sage.combinat sage.rings.finite_rings """ Stream Ciphers """ diff --git a/src/sage/crypto/util.py b/src/sage/crypto/util.py index 0e0e9c1ed1a..da298a81001 100644 --- a/src/sage/crypto/util.py +++ b/src/sage/crypto/util.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat +# sage.doctest: needs sage.combinat """ Utility Functions for Cryptography From 614be8aa74c17293ae67e83be4adb1cbd9333db8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 7 Aug 2023 22:44:11 -0700 Subject: [PATCH 08/15] src/sage/crypto: sage -fixdoctests --only-tags --- src/sage/crypto/boolean_function.pyx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index bb51d7f5c89..6baf04179c7 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -563,21 +563,21 @@ cdef class BooleanFunction(SageObject): sage: B.truth_table(format='hex') '43' - sage: BooleanFunction('00ab').truth_table(format='hex') + sage: BooleanFunction('00ab').truth_table(format='hex') # needs sage.rings.polynomial.pbori '00ab' sage: H = '0abbacadabbacad0' sage: len(H) 16 - sage: T = BooleanFunction(H).truth_table(format='hex') + sage: T = BooleanFunction(H).truth_table(format='hex') # needs sage.rings.polynomial.pbori sage: T == H True sage: H = H * 4 - sage: T = BooleanFunction(H).truth_table(format='hex') + sage: T = BooleanFunction(H).truth_table(format='hex') # needs sage.rings.polynomial.pbori sage: T == H True sage: H = H * 4 - sage: T = BooleanFunction(H).truth_table(format='hex') + sage: T = BooleanFunction(H).truth_table(format='hex') # needs sage.rings.polynomial.pbori sage: T == H True sage: len(T) @@ -1074,7 +1074,7 @@ cdef class BooleanFunction(SageObject): 2 sage: R. = GF(2^8,'a')[] # needs sage.rings.finite_rings - sage: B = BooleanFunction(x^31) # needs sage.rings.finite_rings + sage: B = BooleanFunction(x^31) # needs sage.rings.finite_rings sage.rings.polynomial.pbori sage: B.algebraic_immunity() # needs sage.rings.finite_rings 4 """ From 6d39144ba271717acdc6855808ca4bb649479431 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 19 Aug 2023 12:02:25 -0700 Subject: [PATCH 09/15] sage.crypto.block_cipher: Modularization fix --- src/sage/crypto/block_cipher/des.py | 8 ++++---- src/sage/crypto/block_cipher/present.py | 10 ++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/sage/crypto/block_cipher/des.py b/src/sage/crypto/block_cipher/des.py index 04d35430924..08afe715710 100644 --- a/src/sage/crypto/block_cipher/des.py +++ b/src/sage/crypto/block_cipher/des.py @@ -78,7 +78,7 @@ from sage.rings.integer_ring import ZZ from sage.modules.free_module_element import vector from sage.rings.finite_rings.finite_field_constructor import GF -from sage.modules.vector_mod2_dense import Vector_mod2_dense +from sage.structure.element import Vector from sage.rings.integer import Integer from sage.crypto.sboxes import DES_S1_1, DES_S1_2, DES_S1_3, DES_S1_4 from sage.crypto.sboxes import DES_S2_1, DES_S2_2, DES_S2_3, DES_S2_4 @@ -512,7 +512,7 @@ def encrypt(self, plaintext, key): sage: des.encrypt(P, K56) == C True """ - if isinstance(plaintext, (list, tuple, Vector_mod2_dense)): + if isinstance(plaintext, (list, tuple, Vector)): inputType = 'vector' elif isinstance(plaintext, (Integer, int)): inputType = 'integer' @@ -569,7 +569,7 @@ def decrypt(self, ciphertext, key): sage: des.decrypt(C, K56).hex() == P True """ - if isinstance(ciphertext, (list, tuple, Vector_mod2_dense)): + if isinstance(ciphertext, (list, tuple, Vector)): inputType = 'vector' elif isinstance(ciphertext, (Integer, int)): inputType = 'integer' @@ -869,7 +869,7 @@ def __call__(self, key): pass a ``masterKey`` value on initialisation. Otherwise you can omit ``masterKey`` and pass a key when you call the object. """ - if isinstance(key, (list, tuple, Vector_mod2_dense)): + if isinstance(key, (list, tuple, Vector)): inputType = 'vector' elif isinstance(key, (Integer, int)): inputType = 'integer' diff --git a/src/sage/crypto/block_cipher/present.py b/src/sage/crypto/block_cipher/present.py index 5a7cda2d998..6e5605692a1 100644 --- a/src/sage/crypto/block_cipher/present.py +++ b/src/sage/crypto/block_cipher/present.py @@ -62,13 +62,11 @@ from sage.structure.sage_object import SageObject from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer -from sage.misc.lazy_import import lazy_import from sage.modules.free_module_element import vector from sage.rings.finite_rings.finite_field_constructor import GF +from sage.structure.element import Vector from sage.crypto.sboxes import PRESENT as PRESENTSBOX -lazy_import('sage.modules.vector_mod2_dense', 'Vector_mod2_dense') - def _smallscale_present_linearlayer(nsboxes=16): """ @@ -420,7 +418,7 @@ def encrypt(self, plaintext, key): \leq 32` and current STATE `b_{63} \dots b_0`, addRoundkey consists of the operation for `0 \leq j \leq 63`, `b_j = b_j \oplus \kappa^i_j`. """ - if isinstance(plaintext, (list, tuple, Vector_mod2_dense)): + if isinstance(plaintext, (list, tuple, Vector)): inputType = 'vector' elif isinstance(plaintext, (Integer, int)): inputType = 'integer' @@ -476,7 +474,7 @@ def decrypt(self, ciphertext, key): sage: present.decrypt(c4, k4) == p4 True """ - if isinstance(ciphertext, (list, tuple, Vector_mod2_dense)): + if isinstance(ciphertext, (list, tuple, Vector)): inputType = 'vector' elif isinstance(ciphertext, (Integer, int)): inputType = 'integer' @@ -776,7 +774,7 @@ def __call__(self, K): pass a ``master_key`` value on initialisation. Otherwise you can omit ``master_key`` and pass a key when you call the object. """ - if isinstance(K, (list, tuple, Vector_mod2_dense)): + if isinstance(K, (list, tuple, Vector)): inputType = 'vector' elif isinstance(K, (Integer, int)): inputType = 'integer' From 9d5554cc62745f034fbb56861c5a326686291d3e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 19 Aug 2023 14:29:36 -0700 Subject: [PATCH 10/15] sage.crypto: Update # needs, use more block tags, doctest cosmetics --- src/sage/crypto/block_cipher/miniaes.py | 2 +- src/sage/crypto/boolean_function.pyx | 49 ++--- src/sage/crypto/classical.py | 10 +- src/sage/crypto/classical_cipher.py | 4 +- src/sage/crypto/cryptosystem.py | 28 +-- src/sage/crypto/lwe.py | 20 +- src/sage/crypto/mq/rijndael_gf.py | 173 +++++++++--------- src/sage/crypto/mq/sr.py | 50 ++--- src/sage/crypto/public_key/blum_goldwasser.py | 52 +++--- src/sage/crypto/sbox.pyx | 24 +-- src/sage/crypto/util.py | 18 +- 11 files changed, 226 insertions(+), 204 deletions(-) diff --git a/src/sage/crypto/block_cipher/miniaes.py b/src/sage/crypto/block_cipher/miniaes.py index 0c7bc5ae979..6eb9568b9fc 100644 --- a/src/sage/crypto/block_cipher/miniaes.py +++ b/src/sage/crypto/block_cipher/miniaes.py @@ -1,4 +1,4 @@ -# sage.doctest: needs sage.modules sage.rings.finite_rings +# sage.doctest: needs sage.combinat sage.modules sage.rings.finite_rings r""" Mini-AES diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index 6baf04179c7..cd7c89fc944 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -17,7 +17,7 @@ EXAMPLES:: Boolean function with 8 variables sage: B.nonlinearity() 112 - sage: B.algebraic_immunity() + sage: B.algebraic_immunity() # needs sage.rings.polynomial.pbori 4 AUTHOR: @@ -62,7 +62,7 @@ cdef walsh_hadamard(long *f, int ldn): sage: from sage.crypto.boolean_function import BooleanFunction sage: B = BooleanFunction([1,0,0,1]) - sage: B.walsh_hadamard_transform() # indirect doctest + sage: B.walsh_hadamard_transform() # indirect doctest (0, 0, 0, -4) """ cdef long n, ldm, m, mh, t1, t2, r, j, u, v @@ -566,23 +566,24 @@ cdef class BooleanFunction(SageObject): sage: BooleanFunction('00ab').truth_table(format='hex') # needs sage.rings.polynomial.pbori '00ab' + sage: # needs sage.rings.polynomial.pbori sage: H = '0abbacadabbacad0' sage: len(H) 16 - sage: T = BooleanFunction(H).truth_table(format='hex') # needs sage.rings.polynomial.pbori + sage: T = BooleanFunction(H).truth_table(format='hex') sage: T == H True sage: H = H * 4 - sage: T = BooleanFunction(H).truth_table(format='hex') # needs sage.rings.polynomial.pbori + sage: T = BooleanFunction(H).truth_table(format='hex') sage: T == H True sage: H = H * 4 - sage: T = BooleanFunction(H).truth_table(format='hex') # needs sage.rings.polynomial.pbori + sage: T = BooleanFunction(H).truth_table(format='hex') sage: T == H True sage: len(T) 256 - sage: B.truth_table(format='oct') # needs sage.rings.polynomial.pbori + sage: B.truth_table(format='oct') Traceback (most recent call last): ... ValueError: unknown output format @@ -1073,9 +1074,10 @@ cdef class BooleanFunction(SageObject): sage: B.algebraic_immunity() 2 - sage: R. = GF(2^8,'a')[] # needs sage.rings.finite_rings - sage: B = BooleanFunction(x^31) # needs sage.rings.finite_rings sage.rings.polynomial.pbori - sage: B.algebraic_immunity() # needs sage.rings.finite_rings + sage: # needs sage.rings.finite_rings sage.rings.polynomial.pbori + sage: R. = GF(2^8,'a')[] + sage: B = BooleanFunction(x^31) + sage: B.algebraic_immunity() 4 """ f = self @@ -1101,13 +1103,14 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction - sage: B. = BooleanPolynomialRing() # needs sage.rings.polynomial.pbori - sage: f = BooleanFunction(x1*x2 + x1*x2*x3 + x1) # needs sage.rings.polynomial.pbori - sage: f.algebraic_degree() # needs sage.rings.polynomial.pbori + sage: B. = BooleanPolynomialRing() + sage: f = BooleanFunction(x1*x2 + x1*x2*x3 + x1) + sage: f.algebraic_degree() 3 sage: g = BooleanFunction([0, 0]) - sage: g.algebraic_degree() # needs sage.rings.polynomial.pbori + sage: g.algebraic_degree() -1 """ return self.algebraic_normal_form().degree() @@ -1247,15 +1250,16 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: + sage: # needs sage.modules sage: from sage.crypto.boolean_function import BooleanFunction sage: f = BooleanFunction([0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0]) - sage: LS = f.linear_structures() # needs sage.modules - sage: LS.dimension() # needs sage.modules + sage: LS = f.linear_structures() + sage: LS.dimension() 2 - sage: LS.basis_matrix() # needs sage.modules + sage: LS.basis_matrix() [1 0 0 0] [0 0 0 1] - sage: LS.list() # needs sage.modules + sage: LS.list() [(0, 0, 0, 0), (1, 0, 0, 0), (0, 0, 0, 1), (1, 0, 0, 1)] """ from sage.modules.free_module import VectorSpace @@ -1282,15 +1286,16 @@ cdef class BooleanFunction(SageObject): EXAMPLES:: + sage: # needs sage.rings.polynomial.pbori sage: from sage.crypto.boolean_function import BooleanFunction sage: f = BooleanFunction([0,1,0,1,0,1,0,1]) - sage: f.derivative(1).algebraic_normal_form() # needs sage.rings.polynomial.pbori + sage: f.derivative(1).algebraic_normal_form() 1 sage: u = [1,0,0] - sage: f.derivative(u).algebraic_normal_form() # needs sage.rings.polynomial.pbori + sage: f.derivative(u).algebraic_normal_form() 1 sage: v = vector(GF(2), u) # needs sage.modules - sage: f.derivative(v).algebraic_normal_form() # needs sage.modules sage.rings.finite_rings sage.rings.polynomial.pbori + sage: f.derivative(v).algebraic_normal_form() # needs sage.modules 1 sage: f.derivative(8).algebraic_normal_form() Traceback (most recent call last): @@ -1392,7 +1397,7 @@ def unpickle_BooleanFunction(bool_list): sage: from sage.crypto.boolean_function import BooleanFunction sage: B = BooleanFunction([0,1,1,0]) - sage: loads(dumps(B)) == B # indirect doctest + sage: loads(dumps(B)) == B # indirect doctest True """ return BooleanFunction(bool_list) @@ -1425,7 +1430,7 @@ cdef class BooleanFunctionIterator: sage: from sage.crypto.boolean_function import BooleanFunction sage: B = BooleanFunction(1) - sage: [b for b in B] # indirect doctest + sage: [b for b in B] # indirect doctest [False, False] """ return self diff --git a/src/sage/crypto/classical.py b/src/sage/crypto/classical.py index 00512513916..242cf881090 100644 --- a/src/sage/crypto/classical.py +++ b/src/sage/crypto/classical.py @@ -1205,7 +1205,7 @@ def inverse_key(self, a, b): capital letters of the English alphabet, there are 12 such integers relatively prime to `n`:: - sage: euler_phi(A.alphabet_size()) + sage: euler_phi(A.alphabet_size()) # needs sage.libs.pari 12 And here is a list of those integers:: @@ -3306,8 +3306,7 @@ def __call__(self, K): sage: M = AlphabeticStrings() sage: E = TranspositionCryptosystem(M,14); E # needs sage.groups Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 - sage: K = [ 14-i for i in range(14) ] - sage: K + sage: K = [14 - i for i in range(14)]; K [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] sage: e = E(K) # needs sage.groups sage: m = M("THECATINTHEHAT") @@ -3331,10 +3330,9 @@ def _repr_(self): EXAMPLES:: sage: A = AlphabeticStrings() - sage: T = TranspositionCryptosystem(A, 14) - sage: T + sage: T = TranspositionCryptosystem(A, 14); T # needs sage.groups Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 - sage: T._repr_() + sage: T._repr_() # needs sage.groups 'Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14' """ return "Transposition cryptosystem on %s of block length %s" % ( diff --git a/src/sage/crypto/classical_cipher.py b/src/sage/crypto/classical_cipher.py index 44bc1460685..55521405fb1 100644 --- a/src/sage/crypto/classical_cipher.py +++ b/src/sage/crypto/classical_cipher.py @@ -477,7 +477,7 @@ def __init__(self, parent, key): sage: K = [ 14-i for i in range(14) ]; K [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] sage: e = E(K) # needs sage.groups - sage: m = S("THECATINTHEHAT") # needs sage.groups + sage: m = S("THECATINTHEHAT") sage: e(m) # needs sage.groups TAHEHTNITACEHT @@ -485,7 +485,7 @@ def __init__(self, parent, key): sage: S = AlphabeticStrings() sage: E = TranspositionCryptosystem(S,15) # needs sage.groups - sage: m = S("THECATANDTHEHAT") # needs sage.groups + sage: m = S("THECATANDTHEHAT") sage: G = E.key_space(); G # needs sage.groups Symmetric group of order 15! as a permutation group sage: g = G([ 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13 ]) # needs sage.groups diff --git a/src/sage/crypto/cryptosystem.py b/src/sage/crypto/cryptosystem.py index 7973dff7ef4..33cc87cf08e 100644 --- a/src/sage/crypto/cryptosystem.py +++ b/src/sage/crypto/cryptosystem.py @@ -97,7 +97,7 @@ class Cryptosystem(parent_old.Parent, Set_generic): Substitution cryptosystem on Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3) Hill cryptosystem on Free binary string monoid of block length 3 - sage: TranspositionCryptosystem(OctalStrings(), 5) + sage: TranspositionCryptosystem(OctalStrings(), 5) # needs sage.groups Transposition cryptosystem on Free octal string monoid of block length 5 sage: VigenereCryptosystem(Radix64Strings(), 7) Vigenere cryptosystem on Free radix 64 string monoid of period 7 @@ -130,7 +130,7 @@ def __init__(self, plaintext_space, ciphertext_space, key_space, Substitution cryptosystem on Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3) Hill cryptosystem on Free binary string monoid of block length 3 - sage: TranspositionCryptosystem(OctalStrings(), 5) + sage: TranspositionCryptosystem(OctalStrings(), 5) # needs sage.groups Transposition cryptosystem on Free octal string monoid of block length 5 sage: VigenereCryptosystem(Radix64Strings(), 7) Vigenere cryptosystem on Free radix 64 string monoid of period 7 @@ -173,9 +173,9 @@ def __eq__(self, right): sage: hill2 = HillCryptosystem(AlphabeticStrings(), 4) sage: hill1 == hill2 True - sage: tran1 = TranspositionCryptosystem(HexadecimalStrings(), 5) - sage: tran2 = TranspositionCryptosystem(HexadecimalStrings(), 5) - sage: tran1 == tran2 + sage: tran1 = TranspositionCryptosystem(HexadecimalStrings(), 5) # needs sage.groups + sage: tran2 = TranspositionCryptosystem(HexadecimalStrings(), 5) # needs sage.groups + sage: tran1 == tran2 # needs sage.groups True sage: vig1 = VigenereCryptosystem(AlphabeticStrings(), 7) sage: vig2 = VigenereCryptosystem(AlphabeticStrings(), 7) @@ -196,9 +196,9 @@ def __eq__(self, right): sage: hill2 = HillCryptosystem(Radix64Strings(), 5) sage: hill1 == hill2 False - sage: tran1 = TranspositionCryptosystem(Radix64Strings(), 3) - sage: tran2 = TranspositionCryptosystem(HexadecimalStrings(), 3) - sage: tran1 == tran2 + sage: tran1 = TranspositionCryptosystem(Radix64Strings(), 3) # needs sage.groups + sage: tran2 = TranspositionCryptosystem(HexadecimalStrings(), 3) # needs sage.groups + sage: tran1 == tran2 # needs sage.groups False sage: vig1 = VigenereCryptosystem(AlphabeticStrings(), 7) sage: vig2 = VigenereCryptosystem(Radix64Strings(), 7) @@ -226,7 +226,7 @@ def plaintext_space(self): Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3).plaintext_space() Free binary string monoid - sage: TranspositionCryptosystem(OctalStrings(), 5).plaintext_space() + sage: TranspositionCryptosystem(OctalStrings(), 5).plaintext_space() # needs sage.groups Free octal string monoid sage: VigenereCryptosystem(Radix64Strings(), 7).plaintext_space() Free radix 64 string monoid @@ -249,7 +249,7 @@ def cipher_domain(self): Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3).cipher_domain() Free binary string monoid - sage: TranspositionCryptosystem(OctalStrings(), 5).cipher_domain() + sage: TranspositionCryptosystem(OctalStrings(), 5).cipher_domain() # needs sage.groups Free octal string monoid sage: VigenereCryptosystem(Radix64Strings(), 7).cipher_domain() Free radix 64 string monoid @@ -270,7 +270,7 @@ def ciphertext_space(self): Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3).ciphertext_space() Free binary string monoid - sage: TranspositionCryptosystem(OctalStrings(), 5).ciphertext_space() + sage: TranspositionCryptosystem(OctalStrings(), 5).ciphertext_space() # needs sage.groups Free octal string monoid sage: VigenereCryptosystem(Radix64Strings(), 7).ciphertext_space() Free radix 64 string monoid @@ -293,7 +293,7 @@ def cipher_codomain(self): Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3).cipher_codomain() Free binary string monoid - sage: TranspositionCryptosystem(OctalStrings(), 5).cipher_codomain() + sage: TranspositionCryptosystem(OctalStrings(), 5).cipher_codomain() # needs sage.groups Free octal string monoid sage: VigenereCryptosystem(Radix64Strings(), 7).cipher_codomain() Free radix 64 string monoid @@ -314,7 +314,7 @@ def key_space(self): Free hexadecimal string monoid sage: HillCryptosystem(BinaryStrings(), 3).key_space() Full MatrixSpace of 3 by 3 dense matrices over Ring of integers modulo 2 - sage: TranspositionCryptosystem(OctalStrings(), 5).key_space() + sage: TranspositionCryptosystem(OctalStrings(), 5).key_space() # needs sage.groups Symmetric group of order 5! as a permutation group sage: VigenereCryptosystem(Radix64Strings(), 7).key_space() Free radix 64 string monoid @@ -336,7 +336,7 @@ def block_length(self): 1 sage: HillCryptosystem(BinaryStrings(), 3).block_length() 3 - sage: TranspositionCryptosystem(OctalStrings(), 5).block_length() + sage: TranspositionCryptosystem(OctalStrings(), 5).block_length() # needs sage.groups 5 sage: VigenereCryptosystem(Radix64Strings(), 7).block_length() 1 diff --git a/src/sage/crypto/lwe.py b/src/sage/crypto/lwe.py index 7d036312aab..5e4687b61a0 100644 --- a/src/sage/crypto/lwe.py +++ b/src/sage/crypto/lwe.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - scipy +# sage.doctest: needs scipy sage.symbolic """ (Ring-)LWE oracle generators @@ -52,6 +52,7 @@ Note that Ring-LWE samples are returned as vectors:: + sage: # needs sage.libs.pari sage: from sage.crypto.lwe import RingLWE sage: from sage.stats.distributions.discrete_gaussian_polynomial import DiscreteGaussianDistributionPolynomialSampler sage: D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], euler_phi(16), 5) @@ -306,7 +307,7 @@ def __init__(self, n, q, D, secret_dist='uniform', m=None): sage: from sage.crypto.lwe import LWE sage: lwe = LWE(n=20, q=next_prime(400), D=D, m=30) sage: _ = [lwe() for _ in range(30)] - sage: lwe() # 31 + sage: lwe() # 31 Traceback (most recent call last): ... IndexError: Number of available samples exhausted. @@ -539,8 +540,8 @@ def __init__(self, N, q, D, poly=None, secret_dist='uniform', m=None): sage: from sage.crypto.lwe import RingLWE sage: from sage.stats.distributions.discrete_gaussian_polynomial import DiscreteGaussianDistributionPolynomialSampler - sage: D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n=euler_phi(20), sigma=3.0) - sage: RingLWE(N=20, q=next_prime(800), D=D) + sage: D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n=euler_phi(20), sigma=3.0) # needs sage.libs.pari + sage: RingLWE(N=20, q=next_prime(800), D=D) # needs sage.libs.pari RingLWE(20, 809, Discrete Gaussian sampler for polynomials of degree < 8 with σ=3.000000 in each component, x^8 - x^6 + x^4 - x^2 + 1, 'uniform', None) """ self.N = ZZ(N) @@ -587,14 +588,15 @@ def __call__(self): """ EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.crypto.lwe import DiscreteGaussianDistributionPolynomialSampler, RingLWE sage: N = 16 - sage: n = euler_phi(N) - sage: D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n, 5) - sage: ringlwe = RingLWE(N, 257, D, secret_dist='uniform') - sage: ringlwe()[0].parent() + sage: n = euler_phi(N) # needs sage.libs.pari + sage: D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n, 5) # needs sage.libs.pari + sage: ringlwe = RingLWE(N, 257, D, secret_dist='uniform') # needs sage.libs.pari + sage: ringlwe()[0].parent() # needs sage.libs.pari Vector space of dimension 8 over Ring of integers modulo 257 - sage: ringlwe()[1].parent() + sage: ringlwe()[1].parent() # needs sage.libs.pari Vector space of dimension 8 over Ring of integers modulo 257 """ if self.m is not None: diff --git a/src/sage/crypto/mq/rijndael_gf.py b/src/sage/crypto/mq/rijndael_gf.py index 45e17cda4b6..c25080a2129 100644 --- a/src/sage/crypto/mq/rijndael_gf.py +++ b/src/sage/crypto/mq/rijndael_gf.py @@ -81,7 +81,7 @@ '3902dc1925dc116a8409850b1dfb9732'. We can use this example to demonstrate the correctness of this implementation:: - sage: rgf = RijndaelGF(4, 4) # change dimensions for this example + sage: rgf = RijndaelGF(4, 4) # change dimensions for this example sage: plain = '3243f6a8885a308d313198a2e0370734' sage: key = '2b7e151628aed2a6abf7158809cf4f3c' sage: expected_ciphertext = '3925841d02dc09fbdc118597196a0b32' @@ -161,8 +161,7 @@ finally perform the inversion step after the affine transformation polynomial has been evaluated. :: - sage: inv_affine = sb_pc(1, 2, algorithm='decrypt', - ....: no_inversion=True) + sage: inv_affine = sb_pc(1, 2, algorithm='decrypt', no_inversion=True) sage: state = rgf._hex_to_GF('ff87968431d86a51645151fa773ad009') sage: evaluated = inv_affine(state.list()) sage: result = evaluated * -1 @@ -253,7 +252,7 @@ ``apply_poly`` a dictionary mapping keywords to their values. :: sage: rgf.apply_poly(rgf.state_vrs, rgf.add_round_key_poly_constr(), - ....: poly_constr_attr={'round' : 5}) + ....: poly_constr_attr={'round': 5}) [a00 + k500 a01 + k501 a02 + k502 a03 + k503] [a10 + k510 a11 + k511 a12 + k512 a13 + k513] [a20 + k520 a21 + k521 a22 + k522 a23 + k523] @@ -270,10 +269,11 @@ when passed an index ``i,j`` will return `g(f(A))_{i,j}` in terms of the entries of `A`. :: + sage: # needs sage.libs.gap sage: rcpc = rgf.compose(rgf.shift_rows_poly_constr(), - ....: rgf.mix_columns_poly_constr()) - sage: rcpc - A polynomial constructor of a round component of Rijndael-GF block cipher with block length 4, key length 6, and 12 rounds. + ....: rgf.mix_columns_poly_constr()); rcpc # needs sage.libs.gap + A polynomial constructor of a round component of Rijndael-GF block cipher + with block length 4, key length 6, and 12 rounds. sage: rcpc(2, 1) a01 + a12 + x*a23 + (x + 1)*a30 @@ -285,7 +285,7 @@ True sage: rcpc = rgf.compose(rgf.mix_columns_poly_constr(), - ....: rgf.shift_rows_poly_constr()) + ....: rgf.shift_rows_poly_constr()) sage: result = rgf.apply_poly(state, rcpc, algorithm='decrypt') sage: new_state = rgf.mix_columns(state, algorithm='decrypt') sage: new_state = rgf.shift_rows(new_state, algorithm='decrypt') @@ -302,8 +302,7 @@ ``compose`` will return a polynomial representing `g(f(A))_{i,j}` in terms of the entries of `A`. :: - sage: poly = rgf.mix_columns_poly_constr()(0, 3) - sage: poly + sage: poly = rgf.mix_columns_poly_constr()(0, 3); poly x*a03 + (x + 1)*a13 + a23 + a33 sage: rgf.compose(rgf.sub_bytes_poly_constr(), poly) (x^3 + x)*a03^254 + @@ -348,16 +347,18 @@ returned ``Round_Component_Poly_Constr`` object's ``__call__`` method must have its own ``algorithm`` keyword defaulted to 'encrypt'. :: + sage: # needs sage.libs.gap sage: poly = rgf.shift_rows_poly_constr()(2, 1) sage: rgf.compose(rgf.mix_columns_poly_constr(), poly, algorithm='decrypt') (x^3 + x^2 + 1)*a03 + (x^3 + 1)*a13 + (x^3 + x^2 + x)*a23 + (x^3 + x + 1)*a33 sage: state = rgf._hex_to_GF('80121e0776fd1d8a8d8c31bc965d1fee') sage: with_decrypt = rgf.compose(rgf.sub_bytes_poly_constr(), - ....: rgf.shift_rows_poly_constr(), algorithm='decrypt') + ....: rgf.shift_rows_poly_constr(), + ....: algorithm='decrypt') sage: result_wd = rgf.apply_poly(state, with_decrypt) sage: no_decrypt = rgf.compose(rgf.sub_bytes_poly_constr(), - ....: rgf.shift_rows_poly_constr()) + ....: rgf.shift_rows_poly_constr()) sage: result_nd = rgf.apply_poly(state, no_decrypt) sage: result_wd == result_nd True @@ -366,10 +367,10 @@ ``compose`` to make ``f`` and ``g`` use those keywords during polynomial creation. :: - sage: rcpc = rgf.compose(rgf.add_round_key_poly_constr(), - ....: rgf.add_round_key_poly_constr(), - ....: f_attr={'round' : 4}, g_attr={'round' : 7}) - sage: rcpc(1, 2) + sage: rcpc = rgf.compose(rgf.add_round_key_poly_constr(), # needs sage.libs.gap + ....: rgf.add_round_key_poly_constr(), + ....: f_attr={'round': 4}, g_attr={'round': 7}) + sage: rcpc(1, 2) # needs sage.libs.gap a12 + k412 + k712 In addition to building polynomial representations of state matrices, we can @@ -1119,14 +1120,16 @@ def _check_valid_PRmatrix(self, PRm, keyword): sage: rgf._check_valid_PRmatrix(5, 'state') Traceback (most recent call last): ... - TypeError: keyword 'state' must be a 4 x 4 matrix with entries from a multivariate PolynomialRing over Finite Field in x of size 2^8 + TypeError: keyword 'state' must be a 4 x 4 matrix with entries from + a multivariate PolynomialRing over Finite Field in x of size 2^8 sage: entries = [rgf._F.random_element() for i in range(24)] sage: wrong_dimensions = matrix(4, 6, entries) sage: rgf._check_valid_PRmatrix(wrong_dimensions, 'state') Traceback (most recent call last): ... - TypeError: keyword 'state' must be a 4 x 4 matrix with entries from a multivariate PolynomialRing over Finite Field in x of size 2^8 + TypeError: keyword 'state' must be a 4 x 4 matrix with entries from + a multivariate PolynomialRing over Finite Field in x of size 2^8 sage: F. = GF(3^4) sage: entries = [F.random_element() for i in range(16)] @@ -1134,7 +1137,8 @@ def _check_valid_PRmatrix(self, PRm, keyword): sage: rgf._check_valid_PRmatrix(wrong_base, 'state') Traceback (most recent call last): ... - TypeError: keyword 'state' must be a 4 x 4 matrix with entries from a multivariate PolynomialRing over Finite Field in x of size 2^8 + TypeError: keyword 'state' must be a 4 x 4 matrix with entries from + a multivariate PolynomialRing over Finite Field in x of size 2^8 """ from sage.rings.polynomial.multi_polynomial_ring_base import \ MPolynomialRing_base @@ -1266,7 +1270,8 @@ def expand_key_poly(self, row, col, round): sage: rgf.compose(rgf.sub_bytes_poly_constr(), rgf.expand_key_poly) Traceback (most recent call last): ... - TypeError: keyword 'g' must be a Round_Component_Poly_Constr or a polynomial over Finite Field in x of size 2^8 + TypeError: keyword 'g' must be a Round_Component_Poly_Constr or + a polynomial over Finite Field in x of size 2^8 sage: state = rgf._hex_to_GF('00000000000000000000000000000000') sage: rgf.apply_poly(state, rgf.expand_key_poly) @@ -1359,7 +1364,7 @@ def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, sage: state = rgf._hex_to_GF('4915598f55e5d7a0daca94fa1f0a63f7') sage: apply_poly_result = rgf.apply_poly(state, - ....: rgf.sub_bytes_poly_constr()) + ....: rgf.sub_bytes_poly_constr()) sage: direct_result = rgf.sub_bytes(state) sage: direct_result == apply_poly_result True @@ -1374,7 +1379,8 @@ def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, sage: key = rgf._hex_to_GF('54d990a16ba09ab596bbf40ea111702f') sage: keys = rgf.expand_key(key) sage: result = rgf.apply_poly(state, - ....: rgf.add_round_key_poly_constr(), keys=keys) + ....: rgf.add_round_key_poly_constr(), + ....: keys=keys) sage: result == rgf.add_round_key(state, key) True @@ -1386,8 +1392,8 @@ def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, dictionary ``poly_constr_attr`` mapping keywords to their values. :: sage: rgf.apply_poly(rgf.state_vrs, - ....: rgf.add_round_key_poly_constr(), - ....: poly_constr_attr={'round' : 5}) + ....: rgf.add_round_key_poly_constr(), + ....: poly_constr_attr={'round': 5}) [a00 + k500 a01 + k501 a02 + k502 a03 + k503] [a10 + k510 a11 + k511 a12 + k512 a13 + k513] [a20 + k520 a21 + k521 a22 + k522 a23 + k523] @@ -1500,9 +1506,9 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): ``Round_Component_Poly_Constr`` object corresponding to the composition of multiple round functions as such:: - sage: fn = rgf.compose(rgf.shift_rows_poly_constr(), - ....: rgf.mix_columns_poly_constr()) - sage: fn(1, 3) + sage: fn = rgf.compose(rgf.shift_rows_poly_constr(), # needs sage.libs.gap + ....: rgf.mix_columns_poly_constr()) + sage: fn(1, 3) # needs sage.libs.gap a03 + x*a10 + (x + 1)*a21 + a32 If we use ``compose`` to make a new ``Round_Component_Poly_Constr`` @@ -1510,7 +1516,7 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): ``compose``:: sage: state = rgf._hex_to_GF('36400926f9336d2d9fb59d23c42c3950') - sage: result = rgf.apply_poly(state, fn) + sage: result = rgf.apply_poly(state, fn) # needs sage.libs.gap sage: rgf._GF_to_hex(result) 'f4bcd45432e554d075f1d6c51dd03b3c' @@ -1521,7 +1527,7 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): :: - sage: fn2 = rgf.compose(rgf.sub_bytes_poly_constr(), fn) + sage: fn2 = rgf.compose(rgf.sub_bytes_poly_constr(), fn) # needs sage.libs.gap If the second argument is a polynomial, then the value of ``algorithm`` is passed directly to the first argument `f` during evaluation. @@ -1529,21 +1535,22 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): object, changing ``algorithm`` does nothing since the returned object has its own ``algorithm='encrypt'`` keyword. :: - sage: f = rgf.compose(rgf.sub_bytes_poly_constr(), - ....: rgf.mix_columns_poly_constr(), algorithm='decrypt') - sage: g = rgf.compose(rgf.sub_bytes_poly_constr(), - ....: rgf.mix_columns_poly_constr()) - sage: all(f(i,j) == g(i,j) for i in range(4) for j in range(4)) + sage: f = rgf.compose(rgf.sub_bytes_poly_constr(), # needs sage.libs.gap + ....: rgf.mix_columns_poly_constr(), + ....: algorithm='decrypt') + sage: g = rgf.compose(rgf.sub_bytes_poly_constr(), # needs sage.libs.gap + ....: rgf.mix_columns_poly_constr()) + sage: all(f(i,j) == g(i,j) for i in range(4) for j in range(4)) # needs sage.libs.gap True We can change the keyword attributes of the ``__call__`` methods of ``f`` and ``g`` by passing dictionaries ``f_attr`` and ``g_attr`` to ``compose``. :: - sage: fn = rgf.compose(rgf.add_round_key_poly_constr(), - ....: rgf.add_round_key_poly_constr(), - ....: f_attr={'round' : 4}, g_attr={'round' : 7}) - sage: fn(1, 2) + sage: fn = rgf.compose(rgf.add_round_key_poly_constr(), # needs sage.libs.gap + ....: rgf.add_round_key_poly_constr(), + ....: f_attr={'round': 4}, g_attr={'round': 7}) + sage: fn(1, 2) # needs sage.libs.gap a12 + k412 + k712 """ if not isinstance(f, RijndaelGF.Round_Component_Poly_Constr): @@ -1573,10 +1580,10 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): return g(f_vals + self.subkey_vrs_list) else: if isinstance(g_attr, dict): - lm = lambda i, j, alg='encrypt' : \ + lm = lambda i, j, alg='encrypt': \ self.compose(f, g(i, j, alg, **g_attr), alg, f_attr, g_attr) else: - lm = lambda i, j, alg='encrypt' : \ + lm = lambda i, j, alg='encrypt': \ self.compose(f, g(i, j, alg), alg, f_attr, g_attr) return RijndaelGF.Round_Component_Poly_Constr(lm, self) @@ -1591,7 +1598,8 @@ def add_round_key_poly_constr(self): sage: rgf = RijndaelGF(4, 4) sage: ark_pc = rgf.add_round_key_poly_constr() sage: ark_pc - A polynomial constructor for the function 'Add Round Key' of Rijndael-GF block cipher with block length 4, key length 4, and 10 rounds. + A polynomial constructor for the function 'Add Round Key' of Rijndael-GF + block cipher with block length 4, key length 4, and 10 rounds. sage: ark_pc(0, 1) a01 + k001 @@ -1617,7 +1625,7 @@ def add_round_key_poly_constr(self): value. :: sage: rgf.apply_poly(rgf.state_vrs, ark_pc, - ....: poly_constr_attr={'round' : 6}) + ....: poly_constr_attr={'round': 6}) [a00 + k600 a01 + k601 a02 + k602 a03 + k603] [a10 + k610 a11 + k611 a12 + k612 a13 + k613] [a20 + k620 a21 + k621 a22 + k622 a23 + k623] @@ -1625,9 +1633,9 @@ def add_round_key_poly_constr(self): :: - sage: rcpc = rgf.compose(ark_pc, ark_pc, - ....: f_attr={'round' : 3}, g_attr={'round' : 5}) - sage: rcpc(3, 1) + sage: rcpc = rgf.compose(ark_pc, ark_pc, # needs sage.libs.gap + ....: f_attr={'round': 3}, g_attr={'round': 5}) + sage: rcpc(3, 1) # needs sage.libs.gap a31 + k331 + k531 """ return self._add_round_key_rcpc @@ -1667,10 +1675,8 @@ def _add_round_key_pc(self, row, col, algorithm='encrypt', round=0): As expected, since the encryption and decryption transformations are identical, changing ``algorithm`` has no effect. - sage: with_encrypt = rgf._add_round_key_pc(3, 2, - ....: 'encrypt') - sage: with_decrypt = rgf._add_round_key_pc(3, 2, - ....: 'decrypt') + sage: with_encrypt = rgf._add_round_key_pc(3, 2, 'encrypt') + sage: with_decrypt = rgf._add_round_key_pc(3, 2, 'decrypt') sage: with_encrypt == with_decrypt True """ @@ -1723,9 +1729,9 @@ def sub_bytes_poly_constr(self): sage: from sage.crypto.mq.rijndael_gf import RijndaelGF sage: rgf = RijndaelGF(4, 4) - sage: sb_pc = rgf.sub_bytes_poly_constr() - sage: sb_pc - A polynomial constructor for the function 'SubBytes' of Rijndael-GF block cipher with block length 4, key length 4, and 10 rounds. + sage: sb_pc = rgf.sub_bytes_poly_constr(); sb_pc + A polynomial constructor for the function 'SubBytes' of Rijndael-GF + block cipher with block length 4, key length 4, and 10 rounds. sage: sb_pc(2, 3) (x^2 + 1)*a23^254 + (x^3 + 1)*a23^253 + @@ -1773,17 +1779,17 @@ def sub_bytes_poly_constr(self): When passing the returned object to ``apply_poly`` and ``compose``, we can make those methods change the keyword ``no_inversion`` of this object's ``__call__`` method by passing the dictionary - ``{'no_inversion' : True}`` to them. :: + ``{'no_inversion': True}`` to them. :: sage: result = rgf.apply_poly(state, sb_pc, - ....: poly_constr_attr={'no_inversion' : True}) + ....: poly_constr_attr={'no_inversion': True}) sage: rgf._GF_to_hex(result) '961c72894526f746aa85fc920adcc719' :: - sage: rcpc = rgf.compose(sb_pc, rgf.shift_rows_poly_constr(), - ....: f_attr={'no_inversion' : True}) + sage: rcpc = rgf.compose(sb_pc, rgf.shift_rows_poly_constr(), # needs sage.libs.gap + ....: f_attr={'no_inversion': True}) Note that if we set ``algorithm='decrypt'`` for ``apply_poly``, it will perform the necessary performance enhancement described above @@ -1848,7 +1854,7 @@ def _sub_bytes_pc(self, row, col, algorithm='encrypt', no_inversion=False): calculated. :: sage: poly = rgf._sub_bytes_pc(0, 0, - ....: algorithm='decrypt', no_inversion=True) + ....: algorithm='decrypt', no_inversion=True) sage: state = rgf._hex_to_GF('b415f8016858552e4bb6124c5f998a4c') sage: poly(state.list()) ^ -1 x^7 + x^6 + x^2 + x @@ -1956,7 +1962,8 @@ def mix_columns_poly_constr(self): sage: rgf = RijndaelGF(4, 4) sage: mc_pc = rgf.mix_columns_poly_constr() sage: mc_pc - A polynomial constructor for the function 'Mix Columns' of Rijndael-GF block cipher with block length 4, key length 4, and 10 rounds. + A polynomial constructor for the function 'Mix Columns' of Rijndael-GF + block cipher with block length 4, key length 4, and 10 rounds. sage: mc_pc(1, 2) a02 + x*a12 + (x + 1)*a22 + a32 sage: mc_pc(1, 0, algorithm='decrypt') @@ -2181,13 +2188,14 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): EXAMPLES:: - sage: from sage.crypto.mq.rijndael_gf import \ - ....: RijndaelGF + sage: from sage.crypto.mq.rijndael_gf import RijndaelGF sage: rgf = RijndaelGF(4, 4) sage: rcpc = RijndaelGF.Round_Component_Poly_Constr( - ....: rgf._shift_rows_pc, rgf, "Shift Rows") + ....: rgf._shift_rows_pc, rgf, "Shift Rows") sage: rcpc - A polynomial constructor for the function 'Shift Rows' of Rijndael-GF block cipher with block length 4, key length 4, and 10 rounds. + A polynomial constructor for the function 'Shift Rows' of + Rijndael-GF block cipher with block length 4, key length 4, + and 10 rounds. If `\phi` is the round component function to which this object corresponds to, then ``__call__(i,j)`` `= \phi(A)_{i,j}`, where @@ -2195,7 +2203,7 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): by ``__call__(i,j)`` will be in terms of the entries of `A`. :: sage: rcpc = RijndaelGF.Round_Component_Poly_Constr( - ....: rgf._mix_columns_pc, rgf, "Mix Columns") + ....: rgf._mix_columns_pc, rgf, "Mix Columns") sage: poly = rcpc(1, 2); poly a02 + x*a12 + (x + 1)*a22 + a32 sage: state = rgf._hex_to_GF('d1876c0f79c4300ab45594add66ff41f') @@ -2210,7 +2218,7 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): ``Round_Component_Poly_Constr`` object will act similarly. :: sage: all(rgf._mix_columns_pc(i, j) == rcpc(i, j) - ....: for i in range(4) for j in range(4)) + ....: for i in range(4) for j in range(4)) True Since all keyword arguments of ``polynomial_constr`` must have a @@ -2225,8 +2233,8 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): ``compose``. :: sage: rgf.apply_poly(rgf.state_vrs, - ....: rgf.add_round_key_poly_constr(), - ....: poly_constr_attr={'round' : 9}) + ....: rgf.add_round_key_poly_constr(), + ....: poly_constr_attr={'round': 9}) [a00 + k900 a01 + k901 a02 + k902 a03 + k903] [a10 + k910 a11 + k911 a12 + k912 a13 + k913] [a20 + k920 a21 + k921 a22 + k922 a23 + k923] @@ -2234,10 +2242,10 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): :: - sage: fn = rgf.compose(rgf.add_round_key_poly_constr(), - ....: rgf.add_round_key_poly_constr(), - ....: f_attr={'round' : 3}, g_attr={'round' : 7}) - sage: fn(2, 3) + sage: fn = rgf.compose(rgf.add_round_key_poly_constr(), # needs sage.libs.gap + ....: rgf.add_round_key_poly_constr(), + ....: f_attr={'round': 3}, g_attr={'round': 7}) + sage: fn(2, 3) # needs sage.libs.gap a23 + k323 + k723 Because all ``Round_Component_Poly_Constr`` objects are callable @@ -2246,9 +2254,9 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): keywords, however, must be checked in ``polynomial_constr``. :: sage: def my_poly_constr(row, col, algorithm='encrypt'): - ....: return x * rgf._F.one() # example body with no checks + ....: return x * rgf._F.one() # example body with no checks sage: rcpc = RijndaelGF.Round_Component_Poly_Constr( - ....: my_poly_constr, rgf, "My Poly Constr") + ....: my_poly_constr, rgf, "My Poly Constr") sage: rcpc(-1, 2) Traceback (most recent call last): ... @@ -2304,15 +2312,14 @@ def __call__(self, row, col, algorithm='encrypt', **kwargs): EXAMPLES:: - sage: from sage.crypto.mq.rijndael_gf import \ - ....: RijndaelGF + sage: from sage.crypto.mq.rijndael_gf import RijndaelGF sage: rgf = RijndaelGF(4, 4) sage: rcpc = RijndaelGF.Round_Component_Poly_Constr( - ....: rgf._shift_rows_pc, rgf, "Shift Rows") + ....: rgf._shift_rows_pc, rgf, "Shift Rows") sage: rcpc(1, 2) a13 sage: all(rcpc(i, j) == rgf._shift_rows_pc(i, j) - ....: for i in range(4) for j in range(4)) + ....: for i in range(4) for j in range(4)) True """ if row not in range(4): @@ -2333,15 +2340,17 @@ def __repr__(self): EXAMPLES:: - sage: from sage.crypto.mq.rijndael_gf import \ - ....: RijndaelGF + sage: from sage.crypto.mq.rijndael_gf import RijndaelGF sage: rgf = RijndaelGF(4, 4) sage: RijndaelGF.Round_Component_Poly_Constr( - ....: rgf._shift_rows_pc, rgf, "Shift Rows") - A polynomial constructor for the function 'Shift Rows' of Rijndael-GF block cipher with block length 4, key length 4, and 10 rounds. + ....: rgf._shift_rows_pc, rgf, "Shift Rows") + A polynomial constructor for the function 'Shift Rows' of + Rijndael-GF block cipher with block length 4, key length 4, + and 10 rounds. sage: RijndaelGF.Round_Component_Poly_Constr( - ....: rgf._shift_rows_pc, rgf) - A polynomial constructor of a round component of Rijndael-GF block cipher with block length 4, key length 4, and 10 rounds. + ....: rgf._shift_rows_pc, rgf) + A polynomial constructor of a round component of Rijndael-GF + block cipher with block length 4, key length 4, and 10 rounds. """ if self._rc_name is None: msg = "A polynomial constructor of a round component of {0}" diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index 9390359300e..ab7ad3d2c96 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -104,8 +104,8 @@ sage: a = K.gen() sage: K = [a] sage: P = [1] - sage: F,s = sr.polynomial_system(P=P, K=K) - sage: F.groebner_basis() + sage: F,s = sr.polynomial_system(P=P, K=K) # needs sage.rings.polynomial.pbori + sage: F.groebner_basis() # needs sage.rings.polynomial.pbori [k100, k101 + 1, k102, k103 + k003, x100 + 1, x101 + k003 + 1, x102 + k003 + 1, x103 + k003, w100, w101, w102 + 1, w103 + k003 + 1, @@ -124,8 +124,8 @@ All solutions can easily be recovered using the variety function for ideals.:: - sage: I = F.ideal() - sage: for V in I.variety(): + sage: I = F.ideal() # needs sage.rings.polynomial.pbori + sage: for V in I.variety(): # needs sage.rings.polynomial.pbori sage.symbolic ....: for k,v in sorted(V.items()): ....: print("{} {}".format(k, v)) ....: print("\n") @@ -174,7 +174,7 @@ We can also verify the correctness of the variety by evaluating all ideal generators on all points.:: - sage: for V in I.variety(): + sage: for V in I.variety(): # needs sage.rings.polynomial.pbori sage.symbolic ....: for f in I.gens(): ....: if f.subs(V) != 0: ....: print("epic fail") @@ -207,7 +207,7 @@ or use ``S`` to find alternative polynomial representations for the S-Box.:: - sage: S.polynomials(degree=3) + sage: S.polynomials(degree=3) # needs sage.libs.singular [x0*x1 + x1*x2 + x0*x3 + x0*y2 + x1 + y0 + y1 + 1, x0*x1 + x0*x2 + x0*y0 + x0*y1 + x0*y2 + x1 + x2 + y0 + y1 + y2, x0*x1 + x0*x2 + x0*x3 + x1*x3 + x0*y0 + x1*y0 + x0*y1 + x0*y3, @@ -1652,7 +1652,7 @@ def variable_dict(self): 'x103': x103} sage: sr = mq.SR(1,1,1,4,gf2=True) - sage: sr.variable_dict() + sage: sr.variable_dict() # needs sage.rings.polynomial.pbori {'k000': k000, 'k001': k001, 'k002': k002, @@ -2004,16 +2004,16 @@ def polynomial_system(self, P=None, K=None, C=None): sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) sage: P = sr.vector([0, 0, 1, 0]) sage: K = sr.vector([1, 0, 0, 1]) - sage: F, s = sr.polynomial_system(P, K) + sage: F, s = sr.polynomial_system(P, K) # needs sage.rings.polynomial.pbori This returns a polynomial system:: - sage: F + sage: F # needs sage.rings.polynomial.pbori Polynomial Sequence with 36 Polynomials in 20 Variables and a solution:: - sage: s # random -- maybe we need a better doctest here? + sage: s # random -- maybe we need a better doctest here? # needs sage.rings.polynomial.pbori {k000: 1, k001: 0, k003: 1, k002: 0} This solution is not the only solution that we can learn from the @@ -2021,24 +2021,25 @@ def polynomial_system(self, P=None, K=None, C=None): :: - sage: F.groebner_basis()[-3:] + sage: F.groebner_basis()[-3:] # needs sage.rings.polynomial.pbori [k000 + 1, k001, k003 + 1] In particular we have two solutions:: - sage: len(F.ideal().variety()) + sage: len(F.ideal().variety()) # needs sage.rings.polynomial.pbori 2 In the following example we provide ``C`` explicitly:: sage: C = sr(P,K) - sage: F,s = sr.polynomial_system(P=P, C=C) - sage: F + sage: F,s = sr.polynomial_system(P=P, C=C) # needs sage.rings.polynomial.pbori + sage: F # needs sage.rings.polynomial.pbori Polynomial Sequence with 36 Polynomials in 20 Variables Alternatively, we can use symbols for the ``P`` and ``C``. First, we have to create a polynomial ring:: + sage: # needs sage.rings.polynomial.pbori sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) sage: R = sr.R sage: vn = sr.varstrs("P",0,1,4) + R.variable_names() + sr.varstrs("C",0,1,4) @@ -2048,6 +2049,7 @@ def polynomial_system(self, P=None, K=None, C=None): Now, we can construct the purely symbolic equation system:: + sage: # needs sage.rings.polynomial.pbori sage: C = sr.vars("C",0); C (C000, C001, C002, C003) sage: P = sr.vars("P",0) @@ -2062,7 +2064,7 @@ def polynomial_system(self, P=None, K=None, C=None): We show that the (returned) key is a solution to the returned system:: sage: sr = mq.SR(3,4,4,8, star=True, gf2=True, polybori=True) - sage: while True: # workaround (see :trac:`31891`) + sage: while True: # workaround (see :trac:`31891`) # needs sage.rings.polynomial.pbori ....: try: ....: F, s = sr.polynomial_system() ....: break @@ -2589,7 +2591,7 @@ def phi(self, l, diffusion_matrix=False): sage: sr = mq.SR(2, 1, 2, 4, gf2=True) sage: k = sr.base_ring() sage: A = matrix(k, 1, 2, [k.gen(), 0] ) - sage: sr.phi(A) + sage: sr.phi(A) # needs sage.libs.gap [0 0] [0 0] [1 0] @@ -2643,7 +2645,7 @@ def antiphi(self, l): sage: sr = mq.SR(gf2=True) sage: A = sr.random_state_array() - sage: sr.antiphi(sr.phi(A)) == A + sage: sr.antiphi(sr.phi(A)) == A # needs sage.libs.gap True """ e = self.e @@ -3146,9 +3148,9 @@ def inversion_polynomials(self, xi, wi, length): EXAMPLES:: sage: sr = mq.SR(1, 1, 1, 8, gf2=True) - sage: xi = sr.vars('x', 1) - sage: wi = sr.vars('w', 1) - sage: sr.inversion_polynomials(xi, wi, len(xi))[:3] + sage: xi = sr.vars('x', 1) # needs sage.rings.polynomial.pbori + sage: wi = sr.vars('w', 1) # needs sage.rings.polynomial.pbori + sage: sr.inversion_polynomials(xi, wi, len(xi))[:3] # needs sage.rings.polynomial.pbori [x100*w100 + x100*w102 + x100*w103 + x100*w107 + x101*w101 + x101*w102 + x101*w106 + x102*w100 + x102*w101 + x102*w105 + x103*w100 + x103*w104 + x104*w103 + x105*w102 + x106*w101 + x107*w100, x100*w101 + x100*w103 + x100*w104 + x101*w100 + x101*w102 + x101*w103 + x101*w107 + x102*w101 + x102*w102 + x102*w106 + x103*w100 + x103*w101 + x103*w105 + x104*w100 + x104*w104 + x105*w103 + x106*w102 + x107*w101, x100*w102 + x100*w104 + x100*w105 + x101*w101 + x101*w103 + x101*w104 + x102*w100 + x102*w102 + x102*w103 + x102*w107 + x103*w101 + x103*w102 + x103*w106 + x104*w100 + x104*w101 + x104*w105 + x105*w100 + x105*w104 + x106*w103 + x107*w102] @@ -3228,7 +3230,7 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, sage: sr = SR_gf2_2(1, 1, 1, e) sage: P = PolynomialRing(GF(2),['x%d'%i for i in range(e)] + ['w%d'%i for i in range(e)],order='lex') sage: X,W = P.gens()[:e],P.gens()[e:] - sage: sr.inversion_polynomials_single_sbox(X, W, groebner=True) + sage: sr.inversion_polynomials_single_sbox(X, W, groebner=True) # needs sage.libs.singular [x0 + w0*w1*w2 + w0*w1 + w0*w2 + w0*w3 + w0 + w1 + w2, x1 + w0*w1*w3 + w0*w3 + w0 + w1*w3 + w1 + w2*w3, x2 + w0*w2*w3 + w0*w2 + w0 + w1*w2 + w1*w3 + w2*w3, @@ -3237,7 +3239,7 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, sage: from sage.crypto.mq.sr import SR_gf2_2 sage: e = 4 sage: sr = SR_gf2_2(1, 1, 1, e) - sage: sr.inversion_polynomials_single_sbox() + sage: sr.inversion_polynomials_single_sbox() # needs sage.libs.singular [w3*w1 + w3*w0 + w3*x2 + w3*x1 + w3 + w2*w1 + w1 + x3 + x2 + x1, w3*w2 + w3*w1 + w3*x3 + w2 + w1 + x3, w3*w2 + w3*w1 + w3*x2 + w3 + w2*x3 + x2 + x1, @@ -3270,8 +3272,8 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, sage: from sage.crypto.mq.sr import SR_gf2_2 sage: e = 4 sage: sr = SR_gf2_2(1, 1, 1, e) - sage: l = sr.inversion_polynomials_single_sbox() - sage: l == sr.inversion_polynomials_single_sbox(biaffine_only=True, correct_only=False) + sage: l = sr.inversion_polynomials_single_sbox() # needs sage.libs.singular + sage: l == sr.inversion_polynomials_single_sbox(biaffine_only=True, correct_only=False) # needs sage.libs.singular True """ diff --git a/src/sage/crypto/public_key/blum_goldwasser.py b/src/sage/crypto/public_key/blum_goldwasser.py index b3382974b15..49cbf914ce5 100644 --- a/src/sage/crypto/public_key/blum_goldwasser.py +++ b/src/sage/crypto/public_key/blum_goldwasser.py @@ -89,6 +89,7 @@ class BlumGoldwasser(PublicKeyCryptosystem): The following encryption/decryption example is taken from Example 8.57, pages 309--310 of [MvOV1996]_:: + sage: # needs sage.symbolic sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: bg = BlumGoldwasser(); bg The Blum-Goldwasser public-key encryption scheme. @@ -112,6 +113,7 @@ class BlumGoldwasser(PublicKeyCryptosystem): private key. Finally, compare the decrypted message with the original plaintext. :: + sage: # needs sage.libs.pari sage.symbolic sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: from sage.crypto.util import bin_to_ascii sage: bg = BlumGoldwasser() @@ -125,8 +127,8 @@ class BlumGoldwasser(PublicKeyCryptosystem): If `(p, q, a, b)` is a private key, then `n = pq` is the corresponding public key. Furthermore, we have `\gcd(p, q) = ap + bq = 1`. :: - sage: p, q, a, b = prikey - sage: pubkey == p * q + sage: p, q, a, b = prikey # needs sage.symbolic + sage: pubkey == p * q # needs sage.symbolic True sage: gcd(p, q) == a*p + b*q == 1 True @@ -265,24 +267,25 @@ def decrypt(self, C, K): Decrypt a longer ciphertext and convert the resulting plaintext into an ASCII string:: + sage: # needs sage.libs.pari sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: from sage.crypto.util import bin_to_ascii sage: bg = BlumGoldwasser() sage: p = 78307; q = 412487 sage: K = bg.private_key(p, q) - sage: C = ([[1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0], \ - ....: [1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1], \ - ....: [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], \ - ....: [0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1], \ - ....: [1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0], \ - ....: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1], \ - ....: [1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0], \ - ....: [1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1], \ - ....: [0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0], \ - ....: [1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1], \ - ....: [1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1], \ - ....: [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0], \ - ....: [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]], 3479653279) + sage: C = ([[1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0], + ....: [1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1], + ....: [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], + ....: [0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1], + ....: [1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0], + ....: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1], + ....: [1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0], + ....: [1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1], + ....: [0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0], + ....: [1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1], + ....: [1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1], + ....: [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0], + ....: [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]], 3479653279) sage: P = bg.decrypt(C, K) sage: bin_to_ascii(flatten(P)) 'Blum-Goldwasser encryption' @@ -416,13 +419,13 @@ def encrypt(self, P, K, seed=None): sage: bg = BlumGoldwasser() sage: p = 499; q = 547; n = p * q sage: P = "10011100000100001100" - sage: C = bg.encrypt(P, n, seed=159201); C + sage: C = bg.encrypt(P, n, seed=159201); C # needs sage.symbolic ([[0, 0, 1, 0], [0, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0]], 139680) Convert the ciphertext sub-blocks into a binary string:: sage: bin = BinaryStrings() - sage: bin(flatten(C[0])) + sage: bin(flatten(C[0])) # needs sage.symbolic 00100000110011100100 Now encrypt an ASCII string. The result is random; no seed is @@ -433,7 +436,7 @@ def encrypt(self, P, K, seed=None): sage: bg = BlumGoldwasser() sage: K = 32300619509 sage: P = "Blum-Goldwasser encryption" - sage: bg.encrypt(P, K) # random + sage: bg.encrypt(P, K) # random # needs sage.symbolic ([[1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0], \ [1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1], \ [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], \ @@ -555,9 +558,9 @@ def private_key(self, p, q): sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: from sage.crypto.util import is_blum_prime sage: bg = BlumGoldwasser() - sage: P = primes_first_n(10); P + sage: P = primes_first_n(10); P # needs sage.libs.pari [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] - sage: [is_blum_prime(_) for _ in P] + sage: [is_blum_prime(_) for _ in P] # needs sage.libs.pari [False, True, False, True, True, False, False, True, True, False] sage: bg.private_key(19, 23) (19, 23, -6, 5) @@ -567,6 +570,7 @@ def private_key(self, p, q): resulting private key `(p, q, a, b)` satisfies `\gcd(p, q) = ap + bq = 1`:: + sage: # needs sage.libs.pari sage: from sage.crypto.util import random_blum_prime sage: p = random_blum_prime(10**4, 10**5) sage: q = random_blum_prime(10**4, 10**5) @@ -629,9 +633,9 @@ def public_key(self, p, q): sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: from sage.crypto.util import is_blum_prime sage: bg = BlumGoldwasser() - sage: P = primes_first_n(10); P + sage: P = primes_first_n(10); P # needs sage.libs.pari [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] - sage: [is_blum_prime(_) for _ in P] + sage: [is_blum_prime(_) for _ in P] # needs sage.libs.pari [False, True, False, True, True, False, False, True, True, False] sage: bg.public_key(3, 7) 21 @@ -640,6 +644,7 @@ def public_key(self, p, q): public key corresponding to those two primes, and test that the public key factorizes into Blum primes:: + sage: # needs sage.libs.pari sage: from sage.crypto.util import random_blum_prime sage: p = random_blum_prime(10**4, 10**5) sage: q = random_blum_prime(10**4, 10**5) @@ -731,6 +736,7 @@ def random_key(self, lbound, ubound, ntries=100): Choosing a random pair of public and private keys. We then test to see if they satisfy the requirements of the Blum-Goldwasser scheme:: + sage: # needs sage.libs.pari sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: from sage.crypto.util import is_blum_prime sage: bg = BlumGoldwasser() @@ -755,7 +761,7 @@ def random_key(self, lbound, ubound, ntries=100): sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: bg = BlumGoldwasser() - sage: pubkey, privkey = bg.random_key(24, 30) + sage: pubkey, privkey = bg.random_key(24, 30) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: No Blum primes within the specified closed interval. diff --git a/src/sage/crypto/sbox.pyx b/src/sage/crypto/sbox.pyx index 7ca51c45934..e2a99aa718e 100644 --- a/src/sage/crypto/sbox.pyx +++ b/src/sage/crypto/sbox.pyx @@ -40,7 +40,7 @@ cdef Py_ssize_t _nterms(Py_ssize_t nvars, Py_ssize_t deg): sage: from sage.crypto.sbox import SBox sage: S = SBox(7,6,0,4,2,5,1,3) - sage: F = S.polynomials(degree=3) # indirect doctest + sage: F = S.polynomials(degree=3) # indirect doctest # needs sage.libs.singular """ cdef Py_ssize_t total = 1 cdef Py_ssize_t divisor = 1 @@ -591,7 +591,7 @@ cdef class SBox(SageObject): ... IndexError: list index out of range sage: from sage.crypto.sboxes import PRESENT - sage: PRESENT.derivative(1).max_degree() < PRESENT.max_degree() + sage: PRESENT.derivative(1).max_degree() < PRESENT.max_degree() # needs sage.rings.polynomial.pbori True """ from sage.structure.element import is_Vector @@ -859,9 +859,9 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox([7,6,0,4,2,5,1,3]) - sage: F = S.polynomials() + sage: F = S.polynomials() # needs sage.libs.singular sage: s = S.solutions() - sage: any(f.subs(_s) for f in F for _s in s) + sage: any(f.subs(_s) for f in F for _s in s) # needs sage.libs.singular False """ if X is None and Y is None: @@ -909,7 +909,7 @@ cdef class SBox(SageObject): By default, this method returns an indirect representation:: - sage: S.polynomials() + sage: S.polynomials() # needs sage.libs.singular [x0*x2 + x1 + y1 + 1, x0*x1 + x1 + x2 + y0 + y1 + y2 + 1, x0*y1 + x0 + x2 + y0 + y2, @@ -931,7 +931,7 @@ cdef class SBox(SageObject): bits are greater than the input bits:: sage: P. = PolynomialRing(GF(2),6,order='lex') - sage: S.polynomials([x0,x1,x2],[y0,y1,y2], groebner=True) + sage: S.polynomials([x0,x1,x2],[y0,y1,y2], groebner=True) # needs sage.libs.singular [y0 + x0*x1 + x0*x2 + x0 + x1*x2 + x1 + 1, y1 + x0*x2 + x1 + 1, y2 + x0 + x1*x2 + x1 + x2 + 1] @@ -1272,11 +1272,11 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox([7,6,0,4,2,5,1,3]) sage: f3 = S.component_function(3) - sage: f3.algebraic_normal_form() + sage: f3.algebraic_normal_form() # needs sage.rings.polynomial.pbori x0*x1 + x0*x2 + x0 + x2 sage: f5 = S.component_function([1, 0, 1]) - sage: f5.algebraic_normal_form() + sage: f5.algebraic_normal_form() # needs sage.rings.polynomial.pbori x0*x2 + x0 + x1*x2 """ cdef Py_ssize_t m = self.m @@ -1451,7 +1451,7 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox(7,6,0,4,2,5,1,3) - sage: S.autocorrelation_table() + sage: S.autocorrelation_table() # needs sage.combinat [ 8 8 8 8 8 8 8 8] [ 8 0 0 0 0 0 0 -8] [ 8 0 -8 0 0 0 0 0] @@ -1575,7 +1575,7 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox([0,1,3,6,7,4,5,2]) - sage: S.linear_structures() + sage: S.linear_structures() # needs sage.combinat [(1, 1, 1), (2, 2, 1), (3, 3, 1), (4, 4, 1), (5, 5, 1), (6, 6, 1), (7, 7, 1)] """ @@ -1653,7 +1653,7 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox([12,5,6,11,9,0,10,13,3,14,15,8,4,7,1,2]) - sage: S.max_degree() + sage: S.max_degree() # needs sage.rings.polynomial.pbori 3 """ ret = ZZ.zero() @@ -1673,7 +1673,7 @@ cdef class SBox(SageObject): sage: from sage.crypto.sbox import SBox sage: S = SBox([12,5,6,11,9,0,10,13,3,14,15,8,4,7,1,2]) - sage: S.min_degree() + sage: S.min_degree() # needs sage.rings.polynomial.pbori 2 """ ret = ZZ(self.m) diff --git a/src/sage/crypto/util.py b/src/sage/crypto/util.py index da298a81001..8590c83db5c 100644 --- a/src/sage/crypto/util.py +++ b/src/sage/crypto/util.py @@ -298,14 +298,14 @@ def has_blum_prime(lbound, ubound): sage: from sage.crypto.util import has_blum_prime sage: from sage.crypto.util import is_blum_prime - sage: has_blum_prime(4, 100) + sage: has_blum_prime(4, 100) # needs sage.libs.pari True sage: for n in range(4, 100): ....: if is_blum_prime(n): ....: print(n) ....: break 7 - sage: has_blum_prime(24, 28) + sage: has_blum_prime(24, 28) # needs sage.libs.pari False TESTS: @@ -378,8 +378,8 @@ def is_blum_prime(n): False sage: is_blum_prime(7) True - sage: p = random_blum_prime(10**3, 10**5) - sage: is_blum_prime(p) + sage: p = random_blum_prime(10**3, 10**5) # needs sage.libs.pari + sage: is_blum_prime(p) # needs sage.libs.pari True """ if n < 0: @@ -487,10 +487,10 @@ def random_blum_prime(lbound, ubound, ntries=100): Choose a random prime and check that it is a Blum prime:: sage: from sage.crypto.util import random_blum_prime - sage: p = random_blum_prime(10**4, 10**5) - sage: is_prime(p) + sage: p = random_blum_prime(10**4, 10**5) # needs sage.libs.pari + sage: is_prime(p) # needs sage.libs.pari True - sage: mod(p, 4) == 3 + sage: mod(p, 4) == 3 # needs sage.libs.pari True TESTS: @@ -501,11 +501,11 @@ def random_blum_prime(lbound, ubound, ntries=100): is not a Blum prime. :: sage: from sage.crypto.util import random_blum_prime - sage: random_blum_prime(24, 30, ntries=10) + sage: random_blum_prime(24, 30, ntries=10) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: No Blum primes within the specified closed interval. - sage: random_blum_prime(24, 28) + sage: random_blum_prime(24, 28) # needs sage.libs.pari Traceback (most recent call last): ... ValueError: No Blum primes within the specified closed interval. From d256d965fd9f840deb31f439326e60bf4cc889db Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 19 Aug 2023 16:02:32 -0700 Subject: [PATCH 11/15] src/sage/crypto/boolean_function.pyx: Fix imports --- src/sage/crypto/boolean_function.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index cd7c89fc944..fa99fab5ea3 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -32,6 +32,7 @@ AUTHOR: from cysignals.signals cimport sig_check from libc.string cimport memcpy +from sage.data_structures.bitset_base cimport * from sage.misc.superseded import deprecated_function_alias from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.finite_rings.finite_field_constructor import GF From 2d897bb69d096498074d686c6e645fd0a23c2d57 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 19 Aug 2023 17:23:29 -0700 Subject: [PATCH 12/15] sage.crypto: More block tags, fixup --- src/sage/crypto/classical.py | 2 +- src/sage/crypto/classical_cipher.py | 18 ++++++++++-------- src/sage/crypto/lwe.py | 14 +++++++------- src/sage/crypto/mq/rijndael_gf.py | 2 +- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/sage/crypto/classical.py b/src/sage/crypto/classical.py index 242cf881090..616dc861652 100644 --- a/src/sage/crypto/classical.py +++ b/src/sage/crypto/classical.py @@ -1435,7 +1435,7 @@ def block_length(self): return self.key_space().nrows() def random_key(self): - """ + r""" A random key within the key space of this Hill cipher. That is, generate a random `m \times m` matrix to be used as a block permutation, where `m` is the block length of this Hill cipher. If diff --git a/src/sage/crypto/classical_cipher.py b/src/sage/crypto/classical_cipher.py index 55521405fb1..e459cefd786 100644 --- a/src/sage/crypto/classical_cipher.py +++ b/src/sage/crypto/classical_cipher.py @@ -470,27 +470,29 @@ def __init__(self, parent, key): EXAMPLES:: + sage: # needs sage.groups sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,14); E # needs sage.groups + sage: E = TranspositionCryptosystem(S,14); E Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14 sage: K = [ 14-i for i in range(14) ]; K [14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] - sage: e = E(K) # needs sage.groups + sage: e = E(K) sage: m = S("THECATINTHEHAT") - sage: e(m) # needs sage.groups + sage: e(m) TAHEHTNITACEHT EXAMPLES:: + sage: # needs sage.groups sage: S = AlphabeticStrings() - sage: E = TranspositionCryptosystem(S,15) # needs sage.groups + sage: E = TranspositionCryptosystem(S,15) sage: m = S("THECATANDTHEHAT") - sage: G = E.key_space(); G # needs sage.groups + sage: G = E.key_space(); G Symmetric group of order 15! as a permutation group - sage: g = G([ 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13 ]) # needs sage.groups - sage: e = E(g) # needs sage.groups - sage: e(m) # needs sage.groups + sage: g = G([ 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13 ]) + sage: e = E(g) + sage: e(m) EHTTACDNAEHTTAH TESTS:: diff --git a/src/sage/crypto/lwe.py b/src/sage/crypto/lwe.py index 5e4687b61a0..0be1b92d77e 100644 --- a/src/sage/crypto/lwe.py +++ b/src/sage/crypto/lwe.py @@ -297,8 +297,8 @@ def __init__(self, n, q, D, secret_dist='uniform', m=None): fix the representation and recover the correct standard deviation of the noise:: - sage: from numpy import std # optional - numpy - sage: while abs(std([e if e <= 200 else e-401 for e in S()]) - 3.0) > 0.01: # optional - numpy + sage: from numpy import std # needs numpy + sage: while abs(std([e if e <= 200 else e-401 for e in S()]) - 3.0) > 0.01: # needs numpy ....: L = [] # reset L to avoid quadratic behaviour ....: add_samples() @@ -591,12 +591,12 @@ def __call__(self): sage: # needs sage.libs.pari sage: from sage.crypto.lwe import DiscreteGaussianDistributionPolynomialSampler, RingLWE sage: N = 16 - sage: n = euler_phi(N) # needs sage.libs.pari - sage: D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n, 5) # needs sage.libs.pari - sage: ringlwe = RingLWE(N, 257, D, secret_dist='uniform') # needs sage.libs.pari - sage: ringlwe()[0].parent() # needs sage.libs.pari + sage: n = euler_phi(N) + sage: D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n, 5) + sage: ringlwe = RingLWE(N, 257, D, secret_dist='uniform') + sage: ringlwe()[0].parent() Vector space of dimension 8 over Ring of integers modulo 257 - sage: ringlwe()[1].parent() # needs sage.libs.pari + sage: ringlwe()[1].parent() Vector space of dimension 8 over Ring of integers modulo 257 """ if self.m is not None: diff --git a/src/sage/crypto/mq/rijndael_gf.py b/src/sage/crypto/mq/rijndael_gf.py index c25080a2129..ba24ed0627e 100644 --- a/src/sage/crypto/mq/rijndael_gf.py +++ b/src/sage/crypto/mq/rijndael_gf.py @@ -271,7 +271,7 @@ sage: # needs sage.libs.gap sage: rcpc = rgf.compose(rgf.shift_rows_poly_constr(), - ....: rgf.mix_columns_poly_constr()); rcpc # needs sage.libs.gap + ....: rgf.mix_columns_poly_constr()); rcpc A polynomial constructor of a round component of Rijndael-GF block cipher with block length 4, key length 6, and 12 rounds. sage: rcpc(2, 1) From 2f0f2f6fb83d35021a2f5999423f6e9216542c17 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 21 Aug 2023 09:13:12 -0700 Subject: [PATCH 13/15] src/sage/crypto/lattice.py: Docstring cosmetics --- src/sage/crypto/lattice.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index e36ec122ae3..e6ff758e3df 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -50,15 +50,22 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, - ``n`` -- Determinant size, primal: `det(L) = q^n`, dual: `det(L) = q^{m-n}`. For ideal lattices this is also the degree of the quotient polynomial. + - ``m`` -- Lattice dimension, `L \subseteq Z^m`. + - ``q`` -- Coefficient size, `q-Z^m \subseteq L`. + - ``seed`` -- Randomness seed. + - ``quotient`` -- For the type ``'ideal'``, this determines the quotient polynomial. Ignored for all other types. + - ``dual`` -- Set this flag if you want a basis for `q-dual(L)`, for example for Regev's LWE bases [Reg2005]_. + - ``ntl`` -- Set this flag if you want the lattice basis in NTL readable format. + - ``lattice`` -- Set this flag if you want a :class:`FreeModule_submodule_with_basis_integer` object instead of an integer matrix representing the basis. From 826f72dba5c05ecade4e316fef314a31136e267c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 21 Aug 2023 09:14:49 -0700 Subject: [PATCH 14/15] src/sage/crypto/classical_cipher.py: Use one more block-scoped tag --- src/sage/crypto/classical_cipher.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/crypto/classical_cipher.py b/src/sage/crypto/classical_cipher.py index e459cefd786..fd2c2464293 100644 --- a/src/sage/crypto/classical_cipher.py +++ b/src/sage/crypto/classical_cipher.py @@ -169,17 +169,18 @@ def __init__(self, parent, key): EXAMPLES:: + sage: # needs sage.modules sage: S = AlphabeticStrings() - sage: E = HillCryptosystem(S,3); E # needs sage.modules + sage: E = HillCryptosystem(S,3); E Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3 - sage: M = E.key_space() # needs sage.modules - sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A # needs sage.modules + sage: M = E.key_space() + sage: A = M([[1,0,1],[0,1,1],[2,2,3]]); A [1 0 1] [0 1 1] [2 2 3] - sage: e = E(A); e # needs sage.modules + sage: e = E(A); e Hill cipher on Free alphabetic string monoid on A-Z of block length 3 - sage: e(S("LAMAISONBLANCHE")) # needs sage.modules + sage: e(S("LAMAISONBLANCHE")) JYVKSKQPELAYKPV TESTS:: From 37a6b46ba75416c083bc0eb9e16949931e96151b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 21 Aug 2023 10:33:09 -0700 Subject: [PATCH 15/15] sage -fixdoctests --long --fixed-point --only-tags src/sage/crypto --- src/sage/crypto/mq/sr.py | 2 +- src/sage/crypto/public_key/blum_goldwasser.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index ab7ad3d2c96..091ff4a96fa 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -2070,7 +2070,7 @@ def polynomial_system(self, P=None, K=None, C=None): ....: break ....: except ZeroDivisionError: ....: pass - sage: F.subs(s).groebner_basis() # long time + sage: F.subs(s).groebner_basis() # long time # needs sage.rings.polynomial.pbori Polynomial Sequence with 1248 Polynomials in 1248 Variables """ plaintext = P diff --git a/src/sage/crypto/public_key/blum_goldwasser.py b/src/sage/crypto/public_key/blum_goldwasser.py index 49cbf914ce5..1d090673400 100644 --- a/src/sage/crypto/public_key/blum_goldwasser.py +++ b/src/sage/crypto/public_key/blum_goldwasser.py @@ -130,7 +130,7 @@ class BlumGoldwasser(PublicKeyCryptosystem): sage: p, q, a, b = prikey # needs sage.symbolic sage: pubkey == p * q # needs sage.symbolic True - sage: gcd(p, q) == a*p + b*q == 1 + sage: gcd(p, q) == a*p + b*q == 1 # needs sage.symbolic True """