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
|
@@ -0,0 +1,2171 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-modules
|
|
2
|
+
# sage.doctest: needs sage.combinat sage.modules sage.rings.finite_rings
|
|
3
|
+
r"""
|
|
4
|
+
Mini-AES
|
|
5
|
+
|
|
6
|
+
A simplified variant of the Advanced Encryption Standard (AES). Note that
|
|
7
|
+
Mini-AES is for educational purposes only. It is a small-scale version of
|
|
8
|
+
the AES designed to help beginners understand the basic structure of AES.
|
|
9
|
+
|
|
10
|
+
AUTHORS:
|
|
11
|
+
|
|
12
|
+
- Minh Van Nguyen (2009-05): initial version
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
# #########################################################################
|
|
16
|
+
# Copyright (c) 2009 Minh Van Nguyen <nguyenminh2@gmail.com>
|
|
17
|
+
#
|
|
18
|
+
# This program is free software; you can redistribute it and/or modify
|
|
19
|
+
# it under the terms of the GNU General Public License as published by
|
|
20
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
21
|
+
# (at your option) any later version.
|
|
22
|
+
#
|
|
23
|
+
# This program is distributed in the hope that it will be useful,
|
|
24
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
25
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
26
|
+
# GNU General Public License for more details.
|
|
27
|
+
#
|
|
28
|
+
# https://www.gnu.org/licenses/
|
|
29
|
+
# #########################################################################
|
|
30
|
+
|
|
31
|
+
from sage.matrix.matrix_dense import Matrix_dense
|
|
32
|
+
from sage.matrix.matrix_space import MatrixSpace
|
|
33
|
+
from sage.monoids.string_monoid import BinaryStrings
|
|
34
|
+
from sage.monoids.string_monoid_element import StringMonoidElement
|
|
35
|
+
from sage.rings.finite_rings.finite_field_constructor import FiniteField
|
|
36
|
+
from sage.rings.integer import Integer
|
|
37
|
+
from sage.structure.sage_object import SageObject
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class MiniAES(SageObject):
|
|
41
|
+
r"""
|
|
42
|
+
This class implements the Mini Advanced Encryption Standard (Mini-AES)
|
|
43
|
+
described in [Pha2002]_. Note that Phan's Mini-AES is for educational purposes
|
|
44
|
+
only and is not secure for practical purposes. Mini-AES is a version of
|
|
45
|
+
the AES with all parameters significantly reduced, but at the same time
|
|
46
|
+
preserving the structure of AES. The goal of Mini-AES is to allow a
|
|
47
|
+
beginner to understand the structure of AES, thus laying a foundation
|
|
48
|
+
for a thorough study of AES. Its goal is as a teaching tool and is
|
|
49
|
+
different from the :mod:`SR <sage.crypto.mq.sr>` small scale variants
|
|
50
|
+
of the AES. SR defines a family of parameterizable variants of the AES
|
|
51
|
+
suitable as a framework for comparing different cryptanalytic techniques
|
|
52
|
+
that can be brought to bear on the AES.
|
|
53
|
+
|
|
54
|
+
EXAMPLES:
|
|
55
|
+
|
|
56
|
+
Encrypt a plaintext::
|
|
57
|
+
|
|
58
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
59
|
+
sage: maes = MiniAES()
|
|
60
|
+
sage: K = FiniteField(16, "x")
|
|
61
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
62
|
+
sage: P = MS([K("x^3 + x"), K("x^2 + 1"), K("x^2 + x"), K("x^3 + x^2")]); P
|
|
63
|
+
<BLANKLINE>
|
|
64
|
+
[ x^3 + x x^2 + 1]
|
|
65
|
+
[ x^2 + x x^3 + x^2]
|
|
66
|
+
sage: key = MS([K("x^3 + x^2"), K("x^3 + x"), K("x^3 + x^2 + x"), K("x^2 + x + 1")]); key
|
|
67
|
+
<BLANKLINE>
|
|
68
|
+
[ x^3 + x^2 x^3 + x]
|
|
69
|
+
[x^3 + x^2 + x x^2 + x + 1]
|
|
70
|
+
sage: C = maes.encrypt(P, key); C
|
|
71
|
+
[ x^3 + x^2 + 1 x^3 + x^2 + x + 1]
|
|
72
|
+
[ x x^3 + x^2 + x]
|
|
73
|
+
|
|
74
|
+
Decrypt the result::
|
|
75
|
+
|
|
76
|
+
sage: plaintxt = maes.decrypt(C, key)
|
|
77
|
+
sage: plaintxt; P
|
|
78
|
+
<BLANKLINE>
|
|
79
|
+
[ x^3 + x x^2 + 1]
|
|
80
|
+
[ x^2 + x x^3 + x^2]
|
|
81
|
+
<BLANKLINE>
|
|
82
|
+
[ x^3 + x x^2 + 1]
|
|
83
|
+
[ x^2 + x x^3 + x^2]
|
|
84
|
+
sage: plaintxt == P
|
|
85
|
+
True
|
|
86
|
+
|
|
87
|
+
We can also work directly with binary strings::
|
|
88
|
+
|
|
89
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
90
|
+
sage: maes = MiniAES()
|
|
91
|
+
sage: bin = BinaryStrings()
|
|
92
|
+
sage: key = bin.encoding("KE"); key
|
|
93
|
+
0100101101000101
|
|
94
|
+
sage: P = bin.encoding("Encrypt this secret message!"); P
|
|
95
|
+
01000101011011100110001101110010011110010111000001110100001000000111010001101000011010010111001100100000011100110110010101100011011100100110010101110100001000000110110101100101011100110111001101100001011001110110010100100001
|
|
96
|
+
sage: C = maes(P, key, algorithm='encrypt'); C
|
|
97
|
+
11100000101000010110001101101001110110010010111011010001100111100000101000101111100110010010100001110101011100111001000010101000001111000101010011010001100111100111001100000001101100110110101001001000011100000101010110110101
|
|
98
|
+
sage: plaintxt = maes(C, key, algorithm='decrypt')
|
|
99
|
+
sage: plaintxt == P
|
|
100
|
+
True
|
|
101
|
+
|
|
102
|
+
Now we work with integers `n` such that `0 \leq n \leq 15`::
|
|
103
|
+
|
|
104
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
105
|
+
sage: maes = MiniAES()
|
|
106
|
+
sage: P = [n for n in range(16)]; P
|
|
107
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
108
|
+
sage: key = [2, 3, 11, 0]; key
|
|
109
|
+
[2, 3, 11, 0]
|
|
110
|
+
sage: P = maes.integer_to_binary(P); P
|
|
111
|
+
0000000100100011010001010110011110001001101010111100110111101111
|
|
112
|
+
sage: key = maes.integer_to_binary(key); key
|
|
113
|
+
0010001110110000
|
|
114
|
+
sage: C = maes(P, key, algorithm='encrypt'); C
|
|
115
|
+
0011101000101110010011000101010100011101010000111000100100011010
|
|
116
|
+
sage: plaintxt = maes(C, key, algorithm='decrypt')
|
|
117
|
+
sage: plaintxt == P
|
|
118
|
+
True
|
|
119
|
+
|
|
120
|
+
Generate some random plaintext and a random secret key. Encrypt the
|
|
121
|
+
plaintext using that secret key and decrypt the result. Then compare the
|
|
122
|
+
decrypted plaintext with the original plaintext::
|
|
123
|
+
|
|
124
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
125
|
+
sage: maes = MiniAES()
|
|
126
|
+
sage: MS = MatrixSpace(FiniteField(16, "x"), 2, 2)
|
|
127
|
+
sage: P = MS.random_element()
|
|
128
|
+
sage: key = maes.random_key()
|
|
129
|
+
sage: C = maes.encrypt(P, key)
|
|
130
|
+
sage: plaintxt = maes.decrypt(C, key)
|
|
131
|
+
sage: plaintxt == P
|
|
132
|
+
True
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
def __init__(self):
|
|
136
|
+
r"""
|
|
137
|
+
A simplified variant of the Advanced Encryption Standard (AES).
|
|
138
|
+
|
|
139
|
+
EXAMPLES::
|
|
140
|
+
|
|
141
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
142
|
+
sage: maes = MiniAES(); maes
|
|
143
|
+
Mini-AES block cipher with 16-bit keys
|
|
144
|
+
sage: MS = MatrixSpace(FiniteField(16, "x"), 2, 2)
|
|
145
|
+
sage: P = MS.random_element()
|
|
146
|
+
sage: key = maes.random_key()
|
|
147
|
+
sage: C = maes.encrypt(P, key)
|
|
148
|
+
sage: plaintxt = maes.decrypt(C, key)
|
|
149
|
+
sage: plaintxt == P
|
|
150
|
+
True
|
|
151
|
+
"""
|
|
152
|
+
from sage.crypto.sbox import SBox
|
|
153
|
+
self._key_size = 16 # the number of bits in a secret key
|
|
154
|
+
B = BinaryStrings()
|
|
155
|
+
K = FiniteField(self._key_size, "x")
|
|
156
|
+
# the S-box for encryption
|
|
157
|
+
self._sboxE = SBox(14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7)
|
|
158
|
+
# the S-box for decryption
|
|
159
|
+
self._sboxD = SBox(14, 3, 4, 8, 1, 12, 10, 15, 7, 13, 9, 6, 11, 2, 0, 5)
|
|
160
|
+
# nibble to finite field element
|
|
161
|
+
self._bin_to_GF = { B("0000"): K("0"),
|
|
162
|
+
B("0001"): K("1"),
|
|
163
|
+
B("0010"): K("x"),
|
|
164
|
+
B("0011"): K("x + 1"),
|
|
165
|
+
B("0100"): K("x^2"),
|
|
166
|
+
B("0101"): K("x^2 + 1"),
|
|
167
|
+
B("0110"): K("x^2 + x"),
|
|
168
|
+
B("0111"): K("x^2 + x + 1"),
|
|
169
|
+
B("1000"): K("x^3"),
|
|
170
|
+
B("1001"): K("x^3 + 1"),
|
|
171
|
+
B("1010"): K("x^3 + x"),
|
|
172
|
+
B("1011"): K("x^3 + x + 1"),
|
|
173
|
+
B("1100"): K("x^3 + x^2"),
|
|
174
|
+
B("1101"): K("x^3 + x^2 + 1"),
|
|
175
|
+
B("1110"): K("x^3 + x^2 + x"),
|
|
176
|
+
B("1111"): K("x^3 + x^2 + x+ 1") }
|
|
177
|
+
# nibble to integer
|
|
178
|
+
self._bin_to_int = { B("0000"): Integer(0),
|
|
179
|
+
B("0001"): Integer(1),
|
|
180
|
+
B("0010"): Integer(2),
|
|
181
|
+
B("0011"): Integer(3),
|
|
182
|
+
B("0100"): Integer(4),
|
|
183
|
+
B("0101"): Integer(5),
|
|
184
|
+
B("0110"): Integer(6),
|
|
185
|
+
B("0111"): Integer(7),
|
|
186
|
+
B("1000"): Integer(8),
|
|
187
|
+
B("1001"): Integer(9),
|
|
188
|
+
B("1010"): Integer(10),
|
|
189
|
+
B("1011"): Integer(11),
|
|
190
|
+
B("1100"): Integer(12),
|
|
191
|
+
B("1101"): Integer(13),
|
|
192
|
+
B("1110"): Integer(14),
|
|
193
|
+
B("1111"): Integer(15) }
|
|
194
|
+
# finite field element to nibble
|
|
195
|
+
self._GF_to_bin = { K("0"): B("0000"),
|
|
196
|
+
K("1"): B("0001"),
|
|
197
|
+
K("x"): B("0010"),
|
|
198
|
+
K("x + 1"): B("0011"),
|
|
199
|
+
K("x^2"): B("0100"),
|
|
200
|
+
K("x^2 + 1"): B("0101"),
|
|
201
|
+
K("x^2 + x"): B("0110"),
|
|
202
|
+
K("x^2 + x + 1"): B("0111"),
|
|
203
|
+
K("x^3"): B("1000"),
|
|
204
|
+
K("x^3 + 1"): B("1001"),
|
|
205
|
+
K("x^3 + x"): B("1010"),
|
|
206
|
+
K("x^3 + x + 1"): B("1011"),
|
|
207
|
+
K("x^3 + x^2"): B("1100"),
|
|
208
|
+
K("x^3 + x^2 + 1"): B("1101"),
|
|
209
|
+
K("x^3 + x^2 + x"): B("1110"),
|
|
210
|
+
K("x^3 + x^2 + x+ 1"): B("1111") }
|
|
211
|
+
# finite field element to integer
|
|
212
|
+
self._GF_to_int = { K("0"): Integer(0),
|
|
213
|
+
K("1"): Integer(1),
|
|
214
|
+
K("x"): Integer(2),
|
|
215
|
+
K("x + 1"): Integer(3),
|
|
216
|
+
K("x^2"): Integer(4),
|
|
217
|
+
K("x^2 + 1"): Integer(5),
|
|
218
|
+
K("x^2 + x"): Integer(6),
|
|
219
|
+
K("x^2 + x + 1"): Integer(7),
|
|
220
|
+
K("x^3"): Integer(8),
|
|
221
|
+
K("x^3 + 1"): Integer(9),
|
|
222
|
+
K("x^3 + x"): Integer(10),
|
|
223
|
+
K("x^3 + x + 1"): Integer(11),
|
|
224
|
+
K("x^3 + x^2"): Integer(12),
|
|
225
|
+
K("x^3 + x^2 + 1"): Integer(13),
|
|
226
|
+
K("x^3 + x^2 + x"): Integer(14),
|
|
227
|
+
K("x^3 + x^2 + x+ 1"): Integer(15) }
|
|
228
|
+
# integer to nibble
|
|
229
|
+
self._int_to_bin = { Integer(0): B("0000"),
|
|
230
|
+
Integer(1): B("0001"),
|
|
231
|
+
Integer(2): B("0010"),
|
|
232
|
+
Integer(3): B("0011"),
|
|
233
|
+
Integer(4): B("0100"),
|
|
234
|
+
Integer(5): B("0101"),
|
|
235
|
+
Integer(6): B("0110"),
|
|
236
|
+
Integer(7): B("0111"),
|
|
237
|
+
Integer(8): B("1000"),
|
|
238
|
+
Integer(9): B("1001"),
|
|
239
|
+
Integer(10): B("1010"),
|
|
240
|
+
Integer(11): B("1011"),
|
|
241
|
+
Integer(12): B("1100"),
|
|
242
|
+
Integer(13): B("1101"),
|
|
243
|
+
Integer(14): B("1110"),
|
|
244
|
+
Integer(15): B("1111") }
|
|
245
|
+
# integer to finite field element
|
|
246
|
+
self._int_to_GF = { Integer(0): K("0"),
|
|
247
|
+
Integer(1): K("1"),
|
|
248
|
+
Integer(2): K("x"),
|
|
249
|
+
Integer(3): K("x + 1"),
|
|
250
|
+
Integer(4): K("x^2"),
|
|
251
|
+
Integer(5): K("x^2 + 1"),
|
|
252
|
+
Integer(6): K("x^2 + x"),
|
|
253
|
+
Integer(7): K("x^2 + x + 1"),
|
|
254
|
+
Integer(8): K("x^3"),
|
|
255
|
+
Integer(9): K("x^3 + 1"),
|
|
256
|
+
Integer(10): K("x^3 + x"),
|
|
257
|
+
Integer(11): K("x^3 + x + 1"),
|
|
258
|
+
Integer(12): K("x^3 + x^2"),
|
|
259
|
+
Integer(13): K("x^3 + x^2 + 1"),
|
|
260
|
+
Integer(14): K("x^3 + x^2 + x"),
|
|
261
|
+
Integer(15): K("x^3 + x^2 + x+ 1") }
|
|
262
|
+
|
|
263
|
+
def __call__(self, B, key, algorithm='encrypt'):
|
|
264
|
+
r"""
|
|
265
|
+
Apply Mini-AES encryption or decryption on the binary string ``B``
|
|
266
|
+
using the key ``key``. The flag ``algorithm`` controls what action is
|
|
267
|
+
to be performed on ``B``.
|
|
268
|
+
|
|
269
|
+
INPUT:
|
|
270
|
+
|
|
271
|
+
- ``B`` -- a binary string, where the number of bits is positive and
|
|
272
|
+
a multiple of 16. The number of 16 bits is evenly divided into four
|
|
273
|
+
nibbles. Hence 16 bits can be conveniently represented as a
|
|
274
|
+
`2 \times 2` matrix block for encryption or decryption.
|
|
275
|
+
|
|
276
|
+
- ``key`` -- a secret key; this must be a 16-bit binary string
|
|
277
|
+
|
|
278
|
+
- ``algorithm`` -- (default: ``'encrypt'``) a string; a flag to signify
|
|
279
|
+
whether encryption or decryption is to be applied to the binary
|
|
280
|
+
string ``B``. The encryption flag is ``'encrypt'`` and the decryption
|
|
281
|
+
flag is ``'decrypt'``.
|
|
282
|
+
|
|
283
|
+
OUTPUT:
|
|
284
|
+
|
|
285
|
+
- The ciphertext (respectively plaintext) corresponding to the
|
|
286
|
+
binary string ``B``.
|
|
287
|
+
|
|
288
|
+
EXAMPLES::
|
|
289
|
+
|
|
290
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
291
|
+
sage: maes = MiniAES()
|
|
292
|
+
sage: bin = BinaryStrings()
|
|
293
|
+
sage: key = bin.encoding("KE"); key
|
|
294
|
+
0100101101000101
|
|
295
|
+
sage: P = bin.encoding("Encrypt this secret message!"); P
|
|
296
|
+
01000101011011100110001101110010011110010111000001110100001000000111010001101000011010010111001100100000011100110110010101100011011100100110010101110100001000000110110101100101011100110111001101100001011001110110010100100001
|
|
297
|
+
sage: C = maes(P, key, algorithm='encrypt'); C
|
|
298
|
+
11100000101000010110001101101001110110010010111011010001100111100000101000101111100110010010100001110101011100111001000010101000001111000101010011010001100111100111001100000001101100110110101001001000011100000101010110110101
|
|
299
|
+
sage: plaintxt = maes(C, key, algorithm='decrypt')
|
|
300
|
+
sage: plaintxt == P
|
|
301
|
+
True
|
|
302
|
+
|
|
303
|
+
TESTS:
|
|
304
|
+
|
|
305
|
+
The binary string ``B`` must be non-empty and the number of bits must
|
|
306
|
+
be a multiple of 16::
|
|
307
|
+
|
|
308
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
309
|
+
sage: maes = MiniAES()
|
|
310
|
+
sage: maes("B", "key")
|
|
311
|
+
Traceback (most recent call last):
|
|
312
|
+
...
|
|
313
|
+
TypeError: input B must be a non-empty binary string with number of bits a multiple of 16
|
|
314
|
+
sage: bin = BinaryStrings()
|
|
315
|
+
sage: B = bin.encoding("A")
|
|
316
|
+
sage: maes(B, "key")
|
|
317
|
+
Traceback (most recent call last):
|
|
318
|
+
...
|
|
319
|
+
ValueError: the number of bits in the binary string B must be positive and a multiple of 16
|
|
320
|
+
|
|
321
|
+
The secret key ``key`` must be a 16-bit binary string::
|
|
322
|
+
|
|
323
|
+
sage: B = bin.encoding("ABCD")
|
|
324
|
+
sage: maes(B, "key")
|
|
325
|
+
Traceback (most recent call last):
|
|
326
|
+
...
|
|
327
|
+
TypeError: secret key must be a 16-bit binary string
|
|
328
|
+
sage: key = bin.encoding("K")
|
|
329
|
+
sage: maes(B, key)
|
|
330
|
+
Traceback (most recent call last):
|
|
331
|
+
...
|
|
332
|
+
ValueError: secret key must be a 16-bit binary string
|
|
333
|
+
|
|
334
|
+
The value for ``algorithm`` must be either ``'encrypt'`` or
|
|
335
|
+
``'decrypt'``::
|
|
336
|
+
|
|
337
|
+
sage: B = bin.encoding("ABCD")
|
|
338
|
+
sage: key = bin.encoding("KE")
|
|
339
|
+
sage: maes(B, key, algorithm='ABC')
|
|
340
|
+
Traceback (most recent call last):
|
|
341
|
+
...
|
|
342
|
+
ValueError: algorithm must be either 'encrypt' or 'decrypt'
|
|
343
|
+
sage: maes(B, key, algorithm='e')
|
|
344
|
+
Traceback (most recent call last):
|
|
345
|
+
...
|
|
346
|
+
ValueError: algorithm must be either 'encrypt' or 'decrypt'
|
|
347
|
+
sage: maes(B, key, algorithm='d')
|
|
348
|
+
Traceback (most recent call last):
|
|
349
|
+
...
|
|
350
|
+
ValueError: algorithm must be either 'encrypt' or 'decrypt'
|
|
351
|
+
"""
|
|
352
|
+
from sage.rings.finite_rings.integer_mod import Mod
|
|
353
|
+
if not isinstance(B, StringMonoidElement):
|
|
354
|
+
raise TypeError("input B must be a non-empty binary string with number of bits a multiple of 16")
|
|
355
|
+
if (len(B) == 0) or (Mod(len(B), self._key_size).lift() != 0):
|
|
356
|
+
raise ValueError("the number of bits in the binary string B must be positive and a multiple of 16")
|
|
357
|
+
if not isinstance(key, StringMonoidElement):
|
|
358
|
+
raise TypeError("secret key must be a 16-bit binary string")
|
|
359
|
+
if len(key) != self._key_size:
|
|
360
|
+
raise ValueError("secret key must be a 16-bit binary string")
|
|
361
|
+
|
|
362
|
+
N = len(B) // self._key_size # the number of 16-bit blocks
|
|
363
|
+
MS = MatrixSpace(FiniteField(self._key_size, "x"), 2, 2)
|
|
364
|
+
bin = BinaryStrings()
|
|
365
|
+
S = ""
|
|
366
|
+
if algorithm == "encrypt":
|
|
367
|
+
# encrypt each 16-bit block in succession
|
|
368
|
+
for i in range(N):
|
|
369
|
+
# here 16 is the number of bits per encryption block
|
|
370
|
+
block = B[i*16 : (i+1)*16]
|
|
371
|
+
matB = MS(self.binary_to_GF(block))
|
|
372
|
+
matK = MS(self.binary_to_GF(key))
|
|
373
|
+
e = self.encrypt(matB, matK)
|
|
374
|
+
e = self.GF_to_binary(e)
|
|
375
|
+
S = "".join([S, str(e)])
|
|
376
|
+
return bin(S)
|
|
377
|
+
elif algorithm == "decrypt":
|
|
378
|
+
# decrypt each 16-bit block in succession
|
|
379
|
+
for i in range(N):
|
|
380
|
+
# here 16 is the number of bits per encryption block
|
|
381
|
+
block = B[i*16 : (i+1)*16]
|
|
382
|
+
matB = MS(self.binary_to_GF(block))
|
|
383
|
+
matK = MS(self.binary_to_GF(key))
|
|
384
|
+
e = self.decrypt(matB, matK)
|
|
385
|
+
e = self.GF_to_binary(e)
|
|
386
|
+
S = "".join([S, str(e)])
|
|
387
|
+
return bin(S)
|
|
388
|
+
else:
|
|
389
|
+
raise ValueError("algorithm must be either 'encrypt' or 'decrypt'")
|
|
390
|
+
|
|
391
|
+
def __eq__(self, other):
|
|
392
|
+
r"""
|
|
393
|
+
Compare ``self`` with ``other``.
|
|
394
|
+
|
|
395
|
+
Mini-AES objects are the same if they have the same key size and
|
|
396
|
+
the same S-boxes.
|
|
397
|
+
|
|
398
|
+
EXAMPLES::
|
|
399
|
+
|
|
400
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
401
|
+
sage: m = MiniAES()
|
|
402
|
+
sage: m == loads(dumps(m))
|
|
403
|
+
True
|
|
404
|
+
"""
|
|
405
|
+
return ( (self._key_size == other._key_size) and
|
|
406
|
+
(self._sboxE == other._sboxE) and
|
|
407
|
+
(self._sboxD == other._sboxD) )
|
|
408
|
+
|
|
409
|
+
def __repr__(self):
|
|
410
|
+
r"""
|
|
411
|
+
Return the string representation of ``self``.
|
|
412
|
+
|
|
413
|
+
EXAMPLES::
|
|
414
|
+
|
|
415
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
416
|
+
sage: m = MiniAES(); m
|
|
417
|
+
Mini-AES block cipher with 16-bit keys
|
|
418
|
+
"""
|
|
419
|
+
return "Mini-AES block cipher with 16-bit keys"
|
|
420
|
+
|
|
421
|
+
def add_key(self, block, rkey):
|
|
422
|
+
r"""
|
|
423
|
+
Return the matrix addition of ``block`` and ``rkey``. Both ``block``
|
|
424
|
+
and ``rkey`` are `2 \times 2` matrices over the finite field
|
|
425
|
+
`\GF{2^4}`. This method just return the matrix addition of
|
|
426
|
+
these two matrices.
|
|
427
|
+
|
|
428
|
+
INPUT:
|
|
429
|
+
|
|
430
|
+
- ``block`` -- a `2 \times 2` matrix with entries over
|
|
431
|
+
`\GF{2^4}`
|
|
432
|
+
|
|
433
|
+
- ``rkey`` -- a round key; a `2 \times 2` matrix with entries over
|
|
434
|
+
`\GF{2^4}`
|
|
435
|
+
|
|
436
|
+
OUTPUT: the matrix addition of ``block`` and ``rkey``
|
|
437
|
+
|
|
438
|
+
EXAMPLES:
|
|
439
|
+
|
|
440
|
+
We can work with elements of `\GF{2^4}`::
|
|
441
|
+
|
|
442
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
443
|
+
sage: maes = MiniAES()
|
|
444
|
+
sage: K = FiniteField(16, "x")
|
|
445
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
446
|
+
sage: D = MS([ [K("x^3 + x^2 + x + 1"), K("x^3 + x")], [K("0"), K("x^3 + x^2")] ]); D
|
|
447
|
+
<BLANKLINE>
|
|
448
|
+
[x^3 + x^2 + x + 1 x^3 + x]
|
|
449
|
+
[ 0 x^3 + x^2]
|
|
450
|
+
sage: k = MS([ [K("x^2 + 1"), K("x^3 + x^2 + x + 1")], [K("x + 1"), K("0")] ]); k
|
|
451
|
+
<BLANKLINE>
|
|
452
|
+
[ x^2 + 1 x^3 + x^2 + x + 1]
|
|
453
|
+
[ x + 1 0]
|
|
454
|
+
sage: maes.add_key(D, k)
|
|
455
|
+
<BLANKLINE>
|
|
456
|
+
[ x^3 + x x^2 + 1]
|
|
457
|
+
[ x + 1 x^3 + x^2]
|
|
458
|
+
|
|
459
|
+
Or work with binary strings::
|
|
460
|
+
|
|
461
|
+
sage: bin = BinaryStrings()
|
|
462
|
+
sage: B = bin.encoding("We"); B
|
|
463
|
+
0101011101100101
|
|
464
|
+
sage: B = MS(maes.binary_to_GF(B)); B
|
|
465
|
+
<BLANKLINE>
|
|
466
|
+
[ x^2 + 1 x^2 + x + 1]
|
|
467
|
+
[ x^2 + x x^2 + 1]
|
|
468
|
+
sage: key = bin.encoding("KY"); key
|
|
469
|
+
0100101101011001
|
|
470
|
+
sage: key = MS(maes.binary_to_GF(key)); key
|
|
471
|
+
<BLANKLINE>
|
|
472
|
+
[ x^2 x^3 + x + 1]
|
|
473
|
+
[ x^2 + 1 x^3 + 1]
|
|
474
|
+
sage: maes.add_key(B, key)
|
|
475
|
+
<BLANKLINE>
|
|
476
|
+
[ 1 x^3 + x^2]
|
|
477
|
+
[ x + 1 x^3 + x^2]
|
|
478
|
+
|
|
479
|
+
We can also work with integers `n` such that `0 \leq n \leq 15`::
|
|
480
|
+
|
|
481
|
+
sage: N = [2, 3, 5, 7]; N
|
|
482
|
+
[2, 3, 5, 7]
|
|
483
|
+
sage: key = [9, 11, 13, 15]; key
|
|
484
|
+
[9, 11, 13, 15]
|
|
485
|
+
sage: N = MS(maes.integer_to_GF(N)); N
|
|
486
|
+
<BLANKLINE>
|
|
487
|
+
[ x x + 1]
|
|
488
|
+
[ x^2 + 1 x^2 + x + 1]
|
|
489
|
+
sage: key = MS(maes.integer_to_GF(key)); key
|
|
490
|
+
<BLANKLINE>
|
|
491
|
+
[ x^3 + 1 x^3 + x + 1]
|
|
492
|
+
[ x^3 + x^2 + 1 x^3 + x^2 + x + 1]
|
|
493
|
+
sage: maes.add_key(N, key)
|
|
494
|
+
<BLANKLINE>
|
|
495
|
+
[x^3 + x + 1 x^3]
|
|
496
|
+
[ x^3 x^3]
|
|
497
|
+
|
|
498
|
+
TESTS:
|
|
499
|
+
|
|
500
|
+
The input block and key must each be a matrix::
|
|
501
|
+
|
|
502
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
503
|
+
sage: maes = MiniAES()
|
|
504
|
+
sage: K = FiniteField(16, "x")
|
|
505
|
+
sage: MSB = MatrixSpace(K, 2, 2)
|
|
506
|
+
sage: B = MSB([ [K("x^3 + 1"), K("x^2 + x")], [K("x^3 + x^2"), K("x + 1")] ])
|
|
507
|
+
sage: maes.add_key(B, "key")
|
|
508
|
+
Traceback (most recent call last):
|
|
509
|
+
...
|
|
510
|
+
TypeError: round key must be a 2 x 2 matrix over GF(16)
|
|
511
|
+
sage: maes.add_key("block", "key")
|
|
512
|
+
Traceback (most recent call last):
|
|
513
|
+
...
|
|
514
|
+
TypeError: input block must be a 2 x 2 matrix over GF(16)
|
|
515
|
+
|
|
516
|
+
In addition, the dimensions of the input matrices must each be
|
|
517
|
+
`2 \times 2`::
|
|
518
|
+
|
|
519
|
+
sage: MSB = MatrixSpace(K, 1, 2)
|
|
520
|
+
sage: B = MSB([ [K("x^3 + 1"), K("x^2 + x")] ])
|
|
521
|
+
sage: maes.add_key(B, "key")
|
|
522
|
+
Traceback (most recent call last):
|
|
523
|
+
...
|
|
524
|
+
TypeError: input block must be a 2 x 2 matrix over GF(16)
|
|
525
|
+
sage: MSB = MatrixSpace(K, 2, 2)
|
|
526
|
+
sage: B = MSB([ [K("x^3 + 1"), K("x^2 + x")], [K("x^3 + x^2"), K("x + 1")] ])
|
|
527
|
+
sage: MSK = MatrixSpace(K, 1, 2)
|
|
528
|
+
sage: key = MSK([ [K("x^3 + x^2"), K("x^3 + x^2 + x + 1")]])
|
|
529
|
+
sage: maes.add_key(B, key)
|
|
530
|
+
Traceback (most recent call last):
|
|
531
|
+
...
|
|
532
|
+
TypeError: round key must be a 2 x 2 matrix over GF(16)
|
|
533
|
+
"""
|
|
534
|
+
if not isinstance(block, Matrix_dense) or \
|
|
535
|
+
not (block.base_ring().order() == 16 and block.base_ring().is_field()):
|
|
536
|
+
raise TypeError("input block must be a 2 x 2 matrix over GF(16)")
|
|
537
|
+
if not (block.nrows() == block.ncols() == 2):
|
|
538
|
+
raise TypeError("input block must be a 2 x 2 matrix over GF(16)")
|
|
539
|
+
|
|
540
|
+
if not isinstance(rkey, Matrix_dense) or \
|
|
541
|
+
not (rkey.base_ring().order() == 16 and rkey.base_ring().is_field()):
|
|
542
|
+
raise TypeError("round key must be a 2 x 2 matrix over GF(16)")
|
|
543
|
+
if not (rkey.nrows() == rkey.ncols() == 2):
|
|
544
|
+
raise TypeError("round key must be a 2 x 2 matrix over GF(16)")
|
|
545
|
+
|
|
546
|
+
return block + rkey
|
|
547
|
+
|
|
548
|
+
def block_length(self):
|
|
549
|
+
r"""
|
|
550
|
+
Return the block length of Phan's Mini-AES block cipher. A key in
|
|
551
|
+
Phan's Mini-AES is a block of 16 bits. Each nibble of a key can be
|
|
552
|
+
considered as an element of the finite field `\GF{2^4}`.
|
|
553
|
+
Therefore the key consists of four elements from `\GF{2^4}`.
|
|
554
|
+
|
|
555
|
+
OUTPUT:
|
|
556
|
+
|
|
557
|
+
- The block (or key) length in number of bits.
|
|
558
|
+
|
|
559
|
+
EXAMPLES::
|
|
560
|
+
|
|
561
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
562
|
+
sage: maes = MiniAES()
|
|
563
|
+
sage: maes.block_length()
|
|
564
|
+
16
|
|
565
|
+
"""
|
|
566
|
+
return self._key_size
|
|
567
|
+
|
|
568
|
+
def decrypt(self, C, key):
|
|
569
|
+
r"""
|
|
570
|
+
Use Phan's Mini-AES to decrypt the ciphertext ``C`` with the secret
|
|
571
|
+
key ``key``. Both ``C`` and ``key`` must be `2 \times 2` matrices over
|
|
572
|
+
the finite field `\GF{2^4}`. Let `\gamma` denote the
|
|
573
|
+
operation of nibble-sub, `\pi` denote shift-row, `\theta` denote
|
|
574
|
+
mix-column, and `\sigma_{K_i}` denote add-key with the round key
|
|
575
|
+
`K_i`. Then decryption `D` using Phan's Mini-AES is the function
|
|
576
|
+
composition
|
|
577
|
+
|
|
578
|
+
.. MATH::
|
|
579
|
+
|
|
580
|
+
D = \sigma_{K_0} \circ \gamma^{-1} \circ \pi \circ \theta \circ \sigma_{K_1} \circ \gamma^{-1} \circ \pi \circ \sigma_{K_2}
|
|
581
|
+
|
|
582
|
+
where `\gamma^{-1}` is the nibble-sub operation that uses the S-box
|
|
583
|
+
for decryption, and the order of execution is from right to left.
|
|
584
|
+
|
|
585
|
+
INPUT:
|
|
586
|
+
|
|
587
|
+
- ``C`` -- a ciphertext block; must be a `2 \times 2` matrix over
|
|
588
|
+
the finite field `\GF{2^4}`
|
|
589
|
+
|
|
590
|
+
- ``key`` -- a secret key for this Mini-AES block cipher; must be a
|
|
591
|
+
`2 \times 2` matrix over the finite field `\GF{2^4}`
|
|
592
|
+
|
|
593
|
+
OUTPUT: the plaintext corresponding to ``C``
|
|
594
|
+
|
|
595
|
+
EXAMPLES:
|
|
596
|
+
|
|
597
|
+
We encrypt a plaintext, decrypt the ciphertext, then compare the
|
|
598
|
+
decrypted plaintext with the original plaintext. Here we work with
|
|
599
|
+
elements of `\GF{2^4}`::
|
|
600
|
+
|
|
601
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
602
|
+
sage: maes = MiniAES()
|
|
603
|
+
sage: K = FiniteField(16, "x")
|
|
604
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
605
|
+
sage: P = MS([ [K("x^3 + 1"), K("x^2 + x")], [K("x^3 + x^2"), K("x + 1")] ]); P
|
|
606
|
+
<BLANKLINE>
|
|
607
|
+
[ x^3 + 1 x^2 + x]
|
|
608
|
+
[x^3 + x^2 x + 1]
|
|
609
|
+
sage: key = MS([ [K("x^3 + x^2"), K("x^3 + x^2 + x + 1")], [K("x + 1"), K("0")] ]); key
|
|
610
|
+
<BLANKLINE>
|
|
611
|
+
[ x^3 + x^2 x^3 + x^2 + x + 1]
|
|
612
|
+
[ x + 1 0]
|
|
613
|
+
sage: C = maes.encrypt(P, key); C
|
|
614
|
+
[ x + 1 x^2 + 1]
|
|
615
|
+
[x^3 + x^2 + x + 1 x^2]
|
|
616
|
+
sage: plaintxt = maes.decrypt(C, key)
|
|
617
|
+
sage: plaintxt; P
|
|
618
|
+
<BLANKLINE>
|
|
619
|
+
[ x^3 + 1 x^2 + x]
|
|
620
|
+
[x^3 + x^2 x + 1]
|
|
621
|
+
<BLANKLINE>
|
|
622
|
+
[ x^3 + 1 x^2 + x]
|
|
623
|
+
[x^3 + x^2 x + 1]
|
|
624
|
+
sage: plaintxt == P
|
|
625
|
+
True
|
|
626
|
+
|
|
627
|
+
But we can also work with binary strings::
|
|
628
|
+
|
|
629
|
+
sage: bin = BinaryStrings()
|
|
630
|
+
sage: P = bin.encoding("de"); P
|
|
631
|
+
0110010001100101
|
|
632
|
+
sage: P = MS(maes.binary_to_GF(P)); P
|
|
633
|
+
<BLANKLINE>
|
|
634
|
+
[x^2 + x x^2]
|
|
635
|
+
[x^2 + x x^2 + 1]
|
|
636
|
+
sage: key = bin.encoding("ke"); key
|
|
637
|
+
0110101101100101
|
|
638
|
+
sage: key = MS(maes.binary_to_GF(key)); key
|
|
639
|
+
<BLANKLINE>
|
|
640
|
+
[ x^2 + x x^3 + x + 1]
|
|
641
|
+
[ x^2 + x x^2 + 1]
|
|
642
|
+
sage: C = maes.encrypt(P, key)
|
|
643
|
+
sage: plaintxt = maes.decrypt(C, key)
|
|
644
|
+
sage: plaintxt == P
|
|
645
|
+
True
|
|
646
|
+
|
|
647
|
+
Here we work with integers `n` such that `0 \leq n \leq 15`::
|
|
648
|
+
|
|
649
|
+
sage: P = [3, 5, 7, 14]; P
|
|
650
|
+
[3, 5, 7, 14]
|
|
651
|
+
sage: key = [2, 6, 7, 8]; key
|
|
652
|
+
[2, 6, 7, 8]
|
|
653
|
+
sage: P = MS(maes.integer_to_GF(P)); P
|
|
654
|
+
<BLANKLINE>
|
|
655
|
+
[ x + 1 x^2 + 1]
|
|
656
|
+
[ x^2 + x + 1 x^3 + x^2 + x]
|
|
657
|
+
sage: key = MS(maes.integer_to_GF(key)); key
|
|
658
|
+
<BLANKLINE>
|
|
659
|
+
[ x x^2 + x]
|
|
660
|
+
[x^2 + x + 1 x^3]
|
|
661
|
+
sage: C = maes.encrypt(P, key)
|
|
662
|
+
sage: plaintxt = maes.decrypt(C, key)
|
|
663
|
+
sage: plaintxt == P
|
|
664
|
+
True
|
|
665
|
+
|
|
666
|
+
TESTS:
|
|
667
|
+
|
|
668
|
+
The input block must be a matrix::
|
|
669
|
+
|
|
670
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
671
|
+
sage: maes = MiniAES()
|
|
672
|
+
sage: K = FiniteField(16, "x")
|
|
673
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
674
|
+
sage: key = MS([ [K("x^3 + x^2"), K("x^3 + x^2 + x + 1")], [K("x + 1"), K("0")] ])
|
|
675
|
+
sage: maes.decrypt("C", key)
|
|
676
|
+
Traceback (most recent call last):
|
|
677
|
+
...
|
|
678
|
+
TypeError: ciphertext block must be a 2 x 2 matrix over GF(16)
|
|
679
|
+
sage: C = MS([ [K("x^3 + 1"), K("x^2 + x")], [K("x^3 + x^2"), K("x + 1")] ])
|
|
680
|
+
sage: maes.decrypt(C, "key")
|
|
681
|
+
Traceback (most recent call last):
|
|
682
|
+
...
|
|
683
|
+
TypeError: secret key must be a 2 x 2 matrix over GF(16)
|
|
684
|
+
|
|
685
|
+
In addition, the dimensions of the input matrices must be
|
|
686
|
+
`2 \times 2`::
|
|
687
|
+
|
|
688
|
+
sage: MS = MatrixSpace(K, 1, 2)
|
|
689
|
+
sage: C = MS([ [K("x^3 + 1"), K("x^2 + x")]])
|
|
690
|
+
sage: maes.decrypt(C, "key")
|
|
691
|
+
Traceback (most recent call last):
|
|
692
|
+
...
|
|
693
|
+
TypeError: ciphertext block must be a 2 x 2 matrix over GF(16)
|
|
694
|
+
sage: MSC = MatrixSpace(K, 2, 2)
|
|
695
|
+
sage: C = MSC([ [K("x^3 + 1"), K("x^2 + x")], [K("x^3 + x^2"), K("x + 1")] ])
|
|
696
|
+
sage: MSK = MatrixSpace(K, 1, 2)
|
|
697
|
+
sage: key = MSK([ [K("x^3 + x^2"), K("x^3 + x^2 + x + 1")]])
|
|
698
|
+
sage: maes.decrypt(C, key)
|
|
699
|
+
Traceback (most recent call last):
|
|
700
|
+
...
|
|
701
|
+
TypeError: secret key must be a 2 x 2 matrix over GF(16)
|
|
702
|
+
"""
|
|
703
|
+
if not isinstance(C, Matrix_dense) or \
|
|
704
|
+
not (C.base_ring().order() == 16 and C.base_ring().is_field()):
|
|
705
|
+
raise TypeError("ciphertext block must be a 2 x 2 matrix over GF(16)")
|
|
706
|
+
if not (C.nrows() == C.ncols() == 2):
|
|
707
|
+
raise TypeError("ciphertext block must be a 2 x 2 matrix over GF(16)")
|
|
708
|
+
if not isinstance(key, Matrix_dense) or \
|
|
709
|
+
not (key.base_ring().order() == 16 and key.base_ring().is_field()):
|
|
710
|
+
raise TypeError("secret key must be a 2 x 2 matrix over GF(16)")
|
|
711
|
+
if not (key.nrows() == key.ncols() == 2):
|
|
712
|
+
raise TypeError("secret key must be a 2 x 2 matrix over GF(16)")
|
|
713
|
+
|
|
714
|
+
# pre-compute the round keys
|
|
715
|
+
rkey0 = self.round_key(key, 0)
|
|
716
|
+
rkey1 = self.round_key(key, 1)
|
|
717
|
+
rkey2 = self.round_key(key, 2)
|
|
718
|
+
|
|
719
|
+
# now proceed with decrypting the ciphertext
|
|
720
|
+
|
|
721
|
+
# undo the result of round 2
|
|
722
|
+
plaintext = self.add_key(C, rkey2)
|
|
723
|
+
plaintext = self.shift_row(plaintext)
|
|
724
|
+
plaintext = self.nibble_sub(plaintext, algorithm='decrypt')
|
|
725
|
+
|
|
726
|
+
# undo the result of round 1
|
|
727
|
+
plaintext = self.add_key(plaintext, rkey1)
|
|
728
|
+
plaintext = self.mix_column(plaintext)
|
|
729
|
+
plaintext = self.shift_row(plaintext)
|
|
730
|
+
plaintext = self.nibble_sub(plaintext, algorithm='decrypt')
|
|
731
|
+
|
|
732
|
+
# undo the result of round 0
|
|
733
|
+
plaintext = self.add_key(plaintext, rkey0)
|
|
734
|
+
|
|
735
|
+
return plaintext
|
|
736
|
+
|
|
737
|
+
def encrypt(self, P, key):
|
|
738
|
+
r"""
|
|
739
|
+
Use Phan's Mini-AES to encrypt the plaintext ``P`` with the secret
|
|
740
|
+
key ``key``. Both ``P`` and ``key`` must be `2 \times 2` matrices
|
|
741
|
+
over the finite field `\GF{2^4}`. Let `\gamma` denote the
|
|
742
|
+
operation of nibble-sub, `\pi` denote shift-row, `\theta` denote
|
|
743
|
+
mix-column, and `\sigma_{K_i}` denote add-key with the round key
|
|
744
|
+
`K_i`. Then encryption `E` using Phan's Mini-AES is the function
|
|
745
|
+
composition
|
|
746
|
+
|
|
747
|
+
.. MATH::
|
|
748
|
+
|
|
749
|
+
E = \sigma_{K_2} \circ \pi \circ \gamma \circ \sigma_{K_1} \circ \theta \circ \pi \circ \gamma \circ \sigma_{K_0}
|
|
750
|
+
|
|
751
|
+
where the order of execution is from right to left. Note that
|
|
752
|
+
`\gamma` is the nibble-sub operation that uses the S-box for
|
|
753
|
+
encryption.
|
|
754
|
+
|
|
755
|
+
INPUT:
|
|
756
|
+
|
|
757
|
+
- ``P`` -- a plaintext block; must be a `2 \times 2` matrix over
|
|
758
|
+
the finite field `\GF{2^4}`
|
|
759
|
+
|
|
760
|
+
- ``key`` -- a secret key for this Mini-AES block cipher; must be a
|
|
761
|
+
`2 \times 2` matrix over the finite field `\GF{2^4}`
|
|
762
|
+
|
|
763
|
+
OUTPUT: the ciphertext corresponding to ``P``
|
|
764
|
+
|
|
765
|
+
EXAMPLES:
|
|
766
|
+
|
|
767
|
+
Here we work with elements of `\GF{2^4}`::
|
|
768
|
+
|
|
769
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
770
|
+
sage: maes = MiniAES()
|
|
771
|
+
sage: K = FiniteField(16, "x")
|
|
772
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
773
|
+
sage: P = MS([ [K("x^3 + 1"), K("x^2 + x")], [K("x^3 + x^2"), K("x + 1")] ]); P
|
|
774
|
+
<BLANKLINE>
|
|
775
|
+
[ x^3 + 1 x^2 + x]
|
|
776
|
+
[x^3 + x^2 x + 1]
|
|
777
|
+
sage: key = MS([ [K("x^3 + x^2"), K("x^3 + x^2 + x + 1")], [K("x + 1"), K("0")] ]); key
|
|
778
|
+
<BLANKLINE>
|
|
779
|
+
[ x^3 + x^2 x^3 + x^2 + x + 1]
|
|
780
|
+
[ x + 1 0]
|
|
781
|
+
sage: maes.encrypt(P, key)
|
|
782
|
+
[ x + 1 x^2 + 1]
|
|
783
|
+
[x^3 + x^2 + x + 1 x^2]
|
|
784
|
+
|
|
785
|
+
But we can also work with binary strings::
|
|
786
|
+
|
|
787
|
+
sage: bin = BinaryStrings()
|
|
788
|
+
sage: P = bin.encoding("de"); P
|
|
789
|
+
0110010001100101
|
|
790
|
+
sage: P = MS(maes.binary_to_GF(P)); P
|
|
791
|
+
<BLANKLINE>
|
|
792
|
+
[x^2 + x x^2]
|
|
793
|
+
[x^2 + x x^2 + 1]
|
|
794
|
+
sage: key = bin.encoding("ke"); key
|
|
795
|
+
0110101101100101
|
|
796
|
+
sage: key = MS(maes.binary_to_GF(key)); key
|
|
797
|
+
<BLANKLINE>
|
|
798
|
+
[ x^2 + x x^3 + x + 1]
|
|
799
|
+
[ x^2 + x x^2 + 1]
|
|
800
|
+
sage: C = maes.encrypt(P, key)
|
|
801
|
+
sage: plaintxt = maes.decrypt(C, key)
|
|
802
|
+
sage: plaintxt == P
|
|
803
|
+
True
|
|
804
|
+
|
|
805
|
+
Now we work with integers `n` such that `0 \leq n \leq 15`::
|
|
806
|
+
|
|
807
|
+
sage: P = [1, 5, 8, 12]; P
|
|
808
|
+
[1, 5, 8, 12]
|
|
809
|
+
sage: key = [5, 9, 15, 0]; key
|
|
810
|
+
[5, 9, 15, 0]
|
|
811
|
+
sage: P = MS(maes.integer_to_GF(P)); P
|
|
812
|
+
<BLANKLINE>
|
|
813
|
+
[ 1 x^2 + 1]
|
|
814
|
+
[ x^3 x^3 + x^2]
|
|
815
|
+
sage: key = MS(maes.integer_to_GF(key)); key
|
|
816
|
+
<BLANKLINE>
|
|
817
|
+
[ x^2 + 1 x^3 + 1]
|
|
818
|
+
[x^3 + x^2 + x + 1 0]
|
|
819
|
+
sage: C = maes.encrypt(P, key)
|
|
820
|
+
sage: plaintxt = maes.decrypt(C, key)
|
|
821
|
+
sage: plaintxt == P
|
|
822
|
+
True
|
|
823
|
+
|
|
824
|
+
TESTS:
|
|
825
|
+
|
|
826
|
+
The input block must be a matrix::
|
|
827
|
+
|
|
828
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
829
|
+
sage: maes = MiniAES()
|
|
830
|
+
sage: K = FiniteField(16, "x")
|
|
831
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
832
|
+
sage: key = MS([ [K("x^3 + x^2"), K("x^3 + x^2 + x + 1")], [K("x + 1"), K("0")] ])
|
|
833
|
+
sage: maes.encrypt("P", key)
|
|
834
|
+
Traceback (most recent call last):
|
|
835
|
+
...
|
|
836
|
+
TypeError: plaintext block must be a 2 x 2 matrix over GF(16)
|
|
837
|
+
sage: P = MS([ [K("x^3 + 1"), K("x^2 + x")], [K("x^3 + x^2"), K("x + 1")] ])
|
|
838
|
+
sage: maes.encrypt(P, "key")
|
|
839
|
+
Traceback (most recent call last):
|
|
840
|
+
...
|
|
841
|
+
TypeError: secret key must be a 2 x 2 matrix over GF(16)
|
|
842
|
+
|
|
843
|
+
In addition, the dimensions of the input matrices must be
|
|
844
|
+
`2 \times 2`::
|
|
845
|
+
|
|
846
|
+
sage: MS = MatrixSpace(K, 1, 2)
|
|
847
|
+
sage: P = MS([ [K("x^3 + 1"), K("x^2 + x")]])
|
|
848
|
+
sage: maes.encrypt(P, "key")
|
|
849
|
+
Traceback (most recent call last):
|
|
850
|
+
...
|
|
851
|
+
TypeError: plaintext block must be a 2 x 2 matrix over GF(16)
|
|
852
|
+
sage: MSP = MatrixSpace(K, 2, 2)
|
|
853
|
+
sage: P = MSP([ [K("x^3 + 1"), K("x^2 + x")], [K("x^3 + x^2"), K("x + 1")] ])
|
|
854
|
+
sage: MSK = MatrixSpace(K, 1, 2)
|
|
855
|
+
sage: key = MSK([ [K("x^3 + x^2"), K("x^3 + x^2 + x + 1")]])
|
|
856
|
+
sage: maes.encrypt(P, key)
|
|
857
|
+
Traceback (most recent call last):
|
|
858
|
+
...
|
|
859
|
+
TypeError: secret key must be a 2 x 2 matrix over GF(16)
|
|
860
|
+
"""
|
|
861
|
+
if not isinstance(P, Matrix_dense) or \
|
|
862
|
+
not (P.base_ring().order() == 16 and P.base_ring().is_field()):
|
|
863
|
+
raise TypeError("plaintext block must be a 2 x 2 matrix over GF(16)")
|
|
864
|
+
if not (P.nrows() == P.ncols() == 2):
|
|
865
|
+
raise TypeError("plaintext block must be a 2 x 2 matrix over GF(16)")
|
|
866
|
+
if not isinstance(key, Matrix_dense) or \
|
|
867
|
+
not (key.base_ring().order() == 16 and key.base_ring().is_field()):
|
|
868
|
+
raise TypeError("secret key must be a 2 x 2 matrix over GF(16)")
|
|
869
|
+
if not (key.nrows() == key.ncols() == 2):
|
|
870
|
+
raise TypeError("secret key must be a 2 x 2 matrix over GF(16)")
|
|
871
|
+
|
|
872
|
+
# pre-compute the round keys
|
|
873
|
+
rkey0 = self.round_key(key, 0)
|
|
874
|
+
rkey1 = self.round_key(key, 1)
|
|
875
|
+
rkey2 = self.round_key(key, 2)
|
|
876
|
+
|
|
877
|
+
# now proceed with encrypting the plaintext
|
|
878
|
+
|
|
879
|
+
# round 0
|
|
880
|
+
ciphertext = self.add_key(P, rkey0)
|
|
881
|
+
|
|
882
|
+
# round 1
|
|
883
|
+
ciphertext = self.nibble_sub(ciphertext, algorithm='encrypt')
|
|
884
|
+
ciphertext = self.shift_row(ciphertext)
|
|
885
|
+
ciphertext = self.mix_column(ciphertext)
|
|
886
|
+
ciphertext = self.add_key(ciphertext, rkey1)
|
|
887
|
+
|
|
888
|
+
# round 2
|
|
889
|
+
ciphertext = self.nibble_sub(ciphertext, algorithm='encrypt')
|
|
890
|
+
ciphertext = self.shift_row(ciphertext)
|
|
891
|
+
ciphertext = self.add_key(ciphertext, rkey2)
|
|
892
|
+
|
|
893
|
+
return ciphertext
|
|
894
|
+
|
|
895
|
+
def mix_column(self, block):
|
|
896
|
+
r"""
|
|
897
|
+
Return the matrix multiplication of ``block`` with a constant matrix.
|
|
898
|
+
The constant matrix is
|
|
899
|
+
|
|
900
|
+
.. MATH::
|
|
901
|
+
|
|
902
|
+
\begin{bmatrix}
|
|
903
|
+
x + 1 & x \\
|
|
904
|
+
x & x + 1
|
|
905
|
+
\end{bmatrix}
|
|
906
|
+
|
|
907
|
+
If the input block is
|
|
908
|
+
|
|
909
|
+
.. MATH::
|
|
910
|
+
|
|
911
|
+
\begin{bmatrix}
|
|
912
|
+
c_0 & c_2 \\
|
|
913
|
+
c_1 & c_3
|
|
914
|
+
\end{bmatrix}
|
|
915
|
+
|
|
916
|
+
then the output block is
|
|
917
|
+
|
|
918
|
+
.. MATH::
|
|
919
|
+
|
|
920
|
+
\begin{bmatrix}
|
|
921
|
+
d_0 & d_2 \\
|
|
922
|
+
d_1 & d_3
|
|
923
|
+
\end{bmatrix}
|
|
924
|
+
=
|
|
925
|
+
\begin{bmatrix}
|
|
926
|
+
x + 1 & x \\
|
|
927
|
+
x & x + 1
|
|
928
|
+
\end{bmatrix}
|
|
929
|
+
\begin{bmatrix}
|
|
930
|
+
c_0 & c_2 \\
|
|
931
|
+
c_1 & c_3
|
|
932
|
+
\end{bmatrix}
|
|
933
|
+
|
|
934
|
+
INPUT:
|
|
935
|
+
|
|
936
|
+
- ``block`` -- a `2 \times 2` matrix with entries over
|
|
937
|
+
`\GF{2^4}`
|
|
938
|
+
|
|
939
|
+
OUTPUT:
|
|
940
|
+
|
|
941
|
+
- A `2 \times 2` matrix resulting from multiplying the above constant
|
|
942
|
+
matrix with the input matrix ``block``.
|
|
943
|
+
|
|
944
|
+
EXAMPLES:
|
|
945
|
+
|
|
946
|
+
Here we work with elements of `\GF{2^4}`::
|
|
947
|
+
|
|
948
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
949
|
+
sage: maes = MiniAES()
|
|
950
|
+
sage: K = FiniteField(16, "x")
|
|
951
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
952
|
+
sage: mat = MS([ [K("x^2 + x + 1"), K("x^3 + x^2 + 1")], [K("x^3"), K("x")] ])
|
|
953
|
+
sage: maes.mix_column(mat)
|
|
954
|
+
<BLANKLINE>
|
|
955
|
+
[ x^3 + x 0]
|
|
956
|
+
[ x^2 + 1 x^3 + x^2 + x + 1]
|
|
957
|
+
|
|
958
|
+
Multiplying by the identity matrix should leave the constant matrix
|
|
959
|
+
unchanged::
|
|
960
|
+
|
|
961
|
+
sage: eye = MS([ [K("1"), K("0")], [K("0"), K("1")] ])
|
|
962
|
+
sage: maes.mix_column(eye)
|
|
963
|
+
<BLANKLINE>
|
|
964
|
+
[x + 1 x]
|
|
965
|
+
[ x x + 1]
|
|
966
|
+
|
|
967
|
+
We can also work with binary strings::
|
|
968
|
+
|
|
969
|
+
sage: bin = BinaryStrings()
|
|
970
|
+
sage: B = bin.encoding("rT"); B
|
|
971
|
+
0111001001010100
|
|
972
|
+
sage: B = MS(maes.binary_to_GF(B)); B
|
|
973
|
+
<BLANKLINE>
|
|
974
|
+
[x^2 + x + 1 x]
|
|
975
|
+
[ x^2 + 1 x^2]
|
|
976
|
+
sage: maes.mix_column(B)
|
|
977
|
+
<BLANKLINE>
|
|
978
|
+
[ x + 1 x^3 + x^2 + x]
|
|
979
|
+
[ 1 x^3]
|
|
980
|
+
|
|
981
|
+
We can also work with integers `n` such that `0 \leq n \leq 15`::
|
|
982
|
+
|
|
983
|
+
sage: P = [10, 5, 2, 7]; P
|
|
984
|
+
[10, 5, 2, 7]
|
|
985
|
+
sage: P = MS(maes.integer_to_GF(P)); P
|
|
986
|
+
<BLANKLINE>
|
|
987
|
+
[ x^3 + x x^2 + 1]
|
|
988
|
+
[ x x^2 + x + 1]
|
|
989
|
+
sage: maes.mix_column(P)
|
|
990
|
+
<BLANKLINE>
|
|
991
|
+
[x^3 + 1 1]
|
|
992
|
+
[ 1 x + 1]
|
|
993
|
+
|
|
994
|
+
TESTS:
|
|
995
|
+
|
|
996
|
+
The input block must be a matrix::
|
|
997
|
+
|
|
998
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
999
|
+
sage: maes = MiniAES()
|
|
1000
|
+
sage: maes.mix_column("mat")
|
|
1001
|
+
Traceback (most recent call last):
|
|
1002
|
+
...
|
|
1003
|
+
TypeError: input block must be a 2 x 2 matrix over GF(16)
|
|
1004
|
+
|
|
1005
|
+
In addition, the dimensions of the input matrix must be `2 \times 2`::
|
|
1006
|
+
|
|
1007
|
+
sage: K = FiniteField(16, "x")
|
|
1008
|
+
sage: MS = MatrixSpace(K, 1, 2)
|
|
1009
|
+
sage: mat = MS([[K("x^3 + x^2 + x + 1"), K("0")]])
|
|
1010
|
+
sage: maes.mix_column(mat)
|
|
1011
|
+
Traceback (most recent call last):
|
|
1012
|
+
...
|
|
1013
|
+
TypeError: input block must be a 2 x 2 matrix over GF(16)
|
|
1014
|
+
"""
|
|
1015
|
+
if not isinstance(block, Matrix_dense) or \
|
|
1016
|
+
not (block.base_ring().order() == 16 and block.base_ring().is_field()):
|
|
1017
|
+
raise TypeError("input block must be a 2 x 2 matrix over GF(16)")
|
|
1018
|
+
if not (block.nrows() == block.ncols() == 2):
|
|
1019
|
+
raise TypeError("input block must be a 2 x 2 matrix over GF(16)")
|
|
1020
|
+
|
|
1021
|
+
K = FiniteField(self._key_size, "x")
|
|
1022
|
+
MS = MatrixSpace(K, 2, 2)
|
|
1023
|
+
M = MS( [ [K("x + 1"), K("x")],
|
|
1024
|
+
[K("x"), K("x + 1")] ] )
|
|
1025
|
+
return M * block
|
|
1026
|
+
|
|
1027
|
+
def nibble_sub(self, block, algorithm='encrypt'):
|
|
1028
|
+
r"""
|
|
1029
|
+
Substitute a nibble (or a block of 4 bits) using the following S-box:
|
|
1030
|
+
|
|
1031
|
+
.. MATH::
|
|
1032
|
+
|
|
1033
|
+
\begin{tabular}{ll|ll} \hline
|
|
1034
|
+
Input & Output & Input & Output \\\hline
|
|
1035
|
+
0000 & 1110 & 1000 & 0011 \\
|
|
1036
|
+
0001 & 0100 & 1001 & 1010 \\
|
|
1037
|
+
0010 & 1101 & 1010 & 0110 \\
|
|
1038
|
+
0011 & 0001 & 1011 & 1100 \\
|
|
1039
|
+
0100 & 0010 & 1100 & 0101 \\
|
|
1040
|
+
0101 & 1111 & 1101 & 1001 \\
|
|
1041
|
+
0110 & 1011 & 1110 & 0000 \\
|
|
1042
|
+
0111 & 1000 & 1111 & 0111 \\\hline
|
|
1043
|
+
\end{tabular}
|
|
1044
|
+
|
|
1045
|
+
The values in the above S-box are taken from the first row of the first
|
|
1046
|
+
S-box of the Data Encryption Standard (DES). Each nibble can be
|
|
1047
|
+
thought of as an element of the finite field `\GF{2^4}` of 16
|
|
1048
|
+
elements. Thus in terms of `\GF{2^4}`, the S-box can also be
|
|
1049
|
+
specified as:
|
|
1050
|
+
|
|
1051
|
+
.. MATH::
|
|
1052
|
+
|
|
1053
|
+
\begin{tabular}{ll} \hline
|
|
1054
|
+
Input & Output \\\hline
|
|
1055
|
+
$0$ & $x^3 + x^2 + x$ \\
|
|
1056
|
+
$1$ & $x^2$ \\
|
|
1057
|
+
$x$ & $x^3 + x^2 + 1$ \\
|
|
1058
|
+
$x + 1$ & $1$ \\
|
|
1059
|
+
$x^2$ & $x$ \\
|
|
1060
|
+
$x^2 + 1$ & $x^3 + x^2 + x + 1$ \\
|
|
1061
|
+
$x^2 + x$ & $x^3 + x + 1$ \\
|
|
1062
|
+
$x^2 + x + 1$ & $x^3$ \\
|
|
1063
|
+
$x^3$ & $x + 1$ \\
|
|
1064
|
+
$x^3 + 1$ & $x^3 + x$ \\
|
|
1065
|
+
$x^3 + x$ & $x^2 + x$ \\
|
|
1066
|
+
$x^3 + x + 1$ & $x^3 + x^2$ \\
|
|
1067
|
+
$x^3 + x^2$ & $x^2 + 1$ \\
|
|
1068
|
+
$x^3 + x^2 + 1$ & $x^3 + 1$ \\
|
|
1069
|
+
$x^3 + x^2 + x$ & $0$ \\
|
|
1070
|
+
$x^3 + x^2 + x + 1$ & $x^2 + x + 1$ \\\hline
|
|
1071
|
+
\end{tabular}
|
|
1072
|
+
|
|
1073
|
+
Note that the above S-box is used for encryption. The S-box for
|
|
1074
|
+
decryption is obtained from the above S-box by reversing the role of
|
|
1075
|
+
the Input and Output columns. Thus the previous Input column for
|
|
1076
|
+
encryption now becomes the Output column for decryption, and the
|
|
1077
|
+
previous Output column for encryption is now the Input column for
|
|
1078
|
+
decryption. The S-box used for decryption can be specified as:
|
|
1079
|
+
|
|
1080
|
+
.. MATH::
|
|
1081
|
+
|
|
1082
|
+
\begin{tabular}{ll} \hline
|
|
1083
|
+
Input & Output \\\hline
|
|
1084
|
+
$0$ & $x^3 + x^2 + x$ \\
|
|
1085
|
+
$1$ & $x + 1$ \\
|
|
1086
|
+
$x$ & $x^2$ \\
|
|
1087
|
+
$x + 1$ & $x^3$ \\
|
|
1088
|
+
$x^2$ & $1$ \\
|
|
1089
|
+
$x^2 + 1$ & $x^3 + x^2$ \\
|
|
1090
|
+
$x^2 + x$ & $x^3 + x$ \\
|
|
1091
|
+
$x^2 + x + 1$ & $x^3 + x^2 + x + 1$ \\
|
|
1092
|
+
$x^3$ & $x^2 + x + 1$ \\
|
|
1093
|
+
$x^3 + 1$ & $x^3 + x^2 + 1$ \\
|
|
1094
|
+
$x^3 + x$ & $x^3 + 1$ \\
|
|
1095
|
+
$x^3 + x + 1$ & $x^2 + x$ \\
|
|
1096
|
+
$x^3 + x^2$ & $x^3 + x + 1$ \\
|
|
1097
|
+
$x^3 + x^2 + 1$ & $x$ \\
|
|
1098
|
+
$x^3 + x^2 + x$ & $0$ \\
|
|
1099
|
+
$x^3 + x^2 + x + 1$ & $x^2 + 1$ \\\hline
|
|
1100
|
+
\end{tabular}
|
|
1101
|
+
|
|
1102
|
+
INPUT:
|
|
1103
|
+
|
|
1104
|
+
- ``block`` -- a `2 \times 2` matrix with entries over
|
|
1105
|
+
`\GF{2^4}`
|
|
1106
|
+
|
|
1107
|
+
- ``algorithm`` -- (default: ``'encrypt'``) a string; a flag to signify
|
|
1108
|
+
whether this nibble-sub operation is used for encryption or
|
|
1109
|
+
decryption. The encryption flag is ``'encrypt'`` and the decryption
|
|
1110
|
+
flag is ``'decrypt'``.
|
|
1111
|
+
|
|
1112
|
+
OUTPUT: a `2 \times 2` matrix resulting from applying an S-box on
|
|
1113
|
+
entries of the `2 \times 2` matrix ``block``.
|
|
1114
|
+
|
|
1115
|
+
EXAMPLES:
|
|
1116
|
+
|
|
1117
|
+
Here we work with elements of the finite field `\GF{2^4}`::
|
|
1118
|
+
|
|
1119
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1120
|
+
sage: maes = MiniAES()
|
|
1121
|
+
sage: K = FiniteField(16, "x")
|
|
1122
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
1123
|
+
sage: mat = MS([[K("x^3 + x^2 + x + 1"), K("0")], [K("x^2 + x + 1"), K("x^3 + x")]])
|
|
1124
|
+
sage: maes.nibble_sub(mat, algorithm='encrypt')
|
|
1125
|
+
<BLANKLINE>
|
|
1126
|
+
[ x^2 + x + 1 x^3 + x^2 + x]
|
|
1127
|
+
[ x^3 x^2 + x]
|
|
1128
|
+
|
|
1129
|
+
But we can also work with binary strings::
|
|
1130
|
+
|
|
1131
|
+
sage: bin = BinaryStrings()
|
|
1132
|
+
sage: B = bin.encoding("bi"); B
|
|
1133
|
+
0110001001101001
|
|
1134
|
+
sage: B = MS(maes.binary_to_GF(B)); B
|
|
1135
|
+
<BLANKLINE>
|
|
1136
|
+
[x^2 + x x]
|
|
1137
|
+
[x^2 + x x^3 + 1]
|
|
1138
|
+
sage: maes.nibble_sub(B, algorithm='encrypt')
|
|
1139
|
+
<BLANKLINE>
|
|
1140
|
+
[ x^3 + x + 1 x^3 + x^2 + 1]
|
|
1141
|
+
[ x^3 + x + 1 x^3 + x]
|
|
1142
|
+
sage: maes.nibble_sub(B, algorithm='decrypt')
|
|
1143
|
+
<BLANKLINE>
|
|
1144
|
+
[ x^3 + x x^2]
|
|
1145
|
+
[ x^3 + x x^3 + x^2 + 1]
|
|
1146
|
+
|
|
1147
|
+
Here we work with integers `n` such that `0 \leq n \leq 15`::
|
|
1148
|
+
|
|
1149
|
+
sage: P = [2, 6, 8, 14]; P
|
|
1150
|
+
[2, 6, 8, 14]
|
|
1151
|
+
sage: P = MS(maes.integer_to_GF(P)); P
|
|
1152
|
+
<BLANKLINE>
|
|
1153
|
+
[ x x^2 + x]
|
|
1154
|
+
[ x^3 x^3 + x^2 + x]
|
|
1155
|
+
sage: maes.nibble_sub(P, algorithm='encrypt')
|
|
1156
|
+
<BLANKLINE>
|
|
1157
|
+
[x^3 + x^2 + 1 x^3 + x + 1]
|
|
1158
|
+
[ x + 1 0]
|
|
1159
|
+
sage: maes.nibble_sub(P, algorithm='decrypt')
|
|
1160
|
+
<BLANKLINE>
|
|
1161
|
+
[ x^2 x^3 + x]
|
|
1162
|
+
[x^2 + x + 1 0]
|
|
1163
|
+
|
|
1164
|
+
TESTS:
|
|
1165
|
+
|
|
1166
|
+
The input block must be a matrix::
|
|
1167
|
+
|
|
1168
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1169
|
+
sage: maes = MiniAES()
|
|
1170
|
+
sage: maes.nibble_sub("mat")
|
|
1171
|
+
Traceback (most recent call last):
|
|
1172
|
+
...
|
|
1173
|
+
TypeError: input block must be a 2 x 2 matrix over GF(16)
|
|
1174
|
+
|
|
1175
|
+
In addition, the dimensions of the input matrix must be `2 \times 2`::
|
|
1176
|
+
|
|
1177
|
+
sage: K = FiniteField(16, "x")
|
|
1178
|
+
sage: MS = MatrixSpace(K, 1, 2)
|
|
1179
|
+
sage: mat = MS([[K("x^3 + x^2 + x + 1"), K("0")]])
|
|
1180
|
+
sage: maes.nibble_sub(mat)
|
|
1181
|
+
Traceback (most recent call last):
|
|
1182
|
+
...
|
|
1183
|
+
TypeError: input block must be a 2 x 2 matrix over GF(16)
|
|
1184
|
+
|
|
1185
|
+
The value for the option ``algorithm`` must be either the string
|
|
1186
|
+
``'encrypt'`` or ``'decrypt'``::
|
|
1187
|
+
|
|
1188
|
+
sage: K = FiniteField(16, "x")
|
|
1189
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
1190
|
+
sage: mat = MS([[K("x^3 + x^2 + x + 1"), K("0")], [K("x^2 + x + 1"), K("x^3 + x")]])
|
|
1191
|
+
sage: maes.nibble_sub(mat, algorithm='abc')
|
|
1192
|
+
Traceback (most recent call last):
|
|
1193
|
+
...
|
|
1194
|
+
ValueError: the algorithm for nibble-sub must be either 'encrypt' or 'decrypt'
|
|
1195
|
+
sage: maes.nibble_sub(mat, algorithm='e')
|
|
1196
|
+
Traceback (most recent call last):
|
|
1197
|
+
...
|
|
1198
|
+
ValueError: the algorithm for nibble-sub must be either 'encrypt' or 'decrypt'
|
|
1199
|
+
sage: maes.nibble_sub(mat, algorithm='d')
|
|
1200
|
+
Traceback (most recent call last):
|
|
1201
|
+
...
|
|
1202
|
+
ValueError: the algorithm for nibble-sub must be either 'encrypt' or 'decrypt'
|
|
1203
|
+
"""
|
|
1204
|
+
if not isinstance(block, Matrix_dense) or \
|
|
1205
|
+
not (block.base_ring().order() == 16 and block.base_ring().is_field()):
|
|
1206
|
+
raise TypeError("input block must be a 2 x 2 matrix over GF(16)")
|
|
1207
|
+
if not (block.nrows() == block.ncols() == 2):
|
|
1208
|
+
raise TypeError("input block must be a 2 x 2 matrix over GF(16)")
|
|
1209
|
+
|
|
1210
|
+
MS = MatrixSpace(FiniteField(self._key_size, "x"), 2, 2)
|
|
1211
|
+
# get the integer representation of each GF(2^4) element
|
|
1212
|
+
# in the input matrix block
|
|
1213
|
+
lst = [self._GF_to_int[block[i][j]] for i in range(block.nrows()) for j in range(block.ncols())]
|
|
1214
|
+
if algorithm == "encrypt":
|
|
1215
|
+
# Now run each resulting integer through the S-box for
|
|
1216
|
+
# encryption. Then convert the result output by the S-box
|
|
1217
|
+
# to an element of GF(2^4).
|
|
1218
|
+
return MS([self._int_to_GF[self._sboxE[e]] for e in lst])
|
|
1219
|
+
elif algorithm == "decrypt":
|
|
1220
|
+
# Now run each resulting integer through the S-box for
|
|
1221
|
+
# decryption. Then convert the result output by the S-box
|
|
1222
|
+
# to an element of GF(2^4).
|
|
1223
|
+
return MS([self._int_to_GF[self._sboxD[e]] for e in lst])
|
|
1224
|
+
else:
|
|
1225
|
+
raise ValueError("the algorithm for nibble-sub must be either 'encrypt' or 'decrypt'")
|
|
1226
|
+
|
|
1227
|
+
def random_key(self):
|
|
1228
|
+
r"""
|
|
1229
|
+
A random key within the key space of this Mini-AES block cipher. Like
|
|
1230
|
+
the AES, Phan's Mini-AES is a symmetric-key block cipher. A Mini-AES
|
|
1231
|
+
key is a block of 16 bits, or a `2 \times 2` matrix with entries over
|
|
1232
|
+
the finite field `\GF{2^4}`. Thus the number of possible keys is
|
|
1233
|
+
`2^{16} = 16^4`.
|
|
1234
|
+
|
|
1235
|
+
OUTPUT:
|
|
1236
|
+
|
|
1237
|
+
- A `2 \times 2` matrix over the finite field `\GF{2^4}`, used
|
|
1238
|
+
as a secret key for this Mini-AES block cipher.
|
|
1239
|
+
|
|
1240
|
+
EXAMPLES:
|
|
1241
|
+
|
|
1242
|
+
Each nibble of a key is an element of the finite field
|
|
1243
|
+
`\GF{2^4}`::
|
|
1244
|
+
|
|
1245
|
+
sage: K = FiniteField(16, "x")
|
|
1246
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1247
|
+
sage: maes = MiniAES()
|
|
1248
|
+
sage: key = maes.random_key()
|
|
1249
|
+
sage: [key[i][j] in K for i in range(key.nrows()) for j in range(key.ncols())]
|
|
1250
|
+
[True, True, True, True]
|
|
1251
|
+
|
|
1252
|
+
Generate a random key, then perform encryption and decryption using
|
|
1253
|
+
that key::
|
|
1254
|
+
|
|
1255
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1256
|
+
sage: maes = MiniAES()
|
|
1257
|
+
sage: K = FiniteField(16, "x")
|
|
1258
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
1259
|
+
sage: key = maes.random_key()
|
|
1260
|
+
sage: P = MS.random_element()
|
|
1261
|
+
sage: C = maes.encrypt(P, key)
|
|
1262
|
+
sage: plaintxt = maes.decrypt(C, key)
|
|
1263
|
+
sage: plaintxt == P
|
|
1264
|
+
True
|
|
1265
|
+
"""
|
|
1266
|
+
MS = MatrixSpace(FiniteField(16, "x"), 2, 2)
|
|
1267
|
+
return MS.random_element()
|
|
1268
|
+
|
|
1269
|
+
def round_key(self, key, n):
|
|
1270
|
+
r"""
|
|
1271
|
+
Return the round key for round ``n``. Phan's Mini-AES is defined to
|
|
1272
|
+
have two rounds. The round key `K_0` is generated and used prior to
|
|
1273
|
+
the first round, with round keys `K_1` and `K_2` being used in rounds
|
|
1274
|
+
1 and 2 respectively. In total, there are three round keys, each
|
|
1275
|
+
generated from the secret key ``key``.
|
|
1276
|
+
|
|
1277
|
+
INPUT:
|
|
1278
|
+
|
|
1279
|
+
- ``key`` -- the secret key
|
|
1280
|
+
|
|
1281
|
+
- ``n`` -- nonnegative integer; the round number
|
|
1282
|
+
|
|
1283
|
+
OUTPUT: the `n`-th round key
|
|
1284
|
+
|
|
1285
|
+
EXAMPLES:
|
|
1286
|
+
|
|
1287
|
+
Obtaining the round keys from the secret key::
|
|
1288
|
+
|
|
1289
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1290
|
+
sage: maes = MiniAES()
|
|
1291
|
+
sage: K = FiniteField(16, "x")
|
|
1292
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
1293
|
+
sage: key = MS([ [K("x^3 + x^2"), K("x^3 + x^2 + x + 1")], [K("x + 1"), K("0")] ])
|
|
1294
|
+
sage: maes.round_key(key, 0)
|
|
1295
|
+
<BLANKLINE>
|
|
1296
|
+
[ x^3 + x^2 x^3 + x^2 + x + 1]
|
|
1297
|
+
[ x + 1 0]
|
|
1298
|
+
sage: key
|
|
1299
|
+
<BLANKLINE>
|
|
1300
|
+
[ x^3 + x^2 x^3 + x^2 + x + 1]
|
|
1301
|
+
[ x + 1 0]
|
|
1302
|
+
sage: maes.round_key(key, 1)
|
|
1303
|
+
[x^3 + x x^2 + x]
|
|
1304
|
+
[x^3 + 1 x^2 + x]
|
|
1305
|
+
sage: maes.round_key(key, 2)
|
|
1306
|
+
<BLANKLINE>
|
|
1307
|
+
[ x^2 + 1 x^3 + x]
|
|
1308
|
+
[x^3 + x^2 x^3 + x^2]
|
|
1309
|
+
|
|
1310
|
+
TESTS:
|
|
1311
|
+
|
|
1312
|
+
Only two rounds are defined for this AES variant::
|
|
1313
|
+
|
|
1314
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1315
|
+
sage: maes = MiniAES()
|
|
1316
|
+
sage: K = FiniteField(16, "x")
|
|
1317
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
1318
|
+
sage: key = MS([ [K("x^3 + x^2"), K("x^3 + x^2 + x + 1")], [K("x + 1"), K("0")] ])
|
|
1319
|
+
sage: maes.round_key(key, -1)
|
|
1320
|
+
Traceback (most recent call last):
|
|
1321
|
+
...
|
|
1322
|
+
ValueError: Mini-AES only defines two rounds
|
|
1323
|
+
sage: maes.round_key(key, 3)
|
|
1324
|
+
Traceback (most recent call last):
|
|
1325
|
+
...
|
|
1326
|
+
ValueError: Mini-AES only defines two rounds
|
|
1327
|
+
|
|
1328
|
+
The input key must be a matrix::
|
|
1329
|
+
|
|
1330
|
+
sage: maes.round_key("key", 0)
|
|
1331
|
+
Traceback (most recent call last):
|
|
1332
|
+
...
|
|
1333
|
+
TypeError: secret key must be a 2 x 2 matrix over GF(16)
|
|
1334
|
+
|
|
1335
|
+
In addition, the dimensions of the key matrix must be `2 \times 2`::
|
|
1336
|
+
|
|
1337
|
+
sage: K = FiniteField(16, "x")
|
|
1338
|
+
sage: MS = MatrixSpace(K, 1, 2)
|
|
1339
|
+
sage: key = MS([[K("x^3 + x^2 + x + 1"), K("0")]])
|
|
1340
|
+
sage: maes.round_key(key, 2)
|
|
1341
|
+
Traceback (most recent call last):
|
|
1342
|
+
...
|
|
1343
|
+
TypeError: secret key must be a 2 x 2 matrix over GF(16)
|
|
1344
|
+
"""
|
|
1345
|
+
if not isinstance(key, Matrix_dense) or \
|
|
1346
|
+
not (key.base_ring().order() == 16 and key.base_ring().is_field()):
|
|
1347
|
+
raise TypeError("secret key must be a 2 x 2 matrix over GF(16)")
|
|
1348
|
+
if not (key.nrows() == key.ncols() == 2):
|
|
1349
|
+
raise TypeError("secret key must be a 2 x 2 matrix over GF(16)")
|
|
1350
|
+
|
|
1351
|
+
K = FiniteField(self._key_size, "x")
|
|
1352
|
+
MS = MatrixSpace(K, 2, 2)
|
|
1353
|
+
# round 0
|
|
1354
|
+
if n == 0:
|
|
1355
|
+
return key
|
|
1356
|
+
# round 1
|
|
1357
|
+
if n == 1:
|
|
1358
|
+
round_constant_1 = K("1")
|
|
1359
|
+
w4 = key[0][0] + self._sboxE[key[1][1]] + round_constant_1
|
|
1360
|
+
w5 = key[1][0] + w4
|
|
1361
|
+
w6 = key[0][1] + w5
|
|
1362
|
+
w7 = key[1][1] + w6
|
|
1363
|
+
return MS([ [w4, w6], [w5, w7] ])
|
|
1364
|
+
# round 2
|
|
1365
|
+
if n == 2:
|
|
1366
|
+
round_constant_2 = K("x")
|
|
1367
|
+
key1 = self.round_key(key, 1)
|
|
1368
|
+
w8 = key1[0][0] + self._sboxE[key1[1][1]] + round_constant_2
|
|
1369
|
+
w9 = key1[1][0] + w8
|
|
1370
|
+
w10 = key1[0][1] + w9
|
|
1371
|
+
w11 = key1[1][1] + w10
|
|
1372
|
+
return MS([ [w8, w10], [w9, w11] ])
|
|
1373
|
+
# unsupported round number
|
|
1374
|
+
if (n < 0) or (n > 2):
|
|
1375
|
+
raise ValueError("Mini-AES only defines two rounds")
|
|
1376
|
+
|
|
1377
|
+
def sbox(self):
|
|
1378
|
+
r"""
|
|
1379
|
+
Return the S-box of Mini-AES.
|
|
1380
|
+
|
|
1381
|
+
EXAMPLES::
|
|
1382
|
+
|
|
1383
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1384
|
+
sage: maes = MiniAES()
|
|
1385
|
+
sage: maes.sbox()
|
|
1386
|
+
(14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7)
|
|
1387
|
+
"""
|
|
1388
|
+
return self._sboxE
|
|
1389
|
+
|
|
1390
|
+
def shift_row(self, block):
|
|
1391
|
+
r"""
|
|
1392
|
+
Rotate each row of ``block`` to the left by different nibble
|
|
1393
|
+
amounts. The first or zero-th row is left unchanged, while the
|
|
1394
|
+
second or row one is rotated left by one nibble. This has the effect
|
|
1395
|
+
of only interchanging the nibbles in the second row. Let
|
|
1396
|
+
`b_0, b_1, b_2, b_3` be four nibbles arranged as the following
|
|
1397
|
+
`2 \times 2` matrix
|
|
1398
|
+
|
|
1399
|
+
.. MATH::
|
|
1400
|
+
|
|
1401
|
+
\begin{bmatrix}
|
|
1402
|
+
b_0 & b_2 \\
|
|
1403
|
+
b_1 & b_3
|
|
1404
|
+
\end{bmatrix}
|
|
1405
|
+
|
|
1406
|
+
Then the operation of shift-row is the mapping
|
|
1407
|
+
|
|
1408
|
+
.. MATH::
|
|
1409
|
+
|
|
1410
|
+
\begin{bmatrix}
|
|
1411
|
+
b_0 & b_2 \\
|
|
1412
|
+
b_1 & b_3
|
|
1413
|
+
\end{bmatrix}
|
|
1414
|
+
\longmapsto
|
|
1415
|
+
\begin{bmatrix}
|
|
1416
|
+
b_0 & b_2 \\
|
|
1417
|
+
b_3 & b_1
|
|
1418
|
+
\end{bmatrix}
|
|
1419
|
+
|
|
1420
|
+
INPUT:
|
|
1421
|
+
|
|
1422
|
+
- ``block`` -- a `2 \times 2` matrix with entries over
|
|
1423
|
+
`\GF{2^4}`
|
|
1424
|
+
|
|
1425
|
+
OUTPUT: a `2 \times 2` matrix resulting from applying shift-row on ``block``
|
|
1426
|
+
|
|
1427
|
+
EXAMPLES:
|
|
1428
|
+
|
|
1429
|
+
Here we work with elements of the finite field `\GF{2^4}`::
|
|
1430
|
+
|
|
1431
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1432
|
+
sage: maes = MiniAES()
|
|
1433
|
+
sage: K = FiniteField(16, "x")
|
|
1434
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
1435
|
+
sage: mat = MS([[K("x^3 + x^2 + x + 1"), K("0")], [K("x^2 + x + 1"), K("x^3 + x")]])
|
|
1436
|
+
sage: maes.shift_row(mat)
|
|
1437
|
+
<BLANKLINE>
|
|
1438
|
+
[x^3 + x^2 + x + 1 0]
|
|
1439
|
+
[ x^3 + x x^2 + x + 1]
|
|
1440
|
+
sage: mat
|
|
1441
|
+
<BLANKLINE>
|
|
1442
|
+
[x^3 + x^2 + x + 1 0]
|
|
1443
|
+
[ x^2 + x + 1 x^3 + x]
|
|
1444
|
+
|
|
1445
|
+
But we can also work with binary strings::
|
|
1446
|
+
|
|
1447
|
+
sage: bin = BinaryStrings()
|
|
1448
|
+
sage: B = bin.encoding("Qt"); B
|
|
1449
|
+
0101000101110100
|
|
1450
|
+
sage: B = MS(maes.binary_to_GF(B)); B
|
|
1451
|
+
<BLANKLINE>
|
|
1452
|
+
[ x^2 + 1 1]
|
|
1453
|
+
[x^2 + x + 1 x^2]
|
|
1454
|
+
sage: maes.shift_row(B)
|
|
1455
|
+
<BLANKLINE>
|
|
1456
|
+
[ x^2 + 1 1]
|
|
1457
|
+
[ x^2 x^2 + x + 1]
|
|
1458
|
+
|
|
1459
|
+
Here we work with integers `n` such that `0 \leq n \leq 15`::
|
|
1460
|
+
|
|
1461
|
+
sage: P = [3, 6, 9, 12]; P
|
|
1462
|
+
[3, 6, 9, 12]
|
|
1463
|
+
sage: P = MS(maes.integer_to_GF(P)); P
|
|
1464
|
+
<BLANKLINE>
|
|
1465
|
+
[ x + 1 x^2 + x]
|
|
1466
|
+
[ x^3 + 1 x^3 + x^2]
|
|
1467
|
+
sage: maes.shift_row(P)
|
|
1468
|
+
<BLANKLINE>
|
|
1469
|
+
[ x + 1 x^2 + x]
|
|
1470
|
+
[x^3 + x^2 x^3 + 1]
|
|
1471
|
+
|
|
1472
|
+
TESTS:
|
|
1473
|
+
|
|
1474
|
+
The input block must be a matrix::
|
|
1475
|
+
|
|
1476
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1477
|
+
sage: maes = MiniAES()
|
|
1478
|
+
sage: maes.shift_row("block")
|
|
1479
|
+
Traceback (most recent call last):
|
|
1480
|
+
...
|
|
1481
|
+
TypeError: input block must be a 2 x 2 matrix over GF(16)
|
|
1482
|
+
|
|
1483
|
+
In addition, the dimensions of the input matrix must be `2 \times 2`::
|
|
1484
|
+
|
|
1485
|
+
sage: K = FiniteField(16, "x")
|
|
1486
|
+
sage: MS = MatrixSpace(K, 1, 2)
|
|
1487
|
+
sage: mat = MS([[K("x^3 + x^2 + x + 1"), K("0")]])
|
|
1488
|
+
sage: maes.shift_row(mat)
|
|
1489
|
+
Traceback (most recent call last):
|
|
1490
|
+
...
|
|
1491
|
+
TypeError: input block must be a 2 x 2 matrix over GF(16)
|
|
1492
|
+
"""
|
|
1493
|
+
if not isinstance(block, Matrix_dense) or \
|
|
1494
|
+
not (block.base_ring().order() == 16 and block.base_ring().is_field()):
|
|
1495
|
+
raise TypeError("input block must be a 2 x 2 matrix over GF(16)")
|
|
1496
|
+
if not (block.nrows() == block.ncols() == 2):
|
|
1497
|
+
raise TypeError("input block must be a 2 x 2 matrix over GF(16)")
|
|
1498
|
+
|
|
1499
|
+
MS = MatrixSpace(FiniteField(self._key_size, "x"), 2, 2)
|
|
1500
|
+
mat = MS([ [block[0][0], block[0][1]],
|
|
1501
|
+
[block[1][1], block[1][0]] ] )
|
|
1502
|
+
return mat
|
|
1503
|
+
|
|
1504
|
+
### conversion functions to convert between different data formats
|
|
1505
|
+
|
|
1506
|
+
def GF_to_binary(self, G):
|
|
1507
|
+
r"""
|
|
1508
|
+
Return the binary representation of ``G``.
|
|
1509
|
+
If ``G`` is an element of the finite field `\GF{2^4}`, then
|
|
1510
|
+
obtain the binary representation of ``G``. If ``G`` is a list of
|
|
1511
|
+
elements belonging to `\GF{2^4}`, obtain the 4-bit
|
|
1512
|
+
representation of each element of the list, then concatenate the
|
|
1513
|
+
resulting 4-bit strings into a binary string. If ``G`` is a matrix
|
|
1514
|
+
with entries over `\GF{2^4}`, convert each matrix entry to its
|
|
1515
|
+
4-bit representation, then concatenate the 4-bit strings. The
|
|
1516
|
+
concatenation is performed starting from the top-left corner of the
|
|
1517
|
+
matrix, working across left to right, top to bottom. Each element of
|
|
1518
|
+
`\GF{2^4}` can be associated with a unique 4-bit string
|
|
1519
|
+
according to the following table:
|
|
1520
|
+
|
|
1521
|
+
.. MATH::
|
|
1522
|
+
|
|
1523
|
+
\begin{tabular}{ll|ll} \hline
|
|
1524
|
+
4-bit string & $\GF{2^4}$ & 4-bit string & $\GF{2^4}$ \\\hline
|
|
1525
|
+
0000 & $0$ & 1000 & $x^3$ \\
|
|
1526
|
+
0001 & $1$ & 1001 & $x^3 + 1$ \\
|
|
1527
|
+
0010 & $x$ & 1010 & $x^3 + x$ \\
|
|
1528
|
+
0011 & $x + 1$ & 1011 & $x^3 + x + 1$ \\
|
|
1529
|
+
0100 & $x^2$ & 1100 & $x^3 + x^2$ \\
|
|
1530
|
+
0101 & $x^2 + 1$ & 1101 & $x^3 + x^2 + 1$ \\
|
|
1531
|
+
0110 & $x^2 + x$ & 1110 & $x^3 + x^2 + x$ \\
|
|
1532
|
+
0111 & $x^2 + x + 1$ & 1111 & $x^3 + x^2 + x+ 1$ \\\hline
|
|
1533
|
+
\end{tabular}
|
|
1534
|
+
|
|
1535
|
+
INPUT:
|
|
1536
|
+
|
|
1537
|
+
- ``G`` -- an element of `\GF{2^4}`, a list of elements of
|
|
1538
|
+
`\GF{2^4}`, or a matrix over `\GF{2^4}`
|
|
1539
|
+
|
|
1540
|
+
OUTPUT: a binary string representation of ``G``
|
|
1541
|
+
|
|
1542
|
+
EXAMPLES:
|
|
1543
|
+
|
|
1544
|
+
Obtain the binary representation of all elements of `\GF{2^4}`::
|
|
1545
|
+
|
|
1546
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1547
|
+
sage: maes = MiniAES()
|
|
1548
|
+
sage: K = FiniteField(16, "x")
|
|
1549
|
+
sage: S = Set(K); len(S) # GF(2^4) has this many elements
|
|
1550
|
+
16
|
|
1551
|
+
sage: [maes.GF_to_binary(S[i]) for i in range(len(S))]
|
|
1552
|
+
<BLANKLINE>
|
|
1553
|
+
[0000,
|
|
1554
|
+
0001,
|
|
1555
|
+
0010,
|
|
1556
|
+
0011,
|
|
1557
|
+
0100,
|
|
1558
|
+
0101,
|
|
1559
|
+
0110,
|
|
1560
|
+
0111,
|
|
1561
|
+
1000,
|
|
1562
|
+
1001,
|
|
1563
|
+
1010,
|
|
1564
|
+
1011,
|
|
1565
|
+
1100,
|
|
1566
|
+
1101,
|
|
1567
|
+
1110,
|
|
1568
|
+
1111]
|
|
1569
|
+
|
|
1570
|
+
The binary representation of a list of elements belonging to
|
|
1571
|
+
`\GF{2^4}`::
|
|
1572
|
+
|
|
1573
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1574
|
+
sage: maes = MiniAES()
|
|
1575
|
+
sage: K = FiniteField(16, "x")
|
|
1576
|
+
sage: G = [K("x^2 + x + 1"), K("x^3 + x^2"), K("x"), K("x^3 + x + 1"), K("x^3 + x^2 + x + 1"), K("x^2 + x"), K("1"), K("x^2 + x + 1")]
|
|
1577
|
+
sage: maes.GF_to_binary(G)
|
|
1578
|
+
01111100001010111111011000010111
|
|
1579
|
+
|
|
1580
|
+
The binary representation of a matrix over `\GF{2^4}`::
|
|
1581
|
+
|
|
1582
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1583
|
+
sage: maes = MiniAES()
|
|
1584
|
+
sage: K = FiniteField(16, "x")
|
|
1585
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
1586
|
+
sage: G = MS([K("x^3 + x^2"), K("x + 1"), K("x^2 + x + 1"), K("x^3 + x^2 + x")]); G
|
|
1587
|
+
<BLANKLINE>
|
|
1588
|
+
[ x^3 + x^2 x + 1]
|
|
1589
|
+
[ x^2 + x + 1 x^3 + x^2 + x]
|
|
1590
|
+
sage: maes.GF_to_binary(G)
|
|
1591
|
+
1100001101111110
|
|
1592
|
+
sage: MS = MatrixSpace(K, 2, 4)
|
|
1593
|
+
sage: G = MS([K("x^2 + x + 1"), K("x^3 + x^2"), K("x"), K("x^3 + x + 1"), K("x^3 + x^2 + x + 1"), K("x^2 + x"), K("1"), K("x^2 + x + 1")]); G
|
|
1594
|
+
<BLANKLINE>
|
|
1595
|
+
[ x^2 + x + 1 x^3 + x^2 x x^3 + x + 1]
|
|
1596
|
+
[x^3 + x^2 + x + 1 x^2 + x 1 x^2 + x + 1]
|
|
1597
|
+
sage: maes.GF_to_binary(G)
|
|
1598
|
+
01111100001010111111011000010111
|
|
1599
|
+
|
|
1600
|
+
TESTS:
|
|
1601
|
+
|
|
1602
|
+
Input must be an element of `\GF{2^4}`::
|
|
1603
|
+
|
|
1604
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1605
|
+
sage: maes = MiniAES()
|
|
1606
|
+
sage: K = FiniteField(8, "x")
|
|
1607
|
+
sage: G = K.random_element()
|
|
1608
|
+
sage: maes.GF_to_binary(G)
|
|
1609
|
+
Traceback (most recent call last):
|
|
1610
|
+
...
|
|
1611
|
+
TypeError: input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)
|
|
1612
|
+
|
|
1613
|
+
A list of elements belonging to `\GF{2^4}`::
|
|
1614
|
+
|
|
1615
|
+
sage: maes.GF_to_binary([])
|
|
1616
|
+
Traceback (most recent call last):
|
|
1617
|
+
...
|
|
1618
|
+
ValueError: input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)
|
|
1619
|
+
sage: G = [K.random_element() for i in range(5)]
|
|
1620
|
+
sage: maes.GF_to_binary(G)
|
|
1621
|
+
Traceback (most recent call last):
|
|
1622
|
+
...
|
|
1623
|
+
KeyError:...
|
|
1624
|
+
|
|
1625
|
+
A matrix over `\GF{2^4}`::
|
|
1626
|
+
|
|
1627
|
+
sage: MS = MatrixSpace(FiniteField(7, "x"), 4, 5)
|
|
1628
|
+
sage: maes.GF_to_binary(MS.random_element())
|
|
1629
|
+
Traceback (most recent call last):
|
|
1630
|
+
...
|
|
1631
|
+
TypeError: input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)
|
|
1632
|
+
"""
|
|
1633
|
+
B = BinaryStrings()
|
|
1634
|
+
K = FiniteField(self._key_size, "x")
|
|
1635
|
+
# G is an element over GF(16)
|
|
1636
|
+
if G in K:
|
|
1637
|
+
return self._GF_to_bin[G]
|
|
1638
|
+
# G is a list of elements over GF(16)
|
|
1639
|
+
elif isinstance(G, list):
|
|
1640
|
+
if len(G) == 0:
|
|
1641
|
+
raise ValueError("input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)")
|
|
1642
|
+
S = "".join(str(self._GF_to_bin[g]) for g in G)
|
|
1643
|
+
return B(S)
|
|
1644
|
+
# G is a matrix over GF(16)
|
|
1645
|
+
elif isinstance(G, Matrix_dense):
|
|
1646
|
+
if G.base_ring() is not K:
|
|
1647
|
+
raise TypeError("input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)")
|
|
1648
|
+
S = "".join(str(self._GF_to_bin[G[i][j]])
|
|
1649
|
+
for i in range(G.nrows()) for j in range(G.ncols()))
|
|
1650
|
+
return B(S)
|
|
1651
|
+
# the type of G doesn't match the supported types
|
|
1652
|
+
else:
|
|
1653
|
+
raise TypeError("input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)")
|
|
1654
|
+
|
|
1655
|
+
def GF_to_integer(self, G):
|
|
1656
|
+
r"""
|
|
1657
|
+
Return the integer representation of the finite field element ``G``.
|
|
1658
|
+
If ``G`` is an element of the finite field `\GF{2^4}`, then
|
|
1659
|
+
obtain the integer representation of ``G``. If ``G`` is a list of
|
|
1660
|
+
elements belonging to `\GF{2^4}`, obtain the integer
|
|
1661
|
+
representation of each element of the list, and return the result
|
|
1662
|
+
as a list of integers. If ``G`` is a matrix with entries over
|
|
1663
|
+
`\GF{2^4}`, convert each matrix entry to its integer representation,
|
|
1664
|
+
and return the result as a list of integers. The resulting list is
|
|
1665
|
+
obtained by starting from the top-left corner of the matrix, working
|
|
1666
|
+
across left to right, top to bottom. Each element of `\GF{2^4}` can
|
|
1667
|
+
be associated with a unique integer according to the following table:
|
|
1668
|
+
|
|
1669
|
+
.. MATH::
|
|
1670
|
+
|
|
1671
|
+
\begin{tabular}{ll|ll} \hline
|
|
1672
|
+
integer & $\GF{2^4}$ & integer & $\GF{2^4}$ \\\hline
|
|
1673
|
+
0 & $0$ & 8 & $x^3$ \\
|
|
1674
|
+
1 & $1$ & 9 & $x^3 + 1$ \\
|
|
1675
|
+
2 & $x$ & 10 & $x^3 + x$ \\
|
|
1676
|
+
3 & $x + 1$ & 11 & $x^3 + x + 1$ \\
|
|
1677
|
+
4 & $x^2$ & 12 & $x^3 + x^2$ \\
|
|
1678
|
+
5 & $x^2 + 1$ & 13 & $x^3 + x^2 + 1$ \\
|
|
1679
|
+
6 & $x^2 + x$ & 14 & $x^3 + x^2 + x$ \\
|
|
1680
|
+
7 & $x^2 + x + 1$ & 15 & $x^3 + x^2 + x+ 1$ \\\hline
|
|
1681
|
+
\end{tabular}
|
|
1682
|
+
|
|
1683
|
+
INPUT:
|
|
1684
|
+
|
|
1685
|
+
- ``G`` -- an element of `\GF{2^4}`, a list of elements belonging to
|
|
1686
|
+
`\GF{2^4}`, or a matrix over `\GF{2^4}`
|
|
1687
|
+
|
|
1688
|
+
OUTPUT: the integer representation of ``G``
|
|
1689
|
+
|
|
1690
|
+
EXAMPLES:
|
|
1691
|
+
|
|
1692
|
+
Obtain the integer representation of all elements of `\GF{2^4}`::
|
|
1693
|
+
|
|
1694
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1695
|
+
sage: maes = MiniAES()
|
|
1696
|
+
sage: K = FiniteField(16, "x")
|
|
1697
|
+
sage: S = Set(K); len(S) # GF(2^4) has this many elements
|
|
1698
|
+
16
|
|
1699
|
+
sage: [maes.GF_to_integer(S[i]) for i in range(len(S))]
|
|
1700
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
1701
|
+
|
|
1702
|
+
The integer representation of a list of elements belonging to
|
|
1703
|
+
`\GF{2^4}`::
|
|
1704
|
+
|
|
1705
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1706
|
+
sage: maes = MiniAES()
|
|
1707
|
+
sage: K = FiniteField(16, "x")
|
|
1708
|
+
sage: G = [K("x^2 + x + 1"), K("x^3 + x^2"), K("x"), K("x^3 + x + 1"), K("x^3 + x^2 + x + 1"), K("x^2 + x"), K("1"), K("x^2 + x + 1")]
|
|
1709
|
+
sage: maes.GF_to_integer(G)
|
|
1710
|
+
[7, 12, 2, 11, 15, 6, 1, 7]
|
|
1711
|
+
|
|
1712
|
+
The integer representation of a matrix over `\GF{2^4}`::
|
|
1713
|
+
|
|
1714
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1715
|
+
sage: maes = MiniAES()
|
|
1716
|
+
sage: K = FiniteField(16, "x")
|
|
1717
|
+
sage: MS = MatrixSpace(K, 2, 2)
|
|
1718
|
+
sage: G = MS([K("x^3 + x^2"), K("x + 1"), K("x^2 + x + 1"), K("x^3 + x^2 + x")]); G
|
|
1719
|
+
<BLANKLINE>
|
|
1720
|
+
[ x^3 + x^2 x + 1]
|
|
1721
|
+
[ x^2 + x + 1 x^3 + x^2 + x]
|
|
1722
|
+
sage: maes.GF_to_integer(G)
|
|
1723
|
+
[12, 3, 7, 14]
|
|
1724
|
+
sage: MS = MatrixSpace(K, 2, 4)
|
|
1725
|
+
sage: G = MS([K("x^2 + x + 1"), K("x^3 + x^2"), K("x"), K("x^3 + x + 1"), K("x^3 + x^2 + x + 1"), K("x^2 + x"), K("1"), K("x^2 + x + 1")]); G
|
|
1726
|
+
<BLANKLINE>
|
|
1727
|
+
[ x^2 + x + 1 x^3 + x^2 x x^3 + x + 1]
|
|
1728
|
+
[x^3 + x^2 + x + 1 x^2 + x 1 x^2 + x + 1]
|
|
1729
|
+
sage: maes.GF_to_integer(G)
|
|
1730
|
+
[7, 12, 2, 11, 15, 6, 1, 7]
|
|
1731
|
+
|
|
1732
|
+
TESTS:
|
|
1733
|
+
|
|
1734
|
+
Input must be an element of `\GF{2^4}`::
|
|
1735
|
+
|
|
1736
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1737
|
+
sage: maes = MiniAES()
|
|
1738
|
+
sage: K = FiniteField(7, "x")
|
|
1739
|
+
sage: G = K.random_element()
|
|
1740
|
+
sage: maes.GF_to_integer(G)
|
|
1741
|
+
Traceback (most recent call last):
|
|
1742
|
+
...
|
|
1743
|
+
TypeError: input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)
|
|
1744
|
+
|
|
1745
|
+
A list of elements belonging to `\GF{2^4}`::
|
|
1746
|
+
|
|
1747
|
+
sage: maes.GF_to_integer([])
|
|
1748
|
+
Traceback (most recent call last):
|
|
1749
|
+
...
|
|
1750
|
+
ValueError: input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)
|
|
1751
|
+
sage: G = [K.random_element() for i in range(5)]
|
|
1752
|
+
sage: maes.GF_to_integer(G)
|
|
1753
|
+
Traceback (most recent call last):
|
|
1754
|
+
...
|
|
1755
|
+
KeyError:...
|
|
1756
|
+
|
|
1757
|
+
A matrix over `\GF{2^4}`::
|
|
1758
|
+
|
|
1759
|
+
sage: MS = MatrixSpace(FiniteField(7, "x"), 4, 5)
|
|
1760
|
+
sage: maes.GF_to_integer(MS.random_element())
|
|
1761
|
+
Traceback (most recent call last):
|
|
1762
|
+
...
|
|
1763
|
+
TypeError: input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)
|
|
1764
|
+
"""
|
|
1765
|
+
K = FiniteField(self._key_size, "x")
|
|
1766
|
+
# G is an element over GF(16)
|
|
1767
|
+
if G in K:
|
|
1768
|
+
return self._GF_to_int[G]
|
|
1769
|
+
# G is a list of elements over GF(16)
|
|
1770
|
+
elif isinstance(G, list):
|
|
1771
|
+
if len(G) == 0:
|
|
1772
|
+
raise ValueError("input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)")
|
|
1773
|
+
return [self._GF_to_int[g] for g in G]
|
|
1774
|
+
# G is a matrix over GF(16)
|
|
1775
|
+
elif isinstance(G, Matrix_dense):
|
|
1776
|
+
if G.base_ring() is not K:
|
|
1777
|
+
raise TypeError("input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)")
|
|
1778
|
+
return [self._GF_to_int[G[i][j]] for i in range(G.nrows()) for j in range(G.ncols())]
|
|
1779
|
+
# the type of G doesn't match the supported types
|
|
1780
|
+
else:
|
|
1781
|
+
raise TypeError("input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)")
|
|
1782
|
+
|
|
1783
|
+
def binary_to_GF(self, B):
|
|
1784
|
+
r"""
|
|
1785
|
+
Return a list of elements of `\GF{2^4}` that represents the
|
|
1786
|
+
binary string ``B``. The number of bits in ``B`` must be greater
|
|
1787
|
+
than zero and a multiple of 4. Each nibble (or 4-bit string) is
|
|
1788
|
+
uniquely associated with an element of `\GF{2^4}` as
|
|
1789
|
+
specified by the following table:
|
|
1790
|
+
|
|
1791
|
+
.. MATH::
|
|
1792
|
+
|
|
1793
|
+
\begin{tabular}{ll|ll} \hline
|
|
1794
|
+
4-bit string & $\GF{2^4}$ & 4-bit string & $\GF{2^4}$ \\\hline
|
|
1795
|
+
0000 & $0$ & 1000 & $x^3$ \\
|
|
1796
|
+
0001 & $1$ & 1001 & $x^3 + 1$ \\
|
|
1797
|
+
0010 & $x$ & 1010 & $x^3 + x$ \\
|
|
1798
|
+
0011 & $x + 1$ & 1011 & $x^3 + x + 1$ \\
|
|
1799
|
+
0100 & $x^2$ & 1100 & $x^3 + x^2$ \\
|
|
1800
|
+
0101 & $x^2 + 1$ & 1101 & $x^3 + x^2 + 1$ \\
|
|
1801
|
+
0110 & $x^2 + x$ & 1110 & $x^3 + x^2 + x$ \\
|
|
1802
|
+
0111 & $x^2 + x + 1$ & 1111 & $x^3 + x^2 + x+ 1$ \\\hline
|
|
1803
|
+
\end{tabular}
|
|
1804
|
+
|
|
1805
|
+
INPUT:
|
|
1806
|
+
|
|
1807
|
+
- ``B`` -- a binary string, where the number of bits is positive and
|
|
1808
|
+
a multiple of 4
|
|
1809
|
+
|
|
1810
|
+
OUTPUT:
|
|
1811
|
+
|
|
1812
|
+
- A list of elements of the finite field `\GF{2^4}` that
|
|
1813
|
+
represent the binary string ``B``.
|
|
1814
|
+
|
|
1815
|
+
EXAMPLES:
|
|
1816
|
+
|
|
1817
|
+
Obtain all the elements of the finite field `\GF{2^4}`::
|
|
1818
|
+
|
|
1819
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1820
|
+
sage: maes = MiniAES()
|
|
1821
|
+
sage: bin = BinaryStrings()
|
|
1822
|
+
sage: B = bin("0000000100100011010001010110011110001001101010111100110111101111")
|
|
1823
|
+
sage: maes.binary_to_GF(B)
|
|
1824
|
+
<BLANKLINE>
|
|
1825
|
+
[0,
|
|
1826
|
+
1,
|
|
1827
|
+
x,
|
|
1828
|
+
x + 1,
|
|
1829
|
+
x^2,
|
|
1830
|
+
x^2 + 1,
|
|
1831
|
+
x^2 + x,
|
|
1832
|
+
x^2 + x + 1,
|
|
1833
|
+
x^3,
|
|
1834
|
+
x^3 + 1,
|
|
1835
|
+
x^3 + x,
|
|
1836
|
+
x^3 + x + 1,
|
|
1837
|
+
x^3 + x^2,
|
|
1838
|
+
x^3 + x^2 + 1,
|
|
1839
|
+
x^3 + x^2 + x,
|
|
1840
|
+
x^3 + x^2 + x + 1]
|
|
1841
|
+
|
|
1842
|
+
TESTS:
|
|
1843
|
+
|
|
1844
|
+
The input ``B`` must be a non-empty binary string, where the number
|
|
1845
|
+
of bits is a multiple of 4::
|
|
1846
|
+
|
|
1847
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1848
|
+
sage: maes = MiniAES()
|
|
1849
|
+
sage: maes.binary_to_GF("")
|
|
1850
|
+
Traceback (most recent call last):
|
|
1851
|
+
...
|
|
1852
|
+
ValueError: the number of bits in the binary string B must be positive and a multiple of 4
|
|
1853
|
+
sage: maes.binary_to_GF("101")
|
|
1854
|
+
Traceback (most recent call last):
|
|
1855
|
+
...
|
|
1856
|
+
ValueError: the number of bits in the binary string B must be positive and a multiple of 4
|
|
1857
|
+
"""
|
|
1858
|
+
from sage.rings.finite_rings.integer_mod import Mod
|
|
1859
|
+
bin = BinaryStrings()
|
|
1860
|
+
b = bin(B)
|
|
1861
|
+
# an empty string
|
|
1862
|
+
if len(b) == 0:
|
|
1863
|
+
raise ValueError("the number of bits in the binary string B must be positive and a multiple of 4")
|
|
1864
|
+
# a string with number of bits that is a multiple of 4
|
|
1865
|
+
if Mod(len(b), 4).lift() == 0:
|
|
1866
|
+
M = len(b) // 4 # the number of nibbles
|
|
1867
|
+
return [self._bin_to_GF[b[i*4 : (i+1)*4]] for i in range(M)]
|
|
1868
|
+
else:
|
|
1869
|
+
raise ValueError("the number of bits in the binary string B must be positive and a multiple of 4")
|
|
1870
|
+
|
|
1871
|
+
def binary_to_integer(self, B):
|
|
1872
|
+
r"""
|
|
1873
|
+
Return a list of integers representing the binary string ``B``. The
|
|
1874
|
+
number of bits in ``B`` must be greater than zero and a multiple of
|
|
1875
|
+
4. Each nibble (or 4-bit string) is uniquely associated with an
|
|
1876
|
+
integer as specified by the following table:
|
|
1877
|
+
|
|
1878
|
+
.. MATH::
|
|
1879
|
+
|
|
1880
|
+
\begin{tabular}{ll|ll} \hline
|
|
1881
|
+
4-bit string & integer & 4-bit string & integer \\\hline
|
|
1882
|
+
0000 & 0 & 1000 & 8 \\
|
|
1883
|
+
0001 & 1 & 1001 & 9 \\
|
|
1884
|
+
0010 & 2 & 1010 & 10 \\
|
|
1885
|
+
0011 & 3 & 1011 & 11 \\
|
|
1886
|
+
0100 & 4 & 1100 & 12 \\
|
|
1887
|
+
0101 & 5 & 1101 & 13 \\
|
|
1888
|
+
0110 & 6 & 1110 & 14 \\
|
|
1889
|
+
0111 & 7 & 1111 & 15 \\\hline
|
|
1890
|
+
\end{tabular}
|
|
1891
|
+
|
|
1892
|
+
INPUT:
|
|
1893
|
+
|
|
1894
|
+
- ``B`` -- a binary string, where the number of bits is positive and
|
|
1895
|
+
a multiple of 4
|
|
1896
|
+
|
|
1897
|
+
OUTPUT: list of integers that represent the binary string ``B``
|
|
1898
|
+
|
|
1899
|
+
EXAMPLES:
|
|
1900
|
+
|
|
1901
|
+
Obtain the integer representation of every 4-bit string::
|
|
1902
|
+
|
|
1903
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1904
|
+
sage: maes = MiniAES()
|
|
1905
|
+
sage: bin = BinaryStrings()
|
|
1906
|
+
sage: B = bin("0000000100100011010001010110011110001001101010111100110111101111")
|
|
1907
|
+
sage: maes.binary_to_integer(B)
|
|
1908
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
1909
|
+
|
|
1910
|
+
TESTS:
|
|
1911
|
+
|
|
1912
|
+
The input ``B`` must be a non-empty binary string, where the number
|
|
1913
|
+
of bits is a multiple of 4::
|
|
1914
|
+
|
|
1915
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1916
|
+
sage: maes = MiniAES()
|
|
1917
|
+
sage: maes.binary_to_integer("")
|
|
1918
|
+
Traceback (most recent call last):
|
|
1919
|
+
...
|
|
1920
|
+
ValueError: the number of bits in the binary string B must be positive and a multiple of 4
|
|
1921
|
+
sage: maes.binary_to_integer("101")
|
|
1922
|
+
Traceback (most recent call last):
|
|
1923
|
+
...
|
|
1924
|
+
ValueError: the number of bits in the binary string B must be positive and a multiple of 4
|
|
1925
|
+
"""
|
|
1926
|
+
from sage.rings.finite_rings.integer_mod import Mod
|
|
1927
|
+
bin = BinaryStrings()
|
|
1928
|
+
b = bin(B)
|
|
1929
|
+
# an empty string
|
|
1930
|
+
if len(b) == 0:
|
|
1931
|
+
raise ValueError("the number of bits in the binary string B must be positive and a multiple of 4")
|
|
1932
|
+
# a string with number of bits that is a multiple of 4
|
|
1933
|
+
if Mod(len(b), 4).lift() == 0:
|
|
1934
|
+
M = len(b) // 4 # the number of nibbles
|
|
1935
|
+
return [self._bin_to_int[b[i*4 : (i+1)*4]] for i in range(M)]
|
|
1936
|
+
else:
|
|
1937
|
+
raise ValueError("the number of bits in the binary string B must be positive and a multiple of 4")
|
|
1938
|
+
|
|
1939
|
+
def integer_to_binary(self, N):
|
|
1940
|
+
r"""
|
|
1941
|
+
Return the binary representation of ``N``. If `N` is an integer such
|
|
1942
|
+
that `0 \leq N \leq 15`, return the binary representation of ``N``.
|
|
1943
|
+
If ``N`` is a list of integers each of which is `\geq 0` and
|
|
1944
|
+
`\leq 15`, then obtain the binary representation of each integer,
|
|
1945
|
+
and concatenate the individual binary representations into a single
|
|
1946
|
+
binary string. Each integer between 0 and 15, inclusive, can be
|
|
1947
|
+
associated with a unique 4-bit string according to the following
|
|
1948
|
+
table:
|
|
1949
|
+
|
|
1950
|
+
.. MATH::
|
|
1951
|
+
|
|
1952
|
+
\begin{tabular}{ll|ll} \hline
|
|
1953
|
+
4-bit string & integer & 4-bit string & integer \\\hline
|
|
1954
|
+
0000 & 0 & 1000 & 8 \\
|
|
1955
|
+
0001 & 1 & 1001 & 9 \\
|
|
1956
|
+
0010 & 2 & 1010 & 10 \\
|
|
1957
|
+
0011 & 3 & 1011 & 11 \\
|
|
1958
|
+
0100 & 4 & 1100 & 12 \\
|
|
1959
|
+
0101 & 5 & 1101 & 13 \\
|
|
1960
|
+
0110 & 6 & 1110 & 14 \\
|
|
1961
|
+
0111 & 7 & 1111 & 15 \\\hline
|
|
1962
|
+
\end{tabular}
|
|
1963
|
+
|
|
1964
|
+
INPUT:
|
|
1965
|
+
|
|
1966
|
+
- ``N`` -- nonnegative integer less than or equal to 15, or a list
|
|
1967
|
+
of such integers
|
|
1968
|
+
|
|
1969
|
+
OUTPUT: a binary string representing ``N``
|
|
1970
|
+
|
|
1971
|
+
EXAMPLES:
|
|
1972
|
+
|
|
1973
|
+
The binary representations of all integers between 0 and
|
|
1974
|
+
15, inclusive::
|
|
1975
|
+
|
|
1976
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1977
|
+
sage: maes = MiniAES()
|
|
1978
|
+
sage: lst = [n for n in range(16)]; lst
|
|
1979
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
1980
|
+
sage: maes.integer_to_binary(lst)
|
|
1981
|
+
0000000100100011010001010110011110001001101010111100110111101111
|
|
1982
|
+
|
|
1983
|
+
The binary representation of an integer between 0 and 15,
|
|
1984
|
+
inclusive::
|
|
1985
|
+
|
|
1986
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
1987
|
+
sage: maes = MiniAES()
|
|
1988
|
+
sage: maes.integer_to_binary(3)
|
|
1989
|
+
0011
|
|
1990
|
+
sage: maes.integer_to_binary(5)
|
|
1991
|
+
0101
|
|
1992
|
+
sage: maes.integer_to_binary(7)
|
|
1993
|
+
0111
|
|
1994
|
+
|
|
1995
|
+
TESTS:
|
|
1996
|
+
|
|
1997
|
+
The input ``N`` can be an integer, but must be bounded such that
|
|
1998
|
+
`0 \leq N \leq 15`::
|
|
1999
|
+
|
|
2000
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
2001
|
+
sage: maes = MiniAES()
|
|
2002
|
+
sage: maes.integer_to_binary(-1)
|
|
2003
|
+
Traceback (most recent call last):
|
|
2004
|
+
...
|
|
2005
|
+
KeyError:...
|
|
2006
|
+
sage: maes.integer_to_binary("1")
|
|
2007
|
+
Traceback (most recent call last):
|
|
2008
|
+
...
|
|
2009
|
+
TypeError: N must be an integer 0 <= N <= 15 or a list of such integers
|
|
2010
|
+
sage: maes.integer_to_binary("")
|
|
2011
|
+
Traceback (most recent call last):
|
|
2012
|
+
...
|
|
2013
|
+
TypeError: N must be an integer 0 <= N <= 15 or a list of such integers
|
|
2014
|
+
|
|
2015
|
+
The input ``N`` can be a list of integers, but each integer `n` of
|
|
2016
|
+
the list must be `0 \leq n \leq 15`::
|
|
2017
|
+
|
|
2018
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
2019
|
+
sage: maes = MiniAES()
|
|
2020
|
+
sage: maes.integer_to_binary([])
|
|
2021
|
+
Traceback (most recent call last):
|
|
2022
|
+
...
|
|
2023
|
+
ValueError: N must be an integer 0 <= N <= 15 or a list of such integers
|
|
2024
|
+
sage: maes.integer_to_binary([""])
|
|
2025
|
+
Traceback (most recent call last):
|
|
2026
|
+
...
|
|
2027
|
+
KeyError:...
|
|
2028
|
+
sage: maes.integer_to_binary([0, 1, 2, 16])
|
|
2029
|
+
Traceback (most recent call last):
|
|
2030
|
+
...
|
|
2031
|
+
KeyError:...
|
|
2032
|
+
"""
|
|
2033
|
+
if isinstance(N, list):
|
|
2034
|
+
if len(N) == 0:
|
|
2035
|
+
raise ValueError("N must be an integer 0 <= N <= 15 or a list of such integers")
|
|
2036
|
+
bin = BinaryStrings()
|
|
2037
|
+
# Here, we assume that each element of the list is an integer n
|
|
2038
|
+
# such that 0 <= n <= 15. An error will be raised if otherwise.
|
|
2039
|
+
b = "".join(str(self._int_to_bin[n]) for n in N)
|
|
2040
|
+
return bin(b)
|
|
2041
|
+
elif isinstance(N, Integer):
|
|
2042
|
+
# Here, we assume that N is an integer such that 0 <= n <= 15.
|
|
2043
|
+
# An error will be raised if otherwise.
|
|
2044
|
+
return self._int_to_bin[N]
|
|
2045
|
+
else:
|
|
2046
|
+
raise TypeError("N must be an integer 0 <= N <= 15 or a list of such integers")
|
|
2047
|
+
|
|
2048
|
+
def integer_to_GF(self, N):
|
|
2049
|
+
r"""
|
|
2050
|
+
Return the finite field representation of ``N``. If `N` is an
|
|
2051
|
+
integer such that `0 \leq N \leq 15`, return the element of
|
|
2052
|
+
`\GF{2^4}` that represents ``N``. If ``N`` is a list of integers
|
|
2053
|
+
each of which is `\geq 0` and `\leq 15`, then obtain the element
|
|
2054
|
+
of `\GF{2^4}` that represents each such integer, and return a list
|
|
2055
|
+
of such finite field representations. Each integer between 0 and 15,
|
|
2056
|
+
inclusive, can be associated with a unique element of `\GF{2^4}`
|
|
2057
|
+
according to the following table:
|
|
2058
|
+
|
|
2059
|
+
.. MATH::
|
|
2060
|
+
|
|
2061
|
+
\begin{tabular}{ll|ll} \hline
|
|
2062
|
+
integer & $\GF{2^4}$ & integer & $\GF{2^4}$ \\\hline
|
|
2063
|
+
0 & $0$ & 8 & $x^3$ \\
|
|
2064
|
+
1 & $1$ & 9 & $x^3 + 1$ \\
|
|
2065
|
+
2 & $x$ & 10 & $x^3 + x$ \\
|
|
2066
|
+
3 & $x + 1$ & 11 & $x^3 + x + 1$ \\
|
|
2067
|
+
4 & $x^2$ & 12 & $x^3 + x^2$ \\
|
|
2068
|
+
5 & $x^2 + 1$ & 13 & $x^3 + x^2 + 1$ \\
|
|
2069
|
+
6 & $x^2 + x$ & 14 & $x^3 + x^2 + x$ \\
|
|
2070
|
+
7 & $x^2 + x + 1$ & 15 & $x^3 + x^2 + x+ 1$ \\\hline
|
|
2071
|
+
\end{tabular}
|
|
2072
|
+
|
|
2073
|
+
INPUT:
|
|
2074
|
+
|
|
2075
|
+
- ``N`` -- nonnegative integer less than or equal to 15, or a list
|
|
2076
|
+
of such integers
|
|
2077
|
+
|
|
2078
|
+
OUTPUT: elements of the finite field `\GF{2^4}`
|
|
2079
|
+
|
|
2080
|
+
EXAMPLES:
|
|
2081
|
+
|
|
2082
|
+
Obtain the element of `\GF{2^4}` representing an integer `n`, where
|
|
2083
|
+
`0 \leq n \leq 15`::
|
|
2084
|
+
|
|
2085
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
2086
|
+
sage: maes = MiniAES()
|
|
2087
|
+
sage: maes.integer_to_GF(0)
|
|
2088
|
+
0
|
|
2089
|
+
sage: maes.integer_to_GF(2)
|
|
2090
|
+
x
|
|
2091
|
+
sage: maes.integer_to_GF(7)
|
|
2092
|
+
x^2 + x + 1
|
|
2093
|
+
|
|
2094
|
+
Obtain the finite field elements corresponding to all nonnegative
|
|
2095
|
+
integers less than or equal to 15::
|
|
2096
|
+
|
|
2097
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
2098
|
+
sage: maes = MiniAES()
|
|
2099
|
+
sage: lst = [n for n in range(16)]; lst
|
|
2100
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
2101
|
+
sage: maes.integer_to_GF(lst)
|
|
2102
|
+
<BLANKLINE>
|
|
2103
|
+
[0,
|
|
2104
|
+
1,
|
|
2105
|
+
x,
|
|
2106
|
+
x + 1,
|
|
2107
|
+
x^2,
|
|
2108
|
+
x^2 + 1,
|
|
2109
|
+
x^2 + x,
|
|
2110
|
+
x^2 + x + 1,
|
|
2111
|
+
x^3,
|
|
2112
|
+
x^3 + 1,
|
|
2113
|
+
x^3 + x,
|
|
2114
|
+
x^3 + x + 1,
|
|
2115
|
+
x^3 + x^2,
|
|
2116
|
+
x^3 + x^2 + 1,
|
|
2117
|
+
x^3 + x^2 + x,
|
|
2118
|
+
x^3 + x^2 + x + 1]
|
|
2119
|
+
|
|
2120
|
+
TESTS:
|
|
2121
|
+
|
|
2122
|
+
The input ``N`` can be an integer, but it must be such that
|
|
2123
|
+
`0 \leq N \leq 15`::
|
|
2124
|
+
|
|
2125
|
+
sage: from sage.crypto.block_cipher.miniaes import MiniAES
|
|
2126
|
+
sage: maes = MiniAES()
|
|
2127
|
+
sage: maes.integer_to_GF(-1)
|
|
2128
|
+
Traceback (most recent call last):
|
|
2129
|
+
...
|
|
2130
|
+
KeyError:...
|
|
2131
|
+
sage: maes.integer_to_GF(16)
|
|
2132
|
+
Traceback (most recent call last):
|
|
2133
|
+
...
|
|
2134
|
+
KeyError:...
|
|
2135
|
+
sage: maes.integer_to_GF("2")
|
|
2136
|
+
Traceback (most recent call last):
|
|
2137
|
+
...
|
|
2138
|
+
TypeError: N must be an integer 0 <= N <= 15 or a list of such integers
|
|
2139
|
+
|
|
2140
|
+
The input ``N`` can be a list of integers, but each integer `n` in
|
|
2141
|
+
the list must be bounded such that `0 \leq n \leq 15`::
|
|
2142
|
+
|
|
2143
|
+
sage: maes.integer_to_GF([])
|
|
2144
|
+
Traceback (most recent call last):
|
|
2145
|
+
...
|
|
2146
|
+
ValueError: N must be an integer 0 <= N <= 15 or a list of such integers
|
|
2147
|
+
sage: maes.integer_to_GF([""])
|
|
2148
|
+
Traceback (most recent call last):
|
|
2149
|
+
...
|
|
2150
|
+
KeyError:...
|
|
2151
|
+
sage: maes.integer_to_GF([0, 2, 3, "4"])
|
|
2152
|
+
Traceback (most recent call last):
|
|
2153
|
+
...
|
|
2154
|
+
KeyError:...
|
|
2155
|
+
sage: maes.integer_to_GF([0, 2, 3, 16])
|
|
2156
|
+
Traceback (most recent call last):
|
|
2157
|
+
...
|
|
2158
|
+
KeyError:...
|
|
2159
|
+
"""
|
|
2160
|
+
if isinstance(N, list):
|
|
2161
|
+
if len(N) == 0:
|
|
2162
|
+
raise ValueError("N must be an integer 0 <= N <= 15 or a list of such integers")
|
|
2163
|
+
# Here, we assume that each element of the list is an integer n
|
|
2164
|
+
# such that 0 <= n <= 15. An error will be raised if otherwise.
|
|
2165
|
+
return [self._int_to_GF[n] for n in N]
|
|
2166
|
+
elif isinstance(N, Integer):
|
|
2167
|
+
# Here, we assume that N is an integer such that 0 <= n <= 15.
|
|
2168
|
+
# An error will be raised if otherwise.
|
|
2169
|
+
return self._int_to_GF[N]
|
|
2170
|
+
else:
|
|
2171
|
+
raise TypeError("N must be an integer 0 <= N <= 15 or a list of such integers")
|