passagemath-modules 10.6.31rc3__cp314-cp314-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-modules might be problematic. Click here for more details.
- passagemath_modules-10.6.31rc3.dist-info/METADATA +281 -0
- passagemath_modules-10.6.31rc3.dist-info/RECORD +808 -0
- passagemath_modules-10.6.31rc3.dist-info/WHEEL +5 -0
- passagemath_modules-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_modules.libs/libgcc_s-0cd532bd.so.1 +0 -0
- passagemath_modules.libs/libgfortran-2c33b284.so.5.0.0 +0 -0
- passagemath_modules.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- passagemath_modules.libs/libgsl-42cda06f.so.28.0.0 +0 -0
- passagemath_modules.libs/libmpc-d8ebe4b5.so.3.3.1 +0 -0
- passagemath_modules.libs/libmpfr-aaecbfc0.so.6.2.1 +0 -0
- passagemath_modules.libs/libopenblasp-r0-905cb27d.3.29.so +0 -0
- passagemath_modules.libs/libquadmath-bb76a5fc.so.0.0.0 +0 -0
- sage/algebras/all__sagemath_modules.py +20 -0
- sage/algebras/catalog.py +148 -0
- sage/algebras/clifford_algebra.py +3107 -0
- sage/algebras/clifford_algebra_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/algebras/clifford_algebra_element.pxd +16 -0
- sage/algebras/clifford_algebra_element.pyx +997 -0
- sage/algebras/commutative_dga.py +4252 -0
- sage/algebras/exterior_algebra_groebner.cpython-314-x86_64-linux-musl.so +0 -0
- sage/algebras/exterior_algebra_groebner.pxd +55 -0
- sage/algebras/exterior_algebra_groebner.pyx +727 -0
- sage/algebras/finite_dimensional_algebras/all.py +2 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +1029 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd +12 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +706 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +196 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +255 -0
- sage/algebras/finite_gca.py +528 -0
- sage/algebras/group_algebra.py +232 -0
- sage/algebras/lie_algebras/abelian.py +197 -0
- sage/algebras/lie_algebras/affine_lie_algebra.py +1213 -0
- sage/algebras/lie_algebras/all.py +25 -0
- sage/algebras/lie_algebras/all__sagemath_modules.py +1 -0
- sage/algebras/lie_algebras/bch.py +177 -0
- sage/algebras/lie_algebras/bgg_dual_module.py +1184 -0
- sage/algebras/lie_algebras/bgg_resolution.py +232 -0
- sage/algebras/lie_algebras/center_uea.py +767 -0
- sage/algebras/lie_algebras/classical_lie_algebra.py +2516 -0
- sage/algebras/lie_algebras/examples.py +683 -0
- sage/algebras/lie_algebras/free_lie_algebra.py +973 -0
- sage/algebras/lie_algebras/heisenberg.py +820 -0
- sage/algebras/lie_algebras/lie_algebra.py +1562 -0
- sage/algebras/lie_algebras/lie_algebra_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/algebras/lie_algebras/lie_algebra_element.pxd +68 -0
- sage/algebras/lie_algebras/lie_algebra_element.pyx +2122 -0
- sage/algebras/lie_algebras/morphism.py +661 -0
- sage/algebras/lie_algebras/nilpotent_lie_algebra.py +457 -0
- sage/algebras/lie_algebras/onsager.py +1324 -0
- sage/algebras/lie_algebras/poincare_birkhoff_witt.py +816 -0
- sage/algebras/lie_algebras/quotient.py +462 -0
- sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py +355 -0
- sage/algebras/lie_algebras/representation.py +1040 -0
- sage/algebras/lie_algebras/structure_coefficients.py +459 -0
- sage/algebras/lie_algebras/subalgebra.py +967 -0
- sage/algebras/lie_algebras/symplectic_derivation.py +289 -0
- sage/algebras/lie_algebras/verma_module.py +1630 -0
- sage/algebras/lie_algebras/virasoro.py +1186 -0
- sage/algebras/octonion_algebra.cpython-314-x86_64-linux-musl.so +0 -0
- sage/algebras/octonion_algebra.pxd +20 -0
- sage/algebras/octonion_algebra.pyx +987 -0
- sage/algebras/orlik_solomon.py +907 -0
- sage/algebras/orlik_terao.py +779 -0
- sage/algebras/steenrod/all.py +7 -0
- sage/algebras/steenrod/steenrod_algebra.py +4258 -0
- sage/algebras/steenrod/steenrod_algebra_bases.py +1179 -0
- sage/algebras/steenrod/steenrod_algebra_misc.py +1167 -0
- sage/algebras/steenrod/steenrod_algebra_mult.py +954 -0
- sage/algebras/weyl_algebra.py +1126 -0
- sage/all__sagemath_modules.py +62 -0
- sage/calculus/all__sagemath_modules.py +19 -0
- sage/calculus/expr.py +205 -0
- sage/calculus/integration.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/integration.pyx +698 -0
- sage/calculus/interpolation.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/interpolation.pxd +13 -0
- sage/calculus/interpolation.pyx +387 -0
- sage/calculus/interpolators.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/interpolators.pyx +326 -0
- sage/calculus/ode.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/ode.pxd +5 -0
- sage/calculus/ode.pyx +610 -0
- sage/calculus/riemann.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/riemann.pyx +1521 -0
- sage/calculus/test_sympy.py +201 -0
- sage/calculus/transforms/all.py +7 -0
- sage/calculus/transforms/dft.py +844 -0
- sage/calculus/transforms/dwt.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/transforms/dwt.pxd +7 -0
- sage/calculus/transforms/dwt.pyx +160 -0
- sage/calculus/transforms/fft.cpython-314-x86_64-linux-musl.so +0 -0
- sage/calculus/transforms/fft.pxd +12 -0
- sage/calculus/transforms/fft.pyx +487 -0
- sage/calculus/wester.py +662 -0
- sage/coding/abstract_code.py +1108 -0
- sage/coding/ag_code.py +868 -0
- sage/coding/ag_code_decoders.cpython-314-x86_64-linux-musl.so +0 -0
- sage/coding/ag_code_decoders.pyx +2639 -0
- sage/coding/all.py +15 -0
- sage/coding/bch_code.py +494 -0
- sage/coding/binary_code.cpython-314-x86_64-linux-musl.so +0 -0
- sage/coding/binary_code.pxd +124 -0
- sage/coding/binary_code.pyx +4139 -0
- sage/coding/bounds_catalog.py +43 -0
- sage/coding/channel.py +819 -0
- sage/coding/channels_catalog.py +29 -0
- sage/coding/code_bounds.py +755 -0
- sage/coding/code_constructions.py +804 -0
- sage/coding/codes_catalog.py +111 -0
- sage/coding/cyclic_code.py +1329 -0
- sage/coding/databases.py +316 -0
- sage/coding/decoder.py +373 -0
- sage/coding/decoders_catalog.py +88 -0
- sage/coding/delsarte_bounds.py +709 -0
- sage/coding/encoder.py +390 -0
- sage/coding/encoders_catalog.py +64 -0
- sage/coding/extended_code.py +468 -0
- sage/coding/gabidulin_code.py +1058 -0
- sage/coding/golay_code.py +404 -0
- sage/coding/goppa_code.py +441 -0
- sage/coding/grs_code.py +2371 -0
- sage/coding/guava.py +107 -0
- sage/coding/guruswami_sudan/all.py +1 -0
- sage/coding/guruswami_sudan/gs_decoder.py +897 -0
- sage/coding/guruswami_sudan/interpolation.py +409 -0
- sage/coding/guruswami_sudan/utils.py +176 -0
- sage/coding/hamming_code.py +176 -0
- sage/coding/information_set_decoder.py +1032 -0
- sage/coding/kasami_codes.cpython-314-x86_64-linux-musl.so +0 -0
- sage/coding/kasami_codes.pyx +351 -0
- sage/coding/linear_code.py +3067 -0
- sage/coding/linear_code_no_metric.py +1354 -0
- sage/coding/linear_rank_metric.py +961 -0
- sage/coding/parity_check_code.py +353 -0
- sage/coding/punctured_code.py +719 -0
- sage/coding/reed_muller_code.py +999 -0
- sage/coding/self_dual_codes.py +942 -0
- sage/coding/source_coding/all.py +2 -0
- sage/coding/source_coding/huffman.py +553 -0
- sage/coding/subfield_subcode.py +423 -0
- sage/coding/two_weight_db.py +399 -0
- sage/combinat/all__sagemath_modules.py +7 -0
- sage/combinat/cartesian_product.py +347 -0
- sage/combinat/family.py +11 -0
- sage/combinat/free_module.py +1977 -0
- sage/combinat/root_system/all.py +147 -0
- sage/combinat/root_system/ambient_space.py +527 -0
- sage/combinat/root_system/associahedron.py +471 -0
- sage/combinat/root_system/braid_move_calculator.py +143 -0
- sage/combinat/root_system/braid_orbit.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/root_system/braid_orbit.pyx +144 -0
- sage/combinat/root_system/branching_rules.py +2301 -0
- sage/combinat/root_system/cartan_matrix.py +1245 -0
- sage/combinat/root_system/cartan_type.py +3069 -0
- sage/combinat/root_system/coxeter_group.py +162 -0
- sage/combinat/root_system/coxeter_matrix.py +1261 -0
- sage/combinat/root_system/coxeter_type.py +681 -0
- sage/combinat/root_system/dynkin_diagram.py +900 -0
- sage/combinat/root_system/extended_affine_weyl_group.py +2993 -0
- sage/combinat/root_system/fundamental_group.py +795 -0
- sage/combinat/root_system/hecke_algebra_representation.py +1203 -0
- sage/combinat/root_system/integrable_representations.py +1227 -0
- sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +1965 -0
- sage/combinat/root_system/pieri_factors.py +1147 -0
- sage/combinat/root_system/plot.py +1615 -0
- sage/combinat/root_system/root_lattice_realization_algebras.py +1214 -0
- sage/combinat/root_system/root_lattice_realizations.py +4628 -0
- sage/combinat/root_system/root_space.py +487 -0
- sage/combinat/root_system/root_system.py +882 -0
- sage/combinat/root_system/type_A.py +348 -0
- sage/combinat/root_system/type_A_affine.py +227 -0
- sage/combinat/root_system/type_A_infinity.py +241 -0
- sage/combinat/root_system/type_B.py +347 -0
- sage/combinat/root_system/type_BC_affine.py +287 -0
- sage/combinat/root_system/type_B_affine.py +216 -0
- sage/combinat/root_system/type_C.py +317 -0
- sage/combinat/root_system/type_C_affine.py +188 -0
- sage/combinat/root_system/type_D.py +357 -0
- sage/combinat/root_system/type_D_affine.py +208 -0
- sage/combinat/root_system/type_E.py +641 -0
- sage/combinat/root_system/type_E_affine.py +231 -0
- sage/combinat/root_system/type_F.py +387 -0
- sage/combinat/root_system/type_F_affine.py +137 -0
- sage/combinat/root_system/type_G.py +293 -0
- sage/combinat/root_system/type_G_affine.py +132 -0
- sage/combinat/root_system/type_H.py +105 -0
- sage/combinat/root_system/type_I.py +110 -0
- sage/combinat/root_system/type_Q.py +150 -0
- sage/combinat/root_system/type_affine.py +509 -0
- sage/combinat/root_system/type_dual.py +704 -0
- sage/combinat/root_system/type_folded.py +301 -0
- sage/combinat/root_system/type_marked.py +748 -0
- sage/combinat/root_system/type_reducible.py +601 -0
- sage/combinat/root_system/type_relabel.py +730 -0
- sage/combinat/root_system/type_super_A.py +837 -0
- sage/combinat/root_system/weight_lattice_realizations.py +1188 -0
- sage/combinat/root_system/weight_space.py +639 -0
- sage/combinat/root_system/weyl_characters.py +2238 -0
- sage/crypto/__init__.py +4 -0
- sage/crypto/all.py +28 -0
- sage/crypto/block_cipher/all.py +7 -0
- sage/crypto/block_cipher/des.py +1065 -0
- sage/crypto/block_cipher/miniaes.py +2171 -0
- sage/crypto/block_cipher/present.py +909 -0
- sage/crypto/block_cipher/sdes.py +1527 -0
- sage/crypto/boolean_function.cpython-314-x86_64-linux-musl.so +0 -0
- sage/crypto/boolean_function.pxd +10 -0
- sage/crypto/boolean_function.pyx +1487 -0
- sage/crypto/cipher.py +78 -0
- sage/crypto/classical.py +3668 -0
- sage/crypto/classical_cipher.py +569 -0
- sage/crypto/cryptosystem.py +387 -0
- sage/crypto/key_exchange/all.py +7 -0
- sage/crypto/key_exchange/catalog.py +24 -0
- sage/crypto/key_exchange/diffie_hellman.py +323 -0
- sage/crypto/key_exchange/key_exchange_scheme.py +107 -0
- sage/crypto/lattice.py +312 -0
- sage/crypto/lfsr.py +295 -0
- sage/crypto/lwe.py +840 -0
- sage/crypto/mq/__init__.py +4 -0
- sage/crypto/mq/mpolynomialsystemgenerator.py +204 -0
- sage/crypto/mq/rijndael_gf.py +2345 -0
- sage/crypto/mq/sbox.py +7 -0
- sage/crypto/mq/sr.py +3344 -0
- sage/crypto/public_key/all.py +5 -0
- sage/crypto/public_key/blum_goldwasser.py +776 -0
- sage/crypto/sbox.cpython-314-x86_64-linux-musl.so +0 -0
- sage/crypto/sbox.pyx +2090 -0
- sage/crypto/sboxes.py +2090 -0
- sage/crypto/stream.py +390 -0
- sage/crypto/stream_cipher.py +297 -0
- sage/crypto/util.py +519 -0
- sage/ext/all__sagemath_modules.py +1 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_modules.py +2 -0
- sage/ext/interpreters/wrapper_cc.cpython-314-x86_64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_cc.pxd +30 -0
- sage/ext/interpreters/wrapper_cc.pyx +252 -0
- sage/ext/interpreters/wrapper_cdf.cpython-314-x86_64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_cdf.pxd +26 -0
- sage/ext/interpreters/wrapper_cdf.pyx +245 -0
- sage/ext/interpreters/wrapper_rdf.cpython-314-x86_64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_rdf.pxd +23 -0
- sage/ext/interpreters/wrapper_rdf.pyx +221 -0
- sage/ext/interpreters/wrapper_rr.cpython-314-x86_64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_rr.pxd +28 -0
- sage/ext/interpreters/wrapper_rr.pyx +335 -0
- sage/geometry/all__sagemath_modules.py +5 -0
- sage/geometry/toric_lattice.py +1745 -0
- sage/geometry/toric_lattice_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/geometry/toric_lattice_element.pyx +432 -0
- sage/groups/abelian_gps/abelian_group.py +1925 -0
- sage/groups/abelian_gps/abelian_group_element.py +164 -0
- sage/groups/abelian_gps/all__sagemath_modules.py +5 -0
- sage/groups/abelian_gps/dual_abelian_group.py +421 -0
- sage/groups/abelian_gps/dual_abelian_group_element.py +179 -0
- sage/groups/abelian_gps/element_base.py +341 -0
- sage/groups/abelian_gps/values.py +488 -0
- sage/groups/additive_abelian/additive_abelian_group.py +476 -0
- sage/groups/additive_abelian/additive_abelian_wrapper.py +857 -0
- sage/groups/additive_abelian/all.py +4 -0
- sage/groups/additive_abelian/qmodnz.py +231 -0
- sage/groups/additive_abelian/qmodnz_element.py +349 -0
- sage/groups/affine_gps/affine_group.py +535 -0
- sage/groups/affine_gps/all.py +1 -0
- sage/groups/affine_gps/catalog.py +17 -0
- sage/groups/affine_gps/euclidean_group.py +246 -0
- sage/groups/affine_gps/group_element.py +562 -0
- sage/groups/all__sagemath_modules.py +12 -0
- sage/groups/galois_group.py +479 -0
- sage/groups/matrix_gps/all.py +4 -0
- sage/groups/matrix_gps/all__sagemath_modules.py +13 -0
- sage/groups/matrix_gps/catalog.py +26 -0
- sage/groups/matrix_gps/coxeter_group.py +927 -0
- sage/groups/matrix_gps/finitely_generated.py +487 -0
- sage/groups/matrix_gps/group_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/groups/matrix_gps/group_element.pxd +11 -0
- sage/groups/matrix_gps/group_element.pyx +431 -0
- sage/groups/matrix_gps/linear.py +440 -0
- sage/groups/matrix_gps/matrix_group.py +617 -0
- sage/groups/matrix_gps/named_group.py +296 -0
- sage/groups/matrix_gps/orthogonal.py +544 -0
- sage/groups/matrix_gps/symplectic.py +251 -0
- sage/groups/matrix_gps/unitary.py +436 -0
- sage/groups/misc_gps/all__sagemath_modules.py +1 -0
- sage/groups/misc_gps/argument_groups.py +1905 -0
- sage/groups/misc_gps/imaginary_groups.py +479 -0
- sage/groups/perm_gps/all__sagemath_modules.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_modules.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.cpython-314-x86_64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.pxd +41 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.pyx +1167 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.cpython-314-x86_64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.pxd +31 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.pyx +385 -0
- sage/homology/algebraic_topological_model.py +595 -0
- sage/homology/all.py +2 -0
- sage/homology/all__sagemath_modules.py +8 -0
- sage/homology/chain_complex.py +2148 -0
- sage/homology/chain_complex_homspace.py +165 -0
- sage/homology/chain_complex_morphism.py +629 -0
- sage/homology/chain_homotopy.py +604 -0
- sage/homology/chains.py +653 -0
- sage/homology/free_resolution.py +923 -0
- sage/homology/graded_resolution.py +567 -0
- sage/homology/hochschild_complex.py +756 -0
- sage/homology/homology_group.py +188 -0
- sage/homology/homology_morphism.py +422 -0
- sage/homology/homology_vector_space_with_basis.py +1454 -0
- sage/homology/koszul_complex.py +169 -0
- sage/homology/matrix_utils.py +205 -0
- sage/libs/all__sagemath_modules.py +1 -0
- sage/libs/gsl/__init__.py +1 -0
- sage/libs/gsl/airy.pxd +56 -0
- sage/libs/gsl/all.pxd +66 -0
- sage/libs/gsl/array.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/gsl/array.pxd +5 -0
- sage/libs/gsl/array.pyx +102 -0
- sage/libs/gsl/bessel.pxd +208 -0
- sage/libs/gsl/blas.pxd +116 -0
- sage/libs/gsl/blas_types.pxd +34 -0
- sage/libs/gsl/block.pxd +52 -0
- sage/libs/gsl/chebyshev.pxd +37 -0
- sage/libs/gsl/clausen.pxd +12 -0
- sage/libs/gsl/combination.pxd +47 -0
- sage/libs/gsl/complex.pxd +151 -0
- sage/libs/gsl/coulomb.pxd +30 -0
- sage/libs/gsl/coupling.pxd +21 -0
- sage/libs/gsl/dawson.pxd +12 -0
- sage/libs/gsl/debye.pxd +24 -0
- sage/libs/gsl/dilog.pxd +14 -0
- sage/libs/gsl/eigen.pxd +46 -0
- sage/libs/gsl/elementary.pxd +12 -0
- sage/libs/gsl/ellint.pxd +48 -0
- sage/libs/gsl/elljac.pxd +8 -0
- sage/libs/gsl/erf.pxd +32 -0
- sage/libs/gsl/errno.pxd +26 -0
- sage/libs/gsl/exp.pxd +44 -0
- sage/libs/gsl/expint.pxd +44 -0
- sage/libs/gsl/fermi_dirac.pxd +44 -0
- sage/libs/gsl/fft.pxd +121 -0
- sage/libs/gsl/fit.pxd +50 -0
- sage/libs/gsl/gamma.pxd +94 -0
- sage/libs/gsl/gegenbauer.pxd +26 -0
- sage/libs/gsl/histogram.pxd +176 -0
- sage/libs/gsl/hyperg.pxd +52 -0
- sage/libs/gsl/integration.pxd +69 -0
- sage/libs/gsl/interp.pxd +109 -0
- sage/libs/gsl/laguerre.pxd +24 -0
- sage/libs/gsl/lambert.pxd +16 -0
- sage/libs/gsl/legendre.pxd +90 -0
- sage/libs/gsl/linalg.pxd +185 -0
- sage/libs/gsl/log.pxd +26 -0
- sage/libs/gsl/math.pxd +43 -0
- sage/libs/gsl/matrix.pxd +143 -0
- sage/libs/gsl/matrix_complex.pxd +130 -0
- sage/libs/gsl/min.pxd +67 -0
- sage/libs/gsl/monte.pxd +56 -0
- sage/libs/gsl/ntuple.pxd +32 -0
- sage/libs/gsl/odeiv.pxd +70 -0
- sage/libs/gsl/permutation.pxd +78 -0
- sage/libs/gsl/poly.pxd +40 -0
- sage/libs/gsl/pow_int.pxd +12 -0
- sage/libs/gsl/psi.pxd +28 -0
- sage/libs/gsl/qrng.pxd +29 -0
- sage/libs/gsl/random.pxd +257 -0
- sage/libs/gsl/rng.pxd +100 -0
- sage/libs/gsl/roots.pxd +72 -0
- sage/libs/gsl/sort.pxd +36 -0
- sage/libs/gsl/statistics.pxd +59 -0
- sage/libs/gsl/sum.pxd +55 -0
- sage/libs/gsl/synchrotron.pxd +16 -0
- sage/libs/gsl/transport.pxd +24 -0
- sage/libs/gsl/trig.pxd +58 -0
- sage/libs/gsl/types.pxd +137 -0
- sage/libs/gsl/vector.pxd +101 -0
- sage/libs/gsl/vector_complex.pxd +83 -0
- sage/libs/gsl/wavelet.pxd +49 -0
- sage/libs/gsl/zeta.pxd +28 -0
- sage/libs/mpc/__init__.pxd +114 -0
- sage/libs/mpc/types.pxd +28 -0
- sage/libs/mpfr/__init__.pxd +299 -0
- sage/libs/mpfr/types.pxd +26 -0
- sage/libs/mpmath/__init__.py +1 -0
- sage/libs/mpmath/all.py +27 -0
- sage/libs/mpmath/all__sagemath_modules.py +1 -0
- sage/libs/mpmath/utils.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/mpmath/utils.pxd +4 -0
- sage/libs/mpmath/utils.pyx +319 -0
- sage/matrix/action.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/action.pxd +26 -0
- sage/matrix/action.pyx +596 -0
- sage/matrix/all.py +9 -0
- sage/matrix/args.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/args.pxd +144 -0
- sage/matrix/args.pyx +1668 -0
- sage/matrix/benchmark.py +1258 -0
- sage/matrix/berlekamp_massey.py +95 -0
- sage/matrix/compute_J_ideal.py +926 -0
- sage/matrix/constructor.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/constructor.pyx +750 -0
- sage/matrix/docs.py +430 -0
- sage/matrix/echelon_matrix.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/echelon_matrix.pyx +155 -0
- sage/matrix/matrix.pxd +2 -0
- sage/matrix/matrix0.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix0.pxd +68 -0
- sage/matrix/matrix0.pyx +6324 -0
- sage/matrix/matrix1.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix1.pxd +8 -0
- sage/matrix/matrix1.pyx +2851 -0
- sage/matrix/matrix2.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix2.pxd +25 -0
- sage/matrix/matrix2.pyx +20181 -0
- sage/matrix/matrix_cdv.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_cdv.pxd +4 -0
- sage/matrix/matrix_cdv.pyx +93 -0
- sage/matrix/matrix_complex_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_complex_double_dense.pxd +5 -0
- sage/matrix/matrix_complex_double_dense.pyx +98 -0
- sage/matrix/matrix_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_dense.pxd +5 -0
- sage/matrix/matrix_dense.pyx +343 -0
- sage/matrix/matrix_domain_dense.pxd +5 -0
- sage/matrix/matrix_domain_sparse.pxd +5 -0
- sage/matrix/matrix_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_double_dense.pxd +7 -0
- sage/matrix/matrix_double_dense.pyx +3906 -0
- sage/matrix/matrix_double_sparse.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_double_sparse.pxd +6 -0
- sage/matrix/matrix_double_sparse.pyx +248 -0
- sage/matrix/matrix_generic_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_generic_dense.pxd +7 -0
- sage/matrix/matrix_generic_dense.pyx +354 -0
- sage/matrix/matrix_generic_sparse.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_generic_sparse.pxd +7 -0
- sage/matrix/matrix_generic_sparse.pyx +461 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.pxd +5 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.pyx +115 -0
- sage/matrix/matrix_misc.py +313 -0
- sage/matrix/matrix_numpy_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_numpy_dense.pxd +14 -0
- sage/matrix/matrix_numpy_dense.pyx +450 -0
- sage/matrix/matrix_numpy_integer_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_numpy_integer_dense.pxd +7 -0
- sage/matrix/matrix_numpy_integer_dense.pyx +59 -0
- sage/matrix/matrix_polynomial_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_polynomial_dense.pxd +5 -0
- sage/matrix/matrix_polynomial_dense.pyx +5341 -0
- sage/matrix/matrix_real_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_real_double_dense.pxd +7 -0
- sage/matrix/matrix_real_double_dense.pyx +122 -0
- sage/matrix/matrix_space.py +2848 -0
- sage/matrix/matrix_sparse.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_sparse.pxd +5 -0
- sage/matrix/matrix_sparse.pyx +1222 -0
- sage/matrix/matrix_window.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_window.pxd +37 -0
- sage/matrix/matrix_window.pyx +242 -0
- sage/matrix/misc_mpfr.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/misc_mpfr.pyx +80 -0
- sage/matrix/operation_table.py +1182 -0
- sage/matrix/special.py +3666 -0
- sage/matrix/strassen.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matrix/strassen.pyx +851 -0
- sage/matrix/symplectic_basis.py +541 -0
- sage/matrix/template.pxd +6 -0
- sage/matrix/tests.py +71 -0
- sage/matroids/advanced.py +77 -0
- sage/matroids/all.py +13 -0
- sage/matroids/basis_exchange_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/basis_exchange_matroid.pxd +96 -0
- sage/matroids/basis_exchange_matroid.pyx +2344 -0
- sage/matroids/basis_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/basis_matroid.pxd +45 -0
- sage/matroids/basis_matroid.pyx +1217 -0
- sage/matroids/catalog.py +44 -0
- sage/matroids/chow_ring.py +473 -0
- sage/matroids/chow_ring_ideal.py +849 -0
- sage/matroids/circuit_closures_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/circuit_closures_matroid.pxd +16 -0
- sage/matroids/circuit_closures_matroid.pyx +559 -0
- sage/matroids/circuits_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/circuits_matroid.pxd +38 -0
- sage/matroids/circuits_matroid.pyx +947 -0
- sage/matroids/constructor.py +1086 -0
- sage/matroids/database_collections.py +365 -0
- sage/matroids/database_matroids.py +5338 -0
- sage/matroids/dual_matroid.py +583 -0
- sage/matroids/extension.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/extension.pxd +34 -0
- sage/matroids/extension.pyx +519 -0
- sage/matroids/flats_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/flats_matroid.pxd +28 -0
- sage/matroids/flats_matroid.pyx +715 -0
- sage/matroids/gammoid.py +600 -0
- sage/matroids/graphic_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/graphic_matroid.pxd +39 -0
- sage/matroids/graphic_matroid.pyx +2024 -0
- sage/matroids/lean_matrix.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/lean_matrix.pxd +126 -0
- sage/matroids/lean_matrix.pyx +3667 -0
- sage/matroids/linear_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/linear_matroid.pxd +180 -0
- sage/matroids/linear_matroid.pyx +6649 -0
- sage/matroids/matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/matroid.pxd +243 -0
- sage/matroids/matroid.pyx +8759 -0
- sage/matroids/matroids_catalog.py +190 -0
- sage/matroids/matroids_plot_helpers.py +890 -0
- sage/matroids/minor_matroid.py +480 -0
- sage/matroids/minorfix.h +9 -0
- sage/matroids/named_matroids.py +5 -0
- sage/matroids/rank_matroid.py +268 -0
- sage/matroids/set_system.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/set_system.pxd +38 -0
- sage/matroids/set_system.pyx +800 -0
- sage/matroids/transversal_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/transversal_matroid.pxd +14 -0
- sage/matroids/transversal_matroid.pyx +893 -0
- sage/matroids/union_matroid.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/union_matroid.pxd +20 -0
- sage/matroids/union_matroid.pyx +331 -0
- sage/matroids/unpickling.cpython-314-x86_64-linux-musl.so +0 -0
- sage/matroids/unpickling.pyx +843 -0
- sage/matroids/utilities.py +809 -0
- sage/misc/all__sagemath_modules.py +20 -0
- sage/misc/c3.cpython-314-x86_64-linux-musl.so +0 -0
- sage/misc/c3.pyx +238 -0
- sage/misc/compat.py +87 -0
- sage/misc/element_with_label.py +173 -0
- sage/misc/func_persist.py +79 -0
- sage/misc/pickle_old.cpython-314-x86_64-linux-musl.so +0 -0
- sage/misc/pickle_old.pyx +19 -0
- sage/misc/proof.py +7 -0
- sage/misc/replace_dot_all.py +472 -0
- sage/misc/sagedoc_conf.py +168 -0
- sage/misc/sphinxify.py +167 -0
- sage/misc/test_class_pickling.py +85 -0
- sage/modules/all.py +42 -0
- sage/modules/complex_double_vector.py +25 -0
- sage/modules/diamond_cutting.py +380 -0
- sage/modules/fg_pid/all.py +1 -0
- sage/modules/fg_pid/fgp_element.py +456 -0
- sage/modules/fg_pid/fgp_module.py +2091 -0
- sage/modules/fg_pid/fgp_morphism.py +550 -0
- sage/modules/filtered_vector_space.py +1271 -0
- sage/modules/finite_submodule_iter.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/finite_submodule_iter.pxd +27 -0
- sage/modules/finite_submodule_iter.pyx +452 -0
- sage/modules/fp_graded/all.py +1 -0
- sage/modules/fp_graded/element.py +346 -0
- sage/modules/fp_graded/free_element.py +298 -0
- sage/modules/fp_graded/free_homspace.py +53 -0
- sage/modules/fp_graded/free_module.py +1060 -0
- sage/modules/fp_graded/free_morphism.py +217 -0
- sage/modules/fp_graded/homspace.py +563 -0
- sage/modules/fp_graded/module.py +1340 -0
- sage/modules/fp_graded/morphism.py +1990 -0
- sage/modules/fp_graded/steenrod/all.py +1 -0
- sage/modules/fp_graded/steenrod/homspace.py +65 -0
- sage/modules/fp_graded/steenrod/module.py +477 -0
- sage/modules/fp_graded/steenrod/morphism.py +404 -0
- sage/modules/fp_graded/steenrod/profile.py +241 -0
- sage/modules/free_module.py +8447 -0
- sage/modules/free_module_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/free_module_element.pxd +22 -0
- sage/modules/free_module_element.pyx +5445 -0
- sage/modules/free_module_homspace.py +369 -0
- sage/modules/free_module_integer.py +896 -0
- sage/modules/free_module_morphism.py +823 -0
- sage/modules/free_module_pseudohomspace.py +352 -0
- sage/modules/free_module_pseudomorphism.py +578 -0
- sage/modules/free_quadratic_module.py +1706 -0
- sage/modules/free_quadratic_module_integer_symmetric.py +1790 -0
- sage/modules/matrix_morphism.py +1745 -0
- sage/modules/misc.py +103 -0
- sage/modules/module_functors.py +192 -0
- sage/modules/multi_filtered_vector_space.py +719 -0
- sage/modules/ore_module.py +2208 -0
- sage/modules/ore_module_element.py +178 -0
- sage/modules/ore_module_homspace.py +147 -0
- sage/modules/ore_module_morphism.py +968 -0
- sage/modules/quotient_module.py +699 -0
- sage/modules/real_double_vector.py +22 -0
- sage/modules/submodule.py +255 -0
- sage/modules/tensor_operations.py +567 -0
- sage/modules/torsion_quadratic_module.py +1352 -0
- sage/modules/tutorial_free_modules.py +248 -0
- sage/modules/vector_complex_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_complex_double_dense.pxd +6 -0
- sage/modules/vector_complex_double_dense.pyx +117 -0
- sage/modules/vector_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_double_dense.pxd +6 -0
- sage/modules/vector_double_dense.pyx +604 -0
- sage/modules/vector_integer_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_integer_dense.pxd +15 -0
- sage/modules/vector_integer_dense.pyx +361 -0
- sage/modules/vector_integer_sparse.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_integer_sparse.pxd +29 -0
- sage/modules/vector_integer_sparse.pyx +406 -0
- sage/modules/vector_modn_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_modn_dense.pxd +12 -0
- sage/modules/vector_modn_dense.pyx +394 -0
- sage/modules/vector_modn_sparse.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_modn_sparse.pxd +21 -0
- sage/modules/vector_modn_sparse.pyx +298 -0
- sage/modules/vector_numpy_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_numpy_dense.pxd +15 -0
- sage/modules/vector_numpy_dense.pyx +304 -0
- sage/modules/vector_numpy_integer_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_numpy_integer_dense.pxd +7 -0
- sage/modules/vector_numpy_integer_dense.pyx +54 -0
- sage/modules/vector_rational_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_rational_dense.pxd +15 -0
- sage/modules/vector_rational_dense.pyx +387 -0
- sage/modules/vector_rational_sparse.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_rational_sparse.pxd +30 -0
- sage/modules/vector_rational_sparse.pyx +413 -0
- sage/modules/vector_real_double_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/vector_real_double_dense.pxd +6 -0
- sage/modules/vector_real_double_dense.pyx +126 -0
- sage/modules/vector_space_homspace.py +430 -0
- sage/modules/vector_space_morphism.py +989 -0
- sage/modules/with_basis/all.py +15 -0
- sage/modules/with_basis/cell_module.py +494 -0
- sage/modules/with_basis/indexed_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/modules/with_basis/indexed_element.pxd +13 -0
- sage/modules/with_basis/indexed_element.pyx +1058 -0
- sage/modules/with_basis/invariant.py +1075 -0
- sage/modules/with_basis/morphism.py +1636 -0
- sage/modules/with_basis/representation.py +2939 -0
- sage/modules/with_basis/subquotient.py +685 -0
- sage/numerical/all__sagemath_modules.py +6 -0
- sage/numerical/gauss_legendre.cpython-314-x86_64-linux-musl.so +0 -0
- sage/numerical/gauss_legendre.pyx +381 -0
- sage/numerical/optimize.py +910 -0
- sage/probability/all.py +10 -0
- sage/probability/probability_distribution.cpython-314-x86_64-linux-musl.so +0 -0
- sage/probability/probability_distribution.pyx +1242 -0
- sage/probability/random_variable.py +411 -0
- sage/quadratic_forms/all.py +4 -0
- sage/quadratic_forms/all__sagemath_modules.py +15 -0
- sage/quadratic_forms/binary_qf.py +2042 -0
- sage/quadratic_forms/bqf_class_group.py +748 -0
- sage/quadratic_forms/constructions.py +93 -0
- sage/quadratic_forms/count_local_2.cpython-314-x86_64-linux-musl.so +0 -0
- sage/quadratic_forms/count_local_2.pyx +365 -0
- sage/quadratic_forms/extras.py +195 -0
- sage/quadratic_forms/quadratic_form.py +1753 -0
- sage/quadratic_forms/quadratic_form__count_local_2.py +221 -0
- sage/quadratic_forms/quadratic_form__equivalence_testing.py +708 -0
- sage/quadratic_forms/quadratic_form__evaluate.cpython-314-x86_64-linux-musl.so +0 -0
- sage/quadratic_forms/quadratic_form__evaluate.pyx +139 -0
- sage/quadratic_forms/quadratic_form__local_density_congruence.py +977 -0
- sage/quadratic_forms/quadratic_form__local_field_invariants.py +1072 -0
- sage/quadratic_forms/quadratic_form__neighbors.py +424 -0
- sage/quadratic_forms/quadratic_form__reduction_theory.py +488 -0
- sage/quadratic_forms/quadratic_form__split_local_covering.py +416 -0
- sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +657 -0
- sage/quadratic_forms/quadratic_form__theta.py +352 -0
- sage/quadratic_forms/quadratic_form__variable_substitutions.py +370 -0
- sage/quadratic_forms/random_quadraticform.py +209 -0
- sage/quadratic_forms/ternary.cpython-314-x86_64-linux-musl.so +0 -0
- sage/quadratic_forms/ternary.pyx +1154 -0
- sage/quadratic_forms/ternary_qf.py +2027 -0
- sage/rings/all__sagemath_modules.py +28 -0
- sage/rings/asymptotic/all__sagemath_modules.py +1 -0
- sage/rings/asymptotic/misc.py +1252 -0
- sage/rings/cc.py +4 -0
- sage/rings/cfinite_sequence.py +1306 -0
- sage/rings/complex_conversion.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/complex_conversion.pxd +8 -0
- sage/rings/complex_conversion.pyx +23 -0
- sage/rings/complex_double.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/complex_double.pxd +21 -0
- sage/rings/complex_double.pyx +2654 -0
- sage/rings/complex_mpc.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/complex_mpc.pxd +21 -0
- sage/rings/complex_mpc.pyx +2576 -0
- sage/rings/complex_mpfr.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/complex_mpfr.pxd +18 -0
- sage/rings/complex_mpfr.pyx +3602 -0
- sage/rings/derivation.py +2334 -0
- sage/rings/finite_rings/all__sagemath_modules.py +1 -0
- sage/rings/finite_rings/maps_finite_field.py +191 -0
- sage/rings/function_field/all__sagemath_modules.py +8 -0
- sage/rings/function_field/derivations.py +102 -0
- sage/rings/function_field/derivations_rational.py +132 -0
- sage/rings/function_field/differential.py +853 -0
- sage/rings/function_field/divisor.py +1107 -0
- sage/rings/function_field/drinfeld_modules/action.py +199 -0
- sage/rings/function_field/drinfeld_modules/all.py +1 -0
- sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +673 -0
- sage/rings/function_field/drinfeld_modules/drinfeld_module.py +2087 -0
- sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +1131 -0
- sage/rings/function_field/drinfeld_modules/homset.py +420 -0
- sage/rings/function_field/drinfeld_modules/morphism.py +820 -0
- sage/rings/function_field/hermite_form_polynomial.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/function_field/hermite_form_polynomial.pyx +188 -0
- sage/rings/function_field/khuri_makdisi.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/function_field/khuri_makdisi.pyx +935 -0
- sage/rings/invariants/all.py +4 -0
- sage/rings/invariants/invariant_theory.py +4597 -0
- sage/rings/invariants/reconstruction.py +395 -0
- sage/rings/polynomial/all__sagemath_modules.py +17 -0
- sage/rings/polynomial/integer_valued_polynomials.py +1230 -0
- sage/rings/polynomial/laurent_polynomial_mpair.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/polynomial/laurent_polynomial_mpair.pxd +15 -0
- sage/rings/polynomial/laurent_polynomial_mpair.pyx +2023 -0
- sage/rings/polynomial/ore_function_element.py +952 -0
- sage/rings/polynomial/ore_function_field.py +1028 -0
- sage/rings/polynomial/ore_polynomial_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/polynomial/ore_polynomial_element.pxd +48 -0
- sage/rings/polynomial/ore_polynomial_element.pyx +3145 -0
- sage/rings/polynomial/ore_polynomial_ring.py +1334 -0
- sage/rings/polynomial/polynomial_real_mpfr_dense.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +788 -0
- sage/rings/polynomial/q_integer_valued_polynomials.py +1264 -0
- sage/rings/polynomial/skew_polynomial_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/polynomial/skew_polynomial_element.pxd +9 -0
- sage/rings/polynomial/skew_polynomial_element.pyx +684 -0
- sage/rings/polynomial/skew_polynomial_finite_field.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pxd +19 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pyx +1093 -0
- sage/rings/polynomial/skew_polynomial_finite_order.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pxd +10 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pyx +567 -0
- sage/rings/polynomial/skew_polynomial_ring.py +908 -0
- sage/rings/real_double_element_gsl.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/real_double_element_gsl.pxd +8 -0
- sage/rings/real_double_element_gsl.pyx +794 -0
- sage/rings/real_field.py +58 -0
- sage/rings/real_mpfr.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/real_mpfr.pxd +29 -0
- sage/rings/real_mpfr.pyx +6122 -0
- sage/rings/ring_extension.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/ring_extension.pxd +42 -0
- sage/rings/ring_extension.pyx +2779 -0
- sage/rings/ring_extension_conversion.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/ring_extension_conversion.pxd +16 -0
- sage/rings/ring_extension_conversion.pyx +462 -0
- sage/rings/ring_extension_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/ring_extension_element.pxd +21 -0
- sage/rings/ring_extension_element.pyx +1635 -0
- sage/rings/ring_extension_homset.py +64 -0
- sage/rings/ring_extension_morphism.cpython-314-x86_64-linux-musl.so +0 -0
- sage/rings/ring_extension_morphism.pxd +35 -0
- sage/rings/ring_extension_morphism.pyx +920 -0
- sage/schemes/all__sagemath_modules.py +1 -0
- sage/schemes/projective/all__sagemath_modules.py +1 -0
- sage/schemes/projective/coherent_sheaf.py +300 -0
- sage/schemes/projective/cohomology.py +510 -0
- sage/stats/all.py +15 -0
- sage/stats/basic_stats.py +489 -0
- sage/stats/distributions/all.py +7 -0
- sage/stats/distributions/catalog.py +34 -0
- sage/stats/distributions/dgs.h +50 -0
- sage/stats/distributions/dgs.pxd +111 -0
- sage/stats/distributions/dgs_bern.h +400 -0
- sage/stats/distributions/dgs_gauss.h +614 -0
- sage/stats/distributions/dgs_misc.h +104 -0
- sage/stats/distributions/discrete_gaussian_integer.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/distributions/discrete_gaussian_integer.pxd +14 -0
- sage/stats/distributions/discrete_gaussian_integer.pyx +498 -0
- sage/stats/distributions/discrete_gaussian_lattice.py +908 -0
- sage/stats/distributions/discrete_gaussian_polynomial.py +141 -0
- sage/stats/hmm/all.py +15 -0
- sage/stats/hmm/chmm.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/hmm/chmm.pyx +1595 -0
- sage/stats/hmm/distributions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/hmm/distributions.pxd +29 -0
- sage/stats/hmm/distributions.pyx +531 -0
- sage/stats/hmm/hmm.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/hmm/hmm.pxd +17 -0
- sage/stats/hmm/hmm.pyx +1388 -0
- sage/stats/hmm/util.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/hmm/util.pxd +7 -0
- sage/stats/hmm/util.pyx +165 -0
- sage/stats/intlist.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/intlist.pxd +14 -0
- sage/stats/intlist.pyx +588 -0
- sage/stats/r.py +49 -0
- sage/stats/time_series.cpython-314-x86_64-linux-musl.so +0 -0
- sage/stats/time_series.pxd +6 -0
- sage/stats/time_series.pyx +2546 -0
- sage/tensor/all.py +2 -0
- sage/tensor/modules/all.py +8 -0
- sage/tensor/modules/alternating_contr_tensor.py +761 -0
- sage/tensor/modules/comp.py +5598 -0
- sage/tensor/modules/ext_pow_free_module.py +824 -0
- sage/tensor/modules/finite_rank_free_module.py +3589 -0
- sage/tensor/modules/format_utilities.py +333 -0
- sage/tensor/modules/free_module_alt_form.py +858 -0
- sage/tensor/modules/free_module_automorphism.py +1207 -0
- sage/tensor/modules/free_module_basis.py +1074 -0
- sage/tensor/modules/free_module_element.py +284 -0
- sage/tensor/modules/free_module_homset.py +652 -0
- sage/tensor/modules/free_module_linear_group.py +564 -0
- sage/tensor/modules/free_module_morphism.py +1581 -0
- sage/tensor/modules/free_module_tensor.py +3289 -0
- sage/tensor/modules/reflexive_module.py +386 -0
- sage/tensor/modules/tensor_free_module.py +780 -0
- sage/tensor/modules/tensor_free_submodule.py +538 -0
- sage/tensor/modules/tensor_free_submodule_basis.py +140 -0
- sage/tensor/modules/tensor_with_indices.py +1043 -0
sage/crypto/mq/sr.py
ADDED
|
@@ -0,0 +1,3344 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-modules
|
|
2
|
+
# sage.doctest: needs sage.modules sage.rings.finite_rings
|
|
3
|
+
r"""
|
|
4
|
+
Small Scale Variants of the AES (SR) Polynomial System Generator
|
|
5
|
+
|
|
6
|
+
Sage supports polynomial system generation for small scale (and full
|
|
7
|
+
scale) AES variants over `\GF{2}` and `\GF{2^e}`. Also, Sage supports
|
|
8
|
+
both the specification of SR as given in the papers [CMR2005]_ and
|
|
9
|
+
[CMR2006]_ and a variant of SR* which is equivalent to AES.
|
|
10
|
+
|
|
11
|
+
SR is a family of parameterizable variants of the AES suitable as a
|
|
12
|
+
framework for comparing different cryptanalytic techniques that can be
|
|
13
|
+
brought to bear on the AES. It is different from
|
|
14
|
+
:class:`Mini-AES <sage.crypto.block_cipher.miniaes.MiniAES>`, whose
|
|
15
|
+
purpose is as a teaching tool to help beginners understand the basic
|
|
16
|
+
structure and working of the full AES.
|
|
17
|
+
|
|
18
|
+
AUTHORS:
|
|
19
|
+
|
|
20
|
+
- Martin Albrecht (2008,2009-01): usability improvements
|
|
21
|
+
|
|
22
|
+
- Martin Albrecht (2007-09): initial version
|
|
23
|
+
|
|
24
|
+
- Niles Johnson (2010-08): (:issue:`3893`) ``random_element()`` should pass on ``*args`` and ``**kwds``.
|
|
25
|
+
|
|
26
|
+
EXAMPLES:
|
|
27
|
+
|
|
28
|
+
We construct SR(1,1,1,4) and study its properties.
|
|
29
|
+
::
|
|
30
|
+
|
|
31
|
+
sage: sr = mq.SR(1, 1, 1, 4)
|
|
32
|
+
|
|
33
|
+
``n`` is the number of rounds, ``r`` the number of rows in the
|
|
34
|
+
state array, ``c`` the number of columns in the state array, and ``e`` the
|
|
35
|
+
degree of the underlying field.
|
|
36
|
+
|
|
37
|
+
::
|
|
38
|
+
|
|
39
|
+
sage: sr.n, sr.r, sr.c, sr.e
|
|
40
|
+
(1, 1, 1, 4)
|
|
41
|
+
|
|
42
|
+
By default variables are ordered reverse to as they appear, e.g.::
|
|
43
|
+
|
|
44
|
+
sage: print(sr.R.repr_long())
|
|
45
|
+
Polynomial Ring
|
|
46
|
+
Base Ring : Finite Field in a of size 2^4
|
|
47
|
+
Size : 20 Variables
|
|
48
|
+
Block 0 : Ordering : deglex
|
|
49
|
+
Names : k100, k101, k102, k103, x100, x101, x102, x103, w100, w101, w102, w103, s000, s001, s002, s003, k000, k001, k002, k003
|
|
50
|
+
|
|
51
|
+
However, this can be prevented by passing in ``reverse_variables=False`` to the constructor.
|
|
52
|
+
|
|
53
|
+
For SR(1, 1, 1, 4) the ``ShiftRows`` matrix isn't that interesting.::
|
|
54
|
+
|
|
55
|
+
sage: sr.ShiftRows
|
|
56
|
+
[1 0 0 0]
|
|
57
|
+
[0 1 0 0]
|
|
58
|
+
[0 0 1 0]
|
|
59
|
+
[0 0 0 1]
|
|
60
|
+
|
|
61
|
+
Also, the ``MixColumns`` matrix is the identity matrix.::
|
|
62
|
+
|
|
63
|
+
sage: sr.MixColumns
|
|
64
|
+
[1 0 0 0]
|
|
65
|
+
[0 1 0 0]
|
|
66
|
+
[0 0 1 0]
|
|
67
|
+
[0 0 0 1]
|
|
68
|
+
|
|
69
|
+
``Lin``, however, is not the identity matrix.::
|
|
70
|
+
|
|
71
|
+
sage: sr.Lin
|
|
72
|
+
[ a^2 + 1 1 a^3 + a^2 a^2 + 1]
|
|
73
|
+
[ a a 1 a^3 + a^2 + a + 1]
|
|
74
|
+
[ a^3 + a a^2 a^2 1]
|
|
75
|
+
[ 1 a^3 a + 1 a + 1]
|
|
76
|
+
|
|
77
|
+
``M`` and ``Mstar`` are identical for SR(1, 1, 1, 4)::
|
|
78
|
+
|
|
79
|
+
sage: sr.M
|
|
80
|
+
[ a^2 + 1 1 a^3 + a^2 a^2 + 1]
|
|
81
|
+
[ a a 1 a^3 + a^2 + a + 1]
|
|
82
|
+
[ a^3 + a a^2 a^2 1]
|
|
83
|
+
[ 1 a^3 a + 1 a + 1]
|
|
84
|
+
|
|
85
|
+
::
|
|
86
|
+
|
|
87
|
+
sage: sr.Mstar
|
|
88
|
+
[ a^2 + 1 1 a^3 + a^2 a^2 + 1]
|
|
89
|
+
[ a a 1 a^3 + a^2 + a + 1]
|
|
90
|
+
[ a^3 + a a^2 a^2 1]
|
|
91
|
+
[ 1 a^3 a + 1 a + 1]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
However, for larger instances of SR Mstar is not equal to M::
|
|
95
|
+
|
|
96
|
+
sage: sr = mq.SR(10,4,4,8)
|
|
97
|
+
sage: sr.Mstar == ~sr.MixColumns * sr.M
|
|
98
|
+
True
|
|
99
|
+
|
|
100
|
+
We can compute a Groebner basis for the ideals spanned by SR
|
|
101
|
+
instances to recover all solutions to the system.::
|
|
102
|
+
|
|
103
|
+
sage: sr = mq.SR(1,1,1,4, gf2=True, polybori=True)
|
|
104
|
+
sage: K = sr.base_ring()
|
|
105
|
+
sage: a = K.gen()
|
|
106
|
+
sage: K = [a]
|
|
107
|
+
sage: P = [1]
|
|
108
|
+
sage: F,s = sr.polynomial_system(P=P, K=K) # needs sage.rings.polynomial.pbori
|
|
109
|
+
sage: F.groebner_basis() # needs sage.rings.polynomial.pbori
|
|
110
|
+
[k100, k101 + 1, k102, k103 + k003,
|
|
111
|
+
x100 + 1, x101 + k003 + 1, x102 + k003 + 1,
|
|
112
|
+
x103 + k003, w100, w101, w102 + 1, w103 + k003 + 1,
|
|
113
|
+
s000 + 1, s001 + k003, s002 + k003, s003 + k003 + 1,
|
|
114
|
+
k000, k001, k002 + 1]
|
|
115
|
+
|
|
116
|
+
Note that the order of ``k000``, ``k001``, ``k002`` and ``k003`` is
|
|
117
|
+
little endian. Thus the result ``k002 + 1, k001, k000`` indicates that
|
|
118
|
+
the key is either `a` or `a+1`. We can verify that both keys encrypt P
|
|
119
|
+
to the same ciphertext::
|
|
120
|
+
|
|
121
|
+
sage: sr(P,[a])
|
|
122
|
+
[0]
|
|
123
|
+
sage: sr(P,[a+1])
|
|
124
|
+
[0]
|
|
125
|
+
|
|
126
|
+
All solutions can easily be recovered using the variety function for ideals.::
|
|
127
|
+
|
|
128
|
+
sage: I = F.ideal() # needs sage.rings.polynomial.pbori
|
|
129
|
+
sage: for V in I.variety(): # needs sage.rings.polynomial.pbori sage.symbolic
|
|
130
|
+
....: for k,v in sorted(V.items()):
|
|
131
|
+
....: print("{} {}".format(k, v))
|
|
132
|
+
....: print("\n")
|
|
133
|
+
k003 0
|
|
134
|
+
k002 1
|
|
135
|
+
k001 0
|
|
136
|
+
k000 0
|
|
137
|
+
s003 1
|
|
138
|
+
s002 0
|
|
139
|
+
s001 0
|
|
140
|
+
s000 1
|
|
141
|
+
w103 1
|
|
142
|
+
w102 1
|
|
143
|
+
w101 0
|
|
144
|
+
w100 0
|
|
145
|
+
x103 0
|
|
146
|
+
x102 1
|
|
147
|
+
x101 1
|
|
148
|
+
x100 1
|
|
149
|
+
k103 0
|
|
150
|
+
k102 0
|
|
151
|
+
k101 1
|
|
152
|
+
k100 0
|
|
153
|
+
<BLANKLINE>
|
|
154
|
+
k003 1
|
|
155
|
+
k002 1
|
|
156
|
+
k001 0
|
|
157
|
+
k000 0
|
|
158
|
+
s003 0
|
|
159
|
+
s002 1
|
|
160
|
+
s001 1
|
|
161
|
+
s000 1
|
|
162
|
+
w103 0
|
|
163
|
+
w102 1
|
|
164
|
+
w101 0
|
|
165
|
+
w100 0
|
|
166
|
+
x103 1
|
|
167
|
+
x102 0
|
|
168
|
+
x101 0
|
|
169
|
+
x100 1
|
|
170
|
+
k103 1
|
|
171
|
+
k102 0
|
|
172
|
+
k101 1
|
|
173
|
+
k100 0
|
|
174
|
+
|
|
175
|
+
We can also verify the correctness of the variety by evaluating all
|
|
176
|
+
ideal generators on all points.::
|
|
177
|
+
|
|
178
|
+
sage: for V in I.variety(): # needs sage.rings.polynomial.pbori sage.symbolic
|
|
179
|
+
....: for f in I.gens():
|
|
180
|
+
....: if f.subs(V) != 0:
|
|
181
|
+
....: print("epic fail")
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
Note that the S-Box object for SR can be constructed with a call to ``sr.sbox()``::
|
|
185
|
+
|
|
186
|
+
sage: sr = mq.SR(1,1,1,4, gf2=True, polybori=True)
|
|
187
|
+
sage: S = sr.sbox()
|
|
188
|
+
|
|
189
|
+
For example, we can now study the difference distribution table of ``S``::
|
|
190
|
+
|
|
191
|
+
sage: S.difference_distribution_table()
|
|
192
|
+
[16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
|
193
|
+
[ 0 2 2 2 2 0 0 0 2 0 0 0 2 4 0 0]
|
|
194
|
+
[ 0 2 0 4 2 2 2 0 0 2 0 0 0 0 0 2]
|
|
195
|
+
[ 0 2 4 0 0 2 0 0 2 2 0 2 0 0 2 0]
|
|
196
|
+
[ 0 0 2 0 4 2 0 0 0 0 2 0 2 0 2 2]
|
|
197
|
+
[ 0 0 0 2 0 0 0 2 4 2 0 0 2 0 2 2]
|
|
198
|
+
[ 0 4 0 0 0 2 0 2 0 2 2 0 2 2 0 0]
|
|
199
|
+
[ 0 2 0 0 0 0 2 0 0 0 0 2 4 2 2 2]
|
|
200
|
+
[ 0 2 2 0 0 0 2 2 2 0 2 0 0 0 0 4]
|
|
201
|
+
[ 0 0 2 2 0 0 0 0 0 2 2 4 0 2 0 2]
|
|
202
|
+
[ 0 0 2 0 2 0 2 2 0 4 0 2 2 0 0 0]
|
|
203
|
+
[ 0 0 0 0 2 0 2 0 2 2 4 0 0 2 2 0]
|
|
204
|
+
[ 0 0 0 2 0 4 2 0 2 0 2 2 2 0 0 0]
|
|
205
|
+
[ 0 0 0 0 2 2 0 4 2 0 0 2 0 2 0 2]
|
|
206
|
+
[ 0 0 2 2 0 2 4 2 0 0 0 0 0 2 2 0]
|
|
207
|
+
[ 0 2 0 2 2 0 0 2 0 0 2 2 0 0 4 0]
|
|
208
|
+
|
|
209
|
+
or use ``S`` to find alternative polynomial representations for the S-Box.::
|
|
210
|
+
|
|
211
|
+
sage: S.polynomials(degree=3) # needs sage.libs.singular
|
|
212
|
+
[x0*x1 + x1*x2 + x0*x3 + x0*y2 + x1 + y0 + y1 + 1,
|
|
213
|
+
x0*x1 + x0*x2 + x0*y0 + x0*y1 + x0*y2 + x1 + x2 + y0 + y1 + y2,
|
|
214
|
+
x0*x1 + x0*x2 + x0*x3 + x1*x3 + x0*y0 + x1*y0 + x0*y1 + x0*y3,
|
|
215
|
+
x0*x1 + x0*x2 + x0*x3 + x1*x3 + x0*y0 + x1*y1 + x0*y3 + x1 + y0 + y1 + 1,
|
|
216
|
+
x0*x1 + x0*x2 + x0*y2 + x1*y2 + x0*y3 + x0 + x1,
|
|
217
|
+
x0*x3 + x1*x3 + x0*y1 + x0*y2 + x1*y3 + x0 + x1 + x2 + x3 + y0 + y1 + y3 + 1,
|
|
218
|
+
x0*x1 + x1*x3 + x2*x3 + x0*y0 + x0*y2 + x0*y3 + x2 + y0 + y3,
|
|
219
|
+
x0*x1 + x0*x2 + x0*x3 + x1*x3 + x2*y0 + x0*y2 + x0 + x2 + x3 + y3,
|
|
220
|
+
x0*x3 + x1*x3 + x0*y0 + x2*y1 + x0*y2 + x3 + y3,
|
|
221
|
+
x0*x1 + x0*x2 + x0*y0 + x0*y1 + x2*y2 + x0*y3 + x1 + y0 + y1 + 1,
|
|
222
|
+
x0*x3 + x1*x3 + x0*y0 + x0*y1 + x0*y3 + x2*y3 + y0 + y3,
|
|
223
|
+
x0*x1 + x0*x2 + x3*y0 + x0*y1 + x0*y3 + y0,
|
|
224
|
+
x0*y0 + x0*y1 + x3*y1 + x0 + x2 + y0 + y3,
|
|
225
|
+
x0*y0 + x3*y2 + y0,
|
|
226
|
+
x0*x1 + x0*x2 + x0*x3 + x1*x3 + x0*y0 + x0*y2 + x3*y3 + y0,
|
|
227
|
+
x0*x2 + x0*x3 + x0*y1 + y0*y1 + x0*y3 + x2 + x3 + y3,
|
|
228
|
+
x0*x2 + x0*y0 + y0*y2 + x0*y3 + x0 + y0,
|
|
229
|
+
x0*x1 + x0*x2 + x1*x3 + x0*y2 + y0*y3 + y0,
|
|
230
|
+
x0*x1 + x0*y0 + y1*y2 + x0*y3 + x1 + x2 + y0 + 1,
|
|
231
|
+
x0*x2 + x1*x3 + x0*y1 + x0*y2 + x0*y3 + y1*y3 + x0 + y0 + y3,
|
|
232
|
+
x0*x1 + x0*x2 + x0*x3 + x0*y1 + x0*y2 + x0*y3 + y2*y3 + x0 + x1 + x2 + x3 + y1 + y3 + 1,
|
|
233
|
+
x0*x1*x2 + x0*x3 + x0*y0 + x0*y1 + x0*y2 + x0,
|
|
234
|
+
x0*x1*x3 + x0*x2 + x0*x3 + x0*y1 + x0*y3 + x0,
|
|
235
|
+
x0*x1*y0 + x0*x1 + x0*y0 + x0,
|
|
236
|
+
x0*x1*y1,
|
|
237
|
+
x0*x1*y2 + x0*x2 + x0*y2 + x0*y3 + x0,
|
|
238
|
+
x0*x1*y3 + x0*x1 + x0*x3 + x0*y0 + x0*y1 + x0*y2 + x0,
|
|
239
|
+
x0*x2*x3 + x0*x1 + x0*x3 + x0*y1 + x0*y2 + x0*y3 + x0,
|
|
240
|
+
x0*x2*y0 + x0*x1 + x0*x2 + x0*x3 + x0*y1 + x0*y2,
|
|
241
|
+
x0*x2*y1 + x0*x2 + x0*x3 + x0*y0 + x0*y1 + x0*y2 + x0,
|
|
242
|
+
x0*x2*y2 + x0*x2 + x0*y3 + x0,
|
|
243
|
+
x0*x2*y3 + x0*x2 + x0*y3 + x0,
|
|
244
|
+
x0*x3*y0 + x0*x1 + x0*x2 + x0*y0 + x0*y1 + x0*y3,
|
|
245
|
+
x0*x3*y1 + x0*x2 + x0*y1 + x0*y3 + x0,
|
|
246
|
+
x0*x3*y2,
|
|
247
|
+
x0*x3*y3 + x0*x1 + x0*y1 + x0*y2 + x0*y3 + x0,
|
|
248
|
+
x0*y0*y1 + x0*y1,
|
|
249
|
+
x0*y0*y2 + x0*x2 + x0*y3 + x0,
|
|
250
|
+
x0*y0*y3 + x0*x1 + x0*x3 + x0*y0 + x0*y1 + x0*y2 + x0*y3 + x0,
|
|
251
|
+
x0*y1*y2 + x0*x2 + x0*y3 + x0,
|
|
252
|
+
x0*y1*y3 + x0*x3 + x0*y0 + x0*y2 + x0*y3,
|
|
253
|
+
x0*y2*y3 + x0*y2,
|
|
254
|
+
x1*x2*x3 + x0*x1 + x1*x3 + x0*y0 + x0*y1 + x2 + x3 + y3,
|
|
255
|
+
x1*x2*y0 + x0*x1 + x1*x3 + x0*y0 + x0*y1 + x2 + x3 + y3,
|
|
256
|
+
x1*x2*y1 + x0*x1 + x1*x3 + x0*y0 + x1 + x2 + x3 + y0 + y1 + y3 + 1,
|
|
257
|
+
x1*x2*y2 + x0*x1 + x0*y0 + x0*y1 + x0 + x1 + y0 + y1 + 1,
|
|
258
|
+
x1*x2*y3 + x0*x1 + x1*x3 + x0*y0 + x1 + x2 + x3 + y0 + y1 + y3 + 1,
|
|
259
|
+
x1*x3*y0 + x0*x1 + x0*x2 + x0*x3 + x1*x3 + x0*y0 + x0*y1 + x0*y3,
|
|
260
|
+
x1*x3*y1 + x0*x2 + x0*x3 + x0*y3 + x2 + x3 + y3,
|
|
261
|
+
x1*x3*y2 + x0*x2 + x0*x3 + x1*x3 + x0*y1 + x0*y3 + x0,
|
|
262
|
+
x1*x3*y3 + x0*x1 + x0*x2 + x0*x3 + x0*y0 + x0*y1 + x0*y3,
|
|
263
|
+
x1*y0*y1 + x0*x2 + x0*x3 + x0*y3 + x2 + x3 + y3,
|
|
264
|
+
x1*y0*y2 + x0*x2 + x0*x3 + x1*x3 + x0*y1 + x0*y3 + x0,
|
|
265
|
+
x1*y0*y3,
|
|
266
|
+
x1*y1*y2 + x0*x1 + x0*x2 + x0*x3 + x1*x3 + x0*y0 + x0*y3 + x1 + y0 + y1 + 1,
|
|
267
|
+
x1*y1*y3 + x0*x1 + x1*x3 + x0*y0 + x1 + x2 + x3 + y0 + y1 + y3 + 1,
|
|
268
|
+
x1*y2*y3 + x0*x1 + x0*x2 + x1*x3 + x0*y0 + x0*y2 + x0*y3 + x0 + x1 + x2 + x3 + y0 + y1 + y3 + 1,
|
|
269
|
+
x2*x3*y0 + x0*x1 + x0*x3 + x1*x3 + x0*y2 + x0*y3 + x2 + x3 + y3,
|
|
270
|
+
x2*x3*y1 + x0*y1 + x0*y2 + x0*y3 + x3 + y0,
|
|
271
|
+
x2*x3*y2 + x1*x3 + x0*y1 + x0 + x2 + x3 + y3,
|
|
272
|
+
x2*x3*y3,
|
|
273
|
+
x2*y0*y1 + x0*x2 + x0*x3 + x0*y0 + x0*y1 + x0*y2 + x0,
|
|
274
|
+
x2*y0*y2 + x0*x2 + x1*x3 + x0*y1 + x0*y3 + x2 + x3 + y3,
|
|
275
|
+
x2*y0*y3 + x0*x2 + x0*y3 + x0,
|
|
276
|
+
x2*y1*y2 + x0*x1 + x0*x2 + x1*x3 + x0*y0 + x0*y3 + x0 + x1 + x2 + x3 + y0 + y1 + y3 + 1,
|
|
277
|
+
x2*y1*y3 + x0*x3 + x1*x3 + x0*y0 + x0*y1 + x0*y3 + y0 + y3,
|
|
278
|
+
x2*y2*y3 + x0*x1 + x0*x2 + x1*x3 + x0*y0 + x0*y3 + x0 + x1 + x2 + x3 + y0 + y1 + y3 + 1,
|
|
279
|
+
x3*y0*y1 + x0*x3 + x0*y1 + x0 + x2 + x3 + y3,
|
|
280
|
+
x3*y0*y2 + x0*y0 + y0,
|
|
281
|
+
x3*y0*y3 + x1*x3 + x0*y1 + x0*y2 + x0*y3 + y0,
|
|
282
|
+
x3*y1*y2 + x0*x2 + x0*x3 + x0*y3 + x2 + x3 + y3,
|
|
283
|
+
x3*y1*y3 + x0*x2 + x0*x3 + x0*y0 + x0*y2 + x0,
|
|
284
|
+
x3*y2*y3 + x0*x2 + x0*x3 + x1*x3 + x0*y0 + x0*y1 + x0*y3 + x0 + y0,
|
|
285
|
+
y0*y1*y2 + x0*x3 + x0 + x2 + x3 + y3,
|
|
286
|
+
y0*y1*y3 + x0*x3 + x0*y0 + x0*y2 + x0*y3,
|
|
287
|
+
y0*y2*y3 + x0*x3 + x1*x3 + x0*y0 + x0*y1 + y0,
|
|
288
|
+
y1*y2*y3 + x0*x1 + x0*x2 + x1*x3 + x0*y0 + x0*y3 + x0 + x1 + x2 + x3 + y0 + y1 + y3 + 1]
|
|
289
|
+
|
|
290
|
+
sage: S.interpolation_polynomial()
|
|
291
|
+
(a^2 + 1)*x^14 + a^2*x^13 + x^12 + a^2*x^11 + a*x^10 + (a^3 + a)*x^9 +
|
|
292
|
+
(a^3 + 1)*x^7 + (a^3 + a^2 + a)*x^6 + a^2*x^5 + (a + 1)*x^4 + a^2*x^3 +
|
|
293
|
+
(a^3 + a^2 + a)*x^2 + (a^3 + 1)*x + a^2 + a
|
|
294
|
+
|
|
295
|
+
The :class:`SR_gf2_2` gives an example how use alternative polynomial
|
|
296
|
+
representations of the S-Box for construction of polynomial systems.
|
|
297
|
+
|
|
298
|
+
TESTS::
|
|
299
|
+
|
|
300
|
+
sage: sr == loads(dumps(sr))
|
|
301
|
+
True
|
|
302
|
+
|
|
303
|
+
REFERENCES:
|
|
304
|
+
|
|
305
|
+
- [CMR2005]_
|
|
306
|
+
|
|
307
|
+
- [CMR2006]_
|
|
308
|
+
|
|
309
|
+
- [MR2002]_
|
|
310
|
+
"""
|
|
311
|
+
|
|
312
|
+
from sage.matrix.constructor import matrix, random_matrix
|
|
313
|
+
from sage.matrix.matrix_space import MatrixSpace
|
|
314
|
+
from sage.misc.flatten import flatten
|
|
315
|
+
from sage.misc.verbose import get_verbose
|
|
316
|
+
from sage.modules.vector_modn_dense import Vector_modn_dense
|
|
317
|
+
from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
|
|
318
|
+
from sage.rings.integer_ring import ZZ
|
|
319
|
+
from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence
|
|
320
|
+
from sage.rings.polynomial.polynomial_ring_constructor import \
|
|
321
|
+
BooleanPolynomialRing_constructor as BooleanPolynomialRing
|
|
322
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
323
|
+
from sage.rings.polynomial.term_order import TermOrder
|
|
324
|
+
from sage.structure.element import Matrix
|
|
325
|
+
|
|
326
|
+
from .mpolynomialsystemgenerator import MPolynomialSystemGenerator
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def SR(n=1, r=1, c=1, e=4, star=False, **kwargs):
|
|
330
|
+
r"""
|
|
331
|
+
Return a small scale variant of the AES polynomial system
|
|
332
|
+
constructor subject to the following conditions:
|
|
333
|
+
|
|
334
|
+
INPUT:
|
|
335
|
+
|
|
336
|
+
- ``n`` -- the number of rounds (default: 1)
|
|
337
|
+
- ``r`` -- the number of rows in the state array (default: 1)
|
|
338
|
+
- ``c`` -- the number of columns in the state array (default: 1)
|
|
339
|
+
- ``e`` -- the exponent of the finite extension field (default: 4)
|
|
340
|
+
- ``star`` -- determines if SR\* or SR should be constructed (default: ``False``)
|
|
341
|
+
- ``aes_mode`` -- as the SR key schedule specification differs
|
|
342
|
+
slightly from the AES key schedule, this parameter controls
|
|
343
|
+
which schedule to use (default: ``True``)
|
|
344
|
+
- ``gf2`` -- generate polynomial systems over `\GF{2}` rather than
|
|
345
|
+
over `\GF{2^e}` (default: ``False``)
|
|
346
|
+
- ``polybori`` -- use the ``BooleanPolynomialRing`` as polynomial
|
|
347
|
+
representation (default: ``True``, `\GF{2}` only)
|
|
348
|
+
- ``order`` -- string to specify the term ordering of the
|
|
349
|
+
variables (default: ``deglex``)
|
|
350
|
+
- ``postfix`` -- string which is appended after the variable name
|
|
351
|
+
(default: ``''``)
|
|
352
|
+
- ``allow_zero_inversions`` -- boolean to control whether zero
|
|
353
|
+
inversions raise an exception (default: ``False``)
|
|
354
|
+
- ``correct_only`` -- only include correct inversion polynomials
|
|
355
|
+
(default: ``False``, `\GF{2}` only)
|
|
356
|
+
- ``biaffine_only`` -- only include bilinear and biaffine inversion
|
|
357
|
+
polynomials (default: ``True``, `\GF{2}` only)
|
|
358
|
+
|
|
359
|
+
EXAMPLES::
|
|
360
|
+
|
|
361
|
+
sage: sr = mq.SR(1, 1, 1, 4)
|
|
362
|
+
sage: ShiftRows = sr.shift_rows_matrix()
|
|
363
|
+
sage: MixColumns = sr.mix_columns_matrix()
|
|
364
|
+
sage: Lin = sr.lin_matrix()
|
|
365
|
+
sage: M = MixColumns * ShiftRows * Lin
|
|
366
|
+
sage: print(sr.hex_str_matrix(M))
|
|
367
|
+
5 1 C 5
|
|
368
|
+
2 2 1 F
|
|
369
|
+
A 4 4 1
|
|
370
|
+
1 8 3 3
|
|
371
|
+
|
|
372
|
+
::
|
|
373
|
+
|
|
374
|
+
sage: sr = mq.SR(1, 2, 1, 4)
|
|
375
|
+
sage: ShiftRows = sr.shift_rows_matrix()
|
|
376
|
+
sage: MixColumns = sr.mix_columns_matrix()
|
|
377
|
+
sage: Lin = sr.lin_matrix()
|
|
378
|
+
sage: M = MixColumns * ShiftRows * Lin
|
|
379
|
+
sage: print(sr.hex_str_matrix(M))
|
|
380
|
+
F 3 7 F A 2 B A
|
|
381
|
+
A A 5 6 8 8 4 9
|
|
382
|
+
7 8 8 2 D C C 3
|
|
383
|
+
4 6 C C 5 E F F
|
|
384
|
+
A 2 B A F 3 7 F
|
|
385
|
+
8 8 4 9 A A 5 6
|
|
386
|
+
D C C 3 7 8 8 2
|
|
387
|
+
5 E F F 4 6 C C
|
|
388
|
+
|
|
389
|
+
::
|
|
390
|
+
|
|
391
|
+
sage: sr = mq.SR(1, 2, 2, 4)
|
|
392
|
+
sage: ShiftRows = sr.shift_rows_matrix()
|
|
393
|
+
sage: MixColumns = sr.mix_columns_matrix()
|
|
394
|
+
sage: Lin = sr.lin_matrix()
|
|
395
|
+
sage: M = MixColumns * ShiftRows * Lin
|
|
396
|
+
sage: print(sr.hex_str_matrix(M))
|
|
397
|
+
F 3 7 F 0 0 0 0 0 0 0 0 A 2 B A
|
|
398
|
+
A A 5 6 0 0 0 0 0 0 0 0 8 8 4 9
|
|
399
|
+
7 8 8 2 0 0 0 0 0 0 0 0 D C C 3
|
|
400
|
+
4 6 C C 0 0 0 0 0 0 0 0 5 E F F
|
|
401
|
+
A 2 B A 0 0 0 0 0 0 0 0 F 3 7 F
|
|
402
|
+
8 8 4 9 0 0 0 0 0 0 0 0 A A 5 6
|
|
403
|
+
D C C 3 0 0 0 0 0 0 0 0 7 8 8 2
|
|
404
|
+
5 E F F 0 0 0 0 0 0 0 0 4 6 C C
|
|
405
|
+
0 0 0 0 A 2 B A F 3 7 F 0 0 0 0
|
|
406
|
+
0 0 0 0 8 8 4 9 A A 5 6 0 0 0 0
|
|
407
|
+
0 0 0 0 D C C 3 7 8 8 2 0 0 0 0
|
|
408
|
+
0 0 0 0 5 E F F 4 6 C C 0 0 0 0
|
|
409
|
+
0 0 0 0 F 3 7 F A 2 B A 0 0 0 0
|
|
410
|
+
0 0 0 0 A A 5 6 8 8 4 9 0 0 0 0
|
|
411
|
+
0 0 0 0 7 8 8 2 D C C 3 0 0 0 0
|
|
412
|
+
0 0 0 0 4 6 C C 5 E F F 0 0 0 0
|
|
413
|
+
"""
|
|
414
|
+
if not kwargs.get("gf2", False):
|
|
415
|
+
return SR_gf2n(n, r, c, e, star, **kwargs)
|
|
416
|
+
else:
|
|
417
|
+
return SR_gf2(n, r, c, e, star, **kwargs)
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
class SR_generic(MPolynomialSystemGenerator):
|
|
421
|
+
def __init__(self, n=1, r=1, c=1, e=4, star=False, **kwargs):
|
|
422
|
+
"""
|
|
423
|
+
Small Scale Variants of the AES.
|
|
424
|
+
|
|
425
|
+
EXAMPLES::
|
|
426
|
+
|
|
427
|
+
sage: sr = mq.SR(1, 1, 1, 4)
|
|
428
|
+
sage: ShiftRows = sr.shift_rows_matrix()
|
|
429
|
+
sage: MixColumns = sr.mix_columns_matrix()
|
|
430
|
+
sage: Lin = sr.lin_matrix()
|
|
431
|
+
sage: M = MixColumns * ShiftRows * Lin
|
|
432
|
+
sage: print(sr.hex_str_matrix(M))
|
|
433
|
+
5 1 C 5
|
|
434
|
+
2 2 1 F
|
|
435
|
+
A 4 4 1
|
|
436
|
+
1 8 3 3
|
|
437
|
+
"""
|
|
438
|
+
if n-1 not in range(10):
|
|
439
|
+
raise TypeError("n must be between 1 and 10 (inclusive)")
|
|
440
|
+
self._n = n
|
|
441
|
+
|
|
442
|
+
if r not in (1, 2, 4):
|
|
443
|
+
raise TypeError("r must be in (1, 2, 4)")
|
|
444
|
+
self._r = r
|
|
445
|
+
|
|
446
|
+
if c not in (1, 2, 4):
|
|
447
|
+
raise TypeError("c must be in (1, 2, 4)")
|
|
448
|
+
self._c = c
|
|
449
|
+
|
|
450
|
+
if e not in (4, 8):
|
|
451
|
+
raise TypeError("e must be either 4 or 8")
|
|
452
|
+
self._e = e
|
|
453
|
+
|
|
454
|
+
self._star = bool(star)
|
|
455
|
+
|
|
456
|
+
self._base = self.base_ring()
|
|
457
|
+
|
|
458
|
+
self._postfix = kwargs.get("postfix", "")
|
|
459
|
+
self._order = kwargs.get("order", "deglex")
|
|
460
|
+
self._aes_mode = kwargs.get("aes_mode", True)
|
|
461
|
+
self._gf2 = kwargs.get("gf2", False)
|
|
462
|
+
self._allow_zero_inversions = bool(kwargs.get("allow_zero_inversions", False))
|
|
463
|
+
self._reverse_variables = bool(kwargs.get("reverse_variables", True))
|
|
464
|
+
|
|
465
|
+
with AllowZeroInversionsContext(self):
|
|
466
|
+
sub_byte_lookup = {v: self.sub_byte(v) for v in self._base}
|
|
467
|
+
self._sub_byte_lookup = sub_byte_lookup
|
|
468
|
+
|
|
469
|
+
if self._gf2:
|
|
470
|
+
self._polybori = kwargs.get("polybori", True)
|
|
471
|
+
|
|
472
|
+
def new_generator(self, **kwds):
|
|
473
|
+
r"""
|
|
474
|
+
Return a new ``SR`` instance equal to this instance
|
|
475
|
+
except for the parameters passed explicitly to this function.
|
|
476
|
+
|
|
477
|
+
INPUT:
|
|
478
|
+
|
|
479
|
+
- ``**kwds`` -- see the ``SR`` constructor for accepted
|
|
480
|
+
parameters
|
|
481
|
+
|
|
482
|
+
EXAMPLES::
|
|
483
|
+
|
|
484
|
+
sage: sr = mq.SR(2,1,1,4); sr
|
|
485
|
+
SR(2,1,1,4)
|
|
486
|
+
sage: sr.ring().base_ring()
|
|
487
|
+
Finite Field in a of size 2^4
|
|
488
|
+
|
|
489
|
+
::
|
|
490
|
+
|
|
491
|
+
sage: sr2 = sr.new_generator(gf2=True); sr2
|
|
492
|
+
SR(2,1,1,4)
|
|
493
|
+
sage: sr2.ring().base_ring()
|
|
494
|
+
Finite Field of size 2
|
|
495
|
+
sage: sr3 = sr2.new_generator(correct_only=True)
|
|
496
|
+
sage: len(sr2.inversion_polynomials_single_sbox())
|
|
497
|
+
20
|
|
498
|
+
sage: len(sr3.inversion_polynomials_single_sbox())
|
|
499
|
+
19
|
|
500
|
+
"""
|
|
501
|
+
kwds.setdefault("n", self._n)
|
|
502
|
+
kwds.setdefault("r", self._r)
|
|
503
|
+
kwds.setdefault("c", self._c)
|
|
504
|
+
kwds.setdefault("e", self._e)
|
|
505
|
+
kwds.setdefault("star", self._star)
|
|
506
|
+
kwds.setdefault("postfix", self._postfix)
|
|
507
|
+
kwds.setdefault("order", self._order)
|
|
508
|
+
kwds.setdefault("allow_zero_inversions", self._allow_zero_inversions)
|
|
509
|
+
kwds.setdefault("aes_mode", self._aes_mode)
|
|
510
|
+
kwds.setdefault("gf2", self._gf2)
|
|
511
|
+
kwds.setdefault("reverse_variables", self._reverse_variables)
|
|
512
|
+
|
|
513
|
+
try:
|
|
514
|
+
polybori = self._polybori
|
|
515
|
+
except AttributeError:
|
|
516
|
+
polybori = False
|
|
517
|
+
kwds.setdefault("polybori", polybori)
|
|
518
|
+
|
|
519
|
+
try:
|
|
520
|
+
correct_only = self._correct_only
|
|
521
|
+
except AttributeError:
|
|
522
|
+
correct_only = False
|
|
523
|
+
kwds.setdefault("correct_only", correct_only)
|
|
524
|
+
|
|
525
|
+
try:
|
|
526
|
+
biaffine_only = self._biaffine_only
|
|
527
|
+
except AttributeError:
|
|
528
|
+
biaffine_only = False
|
|
529
|
+
kwds.setdefault("biaffine_only", biaffine_only)
|
|
530
|
+
|
|
531
|
+
if self._gf2 == kwds.get('gf2'):
|
|
532
|
+
return self.__class__(**kwds)
|
|
533
|
+
else:
|
|
534
|
+
return SR(**kwds)
|
|
535
|
+
|
|
536
|
+
def __getattr__(self, attr):
|
|
537
|
+
"""
|
|
538
|
+
EXAMPLES::
|
|
539
|
+
|
|
540
|
+
sage: sr = mq.SR(1, 2, 1, 4, gf2=True)
|
|
541
|
+
sage: sr.Mstar
|
|
542
|
+
[1 0 1 1 0 0 0 0]
|
|
543
|
+
[1 1 0 1 0 0 0 0]
|
|
544
|
+
[1 1 1 0 0 0 0 0]
|
|
545
|
+
[0 1 1 1 0 0 0 0]
|
|
546
|
+
[0 0 0 0 1 0 1 1]
|
|
547
|
+
[0 0 0 0 1 1 0 1]
|
|
548
|
+
[0 0 0 0 1 1 1 0]
|
|
549
|
+
[0 0 0 0 0 1 1 1]
|
|
550
|
+
"""
|
|
551
|
+
if attr == "e":
|
|
552
|
+
return self._e
|
|
553
|
+
elif attr == "c":
|
|
554
|
+
return self._c
|
|
555
|
+
elif attr == "n":
|
|
556
|
+
return self._n
|
|
557
|
+
elif attr == "r":
|
|
558
|
+
return self._r
|
|
559
|
+
|
|
560
|
+
elif attr == "R":
|
|
561
|
+
self.R = self.ring()
|
|
562
|
+
return self.R
|
|
563
|
+
elif attr == "k":
|
|
564
|
+
self.k = self.base_ring()
|
|
565
|
+
return self.k
|
|
566
|
+
|
|
567
|
+
elif attr == "Lin":
|
|
568
|
+
self.Lin = self.lin_matrix()
|
|
569
|
+
return self.Lin
|
|
570
|
+
|
|
571
|
+
elif attr == "ShiftRows":
|
|
572
|
+
self.ShiftRows = self.shift_rows_matrix()
|
|
573
|
+
return self.ShiftRows
|
|
574
|
+
|
|
575
|
+
elif attr == "MixColumns":
|
|
576
|
+
self.MixColumns = self.mix_columns_matrix()
|
|
577
|
+
return self.MixColumns
|
|
578
|
+
|
|
579
|
+
elif attr == "M":
|
|
580
|
+
self.M = self.MixColumns * self.ShiftRows * self.Lin
|
|
581
|
+
return self.M
|
|
582
|
+
|
|
583
|
+
elif attr == "Mstar":
|
|
584
|
+
self.Mstar = self.ShiftRows * self.Lin
|
|
585
|
+
return self.Mstar
|
|
586
|
+
|
|
587
|
+
raise AttributeError("%s has no attribute %s" % (type(self), attr))
|
|
588
|
+
|
|
589
|
+
def _repr_(self):
|
|
590
|
+
"""
|
|
591
|
+
EXAMPLES::
|
|
592
|
+
|
|
593
|
+
sage: sr = mq.SR(1, 2, 2, 4); sr #indirect doctest
|
|
594
|
+
SR(1,2,2,4)
|
|
595
|
+
sage: sr = mq.SR(1, 2, 2, 4, star=True); sr
|
|
596
|
+
SR*(1,2,2,4)
|
|
597
|
+
"""
|
|
598
|
+
if self._star:
|
|
599
|
+
return "SR*(%d,%d,%d,%d)" % (self._n, self._r, self._c, self._e)
|
|
600
|
+
else:
|
|
601
|
+
return "SR(%d,%d,%d,%d)" % (self._n, self._r, self._c, self._e)
|
|
602
|
+
|
|
603
|
+
def base_ring(self):
|
|
604
|
+
r"""
|
|
605
|
+
Return the base field of ``self`` as determined by
|
|
606
|
+
``self.e``.
|
|
607
|
+
|
|
608
|
+
EXAMPLES::
|
|
609
|
+
|
|
610
|
+
sage: sr = mq.SR(10, 2, 2, 4)
|
|
611
|
+
sage: sr.base_ring().polynomial()
|
|
612
|
+
a^4 + a + 1
|
|
613
|
+
|
|
614
|
+
The Rijndael polynomial::
|
|
615
|
+
|
|
616
|
+
sage: sr = mq.SR(10, 4, 4, 8)
|
|
617
|
+
sage: sr.base_ring().polynomial()
|
|
618
|
+
a^8 + a^4 + a^3 + a + 1
|
|
619
|
+
"""
|
|
620
|
+
try:
|
|
621
|
+
return self._base
|
|
622
|
+
except AttributeError:
|
|
623
|
+
if self._e == 4:
|
|
624
|
+
self._base = GF(2**4, 'a', modulus=(1, 1, 0, 0, 1))
|
|
625
|
+
elif self._e == 8:
|
|
626
|
+
self._base = GF(2**8, 'a', modulus=(1, 1, 0, 1, 1, 0, 0, 0, 1))
|
|
627
|
+
|
|
628
|
+
return self._base
|
|
629
|
+
|
|
630
|
+
def __eq__(self, other):
|
|
631
|
+
"""
|
|
632
|
+
Two generators are considered equal if they agree on all parameters
|
|
633
|
+
passed to them during construction.
|
|
634
|
+
|
|
635
|
+
EXAMPLES::
|
|
636
|
+
|
|
637
|
+
sage: sr1 = mq.SR(2, 2, 2, 4)
|
|
638
|
+
sage: sr1 == sr1
|
|
639
|
+
True
|
|
640
|
+
|
|
641
|
+
sage: sr2 = mq.SR(2, 2, 2, 4, gf2=True)
|
|
642
|
+
sage: sr1 == sr2
|
|
643
|
+
False
|
|
644
|
+
"""
|
|
645
|
+
for name in ['n', 'r', 'c', 'e', '_postfix', '_order',
|
|
646
|
+
'_allow_zero_inversions', '_aes_mode', '_gf2', '_star']:
|
|
647
|
+
lx = getattr(self, name)
|
|
648
|
+
rx = getattr(other, name)
|
|
649
|
+
if lx != rx:
|
|
650
|
+
return False
|
|
651
|
+
return True
|
|
652
|
+
|
|
653
|
+
def __ne__(self, other):
|
|
654
|
+
"""
|
|
655
|
+
Return whether ``self`` is not equal to ``other``.
|
|
656
|
+
|
|
657
|
+
EXAMPLES::
|
|
658
|
+
|
|
659
|
+
sage: sr1 = mq.SR(2, 2, 2, 4)
|
|
660
|
+
sage: sr1 != sr1
|
|
661
|
+
False
|
|
662
|
+
|
|
663
|
+
sage: sr2 = mq.SR(2, 2, 2, 4, gf2=True)
|
|
664
|
+
sage: sr1 != sr2
|
|
665
|
+
True
|
|
666
|
+
"""
|
|
667
|
+
return not (self == other)
|
|
668
|
+
|
|
669
|
+
def sub_bytes(self, d):
|
|
670
|
+
r"""
|
|
671
|
+
Perform the non-linear transform on ``d``.
|
|
672
|
+
|
|
673
|
+
INPUT:
|
|
674
|
+
|
|
675
|
+
- ``d`` -- state array or something coercible to a state array
|
|
676
|
+
|
|
677
|
+
EXAMPLES::
|
|
678
|
+
|
|
679
|
+
sage: sr = mq.SR(2, 1, 2, 8, gf2=True)
|
|
680
|
+
sage: k = sr.base_ring()
|
|
681
|
+
sage: A = Matrix(k, 1, 2 , [k(1), k.gen()])
|
|
682
|
+
sage: sr.sub_bytes(A)
|
|
683
|
+
[ a^6 + a^5 + a^4 + a^3 + a^2 a^6 + a^5 + a^4 + a^2 + a + 1]
|
|
684
|
+
"""
|
|
685
|
+
d = self.state_array(d)
|
|
686
|
+
return matrix(self.base_ring(), d.nrows(), d.ncols(), [self.sub_byte(b) for b in d.list()])
|
|
687
|
+
|
|
688
|
+
def sub_byte(self, b):
|
|
689
|
+
r"""
|
|
690
|
+
Perform ``SubByte`` on a single byte/halfbyte ``b``.
|
|
691
|
+
|
|
692
|
+
A ``ZeroDivision`` exception is raised if an attempt is made
|
|
693
|
+
to perform an inversion on the zero element. This can be
|
|
694
|
+
disabled by passing ``allow_zero_inversion=True`` to the
|
|
695
|
+
constructor. A zero inversion can result in an inconsistent
|
|
696
|
+
equation system.
|
|
697
|
+
|
|
698
|
+
INPUT:
|
|
699
|
+
|
|
700
|
+
- ``b`` -- an element in ``self.base_ring()``
|
|
701
|
+
|
|
702
|
+
EXAMPLES:
|
|
703
|
+
|
|
704
|
+
The S-Box table for `\GF{2^4}`::
|
|
705
|
+
|
|
706
|
+
sage: sr = mq.SR(1, 1, 1, 4, allow_zero_inversions=True)
|
|
707
|
+
sage: for e in sr.base_ring():
|
|
708
|
+
....: print('% 20s % 20s'%(e, sr.sub_byte(e)))
|
|
709
|
+
0 a^2 + a
|
|
710
|
+
a a^2 + 1
|
|
711
|
+
a^2 a
|
|
712
|
+
a^3 a^3 + 1
|
|
713
|
+
a + 1 a^2
|
|
714
|
+
a^2 + a a^2 + a + 1
|
|
715
|
+
a^3 + a^2 a + 1
|
|
716
|
+
a^3 + a + 1 a^3 + a^2
|
|
717
|
+
a^2 + 1 a^3 + a^2 + a
|
|
718
|
+
a^3 + a a^3 + a^2 + a + 1
|
|
719
|
+
a^2 + a + 1 a^3 + a
|
|
720
|
+
a^3 + a^2 + a 0
|
|
721
|
+
a^3 + a^2 + a + 1 a^3
|
|
722
|
+
a^3 + a^2 + 1 1
|
|
723
|
+
a^3 + 1 a^3 + a^2 + 1
|
|
724
|
+
1 a^3 + a + 1
|
|
725
|
+
"""
|
|
726
|
+
if not b:
|
|
727
|
+
if not self._allow_zero_inversions:
|
|
728
|
+
raise ZeroDivisionError("A zero inversion occurred during an encryption or key schedule.")
|
|
729
|
+
else:
|
|
730
|
+
return self.sbox_constant()
|
|
731
|
+
try:
|
|
732
|
+
return self._sub_byte_lookup[b]
|
|
733
|
+
except AttributeError:
|
|
734
|
+
e = self.e
|
|
735
|
+
k = self.k
|
|
736
|
+
|
|
737
|
+
# inversion
|
|
738
|
+
b = b ** ( 2**e - 2 )
|
|
739
|
+
|
|
740
|
+
# GF(2) linear map
|
|
741
|
+
if e == 4:
|
|
742
|
+
if not hasattr(self, "_L"):
|
|
743
|
+
self._L = matrix(GF(2), 4, 4, [[1, 1, 1, 0],
|
|
744
|
+
[0, 1, 1, 1],
|
|
745
|
+
[1, 0, 1, 1],
|
|
746
|
+
[1, 1, 0, 1]])
|
|
747
|
+
|
|
748
|
+
elif e == 8:
|
|
749
|
+
if not hasattr(self, "_L"):
|
|
750
|
+
self._L = matrix(GF(2), 8, 8, [[1, 0, 0, 0, 1, 1, 1, 1],
|
|
751
|
+
[1, 1, 0, 0, 0, 1, 1, 1],
|
|
752
|
+
[1, 1, 1, 0, 0, 0, 1, 1],
|
|
753
|
+
[1, 1, 1, 1, 0, 0, 0, 1],
|
|
754
|
+
[1, 1, 1, 1, 1, 0, 0, 0],
|
|
755
|
+
[0, 1, 1, 1, 1, 1, 0, 0],
|
|
756
|
+
[0, 0, 1, 1, 1, 1, 1, 0],
|
|
757
|
+
[0, 0, 0, 1, 1, 1, 1, 1]])
|
|
758
|
+
|
|
759
|
+
b = k(self._L * b._vector_())
|
|
760
|
+
|
|
761
|
+
# constant addition
|
|
762
|
+
if e == 4:
|
|
763
|
+
b = b + k.from_integer(6)
|
|
764
|
+
elif e == 8:
|
|
765
|
+
b = b + k.from_integer(99)
|
|
766
|
+
|
|
767
|
+
return b
|
|
768
|
+
|
|
769
|
+
def sbox_constant(self):
|
|
770
|
+
"""
|
|
771
|
+
Return the S-Box constant which is added after `L(x^{-1})` was
|
|
772
|
+
performed. That is ``0x63`` if ``e == 8`` or ``0x6`` if ``e ==
|
|
773
|
+
4``.
|
|
774
|
+
|
|
775
|
+
EXAMPLES::
|
|
776
|
+
|
|
777
|
+
sage: sr = mq.SR(10, 1, 1, 8)
|
|
778
|
+
sage: sr.sbox_constant()
|
|
779
|
+
a^6 + a^5 + a + 1
|
|
780
|
+
"""
|
|
781
|
+
k = self.k
|
|
782
|
+
if self.e == 4:
|
|
783
|
+
return k.from_integer(6)
|
|
784
|
+
elif self.e == 8:
|
|
785
|
+
return k.from_integer(99)
|
|
786
|
+
else:
|
|
787
|
+
raise TypeError("sbox constant only defined for e in (4, 8)")
|
|
788
|
+
|
|
789
|
+
def sbox(self, inversion_only=False):
|
|
790
|
+
r"""
|
|
791
|
+
Return an S-Box object for this SR instance.
|
|
792
|
+
|
|
793
|
+
INPUT:
|
|
794
|
+
|
|
795
|
+
- ``inversion_only`` -- do not include the `\GF{2}` affine map when
|
|
796
|
+
computing the S-Box (default: ``False``)
|
|
797
|
+
|
|
798
|
+
EXAMPLES::
|
|
799
|
+
|
|
800
|
+
sage: sr = mq.SR(1,2,2,4, allow_zero_inversions=True)
|
|
801
|
+
sage: S = sr.sbox(); S
|
|
802
|
+
(6, 11, 5, 4, 2, 14, 7, 10, 9, 13, 15, 12, 3, 1, 0, 8)
|
|
803
|
+
|
|
804
|
+
sage: sr.sub_byte(0)
|
|
805
|
+
a^2 + a
|
|
806
|
+
sage: sage_eval(str(sr.sub_byte(0)), {'a':2})
|
|
807
|
+
6
|
|
808
|
+
sage: S(0)
|
|
809
|
+
6
|
|
810
|
+
|
|
811
|
+
sage: sr.sub_byte(1)
|
|
812
|
+
a^3 + a + 1
|
|
813
|
+
sage: sage_eval(str(sr.sub_byte(1)), {'a':2})
|
|
814
|
+
11
|
|
815
|
+
sage: S(1)
|
|
816
|
+
11
|
|
817
|
+
|
|
818
|
+
sage: sr = mq.SR(1,2,2,8, allow_zero_inversions=True)
|
|
819
|
+
sage: S = sr.sbox(); S
|
|
820
|
+
(99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43,
|
|
821
|
+
254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240,
|
|
822
|
+
173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38,
|
|
823
|
+
54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4,
|
|
824
|
+
199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39,
|
|
825
|
+
178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214,
|
|
826
|
+
179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91,
|
|
827
|
+
106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251,
|
|
828
|
+
67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81,
|
|
829
|
+
163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16,
|
|
830
|
+
255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196,
|
|
831
|
+
167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42,
|
|
832
|
+
144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58,
|
|
833
|
+
10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
|
|
834
|
+
231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234,
|
|
835
|
+
101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198,
|
|
836
|
+
232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102,
|
|
837
|
+
72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225,
|
|
838
|
+
248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206,
|
|
839
|
+
85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65,
|
|
840
|
+
153, 45, 15, 176, 84, 187, 22)
|
|
841
|
+
|
|
842
|
+
sage: sr.sub_byte(0)
|
|
843
|
+
a^6 + a^5 + a + 1
|
|
844
|
+
|
|
845
|
+
sage: sage_eval(str(sr.sub_byte(0)), {'a':2})
|
|
846
|
+
99
|
|
847
|
+
sage: S(0)
|
|
848
|
+
99
|
|
849
|
+
|
|
850
|
+
sage: sr.sub_byte(1)
|
|
851
|
+
a^6 + a^5 + a^4 + a^3 + a^2
|
|
852
|
+
|
|
853
|
+
sage: sage_eval(str(sr.sub_byte(1)), {'a':2})
|
|
854
|
+
124
|
|
855
|
+
|
|
856
|
+
sage: S(1)
|
|
857
|
+
124
|
|
858
|
+
|
|
859
|
+
sage: sr = mq.SR(1,2,2,4, allow_zero_inversions=True)
|
|
860
|
+
sage: S = sr.sbox(inversion_only=True); S
|
|
861
|
+
(0, 1, 9, 14, 13, 11, 7, 6, 15, 2, 12, 5, 10, 4, 3, 8)
|
|
862
|
+
|
|
863
|
+
sage: S(0)
|
|
864
|
+
0
|
|
865
|
+
sage: S(1)
|
|
866
|
+
1
|
|
867
|
+
|
|
868
|
+
sage: S(sr.k.gen())
|
|
869
|
+
a^3 + a + 1
|
|
870
|
+
"""
|
|
871
|
+
from sage.crypto.sbox import SBox
|
|
872
|
+
|
|
873
|
+
k = self.base_ring()
|
|
874
|
+
if not inversion_only:
|
|
875
|
+
with AllowZeroInversionsContext(self):
|
|
876
|
+
S = [self.sub_byte(elem) for elem in sorted(k)]
|
|
877
|
+
return SBox(S)
|
|
878
|
+
else:
|
|
879
|
+
e = self.e
|
|
880
|
+
S = [elem ** (2**e - 2) for elem in sorted(k)]
|
|
881
|
+
return SBox(S)
|
|
882
|
+
|
|
883
|
+
def shift_rows(self, d):
|
|
884
|
+
r"""
|
|
885
|
+
Perform the ``ShiftRows`` operation on ``d``.
|
|
886
|
+
|
|
887
|
+
INPUT:
|
|
888
|
+
|
|
889
|
+
- ``d`` -- state array or something coercible to a state array
|
|
890
|
+
|
|
891
|
+
EXAMPLES::
|
|
892
|
+
|
|
893
|
+
sage: sr = mq.SR(10, 4, 4, 4)
|
|
894
|
+
sage: E = sr.state_array() + 1; E
|
|
895
|
+
[1 0 0 0]
|
|
896
|
+
[0 1 0 0]
|
|
897
|
+
[0 0 1 0]
|
|
898
|
+
[0 0 0 1]
|
|
899
|
+
|
|
900
|
+
::
|
|
901
|
+
|
|
902
|
+
sage: sr.shift_rows(E)
|
|
903
|
+
[1 0 0 0]
|
|
904
|
+
[1 0 0 0]
|
|
905
|
+
[1 0 0 0]
|
|
906
|
+
[1 0 0 0]
|
|
907
|
+
"""
|
|
908
|
+
d = self.state_array(d)
|
|
909
|
+
ret = []
|
|
910
|
+
for i in range(d.nrows()):
|
|
911
|
+
ret += list(d.row(i)[i % d.ncols():]) + list(d.row(i)[:i % d.ncols()])
|
|
912
|
+
return matrix(self.base_ring(), self._r, self._c, ret)
|
|
913
|
+
|
|
914
|
+
def mix_columns(self, d):
|
|
915
|
+
r"""
|
|
916
|
+
Perform the ``MixColumns`` operation on
|
|
917
|
+
``d``.
|
|
918
|
+
|
|
919
|
+
INPUT:
|
|
920
|
+
|
|
921
|
+
- ``d`` -- state array or something coercible to a state array
|
|
922
|
+
|
|
923
|
+
EXAMPLES::
|
|
924
|
+
|
|
925
|
+
sage: sr = mq.SR(10, 4, 4, 4)
|
|
926
|
+
sage: E = sr.state_array() + 1; E
|
|
927
|
+
[1 0 0 0]
|
|
928
|
+
[0 1 0 0]
|
|
929
|
+
[0 0 1 0]
|
|
930
|
+
[0 0 0 1]
|
|
931
|
+
|
|
932
|
+
::
|
|
933
|
+
|
|
934
|
+
sage: sr.mix_columns(E)
|
|
935
|
+
[ a a + 1 1 1]
|
|
936
|
+
[ 1 a a + 1 1]
|
|
937
|
+
[ 1 1 a a + 1]
|
|
938
|
+
[a + 1 1 1 a]
|
|
939
|
+
"""
|
|
940
|
+
d = self.state_array(d)
|
|
941
|
+
k = self.base_ring()
|
|
942
|
+
a = k.gen()
|
|
943
|
+
r = self._r
|
|
944
|
+
if r == 1:
|
|
945
|
+
M = matrix(self.base_ring(), 1, 1, [[1]])
|
|
946
|
+
elif r == 2:
|
|
947
|
+
M = matrix(self.base_ring(), 2, 2, [[a + 1, a],
|
|
948
|
+
[a, a + 1]])
|
|
949
|
+
|
|
950
|
+
elif r == 4:
|
|
951
|
+
M = matrix(self.base_ring(), 4, 4, [[a, a+1, 1, 1],
|
|
952
|
+
[1, a, a+1, 1],
|
|
953
|
+
[1, 1, a, a+1],
|
|
954
|
+
[a+1, 1, 1, a]])
|
|
955
|
+
ret = []
|
|
956
|
+
for column in d.columns():
|
|
957
|
+
ret.append(M * column)
|
|
958
|
+
# AES uses the column major ordering
|
|
959
|
+
return matrix(k, d.ncols(), d.nrows(), ret).transpose()
|
|
960
|
+
|
|
961
|
+
def add_round_key(self, d, key):
|
|
962
|
+
r"""
|
|
963
|
+
Perform the ``AddRoundKey`` operation on
|
|
964
|
+
``d`` using ``key``.
|
|
965
|
+
|
|
966
|
+
INPUT:
|
|
967
|
+
|
|
968
|
+
- ``d`` -- state array or something coercible to a state array
|
|
969
|
+
|
|
970
|
+
- ``key`` -- state array or something coercible to a state array
|
|
971
|
+
|
|
972
|
+
EXAMPLES::
|
|
973
|
+
|
|
974
|
+
sage: sr = mq.SR(10, 4, 4, 4)
|
|
975
|
+
sage: D = sr.random_state_array()
|
|
976
|
+
sage: K = sr.random_state_array()
|
|
977
|
+
sage: sr.add_round_key(D, K) == K + D
|
|
978
|
+
True
|
|
979
|
+
"""
|
|
980
|
+
d = self.state_array(d)
|
|
981
|
+
key = self.state_array(key)
|
|
982
|
+
|
|
983
|
+
return d+key
|
|
984
|
+
|
|
985
|
+
def state_array(self, d=None):
|
|
986
|
+
"""
|
|
987
|
+
Convert the parameter to a state array.
|
|
988
|
+
|
|
989
|
+
INPUT:
|
|
990
|
+
|
|
991
|
+
- ``d`` -- a matrix, a list, or a tuple (default: ``None``)
|
|
992
|
+
|
|
993
|
+
EXAMPLES::
|
|
994
|
+
|
|
995
|
+
sage: sr = mq.SR(2, 2, 2, 4)
|
|
996
|
+
sage: k = sr.base_ring()
|
|
997
|
+
sage: e1 = [k.from_integer(e) for e in range(2*2)]; e1
|
|
998
|
+
[0, 1, a, a + 1]
|
|
999
|
+
sage: e2 = sr.phi( Matrix(k, 2*2, 1, e1) )
|
|
1000
|
+
sage: sr.state_array(e1) # note the column major ordering
|
|
1001
|
+
[ 0 a]
|
|
1002
|
+
[ 1 a + 1]
|
|
1003
|
+
sage: sr.state_array(e2)
|
|
1004
|
+
[ 0 a]
|
|
1005
|
+
[ 1 a + 1]
|
|
1006
|
+
|
|
1007
|
+
::
|
|
1008
|
+
|
|
1009
|
+
sage: sr.state_array()
|
|
1010
|
+
[0 0]
|
|
1011
|
+
[0 0]
|
|
1012
|
+
"""
|
|
1013
|
+
r = self.r
|
|
1014
|
+
c = self.c
|
|
1015
|
+
e = self.e
|
|
1016
|
+
k = self.base_ring()
|
|
1017
|
+
|
|
1018
|
+
if d is None:
|
|
1019
|
+
return matrix(k, r, c)
|
|
1020
|
+
|
|
1021
|
+
if isinstance(d, Matrix):
|
|
1022
|
+
if d.nrows() == r*c*e:
|
|
1023
|
+
return matrix(k, c, r, self.antiphi(d).list()).transpose()
|
|
1024
|
+
elif d.ncols() == c and d.nrows() == r and d.base_ring() == k:
|
|
1025
|
+
return d
|
|
1026
|
+
|
|
1027
|
+
if isinstance(d, tuple([list, tuple])):
|
|
1028
|
+
return matrix(k, c, r, d).transpose()
|
|
1029
|
+
|
|
1030
|
+
def is_state_array(self, d):
|
|
1031
|
+
"""
|
|
1032
|
+
Return ``True`` if ``d`` is a state array, i.e. has the correct
|
|
1033
|
+
dimensions and base field.
|
|
1034
|
+
|
|
1035
|
+
EXAMPLES::
|
|
1036
|
+
|
|
1037
|
+
sage: sr = mq.SR(2, 2, 4, 8)
|
|
1038
|
+
sage: k = sr.base_ring()
|
|
1039
|
+
sage: sr.is_state_array( matrix(k, 2, 4) )
|
|
1040
|
+
True
|
|
1041
|
+
|
|
1042
|
+
::
|
|
1043
|
+
|
|
1044
|
+
sage: sr = mq.SR(2, 2, 4, 8)
|
|
1045
|
+
sage: k = sr.base_ring()
|
|
1046
|
+
sage: sr.is_state_array( matrix(k, 4, 4) )
|
|
1047
|
+
False
|
|
1048
|
+
"""
|
|
1049
|
+
return isinstance(d, Matrix) and \
|
|
1050
|
+
d.nrows() == self.r and \
|
|
1051
|
+
d.ncols() == self.c and \
|
|
1052
|
+
d.base_ring() == self.base_ring()
|
|
1053
|
+
|
|
1054
|
+
def random_state_array(self, *args, **kwds):
|
|
1055
|
+
r"""
|
|
1056
|
+
Return a random element in ``MatrixSpace(self.base_ring(),
|
|
1057
|
+
self.r, self.c)``.
|
|
1058
|
+
|
|
1059
|
+
EXAMPLES::
|
|
1060
|
+
|
|
1061
|
+
sage: sr = mq.SR(2, 2, 2, 4)
|
|
1062
|
+
sage: sr.random_state_array().parent()
|
|
1063
|
+
Full MatrixSpace of 2 by 2 dense matrices over Finite Field in a of size 2^4
|
|
1064
|
+
"""
|
|
1065
|
+
return random_matrix(self.base_ring(), self._r, self._c, *args, **kwds)
|
|
1066
|
+
|
|
1067
|
+
def random_vector(self, *args, **kwds):
|
|
1068
|
+
r"""
|
|
1069
|
+
Return a random vector as it might appear in the algebraic
|
|
1070
|
+
expression of ``self``.
|
|
1071
|
+
|
|
1072
|
+
EXAMPLES::
|
|
1073
|
+
|
|
1074
|
+
sage: mq.SR(2, 2, 2, 4).random_vector().parent()
|
|
1075
|
+
Full MatrixSpace of 16 by 1 dense matrices over Finite Field in a of size 2^4
|
|
1076
|
+
|
|
1077
|
+
.. NOTE::
|
|
1078
|
+
|
|
1079
|
+
`\phi` was already applied to the result.
|
|
1080
|
+
"""
|
|
1081
|
+
return self.vector(self.random_state_array(*args, **kwds))
|
|
1082
|
+
|
|
1083
|
+
def random_element(self, elem_type='vector', *args, **kwds):
|
|
1084
|
+
"""
|
|
1085
|
+
Return a random element for ``self``. Other arguments and keywords are
|
|
1086
|
+
passed to random_* methods.
|
|
1087
|
+
|
|
1088
|
+
INPUT:
|
|
1089
|
+
|
|
1090
|
+
- ``elem_type`` -- either 'vector' or 'state array' (default: ``'vector'``)
|
|
1091
|
+
|
|
1092
|
+
EXAMPLES::
|
|
1093
|
+
|
|
1094
|
+
sage: sr = mq.SR()
|
|
1095
|
+
sage: sr.random_element().parent()
|
|
1096
|
+
Full MatrixSpace of 4 by 1 dense matrices over Finite Field in a of size 2^4
|
|
1097
|
+
sage: sr.random_element('state_array').parent()
|
|
1098
|
+
Full MatrixSpace of 1 by 1 dense matrices over Finite Field in a of size 2^4
|
|
1099
|
+
|
|
1100
|
+
Passes extra positional or keyword arguments through::
|
|
1101
|
+
|
|
1102
|
+
sage: sr.random_element(density=0)
|
|
1103
|
+
[0]
|
|
1104
|
+
[0]
|
|
1105
|
+
[0]
|
|
1106
|
+
[0]
|
|
1107
|
+
"""
|
|
1108
|
+
if elem_type == "vector":
|
|
1109
|
+
return self.random_vector(*args, **kwds)
|
|
1110
|
+
elif elem_type == "state_array":
|
|
1111
|
+
return self.random_state_array(*args, **kwds)
|
|
1112
|
+
else:
|
|
1113
|
+
raise TypeError("parameter type not understood")
|
|
1114
|
+
|
|
1115
|
+
def key_schedule(self, kj, i):
|
|
1116
|
+
"""
|
|
1117
|
+
Return `k_i` for a given `i` and `k_j`
|
|
1118
|
+
with `j = i-1`.
|
|
1119
|
+
|
|
1120
|
+
EXAMPLES::
|
|
1121
|
+
|
|
1122
|
+
sage: sr = mq.SR(10, 4, 4, 8, star=True, allow_zero_inversions=True)
|
|
1123
|
+
sage: ki = sr.state_array()
|
|
1124
|
+
sage: for i in range(10):
|
|
1125
|
+
....: ki = sr.key_schedule(ki, i+1)
|
|
1126
|
+
sage: print(sr.hex_str_matrix(ki))
|
|
1127
|
+
B4 3E 23 6F
|
|
1128
|
+
EF 92 E9 8F
|
|
1129
|
+
5B E2 51 18
|
|
1130
|
+
CB 11 CF 8E
|
|
1131
|
+
"""
|
|
1132
|
+
if i < 0:
|
|
1133
|
+
raise TypeError("i must be >= i")
|
|
1134
|
+
|
|
1135
|
+
if i == 0:
|
|
1136
|
+
return kj
|
|
1137
|
+
|
|
1138
|
+
r = self.r
|
|
1139
|
+
c = self.c
|
|
1140
|
+
F = self.base_ring()
|
|
1141
|
+
a = F.gen()
|
|
1142
|
+
SubByte = self.sub_byte
|
|
1143
|
+
|
|
1144
|
+
rc = matrix(F, r, c, ([a**(i-1)] * c) + [F(0)]*((r-1)*c) )
|
|
1145
|
+
ki = matrix(F, r, c)
|
|
1146
|
+
|
|
1147
|
+
if r == 1:
|
|
1148
|
+
s0 = SubByte(kj[0, c-1])
|
|
1149
|
+
|
|
1150
|
+
if c > 1:
|
|
1151
|
+
for q in range(c):
|
|
1152
|
+
ki[0, q] = s0 + sum([kj[0, t] for t in range(q+1) ])
|
|
1153
|
+
else:
|
|
1154
|
+
ki[0, 0] = s0
|
|
1155
|
+
|
|
1156
|
+
elif r == 2:
|
|
1157
|
+
s0 = SubByte(kj[1, c-1])
|
|
1158
|
+
s1 = SubByte(kj[0, c-1])
|
|
1159
|
+
|
|
1160
|
+
if c > 1:
|
|
1161
|
+
for q in range(c):
|
|
1162
|
+
ki[0, q] = s0 + sum([ kj[0, t] for t in range(q+1) ])
|
|
1163
|
+
ki[1, q] = s1 + sum([ kj[1, t] for t in range(q+1) ])
|
|
1164
|
+
else:
|
|
1165
|
+
ki[0, 0] = s0
|
|
1166
|
+
ki[1, 0] = s1
|
|
1167
|
+
|
|
1168
|
+
elif r == 4:
|
|
1169
|
+
|
|
1170
|
+
if self._aes_mode:
|
|
1171
|
+
s0 = SubByte(kj[1, c-1])
|
|
1172
|
+
s1 = SubByte(kj[2, c-1])
|
|
1173
|
+
s2 = SubByte(kj[3, c-1])
|
|
1174
|
+
s3 = SubByte(kj[0, c-1])
|
|
1175
|
+
else:
|
|
1176
|
+
s0 = SubByte(kj[3, c-1])
|
|
1177
|
+
s1 = SubByte(kj[2, c-1])
|
|
1178
|
+
s2 = SubByte(kj[1, c-1])
|
|
1179
|
+
s3 = SubByte(kj[0, c-1])
|
|
1180
|
+
|
|
1181
|
+
if c > 1:
|
|
1182
|
+
for q in range(c):
|
|
1183
|
+
ki[0, q] = s0 + sum([ kj[0, t] for t in range(q+1) ])
|
|
1184
|
+
ki[1, q] = s1 + sum([ kj[1, t] for t in range(q+1) ])
|
|
1185
|
+
ki[2, q] = s2 + sum([ kj[2, t] for t in range(q+1) ])
|
|
1186
|
+
ki[3, q] = s3 + sum([ kj[3, t] for t in range(q+1) ])
|
|
1187
|
+
|
|
1188
|
+
else:
|
|
1189
|
+
ki[0, 0] = s0
|
|
1190
|
+
ki[1, 0] = s1
|
|
1191
|
+
ki[2, 0] = s2
|
|
1192
|
+
ki[3, 0] = s3
|
|
1193
|
+
ki += rc
|
|
1194
|
+
|
|
1195
|
+
return ki
|
|
1196
|
+
|
|
1197
|
+
def __call__(self, P, K):
|
|
1198
|
+
r"""
|
|
1199
|
+
Encrypts the plaintext `P` using the key `K`.
|
|
1200
|
+
|
|
1201
|
+
Both must be given as state arrays or coercible to state arrays.
|
|
1202
|
+
|
|
1203
|
+
INPUT:
|
|
1204
|
+
|
|
1205
|
+
- ``P`` -- plaintext as state array or something coercible to a
|
|
1206
|
+
qstate array
|
|
1207
|
+
|
|
1208
|
+
- ``K`` -- key as state array or something coercible to a state
|
|
1209
|
+
array
|
|
1210
|
+
|
|
1211
|
+
TESTS:
|
|
1212
|
+
|
|
1213
|
+
The official AES test vectors::
|
|
1214
|
+
|
|
1215
|
+
sage: sr = mq.SR(10, 4, 4, 8, star=True, allow_zero_inversions=True)
|
|
1216
|
+
sage: k = sr.base_ring()
|
|
1217
|
+
sage: plaintext = sr.state_array([k.from_integer(e) for e in range(16)])
|
|
1218
|
+
sage: key = sr.state_array([k.from_integer(e) for e in range(16)])
|
|
1219
|
+
sage: print(sr.hex_str_matrix( sr(plaintext, key) ))
|
|
1220
|
+
0A 41 F1 C6
|
|
1221
|
+
94 6E C3 53
|
|
1222
|
+
0B F0 94 EA
|
|
1223
|
+
B5 45 58 5A
|
|
1224
|
+
|
|
1225
|
+
Brian Gladman's development vectors (dev_vec.txt)::
|
|
1226
|
+
|
|
1227
|
+
sage: sr = mq.SR(10, 4, 4, 8, star=True, allow_zero_inversions=True, aes_mode=True)
|
|
1228
|
+
sage: k = sr.base_ring()
|
|
1229
|
+
sage: plain = '3243f6a8885a308d313198a2e0370734'
|
|
1230
|
+
sage: key = '2b7e151628aed2a6abf7158809cf4f3c'
|
|
1231
|
+
sage: from sage.misc.verbose import set_verbose
|
|
1232
|
+
sage: set_verbose(2)
|
|
1233
|
+
sage: cipher = sr(plain, key)
|
|
1234
|
+
R[01].start 193DE3BEA0F4E22B9AC68D2AE9F84808
|
|
1235
|
+
R[01].s_box D42711AEE0BF98F1B8B45DE51E415230
|
|
1236
|
+
R[01].s_row D4BF5D30E0B452AEB84111F11E2798E5
|
|
1237
|
+
R[01].m_col 046681E5E0CB199A48F8D37A2806264C
|
|
1238
|
+
R[01].k_sch A0FAFE1788542CB123A339392A6C7605
|
|
1239
|
+
R[02].start A49C7FF2689F352B6B5BEA43026A5049
|
|
1240
|
+
R[02].s_box 49DED28945DB96F17F39871A7702533B
|
|
1241
|
+
R[02].s_row 49DB873B453953897F02D2F177DE961A
|
|
1242
|
+
R[02].m_col 584DCAF11B4B5AACDBE7CAA81B6BB0E5
|
|
1243
|
+
R[02].k_sch F2C295F27A96B9435935807A7359F67F
|
|
1244
|
+
R[03].start AA8F5F0361DDE3EF82D24AD26832469A
|
|
1245
|
+
R[03].s_box AC73CF7BEFC111DF13B5D6B545235AB8
|
|
1246
|
+
R[03].s_row ACC1D6B8EFB55A7B1323CFDF457311B5
|
|
1247
|
+
R[03].m_col 75EC0993200B633353C0CF7CBB25D0DC
|
|
1248
|
+
R[03].k_sch 3D80477D4716FE3E1E237E446D7A883B
|
|
1249
|
+
R[04].start 486C4EEE671D9D0D4DE3B138D65F58E7
|
|
1250
|
+
R[04].s_box 52502F2885A45ED7E311C807F6CF6A94
|
|
1251
|
+
R[04].s_row 52A4C89485116A28E3CF2FD7F6505E07
|
|
1252
|
+
R[04].m_col 0FD6DAA9603138BF6FC0106B5EB31301
|
|
1253
|
+
R[04].k_sch EF44A541A8525B7FB671253BDB0BAD00
|
|
1254
|
+
R[05].start E0927FE8C86363C0D9B1355085B8BE01
|
|
1255
|
+
R[05].s_box E14FD29BE8FBFBBA35C89653976CAE7C
|
|
1256
|
+
R[05].s_row E1FB967CE8C8AE9B356CD2BA974FFB53
|
|
1257
|
+
R[05].m_col 25D1A9ADBD11D168B63A338E4C4CC0B0
|
|
1258
|
+
R[05].k_sch D4D1C6F87C839D87CAF2B8BC11F915BC
|
|
1259
|
+
R[06].start F1006F55C1924CEF7CC88B325DB5D50C
|
|
1260
|
+
R[06].s_box A163A8FC784F29DF10E83D234CD503FE
|
|
1261
|
+
R[06].s_row A14F3DFE78E803FC10D5A8DF4C632923
|
|
1262
|
+
R[06].m_col 4B868D6D2C4A8980339DF4E837D218D8
|
|
1263
|
+
R[06].k_sch 6D88A37A110B3EFDDBF98641CA0093FD
|
|
1264
|
+
R[07].start 260E2E173D41B77DE86472A9FDD28B25
|
|
1265
|
+
R[07].s_box F7AB31F02783A9FF9B4340D354B53D3F
|
|
1266
|
+
R[07].s_row F783403F27433DF09BB531FF54ABA9D3
|
|
1267
|
+
R[07].m_col 1415B5BF461615EC274656D7342AD843
|
|
1268
|
+
R[07].k_sch 4E54F70E5F5FC9F384A64FB24EA6DC4F
|
|
1269
|
+
R[08].start 5A4142B11949DC1FA3E019657A8C040C
|
|
1270
|
+
R[08].s_box BE832CC8D43B86C00AE1D44DDA64F2FE
|
|
1271
|
+
R[08].s_row BE3BD4FED4E1F2C80A642CC0DA83864D
|
|
1272
|
+
R[08].m_col 00512FD1B1C889FF54766DCDFA1B99EA
|
|
1273
|
+
R[08].k_sch EAD27321B58DBAD2312BF5607F8D292F
|
|
1274
|
+
R[09].start EA835CF00445332D655D98AD8596B0C5
|
|
1275
|
+
R[09].s_box 87EC4A8CF26EC3D84D4C46959790E7A6
|
|
1276
|
+
R[09].s_row 876E46A6F24CE78C4D904AD897ECC395
|
|
1277
|
+
R[09].m_col 473794ED40D4E4A5A3703AA64C9F42BC
|
|
1278
|
+
R[09].k_sch AC7766F319FADC2128D12941575C006E
|
|
1279
|
+
R[10].s_box E9098972CB31075F3D327D94AF2E2CB5
|
|
1280
|
+
R[10].s_row E9317DB5CB322C723D2E895FAF090794
|
|
1281
|
+
R[10].k_sch D014F9A8C9EE2589E13F0CC8B6630CA6
|
|
1282
|
+
R[10].output 3925841D02DC09FBDC118597196A0B32
|
|
1283
|
+
sage: set_verbose(0)
|
|
1284
|
+
"""
|
|
1285
|
+
r, c, e = self.r, self.c, self.e
|
|
1286
|
+
F = self.base_ring()
|
|
1287
|
+
|
|
1288
|
+
if isinstance(P, str):
|
|
1289
|
+
P = self.state_array([F.from_integer(ZZ(P[i: i + 2], 16)) for i in range(0, len(P), 2)])
|
|
1290
|
+
if isinstance(K, str):
|
|
1291
|
+
K = self.state_array([F.from_integer(ZZ(K[i: i + 2], 16)) for i in range(0, len(K), 2)])
|
|
1292
|
+
|
|
1293
|
+
if self.is_state_array(P) and self.is_state_array(K):
|
|
1294
|
+
_type = self.state_array
|
|
1295
|
+
elif self.is_vector(P) and self.is_vector(K):
|
|
1296
|
+
_type = self.vector
|
|
1297
|
+
elif isinstance(P, (list,tuple)) and isinstance(K, (list,tuple)):
|
|
1298
|
+
if len(P) == len(K) == r*c:
|
|
1299
|
+
_type = self.state_array
|
|
1300
|
+
elif len(P) == len(K) == r*c*e:
|
|
1301
|
+
_type = self.vector
|
|
1302
|
+
else:
|
|
1303
|
+
raise TypeError("length %d or %d doesn't match either %d or %d" % (len(P),len(K),r*c,r*c*e))
|
|
1304
|
+
else:
|
|
1305
|
+
raise TypeError("plaintext or key parameter not understood")
|
|
1306
|
+
|
|
1307
|
+
P = self.state_array(P)
|
|
1308
|
+
K = self.state_array(K)
|
|
1309
|
+
|
|
1310
|
+
AddRoundKey = self.add_round_key
|
|
1311
|
+
SubBytes = self.sub_bytes
|
|
1312
|
+
MixColumns = self.mix_columns
|
|
1313
|
+
ShiftRows = self.shift_rows
|
|
1314
|
+
KeyExpansion = self.key_schedule
|
|
1315
|
+
|
|
1316
|
+
P = AddRoundKey(P, K)
|
|
1317
|
+
|
|
1318
|
+
for r in range(self._n-1):
|
|
1319
|
+
if get_verbose() >= 2:
|
|
1320
|
+
print("R[%02d].start %s" % (r+1, self.hex_str_vector(P)))
|
|
1321
|
+
|
|
1322
|
+
P = SubBytes(P)
|
|
1323
|
+
if get_verbose() >= 2:
|
|
1324
|
+
print("R[%02d].s_box %s" % (r+1, self.hex_str_vector(P)))
|
|
1325
|
+
|
|
1326
|
+
P = ShiftRows(P)
|
|
1327
|
+
if get_verbose() >= 2:
|
|
1328
|
+
print("R[%02d].s_row %s" % (r+1, self.hex_str_vector(P)))
|
|
1329
|
+
|
|
1330
|
+
P = MixColumns(P)
|
|
1331
|
+
if get_verbose() >= 2:
|
|
1332
|
+
print("R[%02d].m_col %s" % (r+1, self.hex_str_vector(P)))
|
|
1333
|
+
|
|
1334
|
+
K = KeyExpansion(K, r+1)
|
|
1335
|
+
if get_verbose() >= 2:
|
|
1336
|
+
print("R[%02d].k_sch %s" % (r+1, self.hex_str_vector(K)))
|
|
1337
|
+
|
|
1338
|
+
P = AddRoundKey(P, K)
|
|
1339
|
+
|
|
1340
|
+
P = SubBytes(P)
|
|
1341
|
+
if get_verbose() >= 2:
|
|
1342
|
+
print("R[%02d].s_box %s" % (self.n, self.hex_str_vector(P)))
|
|
1343
|
+
|
|
1344
|
+
P = ShiftRows(P)
|
|
1345
|
+
if get_verbose() >= 2:
|
|
1346
|
+
print("R[%02d].s_row %s" % (self.n, self.hex_str_vector(P)))
|
|
1347
|
+
|
|
1348
|
+
if not self._star:
|
|
1349
|
+
P = MixColumns(P)
|
|
1350
|
+
if get_verbose() >= 2:
|
|
1351
|
+
print("R[%02d].m_col %s" % (self.n, self.hex_str_vector(P)))
|
|
1352
|
+
|
|
1353
|
+
K = KeyExpansion(K, self._n)
|
|
1354
|
+
if get_verbose() >= 2:
|
|
1355
|
+
print("R[%02d].k_sch %s" % (self.n, self.hex_str_vector(K)))
|
|
1356
|
+
|
|
1357
|
+
P = AddRoundKey(P, K)
|
|
1358
|
+
if get_verbose() >= 2:
|
|
1359
|
+
print("R[%02d].output %s" % (self.n, self.hex_str_vector(P)))
|
|
1360
|
+
|
|
1361
|
+
return _type(P)
|
|
1362
|
+
|
|
1363
|
+
def hex_str(self, M, typ='matrix'):
|
|
1364
|
+
r"""
|
|
1365
|
+
Return a hex string for the provided AES state array/matrix.
|
|
1366
|
+
|
|
1367
|
+
INPUT:
|
|
1368
|
+
|
|
1369
|
+
- ``M`` -- state array
|
|
1370
|
+
|
|
1371
|
+
- ``typ`` -- controls what to return, either 'matrix'
|
|
1372
|
+
or 'vector' (default: ``'matrix'``)
|
|
1373
|
+
|
|
1374
|
+
EXAMPLES::
|
|
1375
|
+
|
|
1376
|
+
sage: sr = mq.SR(2, 2, 2, 4)
|
|
1377
|
+
sage: k = sr.base_ring()
|
|
1378
|
+
sage: A = matrix(k, 2, 2, [1, k.gen(), 0, k.gen()^2])
|
|
1379
|
+
sage: sr.hex_str(A)
|
|
1380
|
+
' 1 2 \n 0 4 \n'
|
|
1381
|
+
|
|
1382
|
+
::
|
|
1383
|
+
|
|
1384
|
+
sage: sr.hex_str(A, typ='vector')
|
|
1385
|
+
'1024'
|
|
1386
|
+
"""
|
|
1387
|
+
if typ == "matrix":
|
|
1388
|
+
return self.hex_str_matrix(M)
|
|
1389
|
+
elif typ == "vector":
|
|
1390
|
+
return self.hex_str_vector(M)
|
|
1391
|
+
else:
|
|
1392
|
+
raise TypeError("parameter type must either be 'matrix' or 'vector'")
|
|
1393
|
+
|
|
1394
|
+
def hex_str_matrix(self, M):
|
|
1395
|
+
r"""
|
|
1396
|
+
Return a two-dimensional AES-like representation of the matrix M.
|
|
1397
|
+
|
|
1398
|
+
That is, show the finite field elements as hex strings.
|
|
1399
|
+
|
|
1400
|
+
INPUT:
|
|
1401
|
+
|
|
1402
|
+
- ``M`` -- an AES state array
|
|
1403
|
+
|
|
1404
|
+
EXAMPLES::
|
|
1405
|
+
|
|
1406
|
+
sage: sr = mq.SR(2, 2, 2, 4)
|
|
1407
|
+
sage: k = sr.base_ring()
|
|
1408
|
+
sage: A = matrix(k, 2, 2, [1, k.gen(), 0, k.gen()^2])
|
|
1409
|
+
sage: sr.hex_str_matrix(A)
|
|
1410
|
+
' 1 2 \n 0 4 \n'
|
|
1411
|
+
"""
|
|
1412
|
+
e = M.base_ring().degree()
|
|
1413
|
+
st = [""]
|
|
1414
|
+
for x in range(M.nrows()):
|
|
1415
|
+
for y in range(M.ncols()):
|
|
1416
|
+
if e == 8:
|
|
1417
|
+
st.append("%02X" % M[x, y].to_integer())
|
|
1418
|
+
else:
|
|
1419
|
+
st.append("%X" % M[x, y].to_integer())
|
|
1420
|
+
st.append("\n")
|
|
1421
|
+
return " ".join(st)
|
|
1422
|
+
|
|
1423
|
+
def hex_str_vector(self, M):
|
|
1424
|
+
"""
|
|
1425
|
+
Return a one-dimensional AES-like representation of the matrix M.
|
|
1426
|
+
|
|
1427
|
+
That is, show the finite field elements as hex strings.
|
|
1428
|
+
|
|
1429
|
+
INPUT:
|
|
1430
|
+
|
|
1431
|
+
- ``M`` -- an AES state array
|
|
1432
|
+
|
|
1433
|
+
EXAMPLES::
|
|
1434
|
+
|
|
1435
|
+
sage: sr = mq.SR(2, 2, 2, 4)
|
|
1436
|
+
sage: k = sr.base_ring()
|
|
1437
|
+
sage: A = matrix(k, 2, 2, [1, k.gen(), 0, k.gen()^2])
|
|
1438
|
+
sage: sr.hex_str_vector(A)
|
|
1439
|
+
'1024'
|
|
1440
|
+
"""
|
|
1441
|
+
e = M.base_ring().degree()
|
|
1442
|
+
st = [""]
|
|
1443
|
+
for y in range(M.ncols()):
|
|
1444
|
+
for x in range(M.nrows()):
|
|
1445
|
+
if e == 8:
|
|
1446
|
+
st.append("%02X" % M[x, y].to_integer())
|
|
1447
|
+
else:
|
|
1448
|
+
st.append("%X" % M[x, y].to_integer())
|
|
1449
|
+
#st.append("\n")
|
|
1450
|
+
return "".join(st)
|
|
1451
|
+
|
|
1452
|
+
def _insert_matrix_into_matrix(self, dst, src, row, col):
|
|
1453
|
+
"""
|
|
1454
|
+
Insert matrix src into matrix dst starting at row and col.
|
|
1455
|
+
|
|
1456
|
+
INPUT:
|
|
1457
|
+
|
|
1458
|
+
- ``dst`` -- a matrix
|
|
1459
|
+
|
|
1460
|
+
- ``src`` -- a matrix
|
|
1461
|
+
|
|
1462
|
+
- ``row`` -- offset row
|
|
1463
|
+
|
|
1464
|
+
- ``col`` -- offset columns
|
|
1465
|
+
|
|
1466
|
+
EXAMPLES::
|
|
1467
|
+
|
|
1468
|
+
sage: sr = mq.SR(10, 4, 4, 4)
|
|
1469
|
+
sage: a = sr.k.gen()
|
|
1470
|
+
sage: A = sr.state_array() + 1; A
|
|
1471
|
+
[1 0 0 0]
|
|
1472
|
+
[0 1 0 0]
|
|
1473
|
+
[0 0 1 0]
|
|
1474
|
+
[0 0 0 1]
|
|
1475
|
+
sage: B = Matrix(sr.base_ring(), 2, 2, [0, a, a+1, a^2]); B
|
|
1476
|
+
[ 0 a]
|
|
1477
|
+
[a + 1 a^2]
|
|
1478
|
+
sage: sr._insert_matrix_into_matrix(A, B, 1, 1)
|
|
1479
|
+
[ 1 0 0 0]
|
|
1480
|
+
[ 0 0 a 0]
|
|
1481
|
+
[ 0 a + 1 a^2 0]
|
|
1482
|
+
[ 0 0 0 1]
|
|
1483
|
+
"""
|
|
1484
|
+
for i in range(src.nrows()):
|
|
1485
|
+
for j in range(src.ncols()):
|
|
1486
|
+
dst[row+i, col+j] = src[i, j]
|
|
1487
|
+
return dst
|
|
1488
|
+
|
|
1489
|
+
def varformatstr(self, name, n=None, rc=None, e=None):
|
|
1490
|
+
r"""
|
|
1491
|
+
Return a format string which is understood by print et al.
|
|
1492
|
+
|
|
1493
|
+
If a numerical value is omitted, the default value of ``self``
|
|
1494
|
+
is used. The numerical values (``n``, ``rc``, ``e``) are used
|
|
1495
|
+
to determine the width of the respective fields in the format
|
|
1496
|
+
string.
|
|
1497
|
+
|
|
1498
|
+
INPUT:
|
|
1499
|
+
|
|
1500
|
+
- ``name`` -- name of the variable
|
|
1501
|
+
- ``n`` -- number of rounds (default: ``None``)
|
|
1502
|
+
- ``rc`` -- number of rows \* number of cols (default: ``None``)
|
|
1503
|
+
- ``e`` -- exponent of base field (default: ``None``)
|
|
1504
|
+
|
|
1505
|
+
EXAMPLES::
|
|
1506
|
+
|
|
1507
|
+
sage: sr = mq.SR(1, 2, 2, 4)
|
|
1508
|
+
sage: sr.varformatstr('x')
|
|
1509
|
+
'x%01d%01d%01d'
|
|
1510
|
+
sage: sr.varformatstr('x', n=1000)
|
|
1511
|
+
'x%03d%03d%03d'
|
|
1512
|
+
"""
|
|
1513
|
+
if n is None:
|
|
1514
|
+
n = self.n
|
|
1515
|
+
if rc is None:
|
|
1516
|
+
rc = self.r * self.c
|
|
1517
|
+
if e is None:
|
|
1518
|
+
e = self.e
|
|
1519
|
+
|
|
1520
|
+
l = str(max([ len(str(rc-1)), len(str(n-1)), len(str(e-1)) ] ))
|
|
1521
|
+
if name not in ("k", "s"):
|
|
1522
|
+
pf = self._postfix
|
|
1523
|
+
else:
|
|
1524
|
+
pf = ""
|
|
1525
|
+
format_string = name + pf + "%0" + l + "d" + "%0" + l + "d" + "%0" + l + "d"
|
|
1526
|
+
return format_string
|
|
1527
|
+
|
|
1528
|
+
def varstr(self, name, nr, rc, e):
|
|
1529
|
+
"""
|
|
1530
|
+
Return a string representing a variable for the small scale
|
|
1531
|
+
AES subject to the given constraints.
|
|
1532
|
+
|
|
1533
|
+
INPUT:
|
|
1534
|
+
|
|
1535
|
+
- ``name`` -- variable name
|
|
1536
|
+
- ``nr`` -- number of round to create variable strings for
|
|
1537
|
+
- ``rc`` -- row*column index in state array
|
|
1538
|
+
- ``e`` -- exponent of base field
|
|
1539
|
+
|
|
1540
|
+
EXAMPLES::
|
|
1541
|
+
|
|
1542
|
+
sage: sr = mq.SR(10, 1, 2, 4)
|
|
1543
|
+
sage: sr.varstr('x', 2, 1, 1)
|
|
1544
|
+
'x211'
|
|
1545
|
+
"""
|
|
1546
|
+
format_string = self.varformatstr(name, self.n, self.r*self.c, self.e)
|
|
1547
|
+
return format_string % (nr, rc, e)
|
|
1548
|
+
|
|
1549
|
+
def varstrs(self, name, nr, rc=None, e=None):
|
|
1550
|
+
"""
|
|
1551
|
+
Return a list of strings representing variables in ``self``.
|
|
1552
|
+
|
|
1553
|
+
INPUT:
|
|
1554
|
+
|
|
1555
|
+
- ``name`` -- variable name
|
|
1556
|
+
- ``nr`` -- number of round to create variable strings for
|
|
1557
|
+
- ``rc`` -- number of rows * number of columns in the state array (default: ``None``)
|
|
1558
|
+
- ``e`` -- exponent of base field (default: ``None``)
|
|
1559
|
+
|
|
1560
|
+
EXAMPLES::
|
|
1561
|
+
|
|
1562
|
+
sage: sr = mq.SR(10, 1, 2, 4)
|
|
1563
|
+
sage: sr.varstrs('x', 2)
|
|
1564
|
+
('x200', 'x201', 'x202', 'x203', 'x210', 'x211', 'x212', 'x213')
|
|
1565
|
+
"""
|
|
1566
|
+
if rc is None:
|
|
1567
|
+
rc = self.r * self.c
|
|
1568
|
+
|
|
1569
|
+
if e is None:
|
|
1570
|
+
e = self.e
|
|
1571
|
+
|
|
1572
|
+
n = self._n
|
|
1573
|
+
|
|
1574
|
+
format_string = self.varformatstr(name, n, rc, e)
|
|
1575
|
+
|
|
1576
|
+
return tuple([format_string % (nr, rci, ei) for rci in range(rc) for ei in range(e)])
|
|
1577
|
+
|
|
1578
|
+
def vars(self, name, nr, rc=None, e=None):
|
|
1579
|
+
"""
|
|
1580
|
+
Return a list of variables in ``self``.
|
|
1581
|
+
|
|
1582
|
+
INPUT:
|
|
1583
|
+
|
|
1584
|
+
- ``name`` -- variable name
|
|
1585
|
+
- ``nr`` -- number of round to create variable strings for
|
|
1586
|
+
- ``rc`` -- number of rounds * number of columns in the state array (default: ``None``)
|
|
1587
|
+
- ``e`` -- exponent of base field (default: ``None``)
|
|
1588
|
+
|
|
1589
|
+
EXAMPLES::
|
|
1590
|
+
|
|
1591
|
+
sage: sr = mq.SR(10, 1, 2, 4)
|
|
1592
|
+
sage: sr.vars('x', 2)
|
|
1593
|
+
(x200, x201, x202, x203, x210, x211, x212, x213)
|
|
1594
|
+
"""
|
|
1595
|
+
gd = self.variable_dict()
|
|
1596
|
+
return tuple([gd[s] for s in self.varstrs(name, nr, rc, e)])
|
|
1597
|
+
|
|
1598
|
+
def variable_dict(self):
|
|
1599
|
+
"""
|
|
1600
|
+
Return a dictionary to access variables in ``self.R`` by their
|
|
1601
|
+
names.
|
|
1602
|
+
|
|
1603
|
+
EXAMPLES::
|
|
1604
|
+
|
|
1605
|
+
sage: sr = mq.SR(1,1,1,4)
|
|
1606
|
+
sage: sr.variable_dict()
|
|
1607
|
+
{'k000': k000,
|
|
1608
|
+
'k001': k001,
|
|
1609
|
+
'k002': k002,
|
|
1610
|
+
'k003': k003,
|
|
1611
|
+
'k100': k100,
|
|
1612
|
+
'k101': k101,
|
|
1613
|
+
'k102': k102,
|
|
1614
|
+
'k103': k103,
|
|
1615
|
+
's000': s000,
|
|
1616
|
+
's001': s001,
|
|
1617
|
+
's002': s002,
|
|
1618
|
+
's003': s003,
|
|
1619
|
+
'w100': w100,
|
|
1620
|
+
'w101': w101,
|
|
1621
|
+
'w102': w102,
|
|
1622
|
+
'w103': w103,
|
|
1623
|
+
'x100': x100,
|
|
1624
|
+
'x101': x101,
|
|
1625
|
+
'x102': x102,
|
|
1626
|
+
'x103': x103}
|
|
1627
|
+
|
|
1628
|
+
sage: sr = mq.SR(1,1,1,4,gf2=True)
|
|
1629
|
+
sage: sr.variable_dict() # needs sage.rings.polynomial.pbori
|
|
1630
|
+
{'k000': k000,
|
|
1631
|
+
'k001': k001,
|
|
1632
|
+
'k002': k002,
|
|
1633
|
+
'k003': k003,
|
|
1634
|
+
'k100': k100,
|
|
1635
|
+
'k101': k101,
|
|
1636
|
+
'k102': k102,
|
|
1637
|
+
'k103': k103,
|
|
1638
|
+
's000': s000,
|
|
1639
|
+
's001': s001,
|
|
1640
|
+
's002': s002,
|
|
1641
|
+
's003': s003,
|
|
1642
|
+
'w100': w100,
|
|
1643
|
+
'w101': w101,
|
|
1644
|
+
'w102': w102,
|
|
1645
|
+
'w103': w103,
|
|
1646
|
+
'x100': x100,
|
|
1647
|
+
'x101': x101,
|
|
1648
|
+
'x102': x102,
|
|
1649
|
+
'x103': x103}
|
|
1650
|
+
"""
|
|
1651
|
+
try:
|
|
1652
|
+
R,gd = self._variable_dict
|
|
1653
|
+
if R is self.R:
|
|
1654
|
+
return gd
|
|
1655
|
+
else:
|
|
1656
|
+
pass
|
|
1657
|
+
except AttributeError:
|
|
1658
|
+
pass
|
|
1659
|
+
|
|
1660
|
+
gd = self.R.gens_dict()
|
|
1661
|
+
self._variable_dict = self.R,gd
|
|
1662
|
+
return gd
|
|
1663
|
+
|
|
1664
|
+
def block_order(self):
|
|
1665
|
+
"""
|
|
1666
|
+
Return a block order for ``self`` where each round is a block.
|
|
1667
|
+
|
|
1668
|
+
EXAMPLES::
|
|
1669
|
+
|
|
1670
|
+
sage: sr = mq.SR(2, 1, 1, 4)
|
|
1671
|
+
sage: sr.block_order()
|
|
1672
|
+
Block term order with blocks:
|
|
1673
|
+
(Degree lexicographic term order of length 16,
|
|
1674
|
+
Degree lexicographic term order of length 16,
|
|
1675
|
+
Degree lexicographic term order of length 4)
|
|
1676
|
+
|
|
1677
|
+
::
|
|
1678
|
+
|
|
1679
|
+
sage: P = sr.ring(order='block')
|
|
1680
|
+
sage: print(P.repr_long())
|
|
1681
|
+
Polynomial Ring
|
|
1682
|
+
Base Ring : Finite Field in a of size 2^4
|
|
1683
|
+
Size : 36 Variables
|
|
1684
|
+
Block 0 : Ordering : deglex
|
|
1685
|
+
Names : k200, k201, k202, k203, x200, x201, x202, x203, w200, w201, w202, w203, s100, s101, s102, s103
|
|
1686
|
+
Block 1 : Ordering : deglex
|
|
1687
|
+
Names : k100, k101, k102, k103, x100, x101, x102, x103, w100, w101, w102, w103, s000, s001, s002, s003
|
|
1688
|
+
Block 2 : Ordering : deglex
|
|
1689
|
+
Names : k000, k001, k002, k003
|
|
1690
|
+
"""
|
|
1691
|
+
r = self.r
|
|
1692
|
+
c = self.c
|
|
1693
|
+
e = self.e
|
|
1694
|
+
n = self.n
|
|
1695
|
+
|
|
1696
|
+
T = None
|
|
1697
|
+
for _n in range(n):
|
|
1698
|
+
T = TermOrder('deglex', r*e + 3*r*c*e ) + T
|
|
1699
|
+
|
|
1700
|
+
T += TermOrder('deglex', r*c*e)
|
|
1701
|
+
|
|
1702
|
+
return T
|
|
1703
|
+
|
|
1704
|
+
def ring(self, order=None, reverse_variables=None):
|
|
1705
|
+
r"""
|
|
1706
|
+
Construct a ring as a base ring for the polynomial system.
|
|
1707
|
+
|
|
1708
|
+
By default, variables are ordered in the reverse of their natural
|
|
1709
|
+
ordering, i.e. the reverse of as they appear.
|
|
1710
|
+
|
|
1711
|
+
INPUT:
|
|
1712
|
+
|
|
1713
|
+
- ``order`` -- a monomial ordering (default: ``None``)
|
|
1714
|
+
- ``reverse_variables`` -- reverse rounds of variables (default: ``True``)
|
|
1715
|
+
|
|
1716
|
+
The variable assignment is as follows:
|
|
1717
|
+
|
|
1718
|
+
- `k_{i,j,l}` -- subkey round `i` word `j` conjugate/bit `l`
|
|
1719
|
+
- `s_{i,j,l}` -- subkey inverse round `i` word `j` conjugate/bit `l`
|
|
1720
|
+
- `w_{i,j,l}` -- inversion input round `i` word `j` conjugate/bit `l`
|
|
1721
|
+
- `x_{i,j,l}` -- inversion output round `i` word `j` conjugate/bit `l`
|
|
1722
|
+
|
|
1723
|
+
|
|
1724
|
+
Note that the variables are ordered in column major ordering
|
|
1725
|
+
in the state array and that the bits are ordered in little
|
|
1726
|
+
endian ordering.
|
|
1727
|
+
|
|
1728
|
+
For example, if `x_{0,1,0}` is a variable over `\GF{2}` for
|
|
1729
|
+
`r=2` and `c=2` then refers to the *most* significant bit of
|
|
1730
|
+
the entry in the position (1,0) in the state array matrix.
|
|
1731
|
+
|
|
1732
|
+
EXAMPLES::
|
|
1733
|
+
|
|
1734
|
+
sage: sr = mq.SR(2, 1, 1, 4)
|
|
1735
|
+
sage: P = sr.ring(order='block')
|
|
1736
|
+
sage: print(P.repr_long())
|
|
1737
|
+
Polynomial Ring
|
|
1738
|
+
Base Ring : Finite Field in a of size 2^4
|
|
1739
|
+
Size : 36 Variables
|
|
1740
|
+
Block 0 : Ordering : deglex
|
|
1741
|
+
Names : k200, k201, k202, k203, x200, x201, x202, x203, w200, w201, w202, w203, s100, s101, s102, s103
|
|
1742
|
+
Block 1 : Ordering : deglex
|
|
1743
|
+
Names : k100, k101, k102, k103, x100, x101, x102, x103, w100, w101, w102, w103, s000, s001, s002, s003
|
|
1744
|
+
Block 2 : Ordering : deglex
|
|
1745
|
+
Names : k000, k001, k002, k003
|
|
1746
|
+
"""
|
|
1747
|
+
r = self.r
|
|
1748
|
+
c = self.c
|
|
1749
|
+
e = self.e
|
|
1750
|
+
n = self.n
|
|
1751
|
+
if not self._gf2:
|
|
1752
|
+
k = self.base_ring()
|
|
1753
|
+
else:
|
|
1754
|
+
k = GF(2)
|
|
1755
|
+
|
|
1756
|
+
if order is not None:
|
|
1757
|
+
self._order = order
|
|
1758
|
+
if self._order == 'block':
|
|
1759
|
+
self._order = self.block_order()
|
|
1760
|
+
|
|
1761
|
+
if reverse_variables is None:
|
|
1762
|
+
reverse_variables = self._reverse_variables
|
|
1763
|
+
|
|
1764
|
+
if reverse_variables:
|
|
1765
|
+
process = reversed
|
|
1766
|
+
else:
|
|
1767
|
+
process = lambda x: x
|
|
1768
|
+
|
|
1769
|
+
if reverse_variables:
|
|
1770
|
+
names = []
|
|
1771
|
+
else:
|
|
1772
|
+
names = self.varstrs("k", 0, r*c, e)
|
|
1773
|
+
|
|
1774
|
+
for _n in process(list(range(n))):
|
|
1775
|
+
names += self.varstrs("k", _n+1, r*c, e)
|
|
1776
|
+
names += self.varstrs("x", _n+1, r*c, e)
|
|
1777
|
+
names += self.varstrs("w", _n+1, r*c, e)
|
|
1778
|
+
names += self.varstrs("s", _n, r, e)
|
|
1779
|
+
|
|
1780
|
+
if reverse_variables:
|
|
1781
|
+
names += self.varstrs("k", 0, r*c, e)
|
|
1782
|
+
|
|
1783
|
+
#from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing
|
|
1784
|
+
|
|
1785
|
+
if self._gf2 and self._polybori:
|
|
1786
|
+
return BooleanPolynomialRing(2*n*r*c*e + (n+1)*r*c*e + n*r*e, names, order=self._order)
|
|
1787
|
+
else:
|
|
1788
|
+
return PolynomialRing(k, 2*n*r*c*e + (n+1)*r*c*e + n*r*e, names, order=self._order)
|
|
1789
|
+
|
|
1790
|
+
def round_polynomials(self, i, plaintext=None, ciphertext=None):
|
|
1791
|
+
r"""
|
|
1792
|
+
Return list of polynomials for a given round `i`.
|
|
1793
|
+
|
|
1794
|
+
If ``i == 0`` a plaintext must be provided, if ``i == n`` a
|
|
1795
|
+
ciphertext must be provided.
|
|
1796
|
+
|
|
1797
|
+
INPUT:
|
|
1798
|
+
|
|
1799
|
+
- ``i`` -- round number
|
|
1800
|
+
|
|
1801
|
+
- ``plaintext`` -- plaintext (optional, mandatory in first round)
|
|
1802
|
+
|
|
1803
|
+
- ``ciphertext`` -- ciphertext (optional, mandatory in last round)
|
|
1804
|
+
|
|
1805
|
+
OUTPUT: tuple
|
|
1806
|
+
|
|
1807
|
+
EXAMPLES::
|
|
1808
|
+
|
|
1809
|
+
sage: sr = mq.SR(1, 1, 1, 4)
|
|
1810
|
+
sage: k = sr.base_ring()
|
|
1811
|
+
sage: p = [k.random_element() for _ in range(sr.r*sr.c)]
|
|
1812
|
+
sage: sr.round_polynomials(0, plaintext=p)
|
|
1813
|
+
(w100 + k000..., w101 + k001..., w102 + k002..., w103 + k003...)
|
|
1814
|
+
"""
|
|
1815
|
+
r = self._r
|
|
1816
|
+
c = self._c
|
|
1817
|
+
e = self._e
|
|
1818
|
+
n = self._n
|
|
1819
|
+
R = self.R
|
|
1820
|
+
|
|
1821
|
+
M = self.M
|
|
1822
|
+
|
|
1823
|
+
_vars = self.vars
|
|
1824
|
+
|
|
1825
|
+
if i == 0:
|
|
1826
|
+
w1 = matrix(R, r*c*e, 1, _vars("w", 1, r*c, e))
|
|
1827
|
+
k0 = matrix(R, r*c*e, 1, _vars("k", 0, r*c, e))
|
|
1828
|
+
if isinstance(plaintext, (tuple, list)) and len(plaintext) == r*c:
|
|
1829
|
+
plaintext = matrix(R, r*c*e, 1, self.phi(plaintext))
|
|
1830
|
+
return tuple((w1 + k0 + plaintext).list())
|
|
1831
|
+
|
|
1832
|
+
elif i > 0 and i <= n:
|
|
1833
|
+
|
|
1834
|
+
if self._star and i == n:
|
|
1835
|
+
M = self.Mstar
|
|
1836
|
+
|
|
1837
|
+
xj = matrix(R, r*c*e, 1, _vars("x", i, r*c, e))
|
|
1838
|
+
ki = matrix(R, r*c*e, 1, _vars("k", i, r*c, e))
|
|
1839
|
+
rcon = matrix(R, r*c*e, 1, self.phi([self.sbox_constant()]*r*c))
|
|
1840
|
+
|
|
1841
|
+
if i < n:
|
|
1842
|
+
wj = matrix(R, r*c*e, 1, _vars("w", i+1, r*c, e))
|
|
1843
|
+
if i == n:
|
|
1844
|
+
if isinstance(ciphertext, (tuple, list)) and len(ciphertext) == r*c:
|
|
1845
|
+
ciphertext = matrix(R, r*c*e, 1, self.phi(ciphertext))
|
|
1846
|
+
wj = ciphertext
|
|
1847
|
+
|
|
1848
|
+
lin = (wj + ki + M * xj + rcon).list()
|
|
1849
|
+
|
|
1850
|
+
wi = matrix(R, r*c*e, 1, _vars("w", i, r*c, e))
|
|
1851
|
+
xi = matrix(R, r*c*e, 1, _vars("x", i, r*c, e))
|
|
1852
|
+
sbox = []
|
|
1853
|
+
sbox += self.inversion_polynomials(xi, wi, r*c*e)
|
|
1854
|
+
sbox += self.field_polynomials("x", i)
|
|
1855
|
+
sbox += self.field_polynomials("w", i)
|
|
1856
|
+
return tuple(lin + sbox)
|
|
1857
|
+
|
|
1858
|
+
def key_schedule_polynomials(self, i):
|
|
1859
|
+
r"""
|
|
1860
|
+
Return polynomials for the `i`-th round of the key
|
|
1861
|
+
schedule.
|
|
1862
|
+
|
|
1863
|
+
INPUT:
|
|
1864
|
+
|
|
1865
|
+
- ``i`` -- round (`0 \leq i \leq n`)
|
|
1866
|
+
|
|
1867
|
+
EXAMPLES::
|
|
1868
|
+
|
|
1869
|
+
sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=False)
|
|
1870
|
+
|
|
1871
|
+
The `0`-th subkey is the user provided key, so only conjugacy
|
|
1872
|
+
relations or field polynomials are added.::
|
|
1873
|
+
|
|
1874
|
+
sage: sr.key_schedule_polynomials(0)
|
|
1875
|
+
(k000^2 + k000, k001^2 + k001, k002^2 + k002, k003^2 + k003)
|
|
1876
|
+
|
|
1877
|
+
The 1st subkey is derived from the user provided key according to
|
|
1878
|
+
the key schedule which is non-linear.::
|
|
1879
|
+
|
|
1880
|
+
sage: sr.key_schedule_polynomials(1)
|
|
1881
|
+
(k100 + s000 + s002 + s003,
|
|
1882
|
+
k101 + s000 + s001 + s003 + 1,
|
|
1883
|
+
k102 + s000 + s001 + s002 + 1,
|
|
1884
|
+
k103 + s001 + s002 + s003 + 1,
|
|
1885
|
+
k100^2 + k100, k101^2 + k101, k102^2 + k102, k103^2 + k103,
|
|
1886
|
+
s000^2 + s000, s001^2 + s001, s002^2 + s002, s003^2 + s003,
|
|
1887
|
+
s000*k000 + s000*k003 + s001*k002 + s002*k001 + s003*k000,
|
|
1888
|
+
s000*k000 + s000*k001 + s001*k000 + s001*k003 + s002*k002 + s003*k001,
|
|
1889
|
+
s000*k001 + s000*k002 + s001*k000 + s001*k001 + s002*k000 + s002*k003 + s003*k002,
|
|
1890
|
+
s000*k000 + s000*k001 + s000*k003 + s001*k001 + s002*k000 + s002*k002 + s003*k000 + k000,
|
|
1891
|
+
s000*k002 + s001*k000 + s001*k001 + s001*k003 + s002*k001 + s003*k000 + s003*k002 + k001,
|
|
1892
|
+
s000*k000 + s000*k001 + s000*k002 + s001*k002 + s002*k000 + s002*k001 + s002*k003 + s003*k001 + k002,
|
|
1893
|
+
s000*k001 + s001*k000 + s001*k002 + s002*k000 + s003*k001 + s003*k003 + k003,
|
|
1894
|
+
s000*k000 + s000*k002 + s000*k003 + s001*k000 + s001*k001 + s002*k002 + s003*k000 + s000,
|
|
1895
|
+
s000*k001 + s000*k003 + s001*k001 + s001*k002 + s002*k000 + s002*k003 + s003*k001 + s001,
|
|
1896
|
+
s000*k000 + s000*k002 + s001*k000 + s001*k002 + s001*k003 + s002*k000 + s002*k001 + s003*k002 + s002,
|
|
1897
|
+
s000*k001 + s000*k002 + s001*k000 + s001*k003 + s002*k001 + s003*k003 + s003,
|
|
1898
|
+
s000*k002 + s001*k001 + s002*k000 + s003*k003 + 1)
|
|
1899
|
+
"""
|
|
1900
|
+
R = self.R
|
|
1901
|
+
r = self.r
|
|
1902
|
+
e = self.e
|
|
1903
|
+
c = self.c
|
|
1904
|
+
k = self.k
|
|
1905
|
+
a = k.gen()
|
|
1906
|
+
|
|
1907
|
+
if i < 0:
|
|
1908
|
+
raise TypeError("i must by >= 0")
|
|
1909
|
+
|
|
1910
|
+
if i == 0:
|
|
1911
|
+
return tuple(self.field_polynomials("k", i, r*c))
|
|
1912
|
+
else:
|
|
1913
|
+
L = self.lin_matrix(r)
|
|
1914
|
+
ki = matrix(R, r*c*e, 1, self.vars("k", i , r*c, e))
|
|
1915
|
+
kj = matrix(R, r*c*e, 1, self.vars("k", i-1, r*c, e))
|
|
1916
|
+
si = matrix(R, r*e, 1, self.vars("s", i-1, r, e))
|
|
1917
|
+
|
|
1918
|
+
rc = matrix(R, r*e, 1, self.phi([a**(i-1)] + [k(0)]*(r-1)) )
|
|
1919
|
+
d = matrix(R, r*e, 1, self.phi([self.sbox_constant()]*r) )
|
|
1920
|
+
|
|
1921
|
+
sbox = []
|
|
1922
|
+
|
|
1923
|
+
sbox += self.field_polynomials("k", i)
|
|
1924
|
+
sbox += self.field_polynomials("s", i-1, r)
|
|
1925
|
+
|
|
1926
|
+
if r == 1:
|
|
1927
|
+
sbox += self.inversion_polynomials(kj[(c - 1)*e:(c - 1)*e + e], si[0:e], e)
|
|
1928
|
+
if r == 2:
|
|
1929
|
+
sbox += self.inversion_polynomials( kj[(2*c - 1)*e : (2*c - 1)*e + e] , si[0:1*e], e )
|
|
1930
|
+
sbox += self.inversion_polynomials( kj[(2*c - 2)*e : (2*c - 2)*e + e] , si[e:2*e], e )
|
|
1931
|
+
if r == 4:
|
|
1932
|
+
if self._aes_mode:
|
|
1933
|
+
sbox += self.inversion_polynomials( kj[(4*c-3)*e : (4*c-3)*e + e] , si[0*e : 1*e] , e )
|
|
1934
|
+
sbox += self.inversion_polynomials( kj[(4*c-2)*e : (4*c-2)*e + e] , si[1*e : 2*e] , e )
|
|
1935
|
+
sbox += self.inversion_polynomials( kj[(4*c-1)*e : (4*c-1)*e + e] , si[2*e : 3*e] , e )
|
|
1936
|
+
sbox += self.inversion_polynomials( kj[(4*c-4)*e : (4*c-4)*e + e] , si[3*e : 4*e] , e )
|
|
1937
|
+
else:
|
|
1938
|
+
sbox += self.inversion_polynomials( kj[(4*c-1)*e : (4*c-1)*e + e] , si[0*e : 1*e] , e )
|
|
1939
|
+
sbox += self.inversion_polynomials( kj[(4*c-2)*e : (4*c-2)*e + e] , si[1*e : 2*e] , e )
|
|
1940
|
+
sbox += self.inversion_polynomials( kj[(4*c-3)*e : (4*c-3)*e + e] , si[2*e : 3*e] , e )
|
|
1941
|
+
sbox += self.inversion_polynomials( kj[(4*c-4)*e : (4*c-4)*e + e] , si[3*e : 4*e] , e )
|
|
1942
|
+
|
|
1943
|
+
si = L * si + d + rc
|
|
1944
|
+
Sum = matrix(R, r*e, 1)
|
|
1945
|
+
lin = []
|
|
1946
|
+
if c > 1:
|
|
1947
|
+
for q in range(c):
|
|
1948
|
+
t = list(range(r*e*(q) , r*e*(q+1)))
|
|
1949
|
+
Sum += kj.matrix_from_rows(t)
|
|
1950
|
+
lin += (ki.matrix_from_rows(t) + si + Sum).list()
|
|
1951
|
+
|
|
1952
|
+
else:
|
|
1953
|
+
lin += (ki + si).list()
|
|
1954
|
+
return tuple(lin + sbox)
|
|
1955
|
+
|
|
1956
|
+
def polynomial_system(self, P=None, K=None, C=None):
|
|
1957
|
+
"""
|
|
1958
|
+
Return a polynomial system for this small scale AES variant for a
|
|
1959
|
+
given plaintext-key pair.
|
|
1960
|
+
|
|
1961
|
+
If neither ``P``, ``K`` nor ``C`` are provided, a random pair
|
|
1962
|
+
(``P``, ``K``) will be generated. If ``P`` and ``C`` are
|
|
1963
|
+
provided no ``K`` needs to be provided.
|
|
1964
|
+
|
|
1965
|
+
INPUT:
|
|
1966
|
+
|
|
1967
|
+
- ``P`` -- vector, list, or tuple (default: ``None``)
|
|
1968
|
+
- ``K`` -- vector, list, or tuple (default: ``None``)
|
|
1969
|
+
- ``C`` -- vector, list, or tuple (default: ``None``)
|
|
1970
|
+
|
|
1971
|
+
EXAMPLES::
|
|
1972
|
+
|
|
1973
|
+
sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True)
|
|
1974
|
+
sage: P = sr.vector([0, 0, 1, 0])
|
|
1975
|
+
sage: K = sr.vector([1, 0, 0, 1])
|
|
1976
|
+
sage: F, s = sr.polynomial_system(P, K) # needs sage.rings.polynomial.pbori
|
|
1977
|
+
|
|
1978
|
+
This returns a polynomial system::
|
|
1979
|
+
|
|
1980
|
+
sage: F # needs sage.rings.polynomial.pbori
|
|
1981
|
+
Polynomial Sequence with 36 Polynomials in 20 Variables
|
|
1982
|
+
|
|
1983
|
+
and a solution::
|
|
1984
|
+
|
|
1985
|
+
sage: s # random -- maybe we need a better doctest here? # needs sage.rings.polynomial.pbori
|
|
1986
|
+
{k000: 1, k001: 0, k003: 1, k002: 0}
|
|
1987
|
+
|
|
1988
|
+
This solution is not the only solution that we can learn from the
|
|
1989
|
+
Groebner basis of the system.
|
|
1990
|
+
|
|
1991
|
+
::
|
|
1992
|
+
|
|
1993
|
+
sage: F.groebner_basis()[-3:] # needs sage.rings.polynomial.pbori
|
|
1994
|
+
[k000 + 1, k001, k003 + 1]
|
|
1995
|
+
|
|
1996
|
+
In particular we have two solutions::
|
|
1997
|
+
|
|
1998
|
+
sage: len(F.ideal().variety()) # needs sage.rings.polynomial.pbori
|
|
1999
|
+
2
|
|
2000
|
+
|
|
2001
|
+
In the following example we provide ``C`` explicitly::
|
|
2002
|
+
|
|
2003
|
+
sage: C = sr(P,K)
|
|
2004
|
+
sage: F,s = sr.polynomial_system(P=P, C=C) # needs sage.rings.polynomial.pbori
|
|
2005
|
+
sage: F # needs sage.rings.polynomial.pbori
|
|
2006
|
+
Polynomial Sequence with 36 Polynomials in 20 Variables
|
|
2007
|
+
|
|
2008
|
+
Alternatively, we can use symbols for the ``P`` and
|
|
2009
|
+
``C``. First, we have to create a polynomial ring::
|
|
2010
|
+
|
|
2011
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
2012
|
+
sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True)
|
|
2013
|
+
sage: R = sr.R
|
|
2014
|
+
sage: vn = sr.varstrs("P",0,1,4) + R.variable_names() + sr.varstrs("C",0,1,4)
|
|
2015
|
+
sage: R = BooleanPolynomialRing(len(vn),vn)
|
|
2016
|
+
sage: sr.R = R
|
|
2017
|
+
|
|
2018
|
+
|
|
2019
|
+
Now, we can construct the purely symbolic equation system::
|
|
2020
|
+
|
|
2021
|
+
sage: # needs sage.rings.polynomial.pbori
|
|
2022
|
+
sage: C = sr.vars("C",0); C
|
|
2023
|
+
(C000, C001, C002, C003)
|
|
2024
|
+
sage: P = sr.vars("P",0)
|
|
2025
|
+
sage: F,s = sr.polynomial_system(P=P,C=C)
|
|
2026
|
+
sage: F
|
|
2027
|
+
Polynomial Sequence with 36 Polynomials in 28 Variables
|
|
2028
|
+
sage: F.part(0)
|
|
2029
|
+
(P000 + w100 + k000, P001 + w101 + k001, P002 + w102 + k002, P003 + w103 + k003)
|
|
2030
|
+
sage: F.part(-2)
|
|
2031
|
+
(k100 + x100 + x102 + x103 + C000, k101 + x100 + x101 + x103 + C001 + 1, ...)
|
|
2032
|
+
|
|
2033
|
+
We show that the (returned) key is a solution to the returned system::
|
|
2034
|
+
|
|
2035
|
+
sage: sr = mq.SR(3,4,4,8, star=True, gf2=True, polybori=True)
|
|
2036
|
+
sage: while True: # workaround (see :issue:`31891`) # needs sage.rings.polynomial.pbori
|
|
2037
|
+
....: try:
|
|
2038
|
+
....: F, s = sr.polynomial_system()
|
|
2039
|
+
....: break
|
|
2040
|
+
....: except ZeroDivisionError:
|
|
2041
|
+
....: pass
|
|
2042
|
+
sage: F.subs(s).groebner_basis() # long time # needs sage.rings.polynomial.pbori
|
|
2043
|
+
Polynomial Sequence with 1248 Polynomials in 1248 Variables
|
|
2044
|
+
"""
|
|
2045
|
+
plaintext = P
|
|
2046
|
+
key = K
|
|
2047
|
+
ciphertext = C
|
|
2048
|
+
|
|
2049
|
+
system = []
|
|
2050
|
+
n = self._n
|
|
2051
|
+
|
|
2052
|
+
data = []
|
|
2053
|
+
|
|
2054
|
+
R = self.R
|
|
2055
|
+
r,c,e = self.r,self.c,self.e
|
|
2056
|
+
|
|
2057
|
+
for d in (plaintext, key, ciphertext):
|
|
2058
|
+
if d is None:
|
|
2059
|
+
data.append( None )
|
|
2060
|
+
elif isinstance(d, (tuple, list)):
|
|
2061
|
+
if isinstance(d[0], int):
|
|
2062
|
+
d = [GF(2)(_) for _ in d]
|
|
2063
|
+
if len(d) == r*c*e and (d[0].parent() is R or d[0].parent() == R):
|
|
2064
|
+
data.append( matrix(R,r*c*e,1,d) )
|
|
2065
|
+
continue
|
|
2066
|
+
try:
|
|
2067
|
+
data.append( self.phi(self.state_array(d)) )
|
|
2068
|
+
except ValueError: # GF2 vectors maybe?
|
|
2069
|
+
data.append( self.vector(d) )
|
|
2070
|
+
elif self.is_state_array(d):
|
|
2071
|
+
data.append( self.phi(d) )
|
|
2072
|
+
elif self.is_vector(d):
|
|
2073
|
+
data.append( d )
|
|
2074
|
+
else:
|
|
2075
|
+
data.append( False )
|
|
2076
|
+
|
|
2077
|
+
plaintext, key, ciphertext = data
|
|
2078
|
+
|
|
2079
|
+
if plaintext is False:
|
|
2080
|
+
raise TypeError("type %s of P not understood" % (type(plaintext)))
|
|
2081
|
+
elif plaintext is None:
|
|
2082
|
+
plaintext = self.random_element("vector")
|
|
2083
|
+
|
|
2084
|
+
if key is None:
|
|
2085
|
+
key = self.random_element("vector")
|
|
2086
|
+
elif key is False and ciphertext is False:
|
|
2087
|
+
raise TypeError("type %s of K not understood" % (type(key)))
|
|
2088
|
+
|
|
2089
|
+
if ciphertext is None:
|
|
2090
|
+
ciphertext = self(plaintext, key)
|
|
2091
|
+
elif ciphertext is False:
|
|
2092
|
+
raise TypeError("type %s of C not understood" % (type(ciphertext)))
|
|
2093
|
+
|
|
2094
|
+
for i in range(n+1):
|
|
2095
|
+
system.append( self.round_polynomials(i, plaintext, ciphertext) )
|
|
2096
|
+
system.append( self.key_schedule_polynomials(i) )
|
|
2097
|
+
|
|
2098
|
+
if key is not None:
|
|
2099
|
+
K = dict(zip(self.vars("k", 0), key.list()))
|
|
2100
|
+
else:
|
|
2101
|
+
K = None
|
|
2102
|
+
return PolynomialSequence(self.R, system), K
|
|
2103
|
+
|
|
2104
|
+
|
|
2105
|
+
class SR_gf2n(SR_generic):
|
|
2106
|
+
r"""
|
|
2107
|
+
Small Scale Variants of the AES polynomial system constructor over
|
|
2108
|
+
`\GF{2^n}`.
|
|
2109
|
+
"""
|
|
2110
|
+
def vector(self, d=None):
|
|
2111
|
+
"""
|
|
2112
|
+
Construct a vector suitable for the algebraic representation of
|
|
2113
|
+
SR, i.e. BES.
|
|
2114
|
+
|
|
2115
|
+
INPUT:
|
|
2116
|
+
|
|
2117
|
+
- ``d`` -- values for vector, must be understood by ``self.phi``
|
|
2118
|
+
(default: ``None``)
|
|
2119
|
+
|
|
2120
|
+
EXAMPLES::
|
|
2121
|
+
|
|
2122
|
+
sage: sr = mq.SR()
|
|
2123
|
+
sage: sr
|
|
2124
|
+
SR(1,1,1,4)
|
|
2125
|
+
sage: k = sr.base_ring()
|
|
2126
|
+
sage: A = Matrix(k, 1, 1, [k.gen()])
|
|
2127
|
+
sage: sr.vector(A)
|
|
2128
|
+
[ a]
|
|
2129
|
+
[ a^2]
|
|
2130
|
+
[ a + 1]
|
|
2131
|
+
[a^2 + 1]
|
|
2132
|
+
"""
|
|
2133
|
+
r = self.r
|
|
2134
|
+
c = self.c
|
|
2135
|
+
e = self.e
|
|
2136
|
+
k = self.base_ring()
|
|
2137
|
+
|
|
2138
|
+
if d is None:
|
|
2139
|
+
return matrix(k, r*c*e, 1)
|
|
2140
|
+
elif d.ncols() == c and d.nrows() == r and d.base_ring() == k:
|
|
2141
|
+
return matrix(k, r*c*e, 1, self.phi(d).transpose().list())
|
|
2142
|
+
|
|
2143
|
+
def is_vector(self, d):
|
|
2144
|
+
"""
|
|
2145
|
+
Return ``True`` if ``d`` can be used as a vector for ``self``.
|
|
2146
|
+
|
|
2147
|
+
EXAMPLES::
|
|
2148
|
+
|
|
2149
|
+
sage: sr = mq.SR()
|
|
2150
|
+
sage: sr
|
|
2151
|
+
SR(1,1,1,4)
|
|
2152
|
+
sage: k = sr.base_ring()
|
|
2153
|
+
sage: A = Matrix(k, 1, 1, [k.gen()])
|
|
2154
|
+
sage: B = sr.vector(A)
|
|
2155
|
+
sage: sr.is_vector(A)
|
|
2156
|
+
False
|
|
2157
|
+
sage: sr.is_vector(B)
|
|
2158
|
+
True
|
|
2159
|
+
"""
|
|
2160
|
+
return isinstance(d, Matrix) and \
|
|
2161
|
+
d.nrows() == self.r*self.c*self.e and \
|
|
2162
|
+
d.ncols() == 1 and \
|
|
2163
|
+
d.base_ring() == self.base_ring()
|
|
2164
|
+
|
|
2165
|
+
def phi(self, l):
|
|
2166
|
+
r"""
|
|
2167
|
+
The operation `\phi` from [MR2002]_.
|
|
2168
|
+
|
|
2169
|
+
Projects state arrays to their algebraic representation.
|
|
2170
|
+
|
|
2171
|
+
INPUT:
|
|
2172
|
+
|
|
2173
|
+
- ``l`` -- element to perform `\phi` on
|
|
2174
|
+
|
|
2175
|
+
EXAMPLES::
|
|
2176
|
+
|
|
2177
|
+
sage: sr = mq.SR(2, 1, 2, 4)
|
|
2178
|
+
sage: k = sr.base_ring()
|
|
2179
|
+
sage: A = matrix(k, 1, 2, [k.gen(), 0] )
|
|
2180
|
+
sage: sr.phi(A)
|
|
2181
|
+
[ a 0]
|
|
2182
|
+
[ a^2 0]
|
|
2183
|
+
[ a + 1 0]
|
|
2184
|
+
[a^2 + 1 0]
|
|
2185
|
+
"""
|
|
2186
|
+
ret = []
|
|
2187
|
+
if isinstance(l, Matrix):
|
|
2188
|
+
for e in l.transpose().list():
|
|
2189
|
+
ret += [e**(2**i) for i in range(self.e)]
|
|
2190
|
+
else:
|
|
2191
|
+
for e in l:
|
|
2192
|
+
ret += [e**(2**i) for i in range(self.e)]
|
|
2193
|
+
if isinstance(l, list):
|
|
2194
|
+
return ret
|
|
2195
|
+
elif isinstance(l, tuple):
|
|
2196
|
+
return tuple(ret)
|
|
2197
|
+
elif isinstance(l, Matrix):
|
|
2198
|
+
return matrix(l.base_ring(), l.ncols(), l.nrows()*self.e, ret).transpose()
|
|
2199
|
+
else:
|
|
2200
|
+
raise TypeError
|
|
2201
|
+
|
|
2202
|
+
def antiphi(self, l):
|
|
2203
|
+
r"""
|
|
2204
|
+
The operation `\phi^{-1}` from [MR2002]_ or the inverse of ``self.phi``.
|
|
2205
|
+
|
|
2206
|
+
INPUT:
|
|
2207
|
+
|
|
2208
|
+
- ``l`` -- a vector in the sense of :meth:`is_vector`
|
|
2209
|
+
|
|
2210
|
+
EXAMPLES::
|
|
2211
|
+
|
|
2212
|
+
sage: sr = mq.SR()
|
|
2213
|
+
sage: A = sr.random_state_array()
|
|
2214
|
+
sage: sr.antiphi(sr.phi(A)) == A
|
|
2215
|
+
True
|
|
2216
|
+
"""
|
|
2217
|
+
if isinstance(l, Matrix):
|
|
2218
|
+
ret = l.transpose().list()[0:-1:self.e]
|
|
2219
|
+
else:
|
|
2220
|
+
ret = l[0:-1:self.e]
|
|
2221
|
+
|
|
2222
|
+
if isinstance(l, list):
|
|
2223
|
+
return ret
|
|
2224
|
+
elif isinstance(l, tuple):
|
|
2225
|
+
return tuple(ret)
|
|
2226
|
+
elif isinstance(l, Matrix):
|
|
2227
|
+
return matrix(self.base_ring(), l.ncols(), l.nrows() // self.e,
|
|
2228
|
+
ret).transpose()
|
|
2229
|
+
else:
|
|
2230
|
+
raise TypeError
|
|
2231
|
+
|
|
2232
|
+
def shift_rows_matrix(self):
|
|
2233
|
+
"""
|
|
2234
|
+
Return the ``ShiftRows`` matrix.
|
|
2235
|
+
|
|
2236
|
+
EXAMPLES::
|
|
2237
|
+
|
|
2238
|
+
sage: sr = mq.SR(1, 2, 2, 4)
|
|
2239
|
+
sage: s = sr.random_state_array()
|
|
2240
|
+
sage: r1 = sr.shift_rows(s)
|
|
2241
|
+
sage: r2 = sr.state_array( sr.shift_rows_matrix() * sr.vector(s) )
|
|
2242
|
+
sage: r1 == r2
|
|
2243
|
+
True
|
|
2244
|
+
"""
|
|
2245
|
+
e = self.e
|
|
2246
|
+
r = self.r
|
|
2247
|
+
c = self.c
|
|
2248
|
+
k = self.base_ring()
|
|
2249
|
+
bs = r*c*e
|
|
2250
|
+
shift_rows = matrix(k, bs, bs)
|
|
2251
|
+
I = MatrixSpace(k, e, e)(1)
|
|
2252
|
+
for x in range(c):
|
|
2253
|
+
for y in range(r):
|
|
2254
|
+
_r = ((x*r)+y) * e
|
|
2255
|
+
_c = (((x*r)+((r+1)*y)) * e) % bs
|
|
2256
|
+
self._insert_matrix_into_matrix(shift_rows, I, _r, _c)
|
|
2257
|
+
|
|
2258
|
+
return shift_rows
|
|
2259
|
+
|
|
2260
|
+
def lin_matrix(self, length=None):
|
|
2261
|
+
"""
|
|
2262
|
+
Return the ``Lin`` matrix.
|
|
2263
|
+
|
|
2264
|
+
If no ``length`` is provided, the standard state space size is
|
|
2265
|
+
used. The key schedule calls this method with an explicit
|
|
2266
|
+
length argument because only ``self.r`` S-Box applications are
|
|
2267
|
+
performed in the key schedule.
|
|
2268
|
+
|
|
2269
|
+
INPUT:
|
|
2270
|
+
|
|
2271
|
+
- ``length`` -- length of state space (default: ``None``)
|
|
2272
|
+
|
|
2273
|
+
EXAMPLES::
|
|
2274
|
+
|
|
2275
|
+
sage: sr = mq.SR(1, 1, 1, 4)
|
|
2276
|
+
sage: sr.lin_matrix()
|
|
2277
|
+
[ a^2 + 1 1 a^3 + a^2 a^2 + 1]
|
|
2278
|
+
[ a a 1 a^3 + a^2 + a + 1]
|
|
2279
|
+
[ a^3 + a a^2 a^2 1]
|
|
2280
|
+
[ 1 a^3 a + 1 a + 1]
|
|
2281
|
+
"""
|
|
2282
|
+
r = self.r
|
|
2283
|
+
c = self.c
|
|
2284
|
+
e = self.e
|
|
2285
|
+
k = self.k
|
|
2286
|
+
|
|
2287
|
+
if length is None:
|
|
2288
|
+
length = r*c
|
|
2289
|
+
|
|
2290
|
+
lin = matrix(self.base_ring(), length*e, length*e)
|
|
2291
|
+
if e == 4:
|
|
2292
|
+
l = [k.from_integer(x) for x in (5, 1, 12, 5)]
|
|
2293
|
+
for k in range( 0, length ):
|
|
2294
|
+
for i in range(4):
|
|
2295
|
+
for j in range(4):
|
|
2296
|
+
lin[k*4+j, k*4+i] = l[(i-j) % 4] ** (2**j)
|
|
2297
|
+
elif e == 8:
|
|
2298
|
+
l = [k.from_integer(x) for x in (5, 9, 249, 37, 244, 1, 181, 143)]
|
|
2299
|
+
for k in range( 0, length ):
|
|
2300
|
+
for i in range(8):
|
|
2301
|
+
for j in range(8):
|
|
2302
|
+
lin[k*8+j, k*8+i] = l[(i-j) % 8] ** (2**j)
|
|
2303
|
+
|
|
2304
|
+
return lin
|
|
2305
|
+
|
|
2306
|
+
def mix_columns_matrix(self):
|
|
2307
|
+
"""
|
|
2308
|
+
Return the ``MixColumns`` matrix.
|
|
2309
|
+
|
|
2310
|
+
EXAMPLES::
|
|
2311
|
+
|
|
2312
|
+
sage: sr = mq.SR(1, 2, 2, 4)
|
|
2313
|
+
sage: s = sr.random_state_array()
|
|
2314
|
+
sage: r1 = sr.mix_columns(s)
|
|
2315
|
+
sage: r2 = sr.state_array(sr.mix_columns_matrix() * sr.vector(s))
|
|
2316
|
+
sage: r1 == r2
|
|
2317
|
+
True
|
|
2318
|
+
"""
|
|
2319
|
+
|
|
2320
|
+
def D(b):
|
|
2321
|
+
"""
|
|
2322
|
+
Return the `e x e` matrix `D` with `b^i` along the
|
|
2323
|
+
diagonal.
|
|
2324
|
+
|
|
2325
|
+
EXAMPLES::
|
|
2326
|
+
|
|
2327
|
+
sage: sr = mq.SR(1, 2, 1, 4)
|
|
2328
|
+
sage: sr.mix_columns_matrix() # indirect doctest
|
|
2329
|
+
[ a + 1 0 0 0 a 0 0 0]
|
|
2330
|
+
[ 0 a^2 + 1 0 0 0 a^2 0 0]
|
|
2331
|
+
[ 0 0 a 0 0 0 a + 1 0]
|
|
2332
|
+
[ 0 0 0 a^2 0 0 0 a^2 + 1]
|
|
2333
|
+
[ a 0 0 0 a + 1 0 0 0]
|
|
2334
|
+
[ 0 a^2 0 0 0 a^2 + 1 0 0]
|
|
2335
|
+
[ 0 0 a + 1 0 0 0 a 0]
|
|
2336
|
+
[ 0 0 0 a^2 + 1 0 0 0 a^2]
|
|
2337
|
+
"""
|
|
2338
|
+
D = matrix(self.base_ring(), self._e, self._e)
|
|
2339
|
+
for i in range(self._e):
|
|
2340
|
+
D[i, i] = b**(2**i)
|
|
2341
|
+
return D
|
|
2342
|
+
|
|
2343
|
+
r = self.r
|
|
2344
|
+
c = self.c
|
|
2345
|
+
e = self.e
|
|
2346
|
+
k = self.k
|
|
2347
|
+
a = k.gen()
|
|
2348
|
+
|
|
2349
|
+
M = matrix(k, r*e, r*e)
|
|
2350
|
+
|
|
2351
|
+
if r == 1:
|
|
2352
|
+
self._insert_matrix_into_matrix(M, D(1), 0, 0)
|
|
2353
|
+
|
|
2354
|
+
elif r == 2:
|
|
2355
|
+
self._insert_matrix_into_matrix(M, D(a+1), 0, 0)
|
|
2356
|
+
self._insert_matrix_into_matrix(M, D(a+1), e, e)
|
|
2357
|
+
self._insert_matrix_into_matrix(M, D(a), e, 0)
|
|
2358
|
+
self._insert_matrix_into_matrix(M, D(a), 0, e)
|
|
2359
|
+
|
|
2360
|
+
elif r == 4:
|
|
2361
|
+
self._insert_matrix_into_matrix(M, D(a), 0, 0)
|
|
2362
|
+
self._insert_matrix_into_matrix(M, D(a), e, e)
|
|
2363
|
+
self._insert_matrix_into_matrix(M, D(a), 2*e, 2*e)
|
|
2364
|
+
self._insert_matrix_into_matrix(M, D(a), 3*e, 3*e)
|
|
2365
|
+
|
|
2366
|
+
self._insert_matrix_into_matrix(M, D(a+1), 0, e)
|
|
2367
|
+
self._insert_matrix_into_matrix(M, D(a+1), e, 2*e)
|
|
2368
|
+
self._insert_matrix_into_matrix(M, D(a+1), 2*e, 3*e)
|
|
2369
|
+
self._insert_matrix_into_matrix(M, D(a+1), 3*e, 0)
|
|
2370
|
+
|
|
2371
|
+
self._insert_matrix_into_matrix(M, D(1), 0, 2*e)
|
|
2372
|
+
self._insert_matrix_into_matrix(M, D(1), e, 3*e)
|
|
2373
|
+
self._insert_matrix_into_matrix(M, D(1), 2*e, 0)
|
|
2374
|
+
self._insert_matrix_into_matrix(M, D(1), 3*e, 1*e)
|
|
2375
|
+
|
|
2376
|
+
self._insert_matrix_into_matrix(M, D(1), 0, 3*e)
|
|
2377
|
+
self._insert_matrix_into_matrix(M, D(1), e, 0)
|
|
2378
|
+
self._insert_matrix_into_matrix(M, D(1), 2*e, 1*e)
|
|
2379
|
+
self._insert_matrix_into_matrix(M, D(1), 3*e, 2*e)
|
|
2380
|
+
|
|
2381
|
+
mix_columns = matrix(k, r*c*e, r*c*e)
|
|
2382
|
+
|
|
2383
|
+
for i in range(c):
|
|
2384
|
+
self._insert_matrix_into_matrix(mix_columns, M, r*e*i, r*e*i)
|
|
2385
|
+
|
|
2386
|
+
return mix_columns
|
|
2387
|
+
|
|
2388
|
+
def inversion_polynomials(self, xi, wi, length):
|
|
2389
|
+
"""
|
|
2390
|
+
Return polynomials to represent the inversion in the AES S-Box.
|
|
2391
|
+
|
|
2392
|
+
INPUT:
|
|
2393
|
+
|
|
2394
|
+
- ``xi`` -- output variables
|
|
2395
|
+
|
|
2396
|
+
- ``wi`` -- input variables
|
|
2397
|
+
|
|
2398
|
+
- ``length`` -- length of both lists
|
|
2399
|
+
|
|
2400
|
+
EXAMPLES::
|
|
2401
|
+
|
|
2402
|
+
sage: sr = mq.SR(1, 1, 1, 8)
|
|
2403
|
+
sage: R = sr.ring()
|
|
2404
|
+
sage: xi = Matrix(R, 8, 1, sr.vars('x', 1))
|
|
2405
|
+
sage: wi = Matrix(R, 8, 1, sr.vars('w', 1))
|
|
2406
|
+
sage: sr.inversion_polynomials(xi, wi, 8)
|
|
2407
|
+
[x100*w100 + 1,
|
|
2408
|
+
x101*w101 + 1,
|
|
2409
|
+
x102*w102 + 1,
|
|
2410
|
+
x103*w103 + 1,
|
|
2411
|
+
x104*w104 + 1,
|
|
2412
|
+
x105*w105 + 1,
|
|
2413
|
+
x106*w106 + 1,
|
|
2414
|
+
x107*w107 + 1]
|
|
2415
|
+
"""
|
|
2416
|
+
return [xi[j, 0]*wi[j, 0] + 1 for j in range(length)]
|
|
2417
|
+
|
|
2418
|
+
def field_polynomials(self, name, i, l=None):
|
|
2419
|
+
r"""
|
|
2420
|
+
Return list of conjugacy polynomials for a given round ``i``
|
|
2421
|
+
and name ``name``.
|
|
2422
|
+
|
|
2423
|
+
INPUT:
|
|
2424
|
+
|
|
2425
|
+
- ``name`` -- variable name
|
|
2426
|
+
- ``i`` -- round number
|
|
2427
|
+
- ``l`` -- r\*c (default: ``None``)
|
|
2428
|
+
|
|
2429
|
+
EXAMPLES::
|
|
2430
|
+
|
|
2431
|
+
sage: sr = mq.SR(3, 1, 1, 8)
|
|
2432
|
+
sage: sr.field_polynomials('x', 2)
|
|
2433
|
+
[x200^2 + x201,
|
|
2434
|
+
x201^2 + x202,
|
|
2435
|
+
x202^2 + x203,
|
|
2436
|
+
x203^2 + x204,
|
|
2437
|
+
x204^2 + x205,
|
|
2438
|
+
x205^2 + x206,
|
|
2439
|
+
x206^2 + x207,
|
|
2440
|
+
x207^2 + x200]
|
|
2441
|
+
"""
|
|
2442
|
+
r = self._r
|
|
2443
|
+
c = self._c
|
|
2444
|
+
e = self._e
|
|
2445
|
+
|
|
2446
|
+
if l is None:
|
|
2447
|
+
l = r*c
|
|
2448
|
+
|
|
2449
|
+
_vars = self.vars(name, i, l, e)
|
|
2450
|
+
return [_vars[e*j+k]**2 - _vars[e*j+(k+1) % e] for j in range(l) for k in range(e)]
|
|
2451
|
+
|
|
2452
|
+
|
|
2453
|
+
class SR_gf2(SR_generic):
|
|
2454
|
+
def __init__(self, n=1, r=1, c=1, e=4, star=False, **kwargs):
|
|
2455
|
+
r"""
|
|
2456
|
+
Small Scale Variants of the AES polynomial system constructor over
|
|
2457
|
+
`\GF{2}`. See help for SR.
|
|
2458
|
+
|
|
2459
|
+
EXAMPLES::
|
|
2460
|
+
|
|
2461
|
+
sage: sr = mq.SR(gf2=True)
|
|
2462
|
+
sage: sr
|
|
2463
|
+
SR(1,1,1,4)
|
|
2464
|
+
"""
|
|
2465
|
+
SR_generic.__init__(self, n, r, c, e, star, **kwargs)
|
|
2466
|
+
self._correct_only = kwargs.get("correct_only", False)
|
|
2467
|
+
self._biaffine_only = kwargs.get("biaffine_only", True)
|
|
2468
|
+
|
|
2469
|
+
def vector(self, d=None):
|
|
2470
|
+
"""
|
|
2471
|
+
Construct a vector suitable for the algebraic representation of
|
|
2472
|
+
SR.
|
|
2473
|
+
|
|
2474
|
+
INPUT:
|
|
2475
|
+
|
|
2476
|
+
- ``d`` -- values for vector (default: ``None``)
|
|
2477
|
+
|
|
2478
|
+
EXAMPLES::
|
|
2479
|
+
|
|
2480
|
+
sage: sr = mq.SR(gf2=True)
|
|
2481
|
+
sage: sr
|
|
2482
|
+
SR(1,1,1,4)
|
|
2483
|
+
sage: k = sr.base_ring()
|
|
2484
|
+
sage: A = Matrix(k, 1, 1, [k.gen()])
|
|
2485
|
+
sage: sr.vector(A)
|
|
2486
|
+
[0]
|
|
2487
|
+
[0]
|
|
2488
|
+
[1]
|
|
2489
|
+
[0]
|
|
2490
|
+
"""
|
|
2491
|
+
r = self.r
|
|
2492
|
+
c = self.c
|
|
2493
|
+
e = self.e
|
|
2494
|
+
k = GF(2)
|
|
2495
|
+
|
|
2496
|
+
if d is None:
|
|
2497
|
+
return matrix(k, r*c*e, 1)
|
|
2498
|
+
elif isinstance(d, Matrix) and d.ncols() == c and d.nrows() == r and d.base_ring() == self.k:
|
|
2499
|
+
l = flatten([self.phi(x) for x in d.transpose().list()], (Vector_modn_dense,list,tuple))
|
|
2500
|
+
return matrix(k, r*c*e, 1, l)
|
|
2501
|
+
elif isinstance(d, (list, tuple)):
|
|
2502
|
+
if len(d) == self.r*self.c:
|
|
2503
|
+
l = flatten([self.phi(x) for x in d], (Vector_modn_dense,list,tuple))
|
|
2504
|
+
return matrix(k, r*c*e, 1, l)
|
|
2505
|
+
elif len(d) == self.r*self.c*self.e:
|
|
2506
|
+
return matrix(k, r*c*e, 1, d)
|
|
2507
|
+
else:
|
|
2508
|
+
raise TypeError
|
|
2509
|
+
else:
|
|
2510
|
+
raise TypeError
|
|
2511
|
+
|
|
2512
|
+
def is_vector(self, d):
|
|
2513
|
+
"""
|
|
2514
|
+
Return ``True`` if the given matrix satisfies the conditions
|
|
2515
|
+
for a vector as it appears in the algebraic expression of
|
|
2516
|
+
``self``.
|
|
2517
|
+
|
|
2518
|
+
INPUT:
|
|
2519
|
+
|
|
2520
|
+
- ``d`` -- matrix
|
|
2521
|
+
|
|
2522
|
+
EXAMPLES::
|
|
2523
|
+
|
|
2524
|
+
sage: sr = mq.SR(gf2=True)
|
|
2525
|
+
sage: sr
|
|
2526
|
+
SR(1,1,1,4)
|
|
2527
|
+
sage: k = sr.base_ring()
|
|
2528
|
+
sage: A = Matrix(k, 1, 1, [k.gen()])
|
|
2529
|
+
sage: B = sr.vector(A)
|
|
2530
|
+
sage: sr.is_vector(A)
|
|
2531
|
+
False
|
|
2532
|
+
sage: sr.is_vector(B)
|
|
2533
|
+
True
|
|
2534
|
+
"""
|
|
2535
|
+
return isinstance(d, Matrix) and \
|
|
2536
|
+
d.nrows() == self.r*self.c*self.e and \
|
|
2537
|
+
d.ncols() == 1 and \
|
|
2538
|
+
d.base_ring() == GF(2)
|
|
2539
|
+
|
|
2540
|
+
def phi(self, l, diffusion_matrix=False):
|
|
2541
|
+
r"""
|
|
2542
|
+
The operation `\phi` from [MR2002]_.
|
|
2543
|
+
|
|
2544
|
+
Given a list/matrix of elements in `\GF{2^e}`, return a
|
|
2545
|
+
matching list/matrix of elements in `\GF{2}`.
|
|
2546
|
+
|
|
2547
|
+
INPUT:
|
|
2548
|
+
|
|
2549
|
+
- ``l`` -- element to perform `\phi` on
|
|
2550
|
+
- ``diffusion_matrix`` -- if ``True``, the given matrix ``l`` is
|
|
2551
|
+
transformed to a matrix which performs the same operation
|
|
2552
|
+
over `\GF{2}` as ``l`` over `\GF{2^n}` (default: ``False``).
|
|
2553
|
+
|
|
2554
|
+
EXAMPLES::
|
|
2555
|
+
|
|
2556
|
+
sage: sr = mq.SR(2, 1, 2, 4, gf2=True)
|
|
2557
|
+
sage: k = sr.base_ring()
|
|
2558
|
+
sage: A = matrix(k, 1, 2, [k.gen(), 0] )
|
|
2559
|
+
sage: sr.phi(A) # needs sage.libs.gap
|
|
2560
|
+
[0 0]
|
|
2561
|
+
[0 0]
|
|
2562
|
+
[1 0]
|
|
2563
|
+
[0 0]
|
|
2564
|
+
"""
|
|
2565
|
+
ret = []
|
|
2566
|
+
r, c, e = self.r, self.c, self.e
|
|
2567
|
+
|
|
2568
|
+
# handle diffusion layer matrices first
|
|
2569
|
+
if isinstance(l, Matrix) and diffusion_matrix and \
|
|
2570
|
+
l.nrows() == r*c and l.ncols() == r*c and \
|
|
2571
|
+
l.base_ring() == self.k:
|
|
2572
|
+
B = matrix(GF(2), r*c*e, r*c*e)
|
|
2573
|
+
for x in range(r*c):
|
|
2574
|
+
for y in range(r*c):
|
|
2575
|
+
T = self._mul_matrix(l[x, y])
|
|
2576
|
+
self._insert_matrix_into_matrix(B, T, x*e, y*e)
|
|
2577
|
+
return B
|
|
2578
|
+
|
|
2579
|
+
# ground field elements
|
|
2580
|
+
if l in self.k:
|
|
2581
|
+
return list(reversed(l._vector_()))
|
|
2582
|
+
|
|
2583
|
+
# remaining matrices
|
|
2584
|
+
if isinstance(l, Matrix):
|
|
2585
|
+
for x in l.transpose().list():
|
|
2586
|
+
ret += list(reversed(x._vector_()))
|
|
2587
|
+
# or lists
|
|
2588
|
+
else:
|
|
2589
|
+
for x in l:
|
|
2590
|
+
ret += list(reversed(x._vector_()))
|
|
2591
|
+
|
|
2592
|
+
if isinstance(l, list):
|
|
2593
|
+
return ret
|
|
2594
|
+
elif isinstance(l, tuple):
|
|
2595
|
+
return tuple(ret)
|
|
2596
|
+
elif isinstance(l, Matrix):
|
|
2597
|
+
return matrix(GF(2), l.ncols(), l.nrows()*self.e, ret).transpose()
|
|
2598
|
+
else:
|
|
2599
|
+
raise TypeError
|
|
2600
|
+
|
|
2601
|
+
def antiphi(self, l):
|
|
2602
|
+
r"""
|
|
2603
|
+
The operation `\phi^{-1}` from [MR2002]_ or the inverse of ``self.phi``.
|
|
2604
|
+
|
|
2605
|
+
INPUT:
|
|
2606
|
+
|
|
2607
|
+
- ``l`` -- a vector in the sense of ``self.is_vector``
|
|
2608
|
+
|
|
2609
|
+
EXAMPLES::
|
|
2610
|
+
|
|
2611
|
+
sage: sr = mq.SR(gf2=True)
|
|
2612
|
+
sage: A = sr.random_state_array()
|
|
2613
|
+
sage: sr.antiphi(sr.phi(A)) == A # needs sage.libs.gap
|
|
2614
|
+
True
|
|
2615
|
+
"""
|
|
2616
|
+
e = self.e
|
|
2617
|
+
V = self.k.vector_space(map=False)
|
|
2618
|
+
|
|
2619
|
+
if isinstance(l, Matrix):
|
|
2620
|
+
l2 = l.transpose().list()
|
|
2621
|
+
else:
|
|
2622
|
+
l2 = l
|
|
2623
|
+
|
|
2624
|
+
ret = []
|
|
2625
|
+
for i in range(0, len(l2), e):
|
|
2626
|
+
ret.append( self.k(V(list(reversed(l2[i:i+e])))) )
|
|
2627
|
+
|
|
2628
|
+
if isinstance(l, list):
|
|
2629
|
+
return ret
|
|
2630
|
+
elif isinstance(l, tuple):
|
|
2631
|
+
return tuple(ret)
|
|
2632
|
+
elif isinstance(l, Matrix):
|
|
2633
|
+
return matrix(self.base_ring(), self.r * self.c, 1, ret)
|
|
2634
|
+
else:
|
|
2635
|
+
raise TypeError
|
|
2636
|
+
|
|
2637
|
+
def shift_rows_matrix(self):
|
|
2638
|
+
"""
|
|
2639
|
+
Return the ``ShiftRows`` matrix.
|
|
2640
|
+
|
|
2641
|
+
EXAMPLES::
|
|
2642
|
+
|
|
2643
|
+
sage: sr = mq.SR(1, 2, 2, 4, gf2=True)
|
|
2644
|
+
sage: s = sr.random_state_array()
|
|
2645
|
+
sage: r1 = sr.shift_rows(s)
|
|
2646
|
+
sage: r2 = sr.state_array( sr.shift_rows_matrix() * sr.vector(s) )
|
|
2647
|
+
sage: r1 == r2
|
|
2648
|
+
True
|
|
2649
|
+
"""
|
|
2650
|
+
r = self.r
|
|
2651
|
+
c = self.c
|
|
2652
|
+
k = self.k
|
|
2653
|
+
bs = r*c
|
|
2654
|
+
shift_rows = matrix(k, r*c, r*c)
|
|
2655
|
+
for x in range(c):
|
|
2656
|
+
for y in range(r):
|
|
2657
|
+
_r = ((x*r)+y)
|
|
2658
|
+
_c = ((x*r)+((r+1)*y)) % bs
|
|
2659
|
+
shift_rows[_r, _c] = 1
|
|
2660
|
+
return self.phi(shift_rows, diffusion_matrix=True)
|
|
2661
|
+
|
|
2662
|
+
def mix_columns_matrix(self):
|
|
2663
|
+
"""
|
|
2664
|
+
Return the ``MixColumns`` matrix.
|
|
2665
|
+
|
|
2666
|
+
EXAMPLES::
|
|
2667
|
+
|
|
2668
|
+
sage: sr = mq.SR(1, 2, 2, 4, gf2=True)
|
|
2669
|
+
sage: s = sr.random_state_array()
|
|
2670
|
+
sage: r1 = sr.mix_columns(s)
|
|
2671
|
+
sage: r2 = sr.state_array(sr.mix_columns_matrix() * sr.vector(s))
|
|
2672
|
+
sage: r1 == r2
|
|
2673
|
+
True
|
|
2674
|
+
"""
|
|
2675
|
+
r = self.r
|
|
2676
|
+
c = self.c
|
|
2677
|
+
k = self.k
|
|
2678
|
+
a = k.gen()
|
|
2679
|
+
|
|
2680
|
+
if r == 1:
|
|
2681
|
+
M = matrix(k, r, r, 1)
|
|
2682
|
+
|
|
2683
|
+
elif r == 2:
|
|
2684
|
+
M = matrix(k, r, r, [a+1, a, a, a+1])
|
|
2685
|
+
|
|
2686
|
+
elif r == 4:
|
|
2687
|
+
M = matrix(k, r, [a, a+1, 1, 1,
|
|
2688
|
+
1, a, a+1, 1,
|
|
2689
|
+
1, 1, a, a+1,
|
|
2690
|
+
a+1, 1, 1, a])
|
|
2691
|
+
|
|
2692
|
+
mix_columns = matrix(k, r*c, r*c)
|
|
2693
|
+
|
|
2694
|
+
for i in range(c):
|
|
2695
|
+
self._insert_matrix_into_matrix(mix_columns, M, r*i, r*i)
|
|
2696
|
+
|
|
2697
|
+
return self.phi(mix_columns, diffusion_matrix=True)
|
|
2698
|
+
|
|
2699
|
+
def lin_matrix(self, length=None):
|
|
2700
|
+
"""
|
|
2701
|
+
Return the ``Lin`` matrix.
|
|
2702
|
+
|
|
2703
|
+
If no ``length`` is provided, the standard state space size is
|
|
2704
|
+
used. The key schedule calls this method with an explicit
|
|
2705
|
+
length argument because only ``self.r`` S-Box applications are
|
|
2706
|
+
performed in the key schedule.
|
|
2707
|
+
|
|
2708
|
+
INPUT:
|
|
2709
|
+
|
|
2710
|
+
- ``length`` -- length of state space (default: ``None``)
|
|
2711
|
+
|
|
2712
|
+
EXAMPLES::
|
|
2713
|
+
|
|
2714
|
+
sage: sr = mq.SR(1, 1, 1, 4, gf2=True)
|
|
2715
|
+
sage: sr.lin_matrix()
|
|
2716
|
+
[1 0 1 1]
|
|
2717
|
+
[1 1 0 1]
|
|
2718
|
+
[1 1 1 0]
|
|
2719
|
+
[0 1 1 1]
|
|
2720
|
+
"""
|
|
2721
|
+
r, c, e = self.r, self.c, self.e
|
|
2722
|
+
|
|
2723
|
+
if length is None:
|
|
2724
|
+
length = r*c
|
|
2725
|
+
|
|
2726
|
+
if e == 8:
|
|
2727
|
+
Z = matrix(GF(2), 8, 8, [1, 0, 0, 0, 1, 1, 1, 1,
|
|
2728
|
+
1, 1, 0, 0, 0, 1, 1, 1,
|
|
2729
|
+
1, 1, 1, 0, 0, 0, 1, 1,
|
|
2730
|
+
1, 1, 1, 1, 0, 0, 0, 1,
|
|
2731
|
+
1, 1, 1, 1, 1, 0, 0, 0,
|
|
2732
|
+
0, 1, 1, 1, 1, 1, 0, 0,
|
|
2733
|
+
0, 0, 1, 1, 1, 1, 1, 0,
|
|
2734
|
+
0, 0, 0, 1, 1, 1, 1, 1])
|
|
2735
|
+
else:
|
|
2736
|
+
Z = matrix(GF(2), 4, 4, [1, 1, 1, 0,
|
|
2737
|
+
0, 1, 1, 1,
|
|
2738
|
+
1, 0, 1, 1,
|
|
2739
|
+
1, 1, 0, 1])
|
|
2740
|
+
|
|
2741
|
+
Z = Z.transpose() # account for endianess mismatch
|
|
2742
|
+
|
|
2743
|
+
lin = matrix(GF(2), length*e, length*e)
|
|
2744
|
+
|
|
2745
|
+
for i in range(length):
|
|
2746
|
+
self._insert_matrix_into_matrix(lin, Z, i*e, i*e)
|
|
2747
|
+
return lin
|
|
2748
|
+
|
|
2749
|
+
def _mul_matrix(self, x):
|
|
2750
|
+
r"""
|
|
2751
|
+
Given an element `x` in self.base_ring(), return a matrix
|
|
2752
|
+
which performs the same operation on a when interpreted over
|
|
2753
|
+
`\GF{2^e}` as `x` over `\GF{2^e}`.
|
|
2754
|
+
|
|
2755
|
+
INPUT:
|
|
2756
|
+
|
|
2757
|
+
- ``x`` -- an element in self.base_ring()
|
|
2758
|
+
|
|
2759
|
+
EXAMPLES::
|
|
2760
|
+
|
|
2761
|
+
sage: sr = mq.SR(gf2=True)
|
|
2762
|
+
sage: a = sr.k.gen()
|
|
2763
|
+
sage: A = sr._mul_matrix(a^2+1)
|
|
2764
|
+
sage: sr.antiphi( A * sr.vector([a+1]) )
|
|
2765
|
+
[a^3 + a^2 + a + 1]
|
|
2766
|
+
|
|
2767
|
+
::
|
|
2768
|
+
|
|
2769
|
+
sage: (a^2 + 1)*(a+1)
|
|
2770
|
+
a^3 + a^2 + a + 1
|
|
2771
|
+
"""
|
|
2772
|
+
k = self.k
|
|
2773
|
+
e = self.e
|
|
2774
|
+
a = k.gen()
|
|
2775
|
+
|
|
2776
|
+
columns = [list(reversed((x * a**i)._vector_()))
|
|
2777
|
+
for i in reversed(range(e))]
|
|
2778
|
+
return matrix(GF(2), e, e, columns).transpose()
|
|
2779
|
+
|
|
2780
|
+
def _square_matrix(self):
|
|
2781
|
+
"""
|
|
2782
|
+
Return a matrix of dimension self.e x self.e which performs the
|
|
2783
|
+
squaring operation over `GF(2^n)` on vectors of length e.
|
|
2784
|
+
|
|
2785
|
+
EXAMPLES::
|
|
2786
|
+
|
|
2787
|
+
sage: sr = mq.SR(gf2=True)
|
|
2788
|
+
sage: a = sr.k.gen()
|
|
2789
|
+
sage: S = sr._square_matrix()
|
|
2790
|
+
sage: sr.antiphi( S * sr.vector([a^3+1]) )
|
|
2791
|
+
[a^3 + a^2 + 1]
|
|
2792
|
+
|
|
2793
|
+
::
|
|
2794
|
+
|
|
2795
|
+
sage: (a^3 + 1)^2
|
|
2796
|
+
a^3 + a^2 + 1
|
|
2797
|
+
"""
|
|
2798
|
+
a = self.k.gen()
|
|
2799
|
+
e = self.e
|
|
2800
|
+
|
|
2801
|
+
columns = []
|
|
2802
|
+
for i in reversed(range(e)):
|
|
2803
|
+
columns.append( list(reversed(((a**i)**2)._vector_())) )
|
|
2804
|
+
return matrix(GF(2), e , e, columns).transpose()
|
|
2805
|
+
|
|
2806
|
+
def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, correct_only=None):
|
|
2807
|
+
"""
|
|
2808
|
+
Return inversion polynomials of a single S-Box.
|
|
2809
|
+
|
|
2810
|
+
INPUT:
|
|
2811
|
+
|
|
2812
|
+
- ``xi`` -- output variables
|
|
2813
|
+
- ``wi`` -- input variables
|
|
2814
|
+
- ``length`` -- length of both lists
|
|
2815
|
+
|
|
2816
|
+
EXAMPLES::
|
|
2817
|
+
|
|
2818
|
+
sage: sr = mq.SR(1, 1, 1, 8, gf2=True)
|
|
2819
|
+
sage: len(sr.inversion_polynomials_single_sbox())
|
|
2820
|
+
24
|
|
2821
|
+
sage: len(sr.inversion_polynomials_single_sbox(correct_only=True))
|
|
2822
|
+
23
|
|
2823
|
+
sage: len(sr.inversion_polynomials_single_sbox(biaffine_only=False))
|
|
2824
|
+
40
|
|
2825
|
+
sage: len(sr.inversion_polynomials_single_sbox(biaffine_only=False, correct_only=True))
|
|
2826
|
+
39
|
|
2827
|
+
|
|
2828
|
+
|
|
2829
|
+
sage: sr = mq.SR(1, 1, 1, 8, gf2=True)
|
|
2830
|
+
sage: l0 = sr.inversion_polynomials_single_sbox(); len(l0)
|
|
2831
|
+
24
|
|
2832
|
+
sage: l1 = sr.inversion_polynomials_single_sbox(correct_only=True); len(l1)
|
|
2833
|
+
23
|
|
2834
|
+
sage: l2 = sr.inversion_polynomials_single_sbox(biaffine_only=False); len(l2)
|
|
2835
|
+
40
|
|
2836
|
+
sage: l3 = sr.inversion_polynomials_single_sbox(biaffine_only=False, correct_only=True); len(l3)
|
|
2837
|
+
39
|
|
2838
|
+
|
|
2839
|
+
sage: set(l0) == set(sr._inversion_polynomials_single_sbox())
|
|
2840
|
+
True
|
|
2841
|
+
sage: set(l1) == set(sr._inversion_polynomials_single_sbox(correct_only=True))
|
|
2842
|
+
True
|
|
2843
|
+
sage: set(l2) == set(sr._inversion_polynomials_single_sbox(biaffine_only=False))
|
|
2844
|
+
True
|
|
2845
|
+
sage: set(l3) == set(sr._inversion_polynomials_single_sbox(biaffine_only=False, correct_only=True))
|
|
2846
|
+
True
|
|
2847
|
+
|
|
2848
|
+
sage: sr = mq.SR(1, 1, 1, 4, gf2=True)
|
|
2849
|
+
sage: l0 = sr.inversion_polynomials_single_sbox(); len(l0)
|
|
2850
|
+
12
|
|
2851
|
+
sage: l1 = sr.inversion_polynomials_single_sbox(correct_only=True); len(l1)
|
|
2852
|
+
11
|
|
2853
|
+
sage: l2 = sr.inversion_polynomials_single_sbox(biaffine_only=False); len(l2)
|
|
2854
|
+
20
|
|
2855
|
+
sage: l3 = sr.inversion_polynomials_single_sbox(biaffine_only=False, correct_only=True); len(l3)
|
|
2856
|
+
19
|
|
2857
|
+
|
|
2858
|
+
sage: set(l0) == set(sr._inversion_polynomials_single_sbox())
|
|
2859
|
+
True
|
|
2860
|
+
sage: set(l1) == set(sr._inversion_polynomials_single_sbox(correct_only=True))
|
|
2861
|
+
True
|
|
2862
|
+
sage: set(l2) == set(sr._inversion_polynomials_single_sbox(biaffine_only=False))
|
|
2863
|
+
True
|
|
2864
|
+
sage: set(l3) == set(sr._inversion_polynomials_single_sbox(biaffine_only=False, correct_only=True))
|
|
2865
|
+
True
|
|
2866
|
+
"""
|
|
2867
|
+
e = self.e
|
|
2868
|
+
|
|
2869
|
+
if biaffine_only is None:
|
|
2870
|
+
biaffine_only = self._biaffine_only
|
|
2871
|
+
if correct_only is None:
|
|
2872
|
+
correct_only = self._correct_only
|
|
2873
|
+
|
|
2874
|
+
if x is None and w is None:
|
|
2875
|
+
# make sure it prints like in the book.
|
|
2876
|
+
names = ["w%d" % i for i in reversed(range(e))] + ["x%d" % i for i in reversed(range(e))]
|
|
2877
|
+
P = PolynomialRing(GF(2), e*2, names, order='lex')
|
|
2878
|
+
x = P.gens()[e:]
|
|
2879
|
+
w = P.gens()[:e]
|
|
2880
|
+
else:
|
|
2881
|
+
if isinstance(x, (tuple, list)):
|
|
2882
|
+
P = x[0].parent()
|
|
2883
|
+
elif isinstance(x, Matrix):
|
|
2884
|
+
P = x.base_ring()
|
|
2885
|
+
else:
|
|
2886
|
+
raise TypeError("x not understood")
|
|
2887
|
+
|
|
2888
|
+
if isinstance(x, Matrix):
|
|
2889
|
+
x = x.column(0).list()
|
|
2890
|
+
if isinstance(w, Matrix):
|
|
2891
|
+
w = w.column(0).list()
|
|
2892
|
+
|
|
2893
|
+
if e == 4:
|
|
2894
|
+
w3,w2,w1,w0 = w
|
|
2895
|
+
x3,x2,x1,x0 = x
|
|
2896
|
+
|
|
2897
|
+
l = [w3*x3 + w3*x0 + w2*x1 + w1*x2 + w0*x3,
|
|
2898
|
+
w3*x3 + w3*x2 + w2*x3 + w2*x0 + w1*x1 + w0*x2,
|
|
2899
|
+
w3*x2 + w3*x1 + w2*x3 + w2*x2 + w1*x3 + w1*x0 + w0*x1,
|
|
2900
|
+
w3*x3 + w3*x2 + w3*x0 + w2*x2 + w1*x3 + w1*x1 + w0*x3 + x3,
|
|
2901
|
+
w3*x1 + w2*x3 + w2*x2 + w2*x0 + w1*x2 + w0*x3 + w0*x1 + x2,
|
|
2902
|
+
w3*x3 + w3*x2 + w3*x1 + w2*x1 + w1*x3 + w1*x2 + w1*x0 + w0*x2 + x1,
|
|
2903
|
+
w3*x2 + w2*x3 + w2*x1 + w1*x3 + w0*x2 + w0*x0 + x0,
|
|
2904
|
+
w3*x3 + w3*x1 + w3*x0 + w3 + w2*x3 + w2*x2 + w1*x1 + w0*x3,
|
|
2905
|
+
w3*x2 + w3*x0 + w2*x2 + w2*x1 + w2 + w1*x3 + w1*x0 + w0*x2,
|
|
2906
|
+
w3*x3 + w3*x1 + w2*x3 + w2*x1 + w2*x0 + w1*x3 + w1*x2 + w1 + w0*x1,
|
|
2907
|
+
w3*x2 + w3*x1 + w2*x3 + w2*x0 + w1*x2 + w0*x0 + w0]
|
|
2908
|
+
|
|
2909
|
+
if not correct_only:
|
|
2910
|
+
l.append(w3*x1 + w2*x2 + w1*x3 + w0*x0 + 1)
|
|
2911
|
+
|
|
2912
|
+
if not biaffine_only:
|
|
2913
|
+
l.extend([w3*x2 + w3*x1 + w3*x0 + w2*x3 + w2*x1 + w1*x3 + w1*x2 + w0*x3 + x3**2 + x3*x2 + x3*x1 + x2**2 + x1**2,
|
|
2914
|
+
w3*x2 + w2*x2 + w2*x1 + w2*x0 + w1*x3 + w1*x1 + w0*x3 + w0*x2 + x3*x2 + x3*x1 + x3*x0 + x2**2 + x2*x1 + x2*x0 + x1*x0,
|
|
2915
|
+
w3*x2 + w3*x1 + w2*x2 + w1*x2 + w1*x1 + w1*x0 + w0*x3 + w0*x1 + x3**2 + x3*x2 + x2*x0 + x1*x0,
|
|
2916
|
+
w3*x3 + w3*x1 + w2*x3 + w2*x2 + w1*x3 + w0*x3 + w0*x2 + w0*x1 + w0*x0 + x3*x1 + x2*x1 + x2*x0 + x0**2,
|
|
2917
|
+
w3**2 + w3*w2 + w3*w1 + w3*x2 + w3*x1 + w3*x0 + w2**2 + w2*x3 + w2*x1 + w1**2 + w1*x3 + w1*x2 + w0*x3,
|
|
2918
|
+
w3*w2 + w3*w1 + w3*w0 + w3*x1 + w3*x0 + w2**2 + w2*w1 + w2*w0 + w2*x3 + w2*x2 + w2*x0 + w1*w0 + w1*x2 + w1*x1 + w0*x2,
|
|
2919
|
+
w3**2 + w3*w2 + w3*x0 + w2*w0 + w2*x3 + w2*x2 + w2*x1 + w1*w0 + w1*x3 + w1*x1 + w1*x0 + w0*x1,
|
|
2920
|
+
w3*w1 + w3*x3 + w3*x2 + w3*x1 + w3*x0 + w2*w1 + w2*w0 + w2*x2 + w2*x0 + w1*x3 + w1*x0 + w0**2 + w0*x0])
|
|
2921
|
+
return l
|
|
2922
|
+
|
|
2923
|
+
else:
|
|
2924
|
+
w7,w6,w5,w4,w3,w2,w1,w0 = w
|
|
2925
|
+
x7,x6,x5,x4,x3,x2,x1,x0 = x
|
|
2926
|
+
|
|
2927
|
+
l = [w7*x7 + w7*x5 + w7*x4 + w7*x0 + w6*x6 + w6*x5 + w6*x1 + w5*x7 + w5*x6 + w5*x2 + w4*x7 + w4*x3 + w3*x4 + w2*x5 + w1*x6 + w0*x7,
|
|
2928
|
+
w7*x6 + w7*x4 + w7*x3 + w6*x7 + w6*x5 + w6*x4 + w6*x0 + w5*x6 + w5*x5 + w5*x1 + w4*x7 + w4*x6 + w4*x2 + w3*x7 + w3*x3 + w2*x4 + w1*x5 + w0*x6,
|
|
2929
|
+
w7*x5 + w7*x3 + w7*x2 + w6*x6 + w6*x4 + w6*x3 + w5*x7 + w5*x5 + w5*x4 + w5*x0 + w4*x6 + w4*x5 + w4*x1 + w3*x7 + w3*x6 + w3*x2 + w2*x7 + w2*x3 + w1*x4 + w0*x5,
|
|
2930
|
+
w7*x7 + w7*x4 + w7*x2 + w7*x1 + w6*x5 + w6*x3 + w6*x2 + w5*x6 + w5*x4 + w5*x3 + w4*x7 + w4*x5 + w4*x4 + w4*x0 + w3*x6 + w3*x5 + w3*x1 + w2*x7 + w2*x6 + w2*x2 + w1*x7 + w1*x3 + w0*x4,
|
|
2931
|
+
w7*x7 + w7*x6 + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x2 + w5*x7 + w5*x6 + w5*x5 + w5*x3 + w4*x7 + w4*x6 + w4*x4 + w3*x7 + w3*x5 + w3*x0 + w2*x6 + w2*x1
|
|
2932
|
+
+ w1*x7 + w1*x2 + w0*x3,
|
|
2933
|
+
w7*x6 + w7*x3 + w7*x2 + w6*x7 + w6*x4 + w6*x3 + w5*x5 + w5*x4 + w4*x6 + w4*x5 + w3*x7 + w3*x6 + w2*x7 + w2*x0 + w1*x1 + w0*x2,
|
|
2934
|
+
w7*x7 + w7*x5 + w7*x2 + w7*x1 + w6*x6 + w6*x3 + w6*x2 + w5*x7 + w5*x4 + w5*x3 + w4*x5 + w4*x4 + w3*x6 + w3*x5 + w2*x7 + w2*x6 + w1*x7 + w1*x0 + w0*x1,
|
|
2935
|
+
w7*x6 + w7*x5 + w7*x2 + w7*x0 + w6*x7 + w6*x4 + w6*x3 + w5*x7 + w5*x6 + w5*x3 + w5*x1 + w4*x5 + w4*x4 + w3*x7 + w3*x4 + w3*x2 + w2*x6 + w2*x5 + w1*x5 + w1*x3 + w0*x7 + w0*x6 + x7,
|
|
2936
|
+
w7*x6 + w7*x3 + w7*x2 + w6*x6 + w6*x5 + w6*x2 + w6*x0 + w5*x7 + w5*x4 + w5*x3 + w4*x7 + w4*x6 + w4*x3 + w4*x1 + w3*x5 + w3*x4 + w2*x7 + w2*x4 + w2*x2 + w1*x6 + w1*x5 + w0*x5 + w0*x3
|
|
2937
|
+
+ x6,
|
|
2938
|
+
w7*x7 + w7*x5 + w7*x4 + w7*x1 + w6*x6 + w6*x3 + w6*x2 + w5*x6 + w5*x5 + w5*x2 + w5*x0 + w4*x7 + w4*x4 + w4*x3 + w3*x7 + w3*x6 + w3*x3 + w3*x1 + w2*x5 + w2*x4 + w1*x7 + w1*x4 + w1*x2
|
|
2939
|
+
+ w0*x6 + w0*x5 + x5,
|
|
2940
|
+
w7*x7 + w7*x5 + w7*x2 + w7*x1 + w6*x7 + w6*x5 + w6*x4 + w6*x1 + w5*x6 + w5*x3 + w5*x2 + w4*x6 + w4*x5 + w4*x2 + w4*x0 + w3*x7 + w3*x4 + w3*x3 + w2*x7 + w2*x6 + w2*x3 + w2*x1 + w1*x5
|
|
2941
|
+
+ w1*x4 + w0*x7 + w0*x4 + w0*x2 + x4,
|
|
2942
|
+
w7*x5 + w7*x4 + w7*x3 + w7*x2 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w6*x1 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w4*x6 + w4*x5 + w4*x4 + w4*x3 + w4*x2 + w3*x7 + w3*x6 + w3*x5 + w3*x4 + w3*x0
|
|
2943
|
+
+ w2*x7 + w2*x6 + w2*x5 + w2*x4 + w2*x3 + w1*x7 + w1*x6 + w1*x5 + w1*x1 + w0*x7 + w0*x6 + w0*x5 + w0*x4 + x3,
|
|
2944
|
+
w7*x7 + w7*x6 + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w6*x7 + w6*x5 + w6*x2 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x2 + w4*x6 + w4*x3 + w3*x7 + w3*x6 + w3*x5 + w3*x3 + w2*x7 + w2*x4 + w2*x0
|
|
2945
|
+
+ w1*x7 + w1*x6 + w1*x4 + w0*x5 + w0*x1 + x2,
|
|
2946
|
+
w7*x6 + w7*x4 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w5*x7 + w5*x5 + w5*x2 + w4*x7 + w4*x6 + w4*x5 + w4*x4 + w4*x2 + w3*x6 + w3*x3 + w2*x7 + w2*x6 + w2*x5 + w2*x3
|
|
2947
|
+
+ w1*x7 + w1*x4 + w1*x0 + w0*x7 + w0*x6 + w0*x4 + x1,
|
|
2948
|
+
w7*x7 + w7*x4 + w7*x3 + w6*x7 + w6*x6 + w6*x3 + w6*x1 + w5*x5 + w5*x4 + w4*x7 + w4*x4 + w4*x2 + w3*x6 + w3*x5 + w2*x5 + w2*x3 + w1*x7 + w1*x6 + w0*x6 + w0*x4 + w0*x0 + x0,
|
|
2949
|
+
w7*x6 + w7*x5 + w7*x3 + w7*x0 + w7 + w6*x7 + w6*x5 + w6*x2 + w6*x0 + w5*x7 + w5*x4 + w5*x2 + w5*x1 + w4*x6 + w4*x4 + w4*x3 + w3*x6 + w3*x5 + w3*x1 + w2*x7 + w2*x3 + w1*x5 + w0*x7,
|
|
2950
|
+
w7*x5 + w7*x4 + w7*x2 + w6*x7 + w6*x6 + w6*x4 + w6*x1 + w6 + w5*x6 + w5*x3 + w5*x1 + w5*x0 + w4*x5 + w4*x3 + w4*x2 + w3*x7 + w3*x5 + w3*x4 + w3*x0 + w2*x7 + w2*x6 + w2*x2 + w1*x4
|
|
2951
|
+
+ w0*x6,
|
|
2952
|
+
w7*x7 + w7*x4 + w7*x3 + w7*x1 + w6*x6 + w6*x5 + w6*x3 + w6*x0 + w5*x7 + w5*x5 + w5*x2 + w5*x0 + w5 + w4*x7 + w4*x4 + w4*x2 + w4*x1 + w3*x6 + w3*x4 + w3*x3 + w2*x6 + w2*x5 + w2*x1
|
|
2953
|
+
+ w1*x7 + w1*x3 + w0*x5,
|
|
2954
|
+
w7*x7 + w7*x6 + w7*x3 + w7*x2 + w7*x0 + w6*x5 + w6*x4 + w6*x2 + w5*x7 + w5*x6 + w5*x4 + w5*x1 + w4*x6 + w4*x3 + w4*x1 + w4*x0 + w4 + w3*x5 + w3*x3 + w3*x2 + w2*x7 + w2*x5 + w2*x4
|
|
2955
|
+
+ w2*x0 + w1*x7 + w1*x6 + w1*x2 + w0*x4,
|
|
2956
|
+
w7*x3 + w7*x2 + w7*x1 + w7*x0 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w6*x1 + w6*x0 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w5*x2 + w5*x1 + w5*x0 + w4*x7 + w4*x6 + w4*x5 + w4*x4
|
|
2957
|
+
+ w4*x3 + w4*x2 + w4*x0 + w3*x7 + w3*x6 + w3*x5 + w3*x4 + w3*x2 + w3 + w2*x7 + w2*x6 + w2*x4 + w1*x6 + w1*x1 + w0*x3,
|
|
2958
|
+
w7*x7 + w7*x6 + w7*x5 + w7*x3 + w7*x2 + w7*x1 + w6*x7 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w5*x7 + w5*x6 + w5*x5 + w5*x3 + w5*x0 + w4*x7 + w4*x5 + w4*x2 + w4*x1 + w3*x7 + w3*x4
|
|
2959
|
+
+ w3*x3 + w2*x6 + w2*x5 + w2 + w1*x7 + w1*x0 + w0*x2,
|
|
2960
|
+
w7*x6 + w7*x5 + w7*x4 + w7*x2 + w7*x1 + w7*x0 + w6*x7 + w6*x6 + w6*x4 + w6*x3 + w6*x2 + w6*x0 + w5*x6 + w5*x5 + w5*x4 + w5*x2 + w4*x7 + w4*x6 + w4*x4 + w4*x1 + w4*x0 + w3*x6
|
|
2961
|
+
+ w3*x3 + w3*x2 + w2*x5 + w2*x4 + w1*x7 + w1*x6 + w1 + w0*x1,
|
|
2962
|
+
w7*x7 + w7*x6 + w7*x4 + w7*x1 + w6*x6 + w6*x3 + w6*x1 + w6*x0 + w5*x5 + w5*x3 + w5*x2 + w4*x7 + w4*x5 + w4*x4 + w4*x0 + w3*x7 + w3*x6 + w3*x2 + w2*x4 + w1*x6 + w0*x0 + w0]
|
|
2963
|
+
|
|
2964
|
+
if not correct_only:
|
|
2965
|
+
l.append(w7*x6 + w7*x5 + w7*x1 + w6*x7 + w6*x6 + w6*x2 + w5*x7 + w5*x3 + w4*x4 + w3*x5 + w2*x6 + w1*x7 + w0*x0 + 1)
|
|
2966
|
+
|
|
2967
|
+
if not biaffine_only:
|
|
2968
|
+
l.extend([w7**2 + w7*w6 + w7*w3 + w7*w1 + w7*x7 + w7*x6 + w7*x5 + w7*x2 + w7*x1 + w7*x0 + w6**2 + w6*w0 + w6*x6 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w6*x0 + w5**2 + w5*w4 + w5*w3
|
|
2969
|
+
+ w5*w2 + w5*x7 + w5*x5 + w5*x4 + w5*x1 + w5*x0 + w4**2 + w4*w2 + w4*w0 + w4*x5 + w4*x4 + w4*x2 + w3*w2 + w3*x6 + w3*x3 + w3*x1 + w3*x0 + w2*x7 + w2*x5 + w2*x4
|
|
2970
|
+
+ w2*x0 + w1*x4 + w0**2 + w0*x0,
|
|
2971
|
+
w7*x6 + w7*x4 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x2 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w5*x1 + w4*x5 + w4*x4 + w4*x3 + w4*x1 + w4*x0 + w3*x7 + w3*x5 + w3*x2
|
|
2972
|
+
+ w2*x7 + w2*x6 + w2*x3 + w1*x7 + w1*x6 + w1*x5 + w1*x4 + w1*x2 + w0*x6 + w0*x5 + w0*x4 + w0*x2 + w0*x1 + x7**2 + x7*x6 + x7*x5 + x7*x3 + x7*x1 + x7*x0 + x6*x2
|
|
2973
|
+
+ x6*x1 + x5*x4 + x5*x3 + x5*x2 + x5*x1 + x4*x3 + x4*x2 + x4*x1 + x3**2 + x3*x2 + x2*x1 + x2*x0,
|
|
2974
|
+
w7*x5 + w7*x4 + w7*x3 + w7*x1 + w7*x0 + w6*x7 + w6*x5 + w6*x2 + w5*x7 + w5*x6 + w5*x3 + w4*x7 + w4*x6 + w4*x5 + w4*x4 + w4*x2 + w3*x6 + w3*x5 + w3*x4 + w3*x2 + w3*x1
|
|
2975
|
+
+ w2*x6 + w2*x3 + w1*x7 + w1*x4 + w0*x7 + w0*x6 + w0*x5 + w0*x3 + x7*x3 + x7*x2 + x6*x5 + x6*x4 + x6*x3 + x6*x2 + x6*x0 + x5*x4 + x5*x3 + x5*x2 + x4**2 + x4*x3
|
|
2976
|
+
+ x3*x2 + x3*x1,
|
|
2977
|
+
w7*w3 + w7*w2 + w7*x6 + w7*x5 + w7*x4 + w7*x1 + w7*x0 + w6*w5 + w6*w4 + w6*w3 + w6*w2 + w6*w0 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w6*x0 + w5*w4 + w5*w3 + w5*w2 + w5*x7
|
|
2978
|
+
+ w5*x6 + w5*x4 + w5*x3 + w5*x0 + w4**2 + w4*w3 + w4*x7 + w4*x4 + w4*x3 + w4*x1 + w3*w2 + w3*w1 + w3*x7 + w3*x5 + w3*x2 + w3*x0 + w2*x6 + w2*x4 + w2*x3 + w1*x7
|
|
2979
|
+
+ w1*x3 + w0*x7,
|
|
2980
|
+
w7*x5 + w7*x2 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x2 + w6*x1 + w5*x5 + w5*x3 + w5*x2 + w4*x3 + w4*x2 + w4*x1 + w3*x6 + w3*x3 + w3*x2 + w3*x0 + w2*x7 + w2*x6
|
|
2981
|
+
+ w2*x5 + w2*x3 + w2*x2 + w1*x6 + w1*x4 + w1*x3 + w0*x4 + w0*x3 + w0*x2 + x7*x5 + x7*x4 + x7*x1 + x7*x0 + x6*x0 + x5**2 + x5*x2 + x5*x1 + x5*x0 + x4**2 + x4*x0
|
|
2982
|
+
+ x3*x2 + x3*x0 + x1**2,
|
|
2983
|
+
w7*w6 + w7*w5 + w7*w4 + w7*w3 + w7*x7 + w7*x5 + w7*x4 + w7*x3 + w7*x0 + w6**2 + w6*w5 + w6*w4 + w6*w2 + w6*w1 + w6*w0 + w6*x7 + w6*x4 + w6*x3 + w6*x2 + w6*x1 + w5*w4
|
|
2984
|
+
+ w5*w1 + w5*w0 + w5*x7 + w5*x6 + w5*x5 + w5*x3 + w5*x2 + w4*w2 + w4*w1 + w4*x7 + w4*x6 + w4*x3 + w4*x2 + w4*x0 + w3*w0 + w3*x7 + w3*x6 + w3*x4 + w3*x1 + w2**2
|
|
2985
|
+
+ w2*x5 + w2*x3 + w2*x2 + w1*x7 + w1*x6 + w1*x2 + w0*x6,
|
|
2986
|
+
w7*w5 + w7*w4 + w7*w1 + w7*w0 + w7*x6 + w7*x2 + w6*w0 + w6*x6 + w6*x3 + w6*x2 + w6*x1 + w5**2 + w5*w2 + w5*w1 + w5*w0 + w5*x7 + w5*x6 + w5*x5 + w5*x2 + w4**2 + w4*w0
|
|
2987
|
+
+ w4*x6 + w4*x1 + w4*x0 + w3*w2 + w3*w0 + w3*x5 + w3*x4 + w3*x3 + w3*x2 + w3*x1 + w3*x0 + w2*x7 + w2*x6 + w2*x5 + w2*x4 + w2*x3 + w2*x2 + w2*x0 + w1**2 + w1*x7
|
|
2988
|
+
+ w1*x6 + w1*x4 + w0*x3,
|
|
2989
|
+
w7*x7 + w7*x6 + w7*x5 + w7*x2 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w5*x5 + w5*x4 + w5*x3 + w5*x1 + w5*x0 + w4*x7 + w4*x5 + w4*x2 + w3*x7 + w3*x6 + w3*x3
|
|
2990
|
+
+ w2*x7 + w2*x6 + w2*x5 + w2*x4 + w2*x2 + w1*x6 + w1*x5 + w1*x4 + w1*x2 + w1*x1 + w0*x6 + w0*x3 + x7**2 + x7*x5 + x7*x3 + x6**2 + x6*x5 + x6*x2 + x6*x0 + x5**2
|
|
2991
|
+
+ x4**2 + x4*x3 + x4*x2 + x4*x1 + x3**2 + x3*x1 + x2*x1,
|
|
2992
|
+
w7**2 + w7*w6 + w7*w5 + w7*w3 + w7*w1 + w7*w0 + w7*x6 + w7*x5 + w7*x3 + w7*x2 + w7*x1 + w6*w2 + w6*w1 + w6*x7 + w6*x6 + w6*x5 + w6*x2 + w6*x1 + w6*x0 + w5*w4 + w5*w3
|
|
2993
|
+
+ w5*w2 + w5*w1 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w5*x1 + w5*x0 + w4*w3 + w4*w2 + w4*w1 + w4*x7 + w4*x5 + w4*x4 + w4*x1 + w4*x0 + w3**2 + w3*w2 + w3*x5 + w3*x4
|
|
2994
|
+
+ w3*x2 + w2*w1 + w2*w0 + w2*x6 + w2*x3 + w2*x1 + w2*x0 + w1*x7 + w1*x5 + w1*x4 + w1*x0 + w0*x4,
|
|
2995
|
+
w7*x7 + w7*x5 + w7*x2 + w6*x7 + w6*x6 + w6*x3 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x2 + w4*x6 + w4*x5 + w4*x4 + w4*x2 + w4*x1 + w3*x6 + w3*x3 + w2*x7 + w2*x4 + w1*x7
|
|
2996
|
+
+ w1*x6 + w1*x5 + w1*x3 + w0*x7 + w0*x6 + w0*x5 + w0*x3 + w0*x2 + w0*x0 + x7**2 + x7*x6 + x7*x3 + x7*x1 + x6**2 + x6*x0 + x5**2 + x5*x4 + x5*x3 + x5*x2 + x4**2
|
|
2997
|
+
+ x4*x2 + x4*x0 + x3*x2 + x0**2,
|
|
2998
|
+
w7*x7 + w7*x6 + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w6*x0 + w5*x7 + w5*x5 + w5*x2 + w4*x7 + w4*x6 + w4*x3 + w3*x7 + w3*x6 + w3*x5 + w3*x4
|
|
2999
|
+
+ w3*x2 + w2*x6 + w2*x5 + w2*x4 + w2*x2 + w2*x1 + w1*x6 + w1*x3 + w0*x7 + w0*x4 + x7*x6 + x7*x5 + x7*x4 + x7*x3 + x6**2 + x6*x5 + x6*x4 + x6*x2 + x6*x1 + x6*x0
|
|
3000
|
+
+ x5*x4 + x5*x1 + x5*x0 + x4*x2 + x4*x1 + x3*x0 + x2**2,
|
|
3001
|
+
w7*x5 + w7*x4 + w7*x3 + w7*x2 + w6*x7 + w6*x1 + w5*x5 + w5*x4 + w5*x3 + w5*x2 + w5*x1 + w4*x7 + w4*x6 + w4*x4 + w4*x3 + w3*x6 + w3*x5 + w3*x4 + w3*x3 + w2*x2 + w2*x0
|
|
3002
|
+
+ w1*x6 + w1*x5 + w1*x4 + w1*x3 + w1*x2 + w0*x7 + w0*x5 + w0*x4 + x7**2 + x7*x4 + x7*x2 + x6*x4 + x6*x3 + x6*x2 + x6*x1 + x5**2 + x5*x4 + x5*x3 + x5*x2 + x5*x0
|
|
3003
|
+
+ x4*x3 + x4*x2 + x4*x1 + x3**2 + x2*x0 + x1*x0,
|
|
3004
|
+
w7*x6 + w7*x5 + w7*x3 + w7*x2 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w5*x7 + w5*x1 + w4*x5 + w4*x4 + w4*x3 + w4*x2 + w4*x1 + w3*x7 + w3*x6 + w3*x4 + w3*x3 + w2*x6 + w2*x5
|
|
3005
|
+
+ w2*x4 + w2*x3 + w1*x2 + w1*x0 + w0*x6 + w0*x5 + w0*x4 + w0*x3 + w0*x2 + x7*x5 + x7*x2 + x7*x0 + x6**2 + x6*x5 + x6*x2 + x6*x1 + x6*x0 + x5**2 + x5*x4 + x4**2
|
|
3006
|
+
+ x4*x2 + x4*x1 + x4*x0 + x3**2 + x3*x2 + x1*x0,
|
|
3007
|
+
w7**2 + w7*w5 + w7*w3 + w7*x7 + w7*x6 + w7*x4 + w7*x3 + w7*x2 + w6**2 + w6*w5 + w6*w2 + w6*w0 + w6*x7 + w6*x6 + w6*x3 + w6*x2 + w6*x1 + w6*x0 + w5**2 + w5*x7 + w5*x6
|
|
3008
|
+
+ w5*x5 + w5*x4 + w5*x2 + w5*x1 + w4**2 + w4*w3 + w4*w2 + w4*w1 + w4*x6 + w4*x5 + w4*x2 + w4*x1 + w3**2 + w3*w1 + w3*x6 + w3*x5 + w3*x3 + w3*x0 + w2*w1 + w2*x7
|
|
3009
|
+
+ w2*x4 + w2*x2 + w2*x1 + w1*x6 + w1*x5 + w1*x1 + w0*x5,
|
|
3010
|
+
w7*w5 + w7*w2 + w7*w0 + w7*x5 + w7*x3 + w6**2 + w6*w5 + w6*w2 + w6*w1 + w6*w0 + w6*x7 + w6*x3 + w6*x2 + w6*x0 + w5**2 + w5*w4 + w5*x7 + w5*x6 + w5*x4 + w5*x2 + w5*x0
|
|
3011
|
+
+ w4**2 + w4*w2 + w4*w1 + w4*w0 + w4*x6 + w4*x4 + w4*x3 + w4*x2 + w4*x0 + w3**2 + w3*w2 + w3*x7 + w3*x6 + w3*x4 + w3*x3 + w3*x2 + w3*x0 + w2*x7 + w2*x6 + w2*x4
|
|
3012
|
+
+ w2*x1 + w2*x0 + w1*w0 + w1*x5 + w1*x4 + w0*x1,
|
|
3013
|
+
w7**2 + w7*w4 + w7*w2 + w7*x6 + w7*x4 + w7*x0 + w6*w4 + w6*w3 + w6*w2 + w6*w1 + w6*x4 + w6*x3 + w6*x1 + w5**2 + w5*w4 + w5*w3 + w5*w2 + w5*w0 + w5*x7 + w5*x5 + w5*x3
|
|
3014
|
+
+ w5*x1 + w5*x0 + w4*w3 + w4*w2 + w4*w1 + w4*x7 + w4*x5 + w4*x4 + w4*x3 + w4*x1 + w4*x0 + w3**2 + w3*x7 + w3*x5 + w3*x4 + w3*x3 + w3*x1 + w2*w0 + w2*x7 + w2*x5
|
|
3015
|
+
+ w2*x2 + w2*x1 + w1*w0 + w1*x6 + w1*x5 + w0*x2])
|
|
3016
|
+
|
|
3017
|
+
return l
|
|
3018
|
+
|
|
3019
|
+
def _inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, correct_only=None):
|
|
3020
|
+
"""
|
|
3021
|
+
Generate inversion polynomials of a single S-box.
|
|
3022
|
+
|
|
3023
|
+
INPUT:
|
|
3024
|
+
|
|
3025
|
+
- ``x`` -- output variables (default: ``None``)
|
|
3026
|
+
- ``w`` -- input variables (default: ``None``)
|
|
3027
|
+
- ``biaffine_only`` -- only include biaffine polynomials (default: object default)
|
|
3028
|
+
- ``correct_only`` -- only include correct polynomials (default: object default)
|
|
3029
|
+
|
|
3030
|
+
EXAMPLES::
|
|
3031
|
+
|
|
3032
|
+
sage: sr = mq.SR(1, 1, 1, 8, gf2=True)
|
|
3033
|
+
sage: len(sr._inversion_polynomials_single_sbox())
|
|
3034
|
+
24
|
|
3035
|
+
sage: len(sr._inversion_polynomials_single_sbox(correct_only=True))
|
|
3036
|
+
23
|
|
3037
|
+
sage: len(sr._inversion_polynomials_single_sbox(biaffine_only=False))
|
|
3038
|
+
40
|
|
3039
|
+
sage: len(sr._inversion_polynomials_single_sbox(biaffine_only=False, correct_only=True))
|
|
3040
|
+
39
|
|
3041
|
+
"""
|
|
3042
|
+
e = self.e
|
|
3043
|
+
|
|
3044
|
+
if biaffine_only is None:
|
|
3045
|
+
biaffine_only = self._biaffine_only
|
|
3046
|
+
if correct_only is None:
|
|
3047
|
+
correct_only = self._correct_only
|
|
3048
|
+
|
|
3049
|
+
if x is None and w is None:
|
|
3050
|
+
# make sure it prints like in the book.
|
|
3051
|
+
names = ["w%d" % i for i in reversed(range(e))] + ["x%d" % i for i in reversed(range(e))]
|
|
3052
|
+
P = PolynomialRing(GF(2), e*2, names, order='lex')
|
|
3053
|
+
x = matrix(P, e, 1, P.gens()[e:])
|
|
3054
|
+
w = matrix(P, e, 1, P.gens()[:e])
|
|
3055
|
+
else:
|
|
3056
|
+
if isinstance(x, (tuple, list)):
|
|
3057
|
+
P = x[0].parent()
|
|
3058
|
+
elif isinstance(x, Matrix):
|
|
3059
|
+
P = x.base_ring()
|
|
3060
|
+
else:
|
|
3061
|
+
raise TypeError("x not understood")
|
|
3062
|
+
|
|
3063
|
+
if isinstance(x, (tuple, list)):
|
|
3064
|
+
x = matrix(P, e, 1, x)
|
|
3065
|
+
if isinstance(w, (tuple, list)):
|
|
3066
|
+
w = matrix(P, e, 1, w)
|
|
3067
|
+
|
|
3068
|
+
T = self._mul_matrix(self.k.gen())
|
|
3069
|
+
o = matrix(P, e, 1, [0]*(e-1) + [1])
|
|
3070
|
+
|
|
3071
|
+
columns = []
|
|
3072
|
+
for i in reversed(range(e)):
|
|
3073
|
+
columns.append((T**i * w).list())
|
|
3074
|
+
Cw = matrix(P, e, e, columns).transpose()
|
|
3075
|
+
|
|
3076
|
+
columns = []
|
|
3077
|
+
for i in reversed(range(e)):
|
|
3078
|
+
columns.append((T**i * x).list())
|
|
3079
|
+
Cx = matrix(P, e, e, columns).transpose()
|
|
3080
|
+
|
|
3081
|
+
S = self._square_matrix()
|
|
3082
|
+
|
|
3083
|
+
l = []
|
|
3084
|
+
if correct_only:
|
|
3085
|
+
l.append( (Cw * x + o).list()[:-1] )
|
|
3086
|
+
else:
|
|
3087
|
+
l.append( (Cw * x + o).list() )
|
|
3088
|
+
l.append( (Cw * S * x + x).list() )
|
|
3089
|
+
l.append( (Cx * S * w + w).list() )
|
|
3090
|
+
if not biaffine_only:
|
|
3091
|
+
l.append( ((Cw * S**2 + Cx*S)*x).list() )
|
|
3092
|
+
l.append( ((Cx * S**2 + Cw*S)*w).list() )
|
|
3093
|
+
|
|
3094
|
+
return sum(l, [])
|
|
3095
|
+
|
|
3096
|
+
def inversion_polynomials(self, xi, wi, length):
|
|
3097
|
+
"""
|
|
3098
|
+
Return polynomials to represent the inversion in the AES S-Box.
|
|
3099
|
+
|
|
3100
|
+
INPUT:
|
|
3101
|
+
|
|
3102
|
+
- ``xi`` -- output variables
|
|
3103
|
+
|
|
3104
|
+
- ``wi`` -- input variables
|
|
3105
|
+
|
|
3106
|
+
- ``length`` -- length of both lists
|
|
3107
|
+
|
|
3108
|
+
EXAMPLES::
|
|
3109
|
+
|
|
3110
|
+
sage: sr = mq.SR(1, 1, 1, 8, gf2=True)
|
|
3111
|
+
sage: xi = sr.vars('x', 1) # needs sage.rings.polynomial.pbori
|
|
3112
|
+
sage: wi = sr.vars('w', 1) # needs sage.rings.polynomial.pbori
|
|
3113
|
+
sage: sr.inversion_polynomials(xi, wi, len(xi))[:3] # needs sage.rings.polynomial.pbori
|
|
3114
|
+
[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,
|
|
3115
|
+
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,
|
|
3116
|
+
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]
|
|
3117
|
+
"""
|
|
3118
|
+
if isinstance(xi, Matrix):
|
|
3119
|
+
xi = xi.list()
|
|
3120
|
+
if isinstance(wi, Matrix):
|
|
3121
|
+
wi = wi.list()
|
|
3122
|
+
|
|
3123
|
+
e = self.e
|
|
3124
|
+
l = []
|
|
3125
|
+
for j in range(0, length, e):
|
|
3126
|
+
l += self.inversion_polynomials_single_sbox(xi[j:j+e], wi[j:j+e])
|
|
3127
|
+
return l
|
|
3128
|
+
|
|
3129
|
+
def field_polynomials(self, name, i, l=None):
|
|
3130
|
+
r"""
|
|
3131
|
+
Return list of field polynomials for a given round ``i`` and
|
|
3132
|
+
name ``name``.
|
|
3133
|
+
|
|
3134
|
+
INPUT:
|
|
3135
|
+
|
|
3136
|
+
- ``name`` -- variable name
|
|
3137
|
+
- ``i`` -- round number
|
|
3138
|
+
- ``l`` -- length of variable list (default: ``None`` = r\*c)
|
|
3139
|
+
|
|
3140
|
+
EXAMPLES::
|
|
3141
|
+
|
|
3142
|
+
sage: sr = mq.SR(3, 1, 1, 8, gf2=True, polybori=False)
|
|
3143
|
+
sage: sr.field_polynomials('x', 2)
|
|
3144
|
+
[x200^2 + x200, x201^2 + x201,
|
|
3145
|
+
x202^2 + x202, x203^2 + x203,
|
|
3146
|
+
x204^2 + x204, x205^2 + x205,
|
|
3147
|
+
x206^2 + x206, x207^2 + x207]
|
|
3148
|
+
|
|
3149
|
+
::
|
|
3150
|
+
|
|
3151
|
+
sage: sr = mq.SR(3, 1, 1, 8, gf2=True, polybori=True)
|
|
3152
|
+
sage: sr.field_polynomials('x', 2)
|
|
3153
|
+
[]
|
|
3154
|
+
"""
|
|
3155
|
+
r = self._r
|
|
3156
|
+
c = self._c
|
|
3157
|
+
e = self._e
|
|
3158
|
+
|
|
3159
|
+
if l is None:
|
|
3160
|
+
l = r*c
|
|
3161
|
+
|
|
3162
|
+
if self._polybori:
|
|
3163
|
+
return []
|
|
3164
|
+
_vars = self.vars(name, i, l, e)
|
|
3165
|
+
return [_vars[e*j+k]**2 - _vars[e*j+k] for j in range(l) for k in range(e)]
|
|
3166
|
+
|
|
3167
|
+
|
|
3168
|
+
class SR_gf2_2(SR_gf2):
|
|
3169
|
+
"""
|
|
3170
|
+
This is an example how to customize the SR constructor.
|
|
3171
|
+
|
|
3172
|
+
In this example, we replace the S-Box inversion polynomials by the
|
|
3173
|
+
polynomials generated by the S-Box class.
|
|
3174
|
+
"""
|
|
3175
|
+
def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, correct_only=None, groebner=False):
|
|
3176
|
+
"""
|
|
3177
|
+
Return inversion polynomials of a single S-Box.
|
|
3178
|
+
|
|
3179
|
+
INPUT:
|
|
3180
|
+
|
|
3181
|
+
- ``x`` -- output variables (default: ``None``)
|
|
3182
|
+
- ``w`` -- input variables (default: ``None``)
|
|
3183
|
+
- ``biaffine_only`` -- ignored (always ``False``)
|
|
3184
|
+
- ``correct_only`` -- ignored (always ``True``)
|
|
3185
|
+
- ``groebner`` -- precompute the Groebner basis for this S-Box (default: ``False``)
|
|
3186
|
+
|
|
3187
|
+
EXAMPLES::
|
|
3188
|
+
|
|
3189
|
+
sage: from sage.crypto.mq.sr import SR_gf2_2
|
|
3190
|
+
sage: e = 4
|
|
3191
|
+
sage: sr = SR_gf2_2(1, 1, 1, e)
|
|
3192
|
+
sage: P = PolynomialRing(GF(2),['x%d'%i for i in range(e)] + ['w%d'%i for i in range(e)],order='lex')
|
|
3193
|
+
sage: X,W = P.gens()[:e],P.gens()[e:]
|
|
3194
|
+
sage: sr.inversion_polynomials_single_sbox(X, W, groebner=True) # needs sage.libs.singular
|
|
3195
|
+
[x0 + w0*w1*w2 + w0*w1 + w0*w2 + w0*w3 + w0 + w1 + w2,
|
|
3196
|
+
x1 + w0*w1*w3 + w0*w3 + w0 + w1*w3 + w1 + w2*w3,
|
|
3197
|
+
x2 + w0*w2*w3 + w0*w2 + w0 + w1*w2 + w1*w3 + w2*w3,
|
|
3198
|
+
x3 + w0*w1*w2 + w0 + w1*w2*w3 + w1*w2 + w1*w3 + w1 + w2 + w3]
|
|
3199
|
+
|
|
3200
|
+
sage: from sage.crypto.mq.sr import SR_gf2_2
|
|
3201
|
+
sage: e = 4
|
|
3202
|
+
sage: sr = SR_gf2_2(1, 1, 1, e)
|
|
3203
|
+
sage: sr.inversion_polynomials_single_sbox() # needs sage.libs.singular
|
|
3204
|
+
[w3*w1 + w3*w0 + w3*x2 + w3*x1 + w3 + w2*w1 + w1 + x3 + x2 + x1,
|
|
3205
|
+
w3*w2 + w3*w1 + w3*x3 + w2 + w1 + x3,
|
|
3206
|
+
w3*w2 + w3*w1 + w3*x2 + w3 + w2*x3 + x2 + x1,
|
|
3207
|
+
w3*w2 + w3*w1 + w3*x3 + w3*x2 + w3*x1 + w3 + w2*x2 + w0 + x3 + x2 + x1 + x0,
|
|
3208
|
+
w3*w2 + w3*w1 + w3*x1 + w3*x0 + w2*x1 + w0 + x3 + x0,
|
|
3209
|
+
w3*w2 + w3*w1 + w3*w0 + w3*x2 + w3*x1 + w2*w0 + w2*x0 + w0 + x3 + x2 + x1 + x0,
|
|
3210
|
+
w3*w2 + w3*x1 + w3 + w2*w0 + w1*w0 + w1 + x3 + x2,
|
|
3211
|
+
w3*w2 + w3*w1 + w3*x1 + w1*x3 + x3 + x2 + x1,
|
|
3212
|
+
w3*x3 + w3*x2 + w3*x0 + w3 + w1*x2 + w1 + w0 + x2 + x0,
|
|
3213
|
+
w3*w2 + w3*w1 + w3*x2 + w3*x1 + w1*x1 + w1 + w0 + x2 + x0,
|
|
3214
|
+
w3*w2 + w3*w1 + w3*w0 + w3*x3 + w3*x1 + w2*w0 + w1*x0 + x3 + x2,
|
|
3215
|
+
w3*w2 + w3*w1 + w3*x2 + w3*x1 + w3*x0 + w3 + w1 + w0*x3 + x3 + x2,
|
|
3216
|
+
w3*w2 + w3*w1 + w3*w0 + w3*x3 + w3 + w2*w0 + w1 + w0*x2 + x3 + x2,
|
|
3217
|
+
w3*w0 + w3*x2 + w2*w0 + w0*x1 + w0 + x3 + x1 + x0,
|
|
3218
|
+
w3*w0 + w3*x3 + w3*x0 + w2*w0 + w1 + w0*x0 + w0 + x3 + x2,
|
|
3219
|
+
w3*w2 + w3 + w1 + x3*x2 + x3 + x1,
|
|
3220
|
+
w3*w2 + w3*x3 + w1 + x3*x1 + x3 + x2,
|
|
3221
|
+
w3*w2 + w3*w0 + w3*x3 + w3*x2 + w3*x1 + w0 + x3*x0 + x1 + x0,
|
|
3222
|
+
w3*w2 + w3*w1 + w3*w0 + w3*x3 + w1 + w0 + x2*x1 + x2 + x0,
|
|
3223
|
+
w3*w2 + w2*w0 + w1 + x3 + x2*x0,
|
|
3224
|
+
w3*x3 + w3*x1 + w2*w0 + w1 + x3 + x2 + x1*x0 + x1]
|
|
3225
|
+
|
|
3226
|
+
TESTS:
|
|
3227
|
+
|
|
3228
|
+
Note that ``biaffine_only`` and ``correct_only`` are always
|
|
3229
|
+
ignored. The former is always false while the second is always
|
|
3230
|
+
true. They are only accepted for compatibility with the base
|
|
3231
|
+
class.
|
|
3232
|
+
|
|
3233
|
+
sage: from sage.crypto.mq.sr import SR_gf2_2
|
|
3234
|
+
sage: e = 4
|
|
3235
|
+
sage: sr = SR_gf2_2(1, 1, 1, e)
|
|
3236
|
+
sage: l = sr.inversion_polynomials_single_sbox() # needs sage.libs.singular
|
|
3237
|
+
sage: l == sr.inversion_polynomials_single_sbox(biaffine_only=True, correct_only=False) # needs sage.libs.singular
|
|
3238
|
+
True
|
|
3239
|
+
"""
|
|
3240
|
+
e = self.e
|
|
3241
|
+
if x is None and w is None:
|
|
3242
|
+
# make sure it prints like in the book.
|
|
3243
|
+
names = ["w%d" % i for i in reversed(range(e))] + ["x%d" % i for i in reversed(range(e))]
|
|
3244
|
+
P = PolynomialRing(GF(2), e*2, names, order='lex')
|
|
3245
|
+
x = P.gens()[e:]
|
|
3246
|
+
w = P.gens()[:e]
|
|
3247
|
+
|
|
3248
|
+
S = self.sbox(inversion_only=True)
|
|
3249
|
+
F = S.polynomials(w, x, degree=e-2, groebner=groebner)
|
|
3250
|
+
return F
|
|
3251
|
+
|
|
3252
|
+
|
|
3253
|
+
class AllowZeroInversionsContext:
|
|
3254
|
+
"""
|
|
3255
|
+
Temporarily allow zero inversion.
|
|
3256
|
+
"""
|
|
3257
|
+
def __init__(self, sr):
|
|
3258
|
+
"""
|
|
3259
|
+
EXAMPLES::
|
|
3260
|
+
|
|
3261
|
+
sage: from sage.crypto.mq.sr import AllowZeroInversionsContext
|
|
3262
|
+
sage: sr = mq.SR(1,2,2,4)
|
|
3263
|
+
sage: with AllowZeroInversionsContext(sr):
|
|
3264
|
+
....: sr.sub_byte(0)
|
|
3265
|
+
a^2 + a
|
|
3266
|
+
"""
|
|
3267
|
+
self.sr = sr
|
|
3268
|
+
|
|
3269
|
+
def __enter__(self):
|
|
3270
|
+
"""
|
|
3271
|
+
EXAMPLES::
|
|
3272
|
+
|
|
3273
|
+
sage: from sage.crypto.mq.sr import AllowZeroInversionsContext
|
|
3274
|
+
sage: sr = mq.SR(1,2,2,4)
|
|
3275
|
+
sage: sr.sub_byte(0)
|
|
3276
|
+
Traceback (most recent call last):
|
|
3277
|
+
...
|
|
3278
|
+
ZeroDivisionError: A zero inversion occurred during an encryption or key schedule.
|
|
3279
|
+
|
|
3280
|
+
sage: with AllowZeroInversionsContext(sr):
|
|
3281
|
+
....: sr.sub_byte(0)
|
|
3282
|
+
a^2 + a
|
|
3283
|
+
"""
|
|
3284
|
+
self.allow_zero_inversions = self.sr._allow_zero_inversions
|
|
3285
|
+
self.sr._allow_zero_inversions = True
|
|
3286
|
+
|
|
3287
|
+
def __exit__(self, typ, value, tb):
|
|
3288
|
+
"""
|
|
3289
|
+
EXAMPLES::
|
|
3290
|
+
|
|
3291
|
+
sage: from sage.crypto.mq.sr import AllowZeroInversionsContext
|
|
3292
|
+
sage: sr = mq.SR(1,2,2,4)
|
|
3293
|
+
sage: with AllowZeroInversionsContext(sr):
|
|
3294
|
+
....: sr.sub_byte(0)
|
|
3295
|
+
a^2 + a
|
|
3296
|
+
sage: sr._allow_zero_inversions
|
|
3297
|
+
False
|
|
3298
|
+
"""
|
|
3299
|
+
self.sr._allow_zero_inversions = self.allow_zero_inversions
|
|
3300
|
+
|
|
3301
|
+
|
|
3302
|
+
def test_consistency(max_n=2, **kwargs):
|
|
3303
|
+
r"""
|
|
3304
|
+
Test all combinations of ``r``, ``c``, ``e`` and ``n`` in ``(1,
|
|
3305
|
+
2)`` for consistency of random encryptions and their polynomial
|
|
3306
|
+
systems. `\GF{2}` and `\GF{2^e}` systems are tested. This test takes
|
|
3307
|
+
a while.
|
|
3308
|
+
|
|
3309
|
+
INPUT:
|
|
3310
|
+
|
|
3311
|
+
- ``max_n`` -- maximal number of rounds to consider (default: 2)
|
|
3312
|
+
- ``kwargs`` -- are passed to the SR constructor
|
|
3313
|
+
|
|
3314
|
+
TESTS:
|
|
3315
|
+
|
|
3316
|
+
The following test called with ``max_n`` = 2 requires a LOT of RAM
|
|
3317
|
+
(much more than 2GB). Since this might cause the doctest to fail
|
|
3318
|
+
on machines with "only" 2GB of RAM, we test ``max_n`` = 1, which
|
|
3319
|
+
has a more reasonable memory usage. ::
|
|
3320
|
+
|
|
3321
|
+
sage: from sage.crypto.mq.sr import test_consistency
|
|
3322
|
+
sage: test_consistency(1) # needs sage.rings.polynomial.pbori, long time (65s on sage.math, 2012)
|
|
3323
|
+
True
|
|
3324
|
+
"""
|
|
3325
|
+
consistent = True
|
|
3326
|
+
for r in (1, 2, 4):
|
|
3327
|
+
for c in (1, 2, 4):
|
|
3328
|
+
for e in (4, 8):
|
|
3329
|
+
for n in range(1, max_n+1):
|
|
3330
|
+
for gf2 in (True, False):
|
|
3331
|
+
zero_division = True
|
|
3332
|
+
while zero_division:
|
|
3333
|
+
sr = SR(n, r, c, e, gf2=gf2, **kwargs)
|
|
3334
|
+
try:
|
|
3335
|
+
F, s = sr.polynomial_system()
|
|
3336
|
+
F = F.subs(s)
|
|
3337
|
+
consistent &= (F.groebner_basis()[0] != 1)
|
|
3338
|
+
if not consistent:
|
|
3339
|
+
print(str(sr) + " is not consistent")
|
|
3340
|
+
zero_division = False
|
|
3341
|
+
|
|
3342
|
+
except ZeroDivisionError:
|
|
3343
|
+
pass
|
|
3344
|
+
return consistent
|