ZhengyangZhang commited on
Commit
3a285fa
·
verified ·
1 Parent(s): 0569dd9

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.12/site-packages/sympy/codegen/__pycache__/__init__.cpython-312.pyc +0 -0
  2. lib/python3.12/site-packages/sympy/codegen/__pycache__/cnodes.cpython-312.pyc +0 -0
  3. lib/python3.12/site-packages/sympy/codegen/__pycache__/numpy_nodes.cpython-312.pyc +0 -0
  4. lib/python3.12/site-packages/sympy/codegen/__pycache__/scipy_nodes.cpython-312.pyc +0 -0
  5. lib/python3.12/site-packages/sympy/crypto/__init__.py +35 -0
  6. lib/python3.12/site-packages/sympy/crypto/__pycache__/__init__.cpython-312.pyc +0 -0
  7. lib/python3.12/site-packages/sympy/crypto/crypto.py +3367 -0
  8. lib/python3.12/site-packages/sympy/crypto/tests/__init__.py +0 -0
  9. lib/python3.12/site-packages/sympy/crypto/tests/__pycache__/__init__.cpython-312.pyc +0 -0
  10. lib/python3.12/site-packages/sympy/crypto/tests/__pycache__/test_crypto.cpython-312.pyc +0 -0
  11. lib/python3.12/site-packages/sympy/crypto/tests/test_crypto.py +562 -0
  12. lib/python3.12/site-packages/sympy/external/__init__.py +20 -0
  13. lib/python3.12/site-packages/sympy/external/__pycache__/__init__.cpython-312.pyc +0 -0
  14. lib/python3.12/site-packages/sympy/external/__pycache__/gmpy.cpython-312.pyc +0 -0
  15. lib/python3.12/site-packages/sympy/external/__pycache__/importtools.cpython-312.pyc +0 -0
  16. lib/python3.12/site-packages/sympy/external/__pycache__/ntheory.cpython-312.pyc +0 -0
  17. lib/python3.12/site-packages/sympy/external/__pycache__/pythonmpq.cpython-312.pyc +0 -0
  18. lib/python3.12/site-packages/sympy/external/gmpy.py +341 -0
  19. lib/python3.12/site-packages/sympy/external/importtools.py +187 -0
  20. lib/python3.12/site-packages/sympy/external/ntheory.py +637 -0
  21. lib/python3.12/site-packages/sympy/external/pythonmpq.py +341 -0
  22. lib/python3.12/site-packages/sympy/external/tests/__init__.py +0 -0
  23. lib/python3.12/site-packages/sympy/external/tests/__pycache__/__init__.cpython-312.pyc +0 -0
  24. lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_autowrap.cpython-312.pyc +0 -0
  25. lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_codegen.cpython-312.pyc +0 -0
  26. lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_gmpy.cpython-312.pyc +0 -0
  27. lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_importtools.cpython-312.pyc +0 -0
  28. lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_ntheory.cpython-312.pyc +0 -0
  29. lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_numpy.cpython-312.pyc +0 -0
  30. lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_pythonmpq.cpython-312.pyc +0 -0
  31. lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_scipy.cpython-312.pyc +0 -0
  32. lib/python3.12/site-packages/sympy/external/tests/test_autowrap.py +313 -0
  33. lib/python3.12/site-packages/sympy/external/tests/test_codegen.py +379 -0
  34. lib/python3.12/site-packages/sympy/external/tests/test_gmpy.py +12 -0
  35. lib/python3.12/site-packages/sympy/external/tests/test_importtools.py +40 -0
  36. lib/python3.12/site-packages/sympy/external/tests/test_ntheory.py +307 -0
  37. lib/python3.12/site-packages/sympy/external/tests/test_numpy.py +335 -0
  38. lib/python3.12/site-packages/sympy/external/tests/test_pythonmpq.py +176 -0
  39. lib/python3.12/site-packages/sympy/external/tests/test_scipy.py +35 -0
  40. lib/python3.12/site-packages/sympy/integrals/__pycache__/integrals.cpython-312.pyc +0 -0
  41. lib/python3.12/site-packages/sympy/integrals/__pycache__/meijerint_doc.cpython-312.pyc +0 -0
  42. lib/python3.12/site-packages/sympy/integrals/__pycache__/rationaltools.cpython-312.pyc +0 -0
  43. lib/python3.12/site-packages/sympy/integrals/__pycache__/rde.cpython-312.pyc +0 -0
  44. lib/python3.12/site-packages/sympy/integrals/__pycache__/risch.cpython-312.pyc +0 -0
  45. lib/python3.12/site-packages/sympy/integrals/__pycache__/singularityfunctions.cpython-312.pyc +0 -0
  46. lib/python3.12/site-packages/sympy/integrals/benchmarks/__init__.py +0 -0
  47. lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/__init__.cpython-312.pyc +0 -0
  48. lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/bench_integrate.cpython-312.pyc +0 -0
  49. lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/bench_trigintegrate.cpython-312.pyc +0 -0
  50. lib/python3.12/site-packages/sympy/integrals/benchmarks/bench_integrate.py +21 -0
lib/python3.12/site-packages/sympy/codegen/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (1.13 kB). View file
 
lib/python3.12/site-packages/sympy/codegen/__pycache__/cnodes.cpython-312.pyc ADDED
Binary file (5.62 kB). View file
 
lib/python3.12/site-packages/sympy/codegen/__pycache__/numpy_nodes.cpython-312.pyc ADDED
Binary file (5.77 kB). View file
 
lib/python3.12/site-packages/sympy/codegen/__pycache__/scipy_nodes.cpython-312.pyc ADDED
Binary file (4.42 kB). View file
 
lib/python3.12/site-packages/sympy/crypto/__init__.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.crypto.crypto import (cycle_list,
2
+ encipher_shift, encipher_affine, encipher_substitution,
3
+ check_and_join, encipher_vigenere, decipher_vigenere, bifid5_square,
4
+ bifid6_square, encipher_hill, decipher_hill,
5
+ encipher_bifid5, encipher_bifid6, decipher_bifid5,
6
+ decipher_bifid6, encipher_kid_rsa, decipher_kid_rsa,
7
+ kid_rsa_private_key, kid_rsa_public_key, decipher_rsa, rsa_private_key,
8
+ rsa_public_key, encipher_rsa, lfsr_connection_polynomial,
9
+ lfsr_autocorrelation, lfsr_sequence, encode_morse, decode_morse,
10
+ elgamal_private_key, elgamal_public_key, decipher_elgamal,
11
+ encipher_elgamal, dh_private_key, dh_public_key, dh_shared_key,
12
+ padded_key, encipher_bifid, decipher_bifid, bifid_square, bifid5,
13
+ bifid6, bifid10, decipher_gm, encipher_gm, gm_public_key,
14
+ gm_private_key, bg_private_key, bg_public_key, encipher_bg, decipher_bg,
15
+ encipher_rot13, decipher_rot13, encipher_atbash, decipher_atbash,
16
+ encipher_railfence, decipher_railfence)
17
+
18
+ __all__ = [
19
+ 'cycle_list', 'encipher_shift', 'encipher_affine',
20
+ 'encipher_substitution', 'check_and_join', 'encipher_vigenere',
21
+ 'decipher_vigenere', 'bifid5_square', 'bifid6_square', 'encipher_hill',
22
+ 'decipher_hill', 'encipher_bifid5', 'encipher_bifid6', 'decipher_bifid5',
23
+ 'decipher_bifid6', 'encipher_kid_rsa', 'decipher_kid_rsa',
24
+ 'kid_rsa_private_key', 'kid_rsa_public_key', 'decipher_rsa',
25
+ 'rsa_private_key', 'rsa_public_key', 'encipher_rsa',
26
+ 'lfsr_connection_polynomial', 'lfsr_autocorrelation', 'lfsr_sequence',
27
+ 'encode_morse', 'decode_morse', 'elgamal_private_key',
28
+ 'elgamal_public_key', 'decipher_elgamal', 'encipher_elgamal',
29
+ 'dh_private_key', 'dh_public_key', 'dh_shared_key', 'padded_key',
30
+ 'encipher_bifid', 'decipher_bifid', 'bifid_square', 'bifid5', 'bifid6',
31
+ 'bifid10', 'decipher_gm', 'encipher_gm', 'gm_public_key',
32
+ 'gm_private_key', 'bg_private_key', 'bg_public_key', 'encipher_bg',
33
+ 'decipher_bg', 'encipher_rot13', 'decipher_rot13', 'encipher_atbash',
34
+ 'decipher_atbash', 'encipher_railfence', 'decipher_railfence',
35
+ ]
lib/python3.12/site-packages/sympy/crypto/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (1.73 kB). View file
 
lib/python3.12/site-packages/sympy/crypto/crypto.py ADDED
@@ -0,0 +1,3367 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ This file contains some classical ciphers and routines
3
+ implementing a linear-feedback shift register (LFSR)
4
+ and the Diffie-Hellman key exchange.
5
+
6
+ .. warning::
7
+
8
+ This module is intended for educational purposes only. Do not use the
9
+ functions in this module for real cryptographic applications. If you wish
10
+ to encrypt real data, we recommend using something like the `cryptography
11
+ <https://cryptography.io/en/latest/>`_ module.
12
+
13
+ """
14
+
15
+ from string import whitespace, ascii_uppercase as uppercase, printable
16
+ from functools import reduce
17
+ import warnings
18
+
19
+ from itertools import cycle
20
+
21
+ from sympy.external.gmpy import GROUND_TYPES
22
+ from sympy.core import Symbol
23
+ from sympy.core.numbers import Rational
24
+ from sympy.core.random import _randrange, _randint
25
+ from sympy.external.gmpy import gcd, invert
26
+ from sympy.functions.combinatorial.numbers import (totient as _euler,
27
+ reduced_totient as _carmichael)
28
+ from sympy.matrices import Matrix
29
+ from sympy.ntheory import isprime, primitive_root, factorint
30
+ from sympy.ntheory.generate import nextprime
31
+ from sympy.ntheory.modular import crt
32
+ from sympy.polys.domains import FF
33
+ from sympy.polys.polytools import Poly
34
+ from sympy.utilities.misc import as_int, filldedent, translate
35
+ from sympy.utilities.iterables import uniq, multiset
36
+ from sympy.utilities.decorator import doctest_depends_on
37
+
38
+
39
+ if GROUND_TYPES == 'flint':
40
+ __doctest_skip__ = ['lfsr_sequence']
41
+
42
+
43
+ class NonInvertibleCipherWarning(RuntimeWarning):
44
+ """A warning raised if the cipher is not invertible."""
45
+ def __init__(self, msg):
46
+ self.fullMessage = msg
47
+
48
+ def __str__(self):
49
+ return '\n\t' + self.fullMessage
50
+
51
+ def warn(self, stacklevel=3):
52
+ warnings.warn(self, stacklevel=stacklevel)
53
+
54
+
55
+ def AZ(s=None):
56
+ """Return the letters of ``s`` in uppercase. In case more than
57
+ one string is passed, each of them will be processed and a list
58
+ of upper case strings will be returned.
59
+
60
+ Examples
61
+ ========
62
+
63
+ >>> from sympy.crypto.crypto import AZ
64
+ >>> AZ('Hello, world!')
65
+ 'HELLOWORLD'
66
+ >>> AZ('Hello, world!'.split())
67
+ ['HELLO', 'WORLD']
68
+
69
+ See Also
70
+ ========
71
+
72
+ check_and_join
73
+
74
+ """
75
+ if not s:
76
+ return uppercase
77
+ t = isinstance(s, str)
78
+ if t:
79
+ s = [s]
80
+ rv = [check_and_join(i.upper().split(), uppercase, filter=True)
81
+ for i in s]
82
+ if t:
83
+ return rv[0]
84
+ return rv
85
+
86
+ bifid5 = AZ().replace('J', '')
87
+ bifid6 = AZ() + '0123456789'
88
+ bifid10 = printable
89
+
90
+
91
+ def padded_key(key, symbols):
92
+ """Return a string of the distinct characters of ``symbols`` with
93
+ those of ``key`` appearing first. A ValueError is raised if
94
+ a) there are duplicate characters in ``symbols`` or
95
+ b) there are characters in ``key`` that are not in ``symbols``.
96
+
97
+ Examples
98
+ ========
99
+
100
+ >>> from sympy.crypto.crypto import padded_key
101
+ >>> padded_key('PUPPY', 'OPQRSTUVWXY')
102
+ 'PUYOQRSTVWX'
103
+ >>> padded_key('RSA', 'ARTIST')
104
+ Traceback (most recent call last):
105
+ ...
106
+ ValueError: duplicate characters in symbols: T
107
+
108
+ """
109
+ syms = list(uniq(symbols))
110
+ if len(syms) != len(symbols):
111
+ extra = ''.join(sorted({
112
+ i for i in symbols if symbols.count(i) > 1}))
113
+ raise ValueError('duplicate characters in symbols: %s' % extra)
114
+ extra = set(key) - set(syms)
115
+ if extra:
116
+ raise ValueError(
117
+ 'characters in key but not symbols: %s' % ''.join(
118
+ sorted(extra)))
119
+ key0 = ''.join(list(uniq(key)))
120
+ # remove from syms characters in key0
121
+ return key0 + translate(''.join(syms), None, key0)
122
+
123
+
124
+ def check_and_join(phrase, symbols=None, filter=None):
125
+ """
126
+ Joins characters of ``phrase`` and if ``symbols`` is given, raises
127
+ an error if any character in ``phrase`` is not in ``symbols``.
128
+
129
+ Parameters
130
+ ==========
131
+
132
+ phrase
133
+ String or list of strings to be returned as a string.
134
+
135
+ symbols
136
+ Iterable of characters allowed in ``phrase``.
137
+
138
+ If ``symbols`` is ``None``, no checking is performed.
139
+
140
+ Examples
141
+ ========
142
+
143
+ >>> from sympy.crypto.crypto import check_and_join
144
+ >>> check_and_join('a phrase')
145
+ 'a phrase'
146
+ >>> check_and_join('a phrase'.upper().split())
147
+ 'APHRASE'
148
+ >>> check_and_join('a phrase!'.upper().split(), 'ARE', filter=True)
149
+ 'ARAE'
150
+ >>> check_and_join('a phrase!'.upper().split(), 'ARE')
151
+ Traceback (most recent call last):
152
+ ...
153
+ ValueError: characters in phrase but not symbols: "!HPS"
154
+
155
+ """
156
+ rv = ''.join(''.join(phrase))
157
+ if symbols is not None:
158
+ symbols = check_and_join(symbols)
159
+ missing = ''.join(sorted(set(rv) - set(symbols)))
160
+ if missing:
161
+ if not filter:
162
+ raise ValueError(
163
+ 'characters in phrase but not symbols: "%s"' % missing)
164
+ rv = translate(rv, None, missing)
165
+ return rv
166
+
167
+
168
+ def _prep(msg, key, alp, default=None):
169
+ if not alp:
170
+ if not default:
171
+ alp = AZ()
172
+ msg = AZ(msg)
173
+ key = AZ(key)
174
+ else:
175
+ alp = default
176
+ else:
177
+ alp = ''.join(alp)
178
+ key = check_and_join(key, alp, filter=True)
179
+ msg = check_and_join(msg, alp, filter=True)
180
+ return msg, key, alp
181
+
182
+
183
+ def cycle_list(k, n):
184
+ """
185
+ Returns the elements of the list ``range(n)`` shifted to the
186
+ left by ``k`` (so the list starts with ``k`` (mod ``n``)).
187
+
188
+ Examples
189
+ ========
190
+
191
+ >>> from sympy.crypto.crypto import cycle_list
192
+ >>> cycle_list(3, 10)
193
+ [3, 4, 5, 6, 7, 8, 9, 0, 1, 2]
194
+
195
+ """
196
+ k = k % n
197
+ return list(range(k, n)) + list(range(k))
198
+
199
+
200
+ ######## shift cipher examples ############
201
+
202
+
203
+ def encipher_shift(msg, key, symbols=None):
204
+ """
205
+ Performs shift cipher encryption on plaintext msg, and returns the
206
+ ciphertext.
207
+
208
+ Parameters
209
+ ==========
210
+
211
+ key : int
212
+ The secret key.
213
+
214
+ msg : str
215
+ Plaintext of upper-case letters.
216
+
217
+ Returns
218
+ =======
219
+
220
+ str
221
+ Ciphertext of upper-case letters.
222
+
223
+ Examples
224
+ ========
225
+
226
+ >>> from sympy.crypto.crypto import encipher_shift, decipher_shift
227
+ >>> msg = "GONAVYBEATARMY"
228
+ >>> ct = encipher_shift(msg, 1); ct
229
+ 'HPOBWZCFBUBSNZ'
230
+
231
+ To decipher the shifted text, change the sign of the key:
232
+
233
+ >>> encipher_shift(ct, -1)
234
+ 'GONAVYBEATARMY'
235
+
236
+ There is also a convenience function that does this with the
237
+ original key:
238
+
239
+ >>> decipher_shift(ct, 1)
240
+ 'GONAVYBEATARMY'
241
+
242
+ Notes
243
+ =====
244
+
245
+ ALGORITHM:
246
+
247
+ STEPS:
248
+ 0. Number the letters of the alphabet from 0, ..., N
249
+ 1. Compute from the string ``msg`` a list ``L1`` of
250
+ corresponding integers.
251
+ 2. Compute from the list ``L1`` a new list ``L2``, given by
252
+ adding ``(k mod 26)`` to each element in ``L1``.
253
+ 3. Compute from the list ``L2`` a string ``ct`` of
254
+ corresponding letters.
255
+
256
+ The shift cipher is also called the Caesar cipher, after
257
+ Julius Caesar, who, according to Suetonius, used it with a
258
+ shift of three to protect messages of military significance.
259
+ Caesar's nephew Augustus reportedly used a similar cipher, but
260
+ with a right shift of 1.
261
+
262
+ References
263
+ ==========
264
+
265
+ .. [1] https://en.wikipedia.org/wiki/Caesar_cipher
266
+ .. [2] https://mathworld.wolfram.com/CaesarsMethod.html
267
+
268
+ See Also
269
+ ========
270
+
271
+ decipher_shift
272
+
273
+ """
274
+ msg, _, A = _prep(msg, '', symbols)
275
+ shift = len(A) - key % len(A)
276
+ key = A[shift:] + A[:shift]
277
+ return translate(msg, key, A)
278
+
279
+
280
+ def decipher_shift(msg, key, symbols=None):
281
+ """
282
+ Return the text by shifting the characters of ``msg`` to the
283
+ left by the amount given by ``key``.
284
+
285
+ Examples
286
+ ========
287
+
288
+ >>> from sympy.crypto.crypto import encipher_shift, decipher_shift
289
+ >>> msg = "GONAVYBEATARMY"
290
+ >>> ct = encipher_shift(msg, 1); ct
291
+ 'HPOBWZCFBUBSNZ'
292
+
293
+ To decipher the shifted text, change the sign of the key:
294
+
295
+ >>> encipher_shift(ct, -1)
296
+ 'GONAVYBEATARMY'
297
+
298
+ Or use this function with the original key:
299
+
300
+ >>> decipher_shift(ct, 1)
301
+ 'GONAVYBEATARMY'
302
+
303
+ """
304
+ return encipher_shift(msg, -key, symbols)
305
+
306
+ def encipher_rot13(msg, symbols=None):
307
+ """
308
+ Performs the ROT13 encryption on a given plaintext ``msg``.
309
+
310
+ Explanation
311
+ ===========
312
+
313
+ ROT13 is a substitution cipher which substitutes each letter
314
+ in the plaintext message for the letter furthest away from it
315
+ in the English alphabet.
316
+
317
+ Equivalently, it is just a Caeser (shift) cipher with a shift
318
+ key of 13 (midway point of the alphabet).
319
+
320
+ References
321
+ ==========
322
+
323
+ .. [1] https://en.wikipedia.org/wiki/ROT13
324
+
325
+ See Also
326
+ ========
327
+
328
+ decipher_rot13
329
+ encipher_shift
330
+
331
+ """
332
+ return encipher_shift(msg, 13, symbols)
333
+
334
+ def decipher_rot13(msg, symbols=None):
335
+ """
336
+ Performs the ROT13 decryption on a given plaintext ``msg``.
337
+
338
+ Explanation
339
+ ============
340
+
341
+ ``decipher_rot13`` is equivalent to ``encipher_rot13`` as both
342
+ ``decipher_shift`` with a key of 13 and ``encipher_shift`` key with a
343
+ key of 13 will return the same results. Nonetheless,
344
+ ``decipher_rot13`` has nonetheless been explicitly defined here for
345
+ consistency.
346
+
347
+ Examples
348
+ ========
349
+
350
+ >>> from sympy.crypto.crypto import encipher_rot13, decipher_rot13
351
+ >>> msg = 'GONAVYBEATARMY'
352
+ >>> ciphertext = encipher_rot13(msg);ciphertext
353
+ 'TBANILORNGNEZL'
354
+ >>> decipher_rot13(ciphertext)
355
+ 'GONAVYBEATARMY'
356
+ >>> encipher_rot13(msg) == decipher_rot13(msg)
357
+ True
358
+ >>> msg == decipher_rot13(ciphertext)
359
+ True
360
+
361
+ """
362
+ return decipher_shift(msg, 13, symbols)
363
+
364
+ ######## affine cipher examples ############
365
+
366
+
367
+ def encipher_affine(msg, key, symbols=None, _inverse=False):
368
+ r"""
369
+ Performs the affine cipher encryption on plaintext ``msg``, and
370
+ returns the ciphertext.
371
+
372
+ Explanation
373
+ ===========
374
+
375
+ Encryption is based on the map `x \rightarrow ax+b` (mod `N`)
376
+ where ``N`` is the number of characters in the alphabet.
377
+ Decryption is based on the map `x \rightarrow cx+d` (mod `N`),
378
+ where `c = a^{-1}` (mod `N`) and `d = -a^{-1}b` (mod `N`).
379
+ In particular, for the map to be invertible, we need
380
+ `\mathrm{gcd}(a, N) = 1` and an error will be raised if this is
381
+ not true.
382
+
383
+ Parameters
384
+ ==========
385
+
386
+ msg : str
387
+ Characters that appear in ``symbols``.
388
+
389
+ a, b : int, int
390
+ A pair integers, with ``gcd(a, N) = 1`` (the secret key).
391
+
392
+ symbols
393
+ String of characters (default = uppercase letters).
394
+
395
+ When no symbols are given, ``msg`` is converted to upper case
396
+ letters and all other characters are ignored.
397
+
398
+ Returns
399
+ =======
400
+
401
+ ct
402
+ String of characters (the ciphertext message)
403
+
404
+ Notes
405
+ =====
406
+
407
+ ALGORITHM:
408
+
409
+ STEPS:
410
+ 0. Number the letters of the alphabet from 0, ..., N
411
+ 1. Compute from the string ``msg`` a list ``L1`` of
412
+ corresponding integers.
413
+ 2. Compute from the list ``L1`` a new list ``L2``, given by
414
+ replacing ``x`` by ``a*x + b (mod N)``, for each element
415
+ ``x`` in ``L1``.
416
+ 3. Compute from the list ``L2`` a string ``ct`` of
417
+ corresponding letters.
418
+
419
+ This is a straightforward generalization of the shift cipher with
420
+ the added complexity of requiring 2 characters to be deciphered in
421
+ order to recover the key.
422
+
423
+ References
424
+ ==========
425
+
426
+ .. [1] https://en.wikipedia.org/wiki/Affine_cipher
427
+
428
+ See Also
429
+ ========
430
+
431
+ decipher_affine
432
+
433
+ """
434
+ msg, _, A = _prep(msg, '', symbols)
435
+ N = len(A)
436
+ a, b = key
437
+ assert gcd(a, N) == 1
438
+ if _inverse:
439
+ c = invert(a, N)
440
+ d = -b*c
441
+ a, b = c, d
442
+ B = ''.join([A[(a*i + b) % N] for i in range(N)])
443
+ return translate(msg, A, B)
444
+
445
+
446
+ def decipher_affine(msg, key, symbols=None):
447
+ r"""
448
+ Return the deciphered text that was made from the mapping,
449
+ `x \rightarrow ax+b` (mod `N`), where ``N`` is the
450
+ number of characters in the alphabet. Deciphering is done by
451
+ reciphering with a new key: `x \rightarrow cx+d` (mod `N`),
452
+ where `c = a^{-1}` (mod `N`) and `d = -a^{-1}b` (mod `N`).
453
+
454
+ Examples
455
+ ========
456
+
457
+ >>> from sympy.crypto.crypto import encipher_affine, decipher_affine
458
+ >>> msg = "GO NAVY BEAT ARMY"
459
+ >>> key = (3, 1)
460
+ >>> encipher_affine(msg, key)
461
+ 'TROBMVENBGBALV'
462
+ >>> decipher_affine(_, key)
463
+ 'GONAVYBEATARMY'
464
+
465
+ See Also
466
+ ========
467
+
468
+ encipher_affine
469
+
470
+ """
471
+ return encipher_affine(msg, key, symbols, _inverse=True)
472
+
473
+
474
+ def encipher_atbash(msg, symbols=None):
475
+ r"""
476
+ Enciphers a given ``msg`` into its Atbash ciphertext and returns it.
477
+
478
+ Explanation
479
+ ===========
480
+
481
+ Atbash is a substitution cipher originally used to encrypt the Hebrew
482
+ alphabet. Atbash works on the principle of mapping each alphabet to its
483
+ reverse / counterpart (i.e. a would map to z, b to y etc.)
484
+
485
+ Atbash is functionally equivalent to the affine cipher with ``a = 25``
486
+ and ``b = 25``
487
+
488
+ See Also
489
+ ========
490
+
491
+ decipher_atbash
492
+
493
+ """
494
+ return encipher_affine(msg, (25, 25), symbols)
495
+
496
+
497
+ def decipher_atbash(msg, symbols=None):
498
+ r"""
499
+ Deciphers a given ``msg`` using Atbash cipher and returns it.
500
+
501
+ Explanation
502
+ ===========
503
+
504
+ ``decipher_atbash`` is functionally equivalent to ``encipher_atbash``.
505
+ However, it has still been added as a separate function to maintain
506
+ consistency.
507
+
508
+ Examples
509
+ ========
510
+
511
+ >>> from sympy.crypto.crypto import encipher_atbash, decipher_atbash
512
+ >>> msg = 'GONAVYBEATARMY'
513
+ >>> encipher_atbash(msg)
514
+ 'TLMZEBYVZGZINB'
515
+ >>> decipher_atbash(msg)
516
+ 'TLMZEBYVZGZINB'
517
+ >>> encipher_atbash(msg) == decipher_atbash(msg)
518
+ True
519
+ >>> msg == encipher_atbash(encipher_atbash(msg))
520
+ True
521
+
522
+ References
523
+ ==========
524
+
525
+ .. [1] https://en.wikipedia.org/wiki/Atbash
526
+
527
+ See Also
528
+ ========
529
+
530
+ encipher_atbash
531
+
532
+ """
533
+ return decipher_affine(msg, (25, 25), symbols)
534
+
535
+ #################### substitution cipher ###########################
536
+
537
+
538
+ def encipher_substitution(msg, old, new=None):
539
+ r"""
540
+ Returns the ciphertext obtained by replacing each character that
541
+ appears in ``old`` with the corresponding character in ``new``.
542
+ If ``old`` is a mapping, then new is ignored and the replacements
543
+ defined by ``old`` are used.
544
+
545
+ Explanation
546
+ ===========
547
+
548
+ This is a more general than the affine cipher in that the key can
549
+ only be recovered by determining the mapping for each symbol.
550
+ Though in practice, once a few symbols are recognized the mappings
551
+ for other characters can be quickly guessed.
552
+
553
+ Examples
554
+ ========
555
+
556
+ >>> from sympy.crypto.crypto import encipher_substitution, AZ
557
+ >>> old = 'OEYAG'
558
+ >>> new = '034^6'
559
+ >>> msg = AZ("go navy! beat army!")
560
+ >>> ct = encipher_substitution(msg, old, new); ct
561
+ '60N^V4B3^T^RM4'
562
+
563
+ To decrypt a substitution, reverse the last two arguments:
564
+
565
+ >>> encipher_substitution(ct, new, old)
566
+ 'GONAVYBEATARMY'
567
+
568
+ In the special case where ``old`` and ``new`` are a permutation of
569
+ order 2 (representing a transposition of characters) their order
570
+ is immaterial:
571
+
572
+ >>> old = 'NAVY'
573
+ >>> new = 'ANYV'
574
+ >>> encipher = lambda x: encipher_substitution(x, old, new)
575
+ >>> encipher('NAVY')
576
+ 'ANYV'
577
+ >>> encipher(_)
578
+ 'NAVY'
579
+
580
+ The substitution cipher, in general, is a method
581
+ whereby "units" (not necessarily single characters) of plaintext
582
+ are replaced with ciphertext according to a regular system.
583
+
584
+ >>> ords = dict(zip('abc', ['\\%i' % ord(i) for i in 'abc']))
585
+ >>> print(encipher_substitution('abc', ords))
586
+ \97\98\99
587
+
588
+ References
589
+ ==========
590
+
591
+ .. [1] https://en.wikipedia.org/wiki/Substitution_cipher
592
+
593
+ """
594
+ return translate(msg, old, new)
595
+
596
+
597
+ ######################################################################
598
+ #################### Vigenere cipher examples ########################
599
+ ######################################################################
600
+
601
+ def encipher_vigenere(msg, key, symbols=None):
602
+ """
603
+ Performs the Vigenere cipher encryption on plaintext ``msg``, and
604
+ returns the ciphertext.
605
+
606
+ Examples
607
+ ========
608
+
609
+ >>> from sympy.crypto.crypto import encipher_vigenere, AZ
610
+ >>> key = "encrypt"
611
+ >>> msg = "meet me on monday"
612
+ >>> encipher_vigenere(msg, key)
613
+ 'QRGKKTHRZQEBPR'
614
+
615
+ Section 1 of the Kryptos sculpture at the CIA headquarters
616
+ uses this cipher and also changes the order of the
617
+ alphabet [2]_. Here is the first line of that section of
618
+ the sculpture:
619
+
620
+ >>> from sympy.crypto.crypto import decipher_vigenere, padded_key
621
+ >>> alp = padded_key('KRYPTOS', AZ())
622
+ >>> key = 'PALIMPSEST'
623
+ >>> msg = 'EMUFPHZLRFAXYUSDJKZLDKRNSHGNFIVJ'
624
+ >>> decipher_vigenere(msg, key, alp)
625
+ 'BETWEENSUBTLESHADINGANDTHEABSENC'
626
+
627
+ Explanation
628
+ ===========
629
+
630
+ The Vigenere cipher is named after Blaise de Vigenere, a sixteenth
631
+ century diplomat and cryptographer, by a historical accident.
632
+ Vigenere actually invented a different and more complicated cipher.
633
+ The so-called *Vigenere cipher* was actually invented
634
+ by Giovan Batista Belaso in 1553.
635
+
636
+ This cipher was used in the 1800's, for example, during the American
637
+ Civil War. The Confederacy used a brass cipher disk to implement the
638
+ Vigenere cipher (now on display in the NSA Museum in Fort
639
+ Meade) [1]_.
640
+
641
+ The Vigenere cipher is a generalization of the shift cipher.
642
+ Whereas the shift cipher shifts each letter by the same amount
643
+ (that amount being the key of the shift cipher) the Vigenere
644
+ cipher shifts a letter by an amount determined by the key (which is
645
+ a word or phrase known only to the sender and receiver).
646
+
647
+ For example, if the key was a single letter, such as "C", then the
648
+ so-called Vigenere cipher is actually a shift cipher with a
649
+ shift of `2` (since "C" is the 2nd letter of the alphabet, if
650
+ you start counting at `0`). If the key was a word with two
651
+ letters, such as "CA", then the so-called Vigenere cipher will
652
+ shift letters in even positions by `2` and letters in odd positions
653
+ are left alone (shifted by `0`, since "A" is the 0th letter, if
654
+ you start counting at `0`).
655
+
656
+
657
+ ALGORITHM:
658
+
659
+ INPUT:
660
+
661
+ ``msg``: string of characters that appear in ``symbols``
662
+ (the plaintext)
663
+
664
+ ``key``: a string of characters that appear in ``symbols``
665
+ (the secret key)
666
+
667
+ ``symbols``: a string of letters defining the alphabet
668
+
669
+
670
+ OUTPUT:
671
+
672
+ ``ct``: string of characters (the ciphertext message)
673
+
674
+ STEPS:
675
+ 0. Number the letters of the alphabet from 0, ..., N
676
+ 1. Compute from the string ``key`` a list ``L1`` of
677
+ corresponding integers. Let ``n1 = len(L1)``.
678
+ 2. Compute from the string ``msg`` a list ``L2`` of
679
+ corresponding integers. Let ``n2 = len(L2)``.
680
+ 3. Break ``L2`` up sequentially into sublists of size
681
+ ``n1``; the last sublist may be smaller than ``n1``
682
+ 4. For each of these sublists ``L`` of ``L2``, compute a
683
+ new list ``C`` given by ``C[i] = L[i] + L1[i] (mod N)``
684
+ to the ``i``-th element in the sublist, for each ``i``.
685
+ 5. Assemble these lists ``C`` by concatenation into a new
686
+ list of length ``n2``.
687
+ 6. Compute from the new list a string ``ct`` of
688
+ corresponding letters.
689
+
690
+ Once it is known that the key is, say, `n` characters long,
691
+ frequency analysis can be applied to every `n`-th letter of
692
+ the ciphertext to determine the plaintext. This method is
693
+ called *Kasiski examination* (although it was first discovered
694
+ by Babbage). If they key is as long as the message and is
695
+ comprised of randomly selected characters -- a one-time pad -- the
696
+ message is theoretically unbreakable.
697
+
698
+ The cipher Vigenere actually discovered is an "auto-key" cipher
699
+ described as follows.
700
+
701
+ ALGORITHM:
702
+
703
+ INPUT:
704
+
705
+ ``key``: a string of letters (the secret key)
706
+
707
+ ``msg``: string of letters (the plaintext message)
708
+
709
+ OUTPUT:
710
+
711
+ ``ct``: string of upper-case letters (the ciphertext message)
712
+
713
+ STEPS:
714
+ 0. Number the letters of the alphabet from 0, ..., N
715
+ 1. Compute from the string ``msg`` a list ``L2`` of
716
+ corresponding integers. Let ``n2 = len(L2)``.
717
+ 2. Let ``n1`` be the length of the key. Append to the
718
+ string ``key`` the first ``n2 - n1`` characters of
719
+ the plaintext message. Compute from this string (also of
720
+ length ``n2``) a list ``L1`` of integers corresponding
721
+ to the letter numbers in the first step.
722
+ 3. Compute a new list ``C`` given by
723
+ ``C[i] = L1[i] + L2[i] (mod N)``.
724
+ 4. Compute from the new list a string ``ct`` of letters
725
+ corresponding to the new integers.
726
+
727
+ To decipher the auto-key ciphertext, the key is used to decipher
728
+ the first ``n1`` characters and then those characters become the
729
+ key to decipher the next ``n1`` characters, etc...:
730
+
731
+ >>> m = AZ('go navy, beat army! yes you can'); m
732
+ 'GONAVYBEATARMYYESYOUCAN'
733
+ >>> key = AZ('gold bug'); n1 = len(key); n2 = len(m)
734
+ >>> auto_key = key + m[:n2 - n1]; auto_key
735
+ 'GOLDBUGGONAVYBEATARMYYE'
736
+ >>> ct = encipher_vigenere(m, auto_key); ct
737
+ 'MCYDWSHKOGAMKZCELYFGAYR'
738
+ >>> n1 = len(key)
739
+ >>> pt = []
740
+ >>> while ct:
741
+ ... part, ct = ct[:n1], ct[n1:]
742
+ ... pt.append(decipher_vigenere(part, key))
743
+ ... key = pt[-1]
744
+ ...
745
+ >>> ''.join(pt) == m
746
+ True
747
+
748
+ References
749
+ ==========
750
+
751
+ .. [1] https://en.wikipedia.org/wiki/Vigenere_cipher
752
+ .. [2] https://web.archive.org/web/20071116100808/https://filebox.vt.edu/users/batman/kryptos.html
753
+ (short URL: https://goo.gl/ijr22d)
754
+
755
+ """
756
+ msg, key, A = _prep(msg, key, symbols)
757
+ map = {c: i for i, c in enumerate(A)}
758
+ key = [map[c] for c in key]
759
+ N = len(map)
760
+ k = len(key)
761
+ rv = []
762
+ for i, m in enumerate(msg):
763
+ rv.append(A[(map[m] + key[i % k]) % N])
764
+ rv = ''.join(rv)
765
+ return rv
766
+
767
+
768
+ def decipher_vigenere(msg, key, symbols=None):
769
+ """
770
+ Decode using the Vigenere cipher.
771
+
772
+ Examples
773
+ ========
774
+
775
+ >>> from sympy.crypto.crypto import decipher_vigenere
776
+ >>> key = "encrypt"
777
+ >>> ct = "QRGK kt HRZQE BPR"
778
+ >>> decipher_vigenere(ct, key)
779
+ 'MEETMEONMONDAY'
780
+
781
+ """
782
+ msg, key, A = _prep(msg, key, symbols)
783
+ map = {c: i for i, c in enumerate(A)}
784
+ N = len(A) # normally, 26
785
+ K = [map[c] for c in key]
786
+ n = len(K)
787
+ C = [map[c] for c in msg]
788
+ rv = ''.join([A[(-K[i % n] + c) % N] for i, c in enumerate(C)])
789
+ return rv
790
+
791
+
792
+ #################### Hill cipher ########################
793
+
794
+
795
+ def encipher_hill(msg, key, symbols=None, pad="Q"):
796
+ r"""
797
+ Return the Hill cipher encryption of ``msg``.
798
+
799
+ Explanation
800
+ ===========
801
+
802
+ The Hill cipher [1]_, invented by Lester S. Hill in the 1920's [2]_,
803
+ was the first polygraphic cipher in which it was practical
804
+ (though barely) to operate on more than three symbols at once.
805
+ The following discussion assumes an elementary knowledge of
806
+ matrices.
807
+
808
+ First, each letter is first encoded as a number starting with 0.
809
+ Suppose your message `msg` consists of `n` capital letters, with no
810
+ spaces. This may be regarded an `n`-tuple M of elements of
811
+ `Z_{26}` (if the letters are those of the English alphabet). A key
812
+ in the Hill cipher is a `k x k` matrix `K`, all of whose entries
813
+ are in `Z_{26}`, such that the matrix `K` is invertible (i.e., the
814
+ linear transformation `K: Z_{N}^k \rightarrow Z_{N}^k`
815
+ is one-to-one).
816
+
817
+
818
+ Parameters
819
+ ==========
820
+
821
+ msg
822
+ Plaintext message of `n` upper-case letters.
823
+
824
+ key
825
+ A `k \times k` invertible matrix `K`, all of whose entries are
826
+ in `Z_{26}` (or whatever number of symbols are being used).
827
+
828
+ pad
829
+ Character (default "Q") to use to make length of text be a
830
+ multiple of ``k``.
831
+
832
+ Returns
833
+ =======
834
+
835
+ ct
836
+ Ciphertext of upper-case letters.
837
+
838
+ Notes
839
+ =====
840
+
841
+ ALGORITHM:
842
+
843
+ STEPS:
844
+ 0. Number the letters of the alphabet from 0, ..., N
845
+ 1. Compute from the string ``msg`` a list ``L`` of
846
+ corresponding integers. Let ``n = len(L)``.
847
+ 2. Break the list ``L`` up into ``t = ceiling(n/k)``
848
+ sublists ``L_1``, ..., ``L_t`` of size ``k`` (with
849
+ the last list "padded" to ensure its size is
850
+ ``k``).
851
+ 3. Compute new list ``C_1``, ..., ``C_t`` given by
852
+ ``C[i] = K*L_i`` (arithmetic is done mod N), for each
853
+ ``i``.
854
+ 4. Concatenate these into a list ``C = C_1 + ... + C_t``.
855
+ 5. Compute from ``C`` a string ``ct`` of corresponding
856
+ letters. This has length ``k*t``.
857
+
858
+ References
859
+ ==========
860
+
861
+ .. [1] https://en.wikipedia.org/wiki/Hill_cipher
862
+ .. [2] Lester S. Hill, Cryptography in an Algebraic Alphabet,
863
+ The American Mathematical Monthly Vol.36, June-July 1929,
864
+ pp.306-312.
865
+
866
+ See Also
867
+ ========
868
+
869
+ decipher_hill
870
+
871
+ """
872
+ assert key.is_square
873
+ assert len(pad) == 1
874
+ msg, pad, A = _prep(msg, pad, symbols)
875
+ map = {c: i for i, c in enumerate(A)}
876
+ P = [map[c] for c in msg]
877
+ N = len(A)
878
+ k = key.cols
879
+ n = len(P)
880
+ m, r = divmod(n, k)
881
+ if r:
882
+ P = P + [map[pad]]*(k - r)
883
+ m += 1
884
+ rv = ''.join([A[c % N] for j in range(m) for c in
885
+ list(key*Matrix(k, 1, [P[i]
886
+ for i in range(k*j, k*(j + 1))]))])
887
+ return rv
888
+
889
+
890
+ def decipher_hill(msg, key, symbols=None):
891
+ """
892
+ Deciphering is the same as enciphering but using the inverse of the
893
+ key matrix.
894
+
895
+ Examples
896
+ ========
897
+
898
+ >>> from sympy.crypto.crypto import encipher_hill, decipher_hill
899
+ >>> from sympy import Matrix
900
+
901
+ >>> key = Matrix([[1, 2], [3, 5]])
902
+ >>> encipher_hill("meet me on monday", key)
903
+ 'UEQDUEODOCTCWQ'
904
+ >>> decipher_hill(_, key)
905
+ 'MEETMEONMONDAY'
906
+
907
+ When the length of the plaintext (stripped of invalid characters)
908
+ is not a multiple of the key dimension, extra characters will
909
+ appear at the end of the enciphered and deciphered text. In order to
910
+ decipher the text, those characters must be included in the text to
911
+ be deciphered. In the following, the key has a dimension of 4 but
912
+ the text is 2 short of being a multiple of 4 so two characters will
913
+ be added.
914
+
915
+ >>> key = Matrix([[1, 1, 1, 2], [0, 1, 1, 0],
916
+ ... [2, 2, 3, 4], [1, 1, 0, 1]])
917
+ >>> msg = "ST"
918
+ >>> encipher_hill(msg, key)
919
+ 'HJEB'
920
+ >>> decipher_hill(_, key)
921
+ 'STQQ'
922
+ >>> encipher_hill(msg, key, pad="Z")
923
+ 'ISPK'
924
+ >>> decipher_hill(_, key)
925
+ 'STZZ'
926
+
927
+ If the last two characters of the ciphertext were ignored in
928
+ either case, the wrong plaintext would be recovered:
929
+
930
+ >>> decipher_hill("HD", key)
931
+ 'ORMV'
932
+ >>> decipher_hill("IS", key)
933
+ 'UIKY'
934
+
935
+ See Also
936
+ ========
937
+
938
+ encipher_hill
939
+
940
+ """
941
+ assert key.is_square
942
+ msg, _, A = _prep(msg, '', symbols)
943
+ map = {c: i for i, c in enumerate(A)}
944
+ C = [map[c] for c in msg]
945
+ N = len(A)
946
+ k = key.cols
947
+ n = len(C)
948
+ m, r = divmod(n, k)
949
+ if r:
950
+ C = C + [0]*(k - r)
951
+ m += 1
952
+ key_inv = key.inv_mod(N)
953
+ rv = ''.join([A[p % N] for j in range(m) for p in
954
+ list(key_inv*Matrix(
955
+ k, 1, [C[i] for i in range(k*j, k*(j + 1))]))])
956
+ return rv
957
+
958
+
959
+ #################### Bifid cipher ########################
960
+
961
+
962
+ def encipher_bifid(msg, key, symbols=None):
963
+ r"""
964
+ Performs the Bifid cipher encryption on plaintext ``msg``, and
965
+ returns the ciphertext.
966
+
967
+ This is the version of the Bifid cipher that uses an `n \times n`
968
+ Polybius square.
969
+
970
+ Parameters
971
+ ==========
972
+
973
+ msg
974
+ Plaintext string.
975
+
976
+ key
977
+ Short string for key.
978
+
979
+ Duplicate characters are ignored and then it is padded with the
980
+ characters in ``symbols`` that were not in the short key.
981
+
982
+ symbols
983
+ `n \times n` characters defining the alphabet.
984
+
985
+ (default is string.printable)
986
+
987
+ Returns
988
+ =======
989
+
990
+ ciphertext
991
+ Ciphertext using Bifid5 cipher without spaces.
992
+
993
+ See Also
994
+ ========
995
+
996
+ decipher_bifid, encipher_bifid5, encipher_bifid6
997
+
998
+ References
999
+ ==========
1000
+
1001
+ .. [1] https://en.wikipedia.org/wiki/Bifid_cipher
1002
+
1003
+ """
1004
+ msg, key, A = _prep(msg, key, symbols, bifid10)
1005
+ long_key = ''.join(uniq(key)) or A
1006
+
1007
+ n = len(A)**.5
1008
+ if n != int(n):
1009
+ raise ValueError(
1010
+ 'Length of alphabet (%s) is not a square number.' % len(A))
1011
+ N = int(n)
1012
+ if len(long_key) < N**2:
1013
+ long_key = list(long_key) + [x for x in A if x not in long_key]
1014
+
1015
+ # the fractionalization
1016
+ row_col = {ch: divmod(i, N) for i, ch in enumerate(long_key)}
1017
+ r, c = zip(*[row_col[x] for x in msg])
1018
+ rc = r + c
1019
+ ch = {i: ch for ch, i in row_col.items()}
1020
+ rv = ''.join(ch[i] for i in zip(rc[::2], rc[1::2]))
1021
+ return rv
1022
+
1023
+
1024
+ def decipher_bifid(msg, key, symbols=None):
1025
+ r"""
1026
+ Performs the Bifid cipher decryption on ciphertext ``msg``, and
1027
+ returns the plaintext.
1028
+
1029
+ This is the version of the Bifid cipher that uses the `n \times n`
1030
+ Polybius square.
1031
+
1032
+ Parameters
1033
+ ==========
1034
+
1035
+ msg
1036
+ Ciphertext string.
1037
+
1038
+ key
1039
+ Short string for key.
1040
+
1041
+ Duplicate characters are ignored and then it is padded with the
1042
+ characters in symbols that were not in the short key.
1043
+
1044
+ symbols
1045
+ `n \times n` characters defining the alphabet.
1046
+
1047
+ (default=string.printable, a `10 \times 10` matrix)
1048
+
1049
+ Returns
1050
+ =======
1051
+
1052
+ deciphered
1053
+ Deciphered text.
1054
+
1055
+ Examples
1056
+ ========
1057
+
1058
+ >>> from sympy.crypto.crypto import (
1059
+ ... encipher_bifid, decipher_bifid, AZ)
1060
+
1061
+ Do an encryption using the bifid5 alphabet:
1062
+
1063
+ >>> alp = AZ().replace('J', '')
1064
+ >>> ct = AZ("meet me on monday!")
1065
+ >>> key = AZ("gold bug")
1066
+ >>> encipher_bifid(ct, key, alp)
1067
+ 'IEILHHFSTSFQYE'
1068
+
1069
+ When entering the text or ciphertext, spaces are ignored so it
1070
+ can be formatted as desired. Re-entering the ciphertext from the
1071
+ preceding, putting 4 characters per line and padding with an extra
1072
+ J, does not cause problems for the deciphering:
1073
+
1074
+ >>> decipher_bifid('''
1075
+ ... IEILH
1076
+ ... HFSTS
1077
+ ... FQYEJ''', key, alp)
1078
+ 'MEETMEONMONDAY'
1079
+
1080
+ When no alphabet is given, all 100 printable characters will be
1081
+ used:
1082
+
1083
+ >>> key = ''
1084
+ >>> encipher_bifid('hello world!', key)
1085
+ 'bmtwmg-bIo*w'
1086
+ >>> decipher_bifid(_, key)
1087
+ 'hello world!'
1088
+
1089
+ If the key is changed, a different encryption is obtained:
1090
+
1091
+ >>> key = 'gold bug'
1092
+ >>> encipher_bifid('hello world!', 'gold_bug')
1093
+ 'hg2sfuei7t}w'
1094
+
1095
+ And if the key used to decrypt the message is not exact, the
1096
+ original text will not be perfectly obtained:
1097
+
1098
+ >>> decipher_bifid(_, 'gold pug')
1099
+ 'heldo~wor6d!'
1100
+
1101
+ """
1102
+ msg, _, A = _prep(msg, '', symbols, bifid10)
1103
+ long_key = ''.join(uniq(key)) or A
1104
+
1105
+ n = len(A)**.5
1106
+ if n != int(n):
1107
+ raise ValueError(
1108
+ 'Length of alphabet (%s) is not a square number.' % len(A))
1109
+ N = int(n)
1110
+ if len(long_key) < N**2:
1111
+ long_key = list(long_key) + [x for x in A if x not in long_key]
1112
+
1113
+ # the reverse fractionalization
1114
+ row_col = {
1115
+ ch: divmod(i, N) for i, ch in enumerate(long_key)}
1116
+ rc = [i for c in msg for i in row_col[c]]
1117
+ n = len(msg)
1118
+ rc = zip(*(rc[:n], rc[n:]))
1119
+ ch = {i: ch for ch, i in row_col.items()}
1120
+ rv = ''.join(ch[i] for i in rc)
1121
+ return rv
1122
+
1123
+
1124
+ def bifid_square(key):
1125
+ """Return characters of ``key`` arranged in a square.
1126
+
1127
+ Examples
1128
+ ========
1129
+
1130
+ >>> from sympy.crypto.crypto import (
1131
+ ... bifid_square, AZ, padded_key, bifid5)
1132
+ >>> bifid_square(AZ().replace('J', ''))
1133
+ Matrix([
1134
+ [A, B, C, D, E],
1135
+ [F, G, H, I, K],
1136
+ [L, M, N, O, P],
1137
+ [Q, R, S, T, U],
1138
+ [V, W, X, Y, Z]])
1139
+
1140
+ >>> bifid_square(padded_key(AZ('gold bug!'), bifid5))
1141
+ Matrix([
1142
+ [G, O, L, D, B],
1143
+ [U, A, C, E, F],
1144
+ [H, I, K, M, N],
1145
+ [P, Q, R, S, T],
1146
+ [V, W, X, Y, Z]])
1147
+
1148
+ See Also
1149
+ ========
1150
+
1151
+ padded_key
1152
+
1153
+ """
1154
+ A = ''.join(uniq(''.join(key)))
1155
+ n = len(A)**.5
1156
+ if n != int(n):
1157
+ raise ValueError(
1158
+ 'Length of alphabet (%s) is not a square number.' % len(A))
1159
+ n = int(n)
1160
+ f = lambda i, j: Symbol(A[n*i + j])
1161
+ rv = Matrix(n, n, f)
1162
+ return rv
1163
+
1164
+
1165
+ def encipher_bifid5(msg, key):
1166
+ r"""
1167
+ Performs the Bifid cipher encryption on plaintext ``msg``, and
1168
+ returns the ciphertext.
1169
+
1170
+ Explanation
1171
+ ===========
1172
+
1173
+ This is the version of the Bifid cipher that uses the `5 \times 5`
1174
+ Polybius square. The letter "J" is ignored so it must be replaced
1175
+ with something else (traditionally an "I") before encryption.
1176
+
1177
+ ALGORITHM: (5x5 case)
1178
+
1179
+ STEPS:
1180
+ 0. Create the `5 \times 5` Polybius square ``S`` associated
1181
+ to ``key`` as follows:
1182
+
1183
+ a) moving from left-to-right, top-to-bottom,
1184
+ place the letters of the key into a `5 \times 5`
1185
+ matrix,
1186
+ b) if the key has less than 25 letters, add the
1187
+ letters of the alphabet not in the key until the
1188
+ `5 \times 5` square is filled.
1189
+
1190
+ 1. Create a list ``P`` of pairs of numbers which are the
1191
+ coordinates in the Polybius square of the letters in
1192
+ ``msg``.
1193
+ 2. Let ``L1`` be the list of all first coordinates of ``P``
1194
+ (length of ``L1 = n``), let ``L2`` be the list of all
1195
+ second coordinates of ``P`` (so the length of ``L2``
1196
+ is also ``n``).
1197
+ 3. Let ``L`` be the concatenation of ``L1`` and ``L2``
1198
+ (length ``L = 2*n``), except that consecutive numbers
1199
+ are paired ``(L[2*i], L[2*i + 1])``. You can regard
1200
+ ``L`` as a list of pairs of length ``n``.
1201
+ 4. Let ``C`` be the list of all letters which are of the
1202
+ form ``S[i, j]``, for all ``(i, j)`` in ``L``. As a
1203
+ string, this is the ciphertext of ``msg``.
1204
+
1205
+ Parameters
1206
+ ==========
1207
+
1208
+ msg : str
1209
+ Plaintext string.
1210
+
1211
+ Converted to upper case and filtered of anything but all letters
1212
+ except J.
1213
+
1214
+ key
1215
+ Short string for key; non-alphabetic letters, J and duplicated
1216
+ characters are ignored and then, if the length is less than 25
1217
+ characters, it is padded with other letters of the alphabet
1218
+ (in alphabetical order).
1219
+
1220
+ Returns
1221
+ =======
1222
+
1223
+ ct
1224
+ Ciphertext (all caps, no spaces).
1225
+
1226
+ Examples
1227
+ ========
1228
+
1229
+ >>> from sympy.crypto.crypto import (
1230
+ ... encipher_bifid5, decipher_bifid5)
1231
+
1232
+ "J" will be omitted unless it is replaced with something else:
1233
+
1234
+ >>> round_trip = lambda m, k: \
1235
+ ... decipher_bifid5(encipher_bifid5(m, k), k)
1236
+ >>> key = 'a'
1237
+ >>> msg = "JOSIE"
1238
+ >>> round_trip(msg, key)
1239
+ 'OSIE'
1240
+ >>> round_trip(msg.replace("J", "I"), key)
1241
+ 'IOSIE'
1242
+ >>> j = "QIQ"
1243
+ >>> round_trip(msg.replace("J", j), key).replace(j, "J")
1244
+ 'JOSIE'
1245
+
1246
+
1247
+ Notes
1248
+ =====
1249
+
1250
+ The Bifid cipher was invented around 1901 by Felix Delastelle.
1251
+ It is a *fractional substitution* cipher, where letters are
1252
+ replaced by pairs of symbols from a smaller alphabet. The
1253
+ cipher uses a `5 \times 5` square filled with some ordering of the
1254
+ alphabet, except that "J" is replaced with "I" (this is a so-called
1255
+ Polybius square; there is a `6 \times 6` analog if you add back in
1256
+ "J" and also append onto the usual 26 letter alphabet, the digits
1257
+ 0, 1, ..., 9).
1258
+ According to Helen Gaines' book *Cryptanalysis*, this type of cipher
1259
+ was used in the field by the German Army during World War I.
1260
+
1261
+ See Also
1262
+ ========
1263
+
1264
+ decipher_bifid5, encipher_bifid
1265
+
1266
+ """
1267
+ msg, key, _ = _prep(msg.upper(), key.upper(), None, bifid5)
1268
+ key = padded_key(key, bifid5)
1269
+ return encipher_bifid(msg, '', key)
1270
+
1271
+
1272
+ def decipher_bifid5(msg, key):
1273
+ r"""
1274
+ Return the Bifid cipher decryption of ``msg``.
1275
+
1276
+ Explanation
1277
+ ===========
1278
+
1279
+ This is the version of the Bifid cipher that uses the `5 \times 5`
1280
+ Polybius square; the letter "J" is ignored unless a ``key`` of
1281
+ length 25 is used.
1282
+
1283
+ Parameters
1284
+ ==========
1285
+
1286
+ msg
1287
+ Ciphertext string.
1288
+
1289
+ key
1290
+ Short string for key; duplicated characters are ignored and if
1291
+ the length is less then 25 characters, it will be padded with
1292
+ other letters from the alphabet omitting "J".
1293
+ Non-alphabetic characters are ignored.
1294
+
1295
+ Returns
1296
+ =======
1297
+
1298
+ plaintext
1299
+ Plaintext from Bifid5 cipher (all caps, no spaces).
1300
+
1301
+ Examples
1302
+ ========
1303
+
1304
+ >>> from sympy.crypto.crypto import encipher_bifid5, decipher_bifid5
1305
+ >>> key = "gold bug"
1306
+ >>> encipher_bifid5('meet me on friday', key)
1307
+ 'IEILEHFSTSFXEE'
1308
+ >>> encipher_bifid5('meet me on monday', key)
1309
+ 'IEILHHFSTSFQYE'
1310
+ >>> decipher_bifid5(_, key)
1311
+ 'MEETMEONMONDAY'
1312
+
1313
+ """
1314
+ msg, key, _ = _prep(msg.upper(), key.upper(), None, bifid5)
1315
+ key = padded_key(key, bifid5)
1316
+ return decipher_bifid(msg, '', key)
1317
+
1318
+
1319
+ def bifid5_square(key=None):
1320
+ r"""
1321
+ 5x5 Polybius square.
1322
+
1323
+ Produce the Polybius square for the `5 \times 5` Bifid cipher.
1324
+
1325
+ Examples
1326
+ ========
1327
+
1328
+ >>> from sympy.crypto.crypto import bifid5_square
1329
+ >>> bifid5_square("gold bug")
1330
+ Matrix([
1331
+ [G, O, L, D, B],
1332
+ [U, A, C, E, F],
1333
+ [H, I, K, M, N],
1334
+ [P, Q, R, S, T],
1335
+ [V, W, X, Y, Z]])
1336
+
1337
+ """
1338
+ if not key:
1339
+ key = bifid5
1340
+ else:
1341
+ _, key, _ = _prep('', key.upper(), None, bifid5)
1342
+ key = padded_key(key, bifid5)
1343
+ return bifid_square(key)
1344
+
1345
+
1346
+ def encipher_bifid6(msg, key):
1347
+ r"""
1348
+ Performs the Bifid cipher encryption on plaintext ``msg``, and
1349
+ returns the ciphertext.
1350
+
1351
+ This is the version of the Bifid cipher that uses the `6 \times 6`
1352
+ Polybius square.
1353
+
1354
+ Parameters
1355
+ ==========
1356
+
1357
+ msg
1358
+ Plaintext string (digits okay).
1359
+
1360
+ key
1361
+ Short string for key (digits okay).
1362
+
1363
+ If ``key`` is less than 36 characters long, the square will be
1364
+ filled with letters A through Z and digits 0 through 9.
1365
+
1366
+ Returns
1367
+ =======
1368
+
1369
+ ciphertext
1370
+ Ciphertext from Bifid cipher (all caps, no spaces).
1371
+
1372
+ See Also
1373
+ ========
1374
+
1375
+ decipher_bifid6, encipher_bifid
1376
+
1377
+ """
1378
+ msg, key, _ = _prep(msg.upper(), key.upper(), None, bifid6)
1379
+ key = padded_key(key, bifid6)
1380
+ return encipher_bifid(msg, '', key)
1381
+
1382
+
1383
+ def decipher_bifid6(msg, key):
1384
+ r"""
1385
+ Performs the Bifid cipher decryption on ciphertext ``msg``, and
1386
+ returns the plaintext.
1387
+
1388
+ This is the version of the Bifid cipher that uses the `6 \times 6`
1389
+ Polybius square.
1390
+
1391
+ Parameters
1392
+ ==========
1393
+
1394
+ msg
1395
+ Ciphertext string (digits okay); converted to upper case
1396
+
1397
+ key
1398
+ Short string for key (digits okay).
1399
+
1400
+ If ``key`` is less than 36 characters long, the square will be
1401
+ filled with letters A through Z and digits 0 through 9.
1402
+ All letters are converted to uppercase.
1403
+
1404
+ Returns
1405
+ =======
1406
+
1407
+ plaintext
1408
+ Plaintext from Bifid cipher (all caps, no spaces).
1409
+
1410
+ Examples
1411
+ ========
1412
+
1413
+ >>> from sympy.crypto.crypto import encipher_bifid6, decipher_bifid6
1414
+ >>> key = "gold bug"
1415
+ >>> encipher_bifid6('meet me on monday at 8am', key)
1416
+ 'KFKLJJHF5MMMKTFRGPL'
1417
+ >>> decipher_bifid6(_, key)
1418
+ 'MEETMEONMONDAYAT8AM'
1419
+
1420
+ """
1421
+ msg, key, _ = _prep(msg.upper(), key.upper(), None, bifid6)
1422
+ key = padded_key(key, bifid6)
1423
+ return decipher_bifid(msg, '', key)
1424
+
1425
+
1426
+ def bifid6_square(key=None):
1427
+ r"""
1428
+ 6x6 Polybius square.
1429
+
1430
+ Produces the Polybius square for the `6 \times 6` Bifid cipher.
1431
+ Assumes alphabet of symbols is "A", ..., "Z", "0", ..., "9".
1432
+
1433
+ Examples
1434
+ ========
1435
+
1436
+ >>> from sympy.crypto.crypto import bifid6_square
1437
+ >>> key = "gold bug"
1438
+ >>> bifid6_square(key)
1439
+ Matrix([
1440
+ [G, O, L, D, B, U],
1441
+ [A, C, E, F, H, I],
1442
+ [J, K, M, N, P, Q],
1443
+ [R, S, T, V, W, X],
1444
+ [Y, Z, 0, 1, 2, 3],
1445
+ [4, 5, 6, 7, 8, 9]])
1446
+
1447
+ """
1448
+ if not key:
1449
+ key = bifid6
1450
+ else:
1451
+ _, key, _ = _prep('', key.upper(), None, bifid6)
1452
+ key = padded_key(key, bifid6)
1453
+ return bifid_square(key)
1454
+
1455
+
1456
+ #################### RSA #############################
1457
+
1458
+ def _decipher_rsa_crt(i, d, factors):
1459
+ """Decipher RSA using chinese remainder theorem from the information
1460
+ of the relatively-prime factors of the modulus.
1461
+
1462
+ Parameters
1463
+ ==========
1464
+
1465
+ i : integer
1466
+ Ciphertext
1467
+
1468
+ d : integer
1469
+ The exponent component.
1470
+
1471
+ factors : list of relatively-prime integers
1472
+ The integers given must be coprime and the product must equal
1473
+ the modulus component of the original RSA key.
1474
+
1475
+ Examples
1476
+ ========
1477
+
1478
+ How to decrypt RSA with CRT:
1479
+
1480
+ >>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key
1481
+ >>> primes = [61, 53]
1482
+ >>> e = 17
1483
+ >>> args = primes + [e]
1484
+ >>> puk = rsa_public_key(*args)
1485
+ >>> prk = rsa_private_key(*args)
1486
+
1487
+ >>> from sympy.crypto.crypto import encipher_rsa, _decipher_rsa_crt
1488
+ >>> msg = 65
1489
+ >>> crt_primes = primes
1490
+ >>> encrypted = encipher_rsa(msg, puk)
1491
+ >>> decrypted = _decipher_rsa_crt(encrypted, prk[1], primes)
1492
+ >>> decrypted
1493
+ 65
1494
+ """
1495
+ moduluses = [pow(i, d, p) for p in factors]
1496
+
1497
+ result = crt(factors, moduluses)
1498
+ if not result:
1499
+ raise ValueError("CRT failed")
1500
+ return result[0]
1501
+
1502
+
1503
+ def _rsa_key(*args, public=True, private=True, totient='Euler', index=None, multipower=None):
1504
+ r"""A private subroutine to generate RSA key
1505
+
1506
+ Parameters
1507
+ ==========
1508
+
1509
+ public, private : bool, optional
1510
+ Flag to generate either a public key, a private key.
1511
+
1512
+ totient : 'Euler' or 'Carmichael'
1513
+ Different notation used for totient.
1514
+
1515
+ multipower : bool, optional
1516
+ Flag to bypass warning for multipower RSA.
1517
+ """
1518
+
1519
+ if len(args) < 2:
1520
+ return False
1521
+
1522
+ if totient not in ('Euler', 'Carmichael'):
1523
+ raise ValueError(
1524
+ "The argument totient={} should either be " \
1525
+ "'Euler', 'Carmichalel'." \
1526
+ .format(totient))
1527
+
1528
+ if totient == 'Euler':
1529
+ _totient = _euler
1530
+ else:
1531
+ _totient = _carmichael
1532
+
1533
+ if index is not None:
1534
+ index = as_int(index)
1535
+ if totient != 'Carmichael':
1536
+ raise ValueError(
1537
+ "Setting the 'index' keyword argument requires totient"
1538
+ "notation to be specified as 'Carmichael'.")
1539
+
1540
+ primes, e = args[:-1], args[-1]
1541
+
1542
+ if not all(isprime(p) for p in primes):
1543
+ new_primes = []
1544
+ for i in primes:
1545
+ new_primes.extend(factorint(i, multiple=True))
1546
+ primes = new_primes
1547
+
1548
+ n = reduce(lambda i, j: i*j, primes)
1549
+
1550
+ tally = multiset(primes)
1551
+ if all(v == 1 for v in tally.values()):
1552
+ phi = int(_totient(tally))
1553
+
1554
+ else:
1555
+ if not multipower:
1556
+ NonInvertibleCipherWarning(
1557
+ 'Non-distinctive primes found in the factors {}. '
1558
+ 'The cipher may not be decryptable for some numbers '
1559
+ 'in the complete residue system Z[{}], but the cipher '
1560
+ 'can still be valid if you restrict the domain to be '
1561
+ 'the reduced residue system Z*[{}]. You can pass '
1562
+ 'the flag multipower=True if you want to suppress this '
1563
+ 'warning.'
1564
+ .format(primes, n, n)
1565
+ # stacklevel=4 because most users will call a function that
1566
+ # calls this function
1567
+ ).warn(stacklevel=4)
1568
+ phi = int(_totient(tally))
1569
+
1570
+ if gcd(e, phi) == 1:
1571
+ if public and not private:
1572
+ if isinstance(index, int):
1573
+ e = e % phi
1574
+ e += index * phi
1575
+ return n, e
1576
+
1577
+ if private and not public:
1578
+ d = invert(e, phi)
1579
+ if isinstance(index, int):
1580
+ d += index * phi
1581
+ return n, d
1582
+
1583
+ return False
1584
+
1585
+
1586
+ def rsa_public_key(*args, **kwargs):
1587
+ r"""Return the RSA *public key* pair, `(n, e)`
1588
+
1589
+ Parameters
1590
+ ==========
1591
+
1592
+ args : naturals
1593
+ If specified as `p, q, e` where `p` and `q` are distinct primes
1594
+ and `e` is a desired public exponent of the RSA, `n = p q` and
1595
+ `e` will be verified against the totient
1596
+ `\phi(n)` (Euler totient) or `\lambda(n)` (Carmichael totient)
1597
+ to be `\gcd(e, \phi(n)) = 1` or `\gcd(e, \lambda(n)) = 1`.
1598
+
1599
+ If specified as `p_1, p_2, \dots, p_n, e` where
1600
+ `p_1, p_2, \dots, p_n` are specified as primes,
1601
+ and `e` is specified as a desired public exponent of the RSA,
1602
+ it will be able to form a multi-prime RSA, which is a more
1603
+ generalized form of the popular 2-prime RSA.
1604
+
1605
+ It can also be possible to form a single-prime RSA by specifying
1606
+ the argument as `p, e`, which can be considered a trivial case
1607
+ of a multiprime RSA.
1608
+
1609
+ Furthermore, it can be possible to form a multi-power RSA by
1610
+ specifying two or more pairs of the primes to be same.
1611
+ However, unlike the two-distinct prime RSA or multi-prime
1612
+ RSA, not every numbers in the complete residue system
1613
+ (`\mathbb{Z}_n`) will be decryptable since the mapping
1614
+ `\mathbb{Z}_{n} \rightarrow \mathbb{Z}_{n}`
1615
+ will not be bijective.
1616
+ (Only except for the trivial case when
1617
+ `e = 1`
1618
+ or more generally,
1619
+
1620
+ .. math::
1621
+ e \in \left \{ 1 + k \lambda(n)
1622
+ \mid k \in \mathbb{Z} \land k \geq 0 \right \}
1623
+
1624
+ when RSA reduces to the identity.)
1625
+ However, the RSA can still be decryptable for the numbers in the
1626
+ reduced residue system (`\mathbb{Z}_n^{\times}`), since the
1627
+ mapping
1628
+ `\mathbb{Z}_{n}^{\times} \rightarrow \mathbb{Z}_{n}^{\times}`
1629
+ can still be bijective.
1630
+
1631
+ If you pass a non-prime integer to the arguments
1632
+ `p_1, p_2, \dots, p_n`, the particular number will be
1633
+ prime-factored and it will become either a multi-prime RSA or a
1634
+ multi-power RSA in its canonical form, depending on whether the
1635
+ product equals its radical or not.
1636
+ `p_1 p_2 \dots p_n = \text{rad}(p_1 p_2 \dots p_n)`
1637
+
1638
+ totient : bool, optional
1639
+ If ``'Euler'``, it uses Euler's totient `\phi(n)` which is
1640
+ :meth:`sympy.functions.combinatorial.numbers.totient` in SymPy.
1641
+
1642
+ If ``'Carmichael'``, it uses Carmichael's totient `\lambda(n)`
1643
+ which is :meth:`sympy.functions.combinatorial.numbers.reduced_totient` in SymPy.
1644
+
1645
+ Unlike private key generation, this is a trivial keyword for
1646
+ public key generation because
1647
+ `\gcd(e, \phi(n)) = 1 \iff \gcd(e, \lambda(n)) = 1`.
1648
+
1649
+ index : nonnegative integer, optional
1650
+ Returns an arbitrary solution of a RSA public key at the index
1651
+ specified at `0, 1, 2, \dots`. This parameter needs to be
1652
+ specified along with ``totient='Carmichael'``.
1653
+
1654
+ Similarly to the non-uniquenss of a RSA private key as described
1655
+ in the ``index`` parameter documentation in
1656
+ :meth:`rsa_private_key`, RSA public key is also not unique and
1657
+ there is an infinite number of RSA public exponents which
1658
+ can behave in the same manner.
1659
+
1660
+ From any given RSA public exponent `e`, there are can be an
1661
+ another RSA public exponent `e + k \lambda(n)` where `k` is an
1662
+ integer, `\lambda` is a Carmichael's totient function.
1663
+
1664
+ However, considering only the positive cases, there can be
1665
+ a principal solution of a RSA public exponent `e_0` in
1666
+ `0 < e_0 < \lambda(n)`, and all the other solutions
1667
+ can be canonicalzed in a form of `e_0 + k \lambda(n)`.
1668
+
1669
+ ``index`` specifies the `k` notation to yield any possible value
1670
+ an RSA public key can have.
1671
+
1672
+ An example of computing any arbitrary RSA public key:
1673
+
1674
+ >>> from sympy.crypto.crypto import rsa_public_key
1675
+ >>> rsa_public_key(61, 53, 17, totient='Carmichael', index=0)
1676
+ (3233, 17)
1677
+ >>> rsa_public_key(61, 53, 17, totient='Carmichael', index=1)
1678
+ (3233, 797)
1679
+ >>> rsa_public_key(61, 53, 17, totient='Carmichael', index=2)
1680
+ (3233, 1577)
1681
+
1682
+ multipower : bool, optional
1683
+ Any pair of non-distinct primes found in the RSA specification
1684
+ will restrict the domain of the cryptosystem, as noted in the
1685
+ explanation of the parameter ``args``.
1686
+
1687
+ SymPy RSA key generator may give a warning before dispatching it
1688
+ as a multi-power RSA, however, you can disable the warning if
1689
+ you pass ``True`` to this keyword.
1690
+
1691
+ Returns
1692
+ =======
1693
+
1694
+ (n, e) : int, int
1695
+ `n` is a product of any arbitrary number of primes given as
1696
+ the argument.
1697
+
1698
+ `e` is relatively prime (coprime) to the Euler totient
1699
+ `\phi(n)`.
1700
+
1701
+ False
1702
+ Returned if less than two arguments are given, or `e` is
1703
+ not relatively prime to the modulus.
1704
+
1705
+ Examples
1706
+ ========
1707
+
1708
+ >>> from sympy.crypto.crypto import rsa_public_key
1709
+
1710
+ A public key of a two-prime RSA:
1711
+
1712
+ >>> p, q, e = 3, 5, 7
1713
+ >>> rsa_public_key(p, q, e)
1714
+ (15, 7)
1715
+ >>> rsa_public_key(p, q, 30)
1716
+ False
1717
+
1718
+ A public key of a multiprime RSA:
1719
+
1720
+ >>> primes = [2, 3, 5, 7, 11, 13]
1721
+ >>> e = 7
1722
+ >>> args = primes + [e]
1723
+ >>> rsa_public_key(*args)
1724
+ (30030, 7)
1725
+
1726
+ Notes
1727
+ =====
1728
+
1729
+ Although the RSA can be generalized over any modulus `n`, using
1730
+ two large primes had became the most popular specification because a
1731
+ product of two large primes is usually the hardest to factor
1732
+ relatively to the digits of `n` can have.
1733
+
1734
+ However, it may need further understanding of the time complexities
1735
+ of each prime-factoring algorithms to verify the claim.
1736
+
1737
+ See Also
1738
+ ========
1739
+
1740
+ rsa_private_key
1741
+ encipher_rsa
1742
+ decipher_rsa
1743
+
1744
+ References
1745
+ ==========
1746
+
1747
+ .. [1] https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29
1748
+
1749
+ .. [2] https://cacr.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
1750
+
1751
+ .. [3] https://link.springer.com/content/pdf/10.1007/BFb0055738.pdf
1752
+
1753
+ .. [4] https://www.itiis.org/digital-library/manuscript/1381
1754
+ """
1755
+ return _rsa_key(*args, public=True, private=False, **kwargs)
1756
+
1757
+
1758
+ def rsa_private_key(*args, **kwargs):
1759
+ r"""Return the RSA *private key* pair, `(n, d)`
1760
+
1761
+ Parameters
1762
+ ==========
1763
+
1764
+ args : naturals
1765
+ The keyword is identical to the ``args`` in
1766
+ :meth:`rsa_public_key`.
1767
+
1768
+ totient : bool, optional
1769
+ If ``'Euler'``, it uses Euler's totient convention `\phi(n)`
1770
+ which is :meth:`sympy.functions.combinatorial.numbers.totient` in SymPy.
1771
+
1772
+ If ``'Carmichael'``, it uses Carmichael's totient convention
1773
+ `\lambda(n)` which is
1774
+ :meth:`sympy.functions.combinatorial.numbers.reduced_totient` in SymPy.
1775
+
1776
+ There can be some output differences for private key generation
1777
+ as examples below.
1778
+
1779
+ Example using Euler's totient:
1780
+
1781
+ >>> from sympy.crypto.crypto import rsa_private_key
1782
+ >>> rsa_private_key(61, 53, 17, totient='Euler')
1783
+ (3233, 2753)
1784
+
1785
+ Example using Carmichael's totient:
1786
+
1787
+ >>> from sympy.crypto.crypto import rsa_private_key
1788
+ >>> rsa_private_key(61, 53, 17, totient='Carmichael')
1789
+ (3233, 413)
1790
+
1791
+ index : nonnegative integer, optional
1792
+ Returns an arbitrary solution of a RSA private key at the index
1793
+ specified at `0, 1, 2, \dots`. This parameter needs to be
1794
+ specified along with ``totient='Carmichael'``.
1795
+
1796
+ RSA private exponent is a non-unique solution of
1797
+ `e d \mod \lambda(n) = 1` and it is possible in any form of
1798
+ `d + k \lambda(n)`, where `d` is an another
1799
+ already-computed private exponent, and `\lambda` is a
1800
+ Carmichael's totient function, and `k` is any integer.
1801
+
1802
+ However, considering only the positive cases, there can be
1803
+ a principal solution of a RSA private exponent `d_0` in
1804
+ `0 < d_0 < \lambda(n)`, and all the other solutions
1805
+ can be canonicalzed in a form of `d_0 + k \lambda(n)`.
1806
+
1807
+ ``index`` specifies the `k` notation to yield any possible value
1808
+ an RSA private key can have.
1809
+
1810
+ An example of computing any arbitrary RSA private key:
1811
+
1812
+ >>> from sympy.crypto.crypto import rsa_private_key
1813
+ >>> rsa_private_key(61, 53, 17, totient='Carmichael', index=0)
1814
+ (3233, 413)
1815
+ >>> rsa_private_key(61, 53, 17, totient='Carmichael', index=1)
1816
+ (3233, 1193)
1817
+ >>> rsa_private_key(61, 53, 17, totient='Carmichael', index=2)
1818
+ (3233, 1973)
1819
+
1820
+ multipower : bool, optional
1821
+ The keyword is identical to the ``multipower`` in
1822
+ :meth:`rsa_public_key`.
1823
+
1824
+ Returns
1825
+ =======
1826
+
1827
+ (n, d) : int, int
1828
+ `n` is a product of any arbitrary number of primes given as
1829
+ the argument.
1830
+
1831
+ `d` is the inverse of `e` (mod `\phi(n)`) where `e` is the
1832
+ exponent given, and `\phi` is a Euler totient.
1833
+
1834
+ False
1835
+ Returned if less than two arguments are given, or `e` is
1836
+ not relatively prime to the totient of the modulus.
1837
+
1838
+ Examples
1839
+ ========
1840
+
1841
+ >>> from sympy.crypto.crypto import rsa_private_key
1842
+
1843
+ A private key of a two-prime RSA:
1844
+
1845
+ >>> p, q, e = 3, 5, 7
1846
+ >>> rsa_private_key(p, q, e)
1847
+ (15, 7)
1848
+ >>> rsa_private_key(p, q, 30)
1849
+ False
1850
+
1851
+ A private key of a multiprime RSA:
1852
+
1853
+ >>> primes = [2, 3, 5, 7, 11, 13]
1854
+ >>> e = 7
1855
+ >>> args = primes + [e]
1856
+ >>> rsa_private_key(*args)
1857
+ (30030, 823)
1858
+
1859
+ See Also
1860
+ ========
1861
+
1862
+ rsa_public_key
1863
+ encipher_rsa
1864
+ decipher_rsa
1865
+
1866
+ References
1867
+ ==========
1868
+
1869
+ .. [1] https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29
1870
+
1871
+ .. [2] https://cacr.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
1872
+
1873
+ .. [3] https://link.springer.com/content/pdf/10.1007/BFb0055738.pdf
1874
+
1875
+ .. [4] https://www.itiis.org/digital-library/manuscript/1381
1876
+ """
1877
+ return _rsa_key(*args, public=False, private=True, **kwargs)
1878
+
1879
+
1880
+ def _encipher_decipher_rsa(i, key, factors=None):
1881
+ n, d = key
1882
+ if not factors:
1883
+ return pow(i, d, n)
1884
+
1885
+ def _is_coprime_set(l):
1886
+ is_coprime_set = True
1887
+ for i in range(len(l)):
1888
+ for j in range(i+1, len(l)):
1889
+ if gcd(l[i], l[j]) != 1:
1890
+ is_coprime_set = False
1891
+ break
1892
+ return is_coprime_set
1893
+
1894
+ prod = reduce(lambda i, j: i*j, factors)
1895
+ if prod == n and _is_coprime_set(factors):
1896
+ return _decipher_rsa_crt(i, d, factors)
1897
+ return _encipher_decipher_rsa(i, key, factors=None)
1898
+
1899
+
1900
+ def encipher_rsa(i, key, factors=None):
1901
+ r"""Encrypt the plaintext with RSA.
1902
+
1903
+ Parameters
1904
+ ==========
1905
+
1906
+ i : integer
1907
+ The plaintext to be encrypted for.
1908
+
1909
+ key : (n, e) where n, e are integers
1910
+ `n` is the modulus of the key and `e` is the exponent of the
1911
+ key. The encryption is computed by `i^e \bmod n`.
1912
+
1913
+ The key can either be a public key or a private key, however,
1914
+ the message encrypted by a public key can only be decrypted by
1915
+ a private key, and vice versa, as RSA is an asymmetric
1916
+ cryptography system.
1917
+
1918
+ factors : list of coprime integers
1919
+ This is identical to the keyword ``factors`` in
1920
+ :meth:`decipher_rsa`.
1921
+
1922
+ Notes
1923
+ =====
1924
+
1925
+ Some specifications may make the RSA not cryptographically
1926
+ meaningful.
1927
+
1928
+ For example, `0`, `1` will remain always same after taking any
1929
+ number of exponentiation, thus, should be avoided.
1930
+
1931
+ Furthermore, if `i^e < n`, `i` may easily be figured out by taking
1932
+ `e` th root.
1933
+
1934
+ And also, specifying the exponent as `1` or in more generalized form
1935
+ as `1 + k \lambda(n)` where `k` is an nonnegative integer,
1936
+ `\lambda` is a carmichael totient, the RSA becomes an identity
1937
+ mapping.
1938
+
1939
+ Examples
1940
+ ========
1941
+
1942
+ >>> from sympy.crypto.crypto import encipher_rsa
1943
+ >>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key
1944
+
1945
+ Public Key Encryption:
1946
+
1947
+ >>> p, q, e = 3, 5, 7
1948
+ >>> puk = rsa_public_key(p, q, e)
1949
+ >>> msg = 12
1950
+ >>> encipher_rsa(msg, puk)
1951
+ 3
1952
+
1953
+ Private Key Encryption:
1954
+
1955
+ >>> p, q, e = 3, 5, 7
1956
+ >>> prk = rsa_private_key(p, q, e)
1957
+ >>> msg = 12
1958
+ >>> encipher_rsa(msg, prk)
1959
+ 3
1960
+
1961
+ Encryption using chinese remainder theorem:
1962
+
1963
+ >>> encipher_rsa(msg, prk, factors=[p, q])
1964
+ 3
1965
+ """
1966
+ return _encipher_decipher_rsa(i, key, factors=factors)
1967
+
1968
+
1969
+ def decipher_rsa(i, key, factors=None):
1970
+ r"""Decrypt the ciphertext with RSA.
1971
+
1972
+ Parameters
1973
+ ==========
1974
+
1975
+ i : integer
1976
+ The ciphertext to be decrypted for.
1977
+
1978
+ key : (n, d) where n, d are integers
1979
+ `n` is the modulus of the key and `d` is the exponent of the
1980
+ key. The decryption is computed by `i^d \bmod n`.
1981
+
1982
+ The key can either be a public key or a private key, however,
1983
+ the message encrypted by a public key can only be decrypted by
1984
+ a private key, and vice versa, as RSA is an asymmetric
1985
+ cryptography system.
1986
+
1987
+ factors : list of coprime integers
1988
+ As the modulus `n` created from RSA key generation is composed
1989
+ of arbitrary prime factors
1990
+ `n = {p_1}^{k_1}{p_2}^{k_2}\dots{p_n}^{k_n}` where
1991
+ `p_1, p_2, \dots, p_n` are distinct primes and
1992
+ `k_1, k_2, \dots, k_n` are positive integers, chinese remainder
1993
+ theorem can be used to compute `i^d \bmod n` from the
1994
+ fragmented modulo operations like
1995
+
1996
+ .. math::
1997
+ i^d \bmod {p_1}^{k_1}, i^d \bmod {p_2}^{k_2}, \dots,
1998
+ i^d \bmod {p_n}^{k_n}
1999
+
2000
+ or like
2001
+
2002
+ .. math::
2003
+ i^d \bmod {p_1}^{k_1}{p_2}^{k_2},
2004
+ i^d \bmod {p_3}^{k_3}, \dots ,
2005
+ i^d \bmod {p_n}^{k_n}
2006
+
2007
+ as long as every moduli does not share any common divisor each
2008
+ other.
2009
+
2010
+ The raw primes used in generating the RSA key pair can be a good
2011
+ option.
2012
+
2013
+ Note that the speed advantage of using this is only viable for
2014
+ very large cases (Like 2048-bit RSA keys) since the
2015
+ overhead of using pure Python implementation of
2016
+ :meth:`sympy.ntheory.modular.crt` may overcompensate the
2017
+ theoretical speed advantage.
2018
+
2019
+ Notes
2020
+ =====
2021
+
2022
+ See the ``Notes`` section in the documentation of
2023
+ :meth:`encipher_rsa`
2024
+
2025
+ Examples
2026
+ ========
2027
+
2028
+ >>> from sympy.crypto.crypto import decipher_rsa, encipher_rsa
2029
+ >>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key
2030
+
2031
+ Public Key Encryption and Decryption:
2032
+
2033
+ >>> p, q, e = 3, 5, 7
2034
+ >>> prk = rsa_private_key(p, q, e)
2035
+ >>> puk = rsa_public_key(p, q, e)
2036
+ >>> msg = 12
2037
+ >>> new_msg = encipher_rsa(msg, prk)
2038
+ >>> new_msg
2039
+ 3
2040
+ >>> decipher_rsa(new_msg, puk)
2041
+ 12
2042
+
2043
+ Private Key Encryption and Decryption:
2044
+
2045
+ >>> p, q, e = 3, 5, 7
2046
+ >>> prk = rsa_private_key(p, q, e)
2047
+ >>> puk = rsa_public_key(p, q, e)
2048
+ >>> msg = 12
2049
+ >>> new_msg = encipher_rsa(msg, puk)
2050
+ >>> new_msg
2051
+ 3
2052
+ >>> decipher_rsa(new_msg, prk)
2053
+ 12
2054
+
2055
+ Decryption using chinese remainder theorem:
2056
+
2057
+ >>> decipher_rsa(new_msg, prk, factors=[p, q])
2058
+ 12
2059
+
2060
+ See Also
2061
+ ========
2062
+
2063
+ encipher_rsa
2064
+ """
2065
+ return _encipher_decipher_rsa(i, key, factors=factors)
2066
+
2067
+
2068
+ #################### kid krypto (kid RSA) #############################
2069
+
2070
+
2071
+ def kid_rsa_public_key(a, b, A, B):
2072
+ r"""
2073
+ Kid RSA is a version of RSA useful to teach grade school children
2074
+ since it does not involve exponentiation.
2075
+
2076
+ Explanation
2077
+ ===========
2078
+
2079
+ Alice wants to talk to Bob. Bob generates keys as follows.
2080
+ Key generation:
2081
+
2082
+ * Select positive integers `a, b, A, B` at random.
2083
+ * Compute `M = a b - 1`, `e = A M + a`, `d = B M + b`,
2084
+ `n = (e d - 1)//M`.
2085
+ * The *public key* is `(n, e)`. Bob sends these to Alice.
2086
+ * The *private key* is `(n, d)`, which Bob keeps secret.
2087
+
2088
+ Encryption: If `p` is the plaintext message then the
2089
+ ciphertext is `c = p e \pmod n`.
2090
+
2091
+ Decryption: If `c` is the ciphertext message then the
2092
+ plaintext is `p = c d \pmod n`.
2093
+
2094
+ Examples
2095
+ ========
2096
+
2097
+ >>> from sympy.crypto.crypto import kid_rsa_public_key
2098
+ >>> a, b, A, B = 3, 4, 5, 6
2099
+ >>> kid_rsa_public_key(a, b, A, B)
2100
+ (369, 58)
2101
+
2102
+ """
2103
+ M = a*b - 1
2104
+ e = A*M + a
2105
+ d = B*M + b
2106
+ n = (e*d - 1)//M
2107
+ return n, e
2108
+
2109
+
2110
+ def kid_rsa_private_key(a, b, A, B):
2111
+ """
2112
+ Compute `M = a b - 1`, `e = A M + a`, `d = B M + b`,
2113
+ `n = (e d - 1) / M`. The *private key* is `d`, which Bob
2114
+ keeps secret.
2115
+
2116
+ Examples
2117
+ ========
2118
+
2119
+ >>> from sympy.crypto.crypto import kid_rsa_private_key
2120
+ >>> a, b, A, B = 3, 4, 5, 6
2121
+ >>> kid_rsa_private_key(a, b, A, B)
2122
+ (369, 70)
2123
+
2124
+ """
2125
+ M = a*b - 1
2126
+ e = A*M + a
2127
+ d = B*M + b
2128
+ n = (e*d - 1)//M
2129
+ return n, d
2130
+
2131
+
2132
+ def encipher_kid_rsa(msg, key):
2133
+ """
2134
+ Here ``msg`` is the plaintext and ``key`` is the public key.
2135
+
2136
+ Examples
2137
+ ========
2138
+
2139
+ >>> from sympy.crypto.crypto import (
2140
+ ... encipher_kid_rsa, kid_rsa_public_key)
2141
+ >>> msg = 200
2142
+ >>> a, b, A, B = 3, 4, 5, 6
2143
+ >>> key = kid_rsa_public_key(a, b, A, B)
2144
+ >>> encipher_kid_rsa(msg, key)
2145
+ 161
2146
+
2147
+ """
2148
+ n, e = key
2149
+ return (msg*e) % n
2150
+
2151
+
2152
+ def decipher_kid_rsa(msg, key):
2153
+ """
2154
+ Here ``msg`` is the plaintext and ``key`` is the private key.
2155
+
2156
+ Examples
2157
+ ========
2158
+
2159
+ >>> from sympy.crypto.crypto import (
2160
+ ... kid_rsa_public_key, kid_rsa_private_key,
2161
+ ... decipher_kid_rsa, encipher_kid_rsa)
2162
+ >>> a, b, A, B = 3, 4, 5, 6
2163
+ >>> d = kid_rsa_private_key(a, b, A, B)
2164
+ >>> msg = 200
2165
+ >>> pub = kid_rsa_public_key(a, b, A, B)
2166
+ >>> pri = kid_rsa_private_key(a, b, A, B)
2167
+ >>> ct = encipher_kid_rsa(msg, pub)
2168
+ >>> decipher_kid_rsa(ct, pri)
2169
+ 200
2170
+
2171
+ """
2172
+ n, d = key
2173
+ return (msg*d) % n
2174
+
2175
+
2176
+ #################### Morse Code ######################################
2177
+
2178
+ morse_char = {
2179
+ ".-": "A", "-...": "B",
2180
+ "-.-.": "C", "-..": "D",
2181
+ ".": "E", "..-.": "F",
2182
+ "--.": "G", "....": "H",
2183
+ "..": "I", ".---": "J",
2184
+ "-.-": "K", ".-..": "L",
2185
+ "--": "M", "-.": "N",
2186
+ "---": "O", ".--.": "P",
2187
+ "--.-": "Q", ".-.": "R",
2188
+ "...": "S", "-": "T",
2189
+ "..-": "U", "...-": "V",
2190
+ ".--": "W", "-..-": "X",
2191
+ "-.--": "Y", "--..": "Z",
2192
+ "-----": "0", ".----": "1",
2193
+ "..---": "2", "...--": "3",
2194
+ "....-": "4", ".....": "5",
2195
+ "-....": "6", "--...": "7",
2196
+ "---..": "8", "----.": "9",
2197
+ ".-.-.-": ".", "--..--": ",",
2198
+ "---...": ":", "-.-.-.": ";",
2199
+ "..--..": "?", "-....-": "-",
2200
+ "..--.-": "_", "-.--.": "(",
2201
+ "-.--.-": ")", ".----.": "'",
2202
+ "-...-": "=", ".-.-.": "+",
2203
+ "-..-.": "/", ".--.-.": "@",
2204
+ "...-..-": "$", "-.-.--": "!"}
2205
+ char_morse = {v: k for k, v in morse_char.items()}
2206
+
2207
+
2208
+ def encode_morse(msg, sep='|', mapping=None):
2209
+ """
2210
+ Encodes a plaintext into popular Morse Code with letters
2211
+ separated by ``sep`` and words by a double ``sep``.
2212
+
2213
+ Examples
2214
+ ========
2215
+
2216
+ >>> from sympy.crypto.crypto import encode_morse
2217
+ >>> msg = 'ATTACK RIGHT FLANK'
2218
+ >>> encode_morse(msg)
2219
+ '.-|-|-|.-|-.-.|-.-||.-.|..|--.|....|-||..-.|.-..|.-|-.|-.-'
2220
+
2221
+ References
2222
+ ==========
2223
+
2224
+ .. [1] https://en.wikipedia.org/wiki/Morse_code
2225
+
2226
+ """
2227
+
2228
+ mapping = mapping or char_morse
2229
+ assert sep not in mapping
2230
+ word_sep = 2*sep
2231
+ mapping[" "] = word_sep
2232
+ suffix = msg and msg[-1] in whitespace
2233
+
2234
+ # normalize whitespace
2235
+ msg = (' ' if word_sep else '').join(msg.split())
2236
+ # omit unmapped chars
2237
+ chars = set(''.join(msg.split()))
2238
+ ok = set(mapping.keys())
2239
+ msg = translate(msg, None, ''.join(chars - ok))
2240
+
2241
+ morsestring = []
2242
+ words = msg.split()
2243
+ for word in words:
2244
+ morseword = []
2245
+ for letter in word:
2246
+ morseletter = mapping[letter]
2247
+ morseword.append(morseletter)
2248
+
2249
+ word = sep.join(morseword)
2250
+ morsestring.append(word)
2251
+
2252
+ return word_sep.join(morsestring) + (word_sep if suffix else '')
2253
+
2254
+
2255
+ def decode_morse(msg, sep='|', mapping=None):
2256
+ """
2257
+ Decodes a Morse Code with letters separated by ``sep``
2258
+ (default is '|') and words by `word_sep` (default is '||)
2259
+ into plaintext.
2260
+
2261
+ Examples
2262
+ ========
2263
+
2264
+ >>> from sympy.crypto.crypto import decode_morse
2265
+ >>> mc = '--|---|...-|.||.|.-|...|-'
2266
+ >>> decode_morse(mc)
2267
+ 'MOVE EAST'
2268
+
2269
+ References
2270
+ ==========
2271
+
2272
+ .. [1] https://en.wikipedia.org/wiki/Morse_code
2273
+
2274
+ """
2275
+
2276
+ mapping = mapping or morse_char
2277
+ word_sep = 2*sep
2278
+ characterstring = []
2279
+ words = msg.strip(word_sep).split(word_sep)
2280
+ for word in words:
2281
+ letters = word.split(sep)
2282
+ chars = [mapping[c] for c in letters]
2283
+ word = ''.join(chars)
2284
+ characterstring.append(word)
2285
+ rv = " ".join(characterstring)
2286
+ return rv
2287
+
2288
+
2289
+ #################### LFSRs ##########################################
2290
+
2291
+
2292
+ @doctest_depends_on(ground_types=['python', 'gmpy'])
2293
+ def lfsr_sequence(key, fill, n):
2294
+ r"""
2295
+ This function creates an LFSR sequence.
2296
+
2297
+ Parameters
2298
+ ==========
2299
+
2300
+ key : list
2301
+ A list of finite field elements, `[c_0, c_1, \ldots, c_k].`
2302
+
2303
+ fill : list
2304
+ The list of the initial terms of the LFSR sequence,
2305
+ `[x_0, x_1, \ldots, x_k].`
2306
+
2307
+ n
2308
+ Number of terms of the sequence that the function returns.
2309
+
2310
+ Returns
2311
+ =======
2312
+
2313
+ L
2314
+ The LFSR sequence defined by
2315
+ `x_{n+1} = c_k x_n + \ldots + c_0 x_{n-k}`, for
2316
+ `n \leq k`.
2317
+
2318
+ Notes
2319
+ =====
2320
+
2321
+ S. Golomb [G]_ gives a list of three statistical properties a
2322
+ sequence of numbers `a = \{a_n\}_{n=1}^\infty`,
2323
+ `a_n \in \{0,1\}`, should display to be considered
2324
+ "random". Define the autocorrelation of `a` to be
2325
+
2326
+ .. math::
2327
+
2328
+ C(k) = C(k,a) = \lim_{N\rightarrow \infty} {1\over N}\sum_{n=1}^N (-1)^{a_n + a_{n+k}}.
2329
+
2330
+ In the case where `a` is periodic with period
2331
+ `P` then this reduces to
2332
+
2333
+ .. math::
2334
+
2335
+ C(k) = {1\over P}\sum_{n=1}^P (-1)^{a_n + a_{n+k}}.
2336
+
2337
+ Assume `a` is periodic with period `P`.
2338
+
2339
+ - balance:
2340
+
2341
+ .. math::
2342
+
2343
+ \left|\sum_{n=1}^P(-1)^{a_n}\right| \leq 1.
2344
+
2345
+ - low autocorrelation:
2346
+
2347
+ .. math::
2348
+
2349
+ C(k) = \left\{ \begin{array}{cc} 1,& k = 0,\\ \epsilon, & k \ne 0. \end{array} \right.
2350
+
2351
+ (For sequences satisfying these first two properties, it is known
2352
+ that `\epsilon = -1/P` must hold.)
2353
+
2354
+ - proportional runs property: In each period, half the runs have
2355
+ length `1`, one-fourth have length `2`, etc.
2356
+ Moreover, there are as many runs of `1`'s as there are of
2357
+ `0`'s.
2358
+
2359
+ Examples
2360
+ ========
2361
+
2362
+ >>> from sympy.crypto.crypto import lfsr_sequence
2363
+ >>> from sympy.polys.domains import FF
2364
+ >>> F = FF(2)
2365
+ >>> fill = [F(1), F(1), F(0), F(1)]
2366
+ >>> key = [F(1), F(0), F(0), F(1)]
2367
+ >>> lfsr_sequence(key, fill, 10)
2368
+ [1 mod 2, 1 mod 2, 0 mod 2, 1 mod 2, 0 mod 2,
2369
+ 1 mod 2, 1 mod 2, 0 mod 2, 0 mod 2, 1 mod 2]
2370
+
2371
+ References
2372
+ ==========
2373
+
2374
+ .. [G] Solomon Golomb, Shift register sequences, Aegean Park Press,
2375
+ Laguna Hills, Ca, 1967
2376
+
2377
+ """
2378
+ if not isinstance(key, list):
2379
+ raise TypeError("key must be a list")
2380
+ if not isinstance(fill, list):
2381
+ raise TypeError("fill must be a list")
2382
+ p = key[0].modulus()
2383
+ F = FF(p)
2384
+ s = fill
2385
+ k = len(fill)
2386
+ L = []
2387
+ for i in range(n):
2388
+ s0 = s[:]
2389
+ L.append(s[0])
2390
+ s = s[1:k]
2391
+ x = sum(int(key[i]*s0[i]) for i in range(k))
2392
+ s.append(F(x))
2393
+ return L # use [int(x) for x in L] for int version
2394
+
2395
+
2396
+ def lfsr_autocorrelation(L, P, k):
2397
+ """
2398
+ This function computes the LFSR autocorrelation function.
2399
+
2400
+ Parameters
2401
+ ==========
2402
+
2403
+ L
2404
+ A periodic sequence of elements of `GF(2)`.
2405
+ L must have length larger than P.
2406
+
2407
+ P
2408
+ The period of L.
2409
+
2410
+ k : int
2411
+ An integer `k` (`0 < k < P`).
2412
+
2413
+ Returns
2414
+ =======
2415
+
2416
+ autocorrelation
2417
+ The k-th value of the autocorrelation of the LFSR L.
2418
+
2419
+ Examples
2420
+ ========
2421
+
2422
+ >>> from sympy.crypto.crypto import (
2423
+ ... lfsr_sequence, lfsr_autocorrelation)
2424
+ >>> from sympy.polys.domains import FF
2425
+ >>> F = FF(2)
2426
+ >>> fill = [F(1), F(1), F(0), F(1)]
2427
+ >>> key = [F(1), F(0), F(0), F(1)]
2428
+ >>> s = lfsr_sequence(key, fill, 20)
2429
+ >>> lfsr_autocorrelation(s, 15, 7)
2430
+ -1/15
2431
+ >>> lfsr_autocorrelation(s, 15, 0)
2432
+ 1
2433
+
2434
+ """
2435
+ if not isinstance(L, list):
2436
+ raise TypeError("L (=%s) must be a list" % L)
2437
+ P = int(P)
2438
+ k = int(k)
2439
+ L0 = L[:P] # slices makes a copy
2440
+ L1 = L0 + L0[:k]
2441
+ L2 = [(-1)**(int(L1[i]) + int(L1[i + k])) for i in range(P)]
2442
+ tot = sum(L2)
2443
+ return Rational(tot, P)
2444
+
2445
+
2446
+ def lfsr_connection_polynomial(s):
2447
+ """
2448
+ This function computes the LFSR connection polynomial.
2449
+
2450
+ Parameters
2451
+ ==========
2452
+
2453
+ s
2454
+ A sequence of elements of even length, with entries in a finite
2455
+ field.
2456
+
2457
+ Returns
2458
+ =======
2459
+
2460
+ C(x)
2461
+ The connection polynomial of a minimal LFSR yielding s.
2462
+
2463
+ This implements the algorithm in section 3 of J. L. Massey's
2464
+ article [M]_.
2465
+
2466
+ Examples
2467
+ ========
2468
+
2469
+ >>> from sympy.crypto.crypto import (
2470
+ ... lfsr_sequence, lfsr_connection_polynomial)
2471
+ >>> from sympy.polys.domains import FF
2472
+ >>> F = FF(2)
2473
+ >>> fill = [F(1), F(1), F(0), F(1)]
2474
+ >>> key = [F(1), F(0), F(0), F(1)]
2475
+ >>> s = lfsr_sequence(key, fill, 20)
2476
+ >>> lfsr_connection_polynomial(s)
2477
+ x**4 + x + 1
2478
+ >>> fill = [F(1), F(0), F(0), F(1)]
2479
+ >>> key = [F(1), F(1), F(0), F(1)]
2480
+ >>> s = lfsr_sequence(key, fill, 20)
2481
+ >>> lfsr_connection_polynomial(s)
2482
+ x**3 + 1
2483
+ >>> fill = [F(1), F(0), F(1)]
2484
+ >>> key = [F(1), F(1), F(0)]
2485
+ >>> s = lfsr_sequence(key, fill, 20)
2486
+ >>> lfsr_connection_polynomial(s)
2487
+ x**3 + x**2 + 1
2488
+ >>> fill = [F(1), F(0), F(1)]
2489
+ >>> key = [F(1), F(0), F(1)]
2490
+ >>> s = lfsr_sequence(key, fill, 20)
2491
+ >>> lfsr_connection_polynomial(s)
2492
+ x**3 + x + 1
2493
+
2494
+ References
2495
+ ==========
2496
+
2497
+ .. [M] James L. Massey, "Shift-Register Synthesis and BCH Decoding."
2498
+ IEEE Trans. on Information Theory, vol. 15(1), pp. 122-127,
2499
+ Jan 1969.
2500
+
2501
+ """
2502
+ # Initialization:
2503
+ p = s[0].modulus()
2504
+ x = Symbol("x")
2505
+ C = 1*x**0
2506
+ B = 1*x**0
2507
+ m = 1
2508
+ b = 1*x**0
2509
+ L = 0
2510
+ N = 0
2511
+ while N < len(s):
2512
+ if L > 0:
2513
+ dC = Poly(C).degree()
2514
+ r = min(L + 1, dC + 1)
2515
+ coeffsC = [C.subs(x, 0)] + [C.coeff(x**i)
2516
+ for i in range(1, dC + 1)]
2517
+ d = (int(s[N]) + sum(coeffsC[i]*int(s[N - i])
2518
+ for i in range(1, r))) % p
2519
+ if L == 0:
2520
+ d = int(s[N])*x**0
2521
+ if d == 0:
2522
+ m += 1
2523
+ N += 1
2524
+ if d > 0:
2525
+ if 2*L > N:
2526
+ C = (C - d*((b**(p - 2)) % p)*x**m*B).expand()
2527
+ m += 1
2528
+ N += 1
2529
+ else:
2530
+ T = C
2531
+ C = (C - d*((b**(p - 2)) % p)*x**m*B).expand()
2532
+ L = N + 1 - L
2533
+ m = 1
2534
+ b = d
2535
+ B = T
2536
+ N += 1
2537
+ dC = Poly(C).degree()
2538
+ coeffsC = [C.subs(x, 0)] + [C.coeff(x**i) for i in range(1, dC + 1)]
2539
+ return sum(coeffsC[i] % p*x**i for i in range(dC + 1)
2540
+ if coeffsC[i] is not None)
2541
+
2542
+
2543
+ #################### ElGamal #############################
2544
+
2545
+
2546
+ def elgamal_private_key(digit=10, seed=None):
2547
+ r"""
2548
+ Return three number tuple as private key.
2549
+
2550
+ Explanation
2551
+ ===========
2552
+
2553
+ Elgamal encryption is based on the mathematical problem
2554
+ called the Discrete Logarithm Problem (DLP). For example,
2555
+
2556
+ `a^{b} \equiv c \pmod p`
2557
+
2558
+ In general, if ``a`` and ``b`` are known, ``ct`` is easily
2559
+ calculated. If ``b`` is unknown, it is hard to use
2560
+ ``a`` and ``ct`` to get ``b``.
2561
+
2562
+ Parameters
2563
+ ==========
2564
+
2565
+ digit : int
2566
+ Minimum number of binary digits for key.
2567
+
2568
+ Returns
2569
+ =======
2570
+
2571
+ tuple : (p, r, d)
2572
+ p = prime number.
2573
+
2574
+ r = primitive root.
2575
+
2576
+ d = random number.
2577
+
2578
+ Notes
2579
+ =====
2580
+
2581
+ For testing purposes, the ``seed`` parameter may be set to control
2582
+ the output of this routine. See sympy.core.random._randrange.
2583
+
2584
+ Examples
2585
+ ========
2586
+
2587
+ >>> from sympy.crypto.crypto import elgamal_private_key
2588
+ >>> from sympy.ntheory import is_primitive_root, isprime
2589
+ >>> a, b, _ = elgamal_private_key()
2590
+ >>> isprime(a)
2591
+ True
2592
+ >>> is_primitive_root(b, a)
2593
+ True
2594
+
2595
+ """
2596
+ randrange = _randrange(seed)
2597
+ p = nextprime(2**digit)
2598
+ return p, primitive_root(p), randrange(2, p)
2599
+
2600
+
2601
+ def elgamal_public_key(key):
2602
+ r"""
2603
+ Return three number tuple as public key.
2604
+
2605
+ Parameters
2606
+ ==========
2607
+
2608
+ key : (p, r, e)
2609
+ Tuple generated by ``elgamal_private_key``.
2610
+
2611
+ Returns
2612
+ =======
2613
+
2614
+ tuple : (p, r, e)
2615
+ `e = r**d \bmod p`
2616
+
2617
+ `d` is a random number in private key.
2618
+
2619
+ Examples
2620
+ ========
2621
+
2622
+ >>> from sympy.crypto.crypto import elgamal_public_key
2623
+ >>> elgamal_public_key((1031, 14, 636))
2624
+ (1031, 14, 212)
2625
+
2626
+ """
2627
+ p, r, e = key
2628
+ return p, r, pow(r, e, p)
2629
+
2630
+
2631
+ def encipher_elgamal(i, key, seed=None):
2632
+ r"""
2633
+ Encrypt message with public key.
2634
+
2635
+ Explanation
2636
+ ===========
2637
+
2638
+ ``i`` is a plaintext message expressed as an integer.
2639
+ ``key`` is public key (p, r, e). In order to encrypt
2640
+ a message, a random number ``a`` in ``range(2, p)``
2641
+ is generated and the encryped message is returned as
2642
+ `c_{1}` and `c_{2}` where:
2643
+
2644
+ `c_{1} \equiv r^{a} \pmod p`
2645
+
2646
+ `c_{2} \equiv m e^{a} \pmod p`
2647
+
2648
+ Parameters
2649
+ ==========
2650
+
2651
+ msg
2652
+ int of encoded message.
2653
+
2654
+ key
2655
+ Public key.
2656
+
2657
+ Returns
2658
+ =======
2659
+
2660
+ tuple : (c1, c2)
2661
+ Encipher into two number.
2662
+
2663
+ Notes
2664
+ =====
2665
+
2666
+ For testing purposes, the ``seed`` parameter may be set to control
2667
+ the output of this routine. See sympy.core.random._randrange.
2668
+
2669
+ Examples
2670
+ ========
2671
+
2672
+ >>> from sympy.crypto.crypto import encipher_elgamal, elgamal_private_key, elgamal_public_key
2673
+ >>> pri = elgamal_private_key(5, seed=[3]); pri
2674
+ (37, 2, 3)
2675
+ >>> pub = elgamal_public_key(pri); pub
2676
+ (37, 2, 8)
2677
+ >>> msg = 36
2678
+ >>> encipher_elgamal(msg, pub, seed=[3])
2679
+ (8, 6)
2680
+
2681
+ """
2682
+ p, r, e = key
2683
+ if i < 0 or i >= p:
2684
+ raise ValueError(
2685
+ 'Message (%s) should be in range(%s)' % (i, p))
2686
+ randrange = _randrange(seed)
2687
+ a = randrange(2, p)
2688
+ return pow(r, a, p), i*pow(e, a, p) % p
2689
+
2690
+
2691
+ def decipher_elgamal(msg, key):
2692
+ r"""
2693
+ Decrypt message with private key.
2694
+
2695
+ `msg = (c_{1}, c_{2})`
2696
+
2697
+ `key = (p, r, d)`
2698
+
2699
+ According to extended Eucliden theorem,
2700
+ `u c_{1}^{d} + p n = 1`
2701
+
2702
+ `u \equiv 1/{{c_{1}}^d} \pmod p`
2703
+
2704
+ `u c_{2} \equiv \frac{1}{c_{1}^d} c_{2} \equiv \frac{1}{r^{ad}} c_{2} \pmod p`
2705
+
2706
+ `\frac{1}{r^{ad}} m e^a \equiv \frac{1}{r^{ad}} m {r^{d a}} \equiv m \pmod p`
2707
+
2708
+ Examples
2709
+ ========
2710
+
2711
+ >>> from sympy.crypto.crypto import decipher_elgamal
2712
+ >>> from sympy.crypto.crypto import encipher_elgamal
2713
+ >>> from sympy.crypto.crypto import elgamal_private_key
2714
+ >>> from sympy.crypto.crypto import elgamal_public_key
2715
+
2716
+ >>> pri = elgamal_private_key(5, seed=[3])
2717
+ >>> pub = elgamal_public_key(pri); pub
2718
+ (37, 2, 8)
2719
+ >>> msg = 17
2720
+ >>> decipher_elgamal(encipher_elgamal(msg, pub), pri) == msg
2721
+ True
2722
+
2723
+ """
2724
+ p, _, d = key
2725
+ c1, c2 = msg
2726
+ u = pow(c1, -d, p)
2727
+ return u * c2 % p
2728
+
2729
+
2730
+ ################ Diffie-Hellman Key Exchange #########################
2731
+
2732
+ def dh_private_key(digit=10, seed=None):
2733
+ r"""
2734
+ Return three integer tuple as private key.
2735
+
2736
+ Explanation
2737
+ ===========
2738
+
2739
+ Diffie-Hellman key exchange is based on the mathematical problem
2740
+ called the Discrete Logarithm Problem (see ElGamal).
2741
+
2742
+ Diffie-Hellman key exchange is divided into the following steps:
2743
+
2744
+ * Alice and Bob agree on a base that consist of a prime ``p``
2745
+ and a primitive root of ``p`` called ``g``
2746
+ * Alice choses a number ``a`` and Bob choses a number ``b`` where
2747
+ ``a`` and ``b`` are random numbers in range `[2, p)`. These are
2748
+ their private keys.
2749
+ * Alice then publicly sends Bob `g^{a} \pmod p` while Bob sends
2750
+ Alice `g^{b} \pmod p`
2751
+ * They both raise the received value to their secretly chosen
2752
+ number (``a`` or ``b``) and now have both as their shared key
2753
+ `g^{ab} \pmod p`
2754
+
2755
+ Parameters
2756
+ ==========
2757
+
2758
+ digit
2759
+ Minimum number of binary digits required in key.
2760
+
2761
+ Returns
2762
+ =======
2763
+
2764
+ tuple : (p, g, a)
2765
+ p = prime number.
2766
+
2767
+ g = primitive root of p.
2768
+
2769
+ a = random number from 2 through p - 1.
2770
+
2771
+ Notes
2772
+ =====
2773
+
2774
+ For testing purposes, the ``seed`` parameter may be set to control
2775
+ the output of this routine. See sympy.core.random._randrange.
2776
+
2777
+ Examples
2778
+ ========
2779
+
2780
+ >>> from sympy.crypto.crypto import dh_private_key
2781
+ >>> from sympy.ntheory import isprime, is_primitive_root
2782
+ >>> p, g, _ = dh_private_key()
2783
+ >>> isprime(p)
2784
+ True
2785
+ >>> is_primitive_root(g, p)
2786
+ True
2787
+ >>> p, g, _ = dh_private_key(5)
2788
+ >>> isprime(p)
2789
+ True
2790
+ >>> is_primitive_root(g, p)
2791
+ True
2792
+
2793
+ """
2794
+ p = nextprime(2**digit)
2795
+ g = primitive_root(p)
2796
+ randrange = _randrange(seed)
2797
+ a = randrange(2, p)
2798
+ return p, g, a
2799
+
2800
+
2801
+ def dh_public_key(key):
2802
+ r"""
2803
+ Return three number tuple as public key.
2804
+
2805
+ This is the tuple that Alice sends to Bob.
2806
+
2807
+ Parameters
2808
+ ==========
2809
+
2810
+ key : (p, g, a)
2811
+ A tuple generated by ``dh_private_key``.
2812
+
2813
+ Returns
2814
+ =======
2815
+
2816
+ tuple : int, int, int
2817
+ A tuple of `(p, g, g^a \mod p)` with `p`, `g` and `a` given as
2818
+ parameters.s
2819
+
2820
+ Examples
2821
+ ========
2822
+
2823
+ >>> from sympy.crypto.crypto import dh_private_key, dh_public_key
2824
+ >>> p, g, a = dh_private_key();
2825
+ >>> _p, _g, x = dh_public_key((p, g, a))
2826
+ >>> p == _p and g == _g
2827
+ True
2828
+ >>> x == pow(g, a, p)
2829
+ True
2830
+
2831
+ """
2832
+ p, g, a = key
2833
+ return p, g, pow(g, a, p)
2834
+
2835
+
2836
+ def dh_shared_key(key, b):
2837
+ """
2838
+ Return an integer that is the shared key.
2839
+
2840
+ This is what Bob and Alice can both calculate using the public
2841
+ keys they received from each other and their private keys.
2842
+
2843
+ Parameters
2844
+ ==========
2845
+
2846
+ key : (p, g, x)
2847
+ Tuple `(p, g, x)` generated by ``dh_public_key``.
2848
+
2849
+ b
2850
+ Random number in the range of `2` to `p - 1`
2851
+ (Chosen by second key exchange member (Bob)).
2852
+
2853
+ Returns
2854
+ =======
2855
+
2856
+ int
2857
+ A shared key.
2858
+
2859
+ Examples
2860
+ ========
2861
+
2862
+ >>> from sympy.crypto.crypto import (
2863
+ ... dh_private_key, dh_public_key, dh_shared_key)
2864
+ >>> prk = dh_private_key();
2865
+ >>> p, g, x = dh_public_key(prk);
2866
+ >>> sk = dh_shared_key((p, g, x), 1000)
2867
+ >>> sk == pow(x, 1000, p)
2868
+ True
2869
+
2870
+ """
2871
+ p, _, x = key
2872
+ if 1 >= b or b >= p:
2873
+ raise ValueError(filldedent('''
2874
+ Value of b should be greater 1 and less
2875
+ than prime %s.''' % p))
2876
+
2877
+ return pow(x, b, p)
2878
+
2879
+
2880
+ ################ Goldwasser-Micali Encryption #########################
2881
+
2882
+
2883
+ def _legendre(a, p):
2884
+ """
2885
+ Returns the legendre symbol of a and p
2886
+ assuming that p is a prime.
2887
+
2888
+ i.e. 1 if a is a quadratic residue mod p
2889
+ -1 if a is not a quadratic residue mod p
2890
+ 0 if a is divisible by p
2891
+
2892
+ Parameters
2893
+ ==========
2894
+
2895
+ a : int
2896
+ The number to test.
2897
+
2898
+ p : prime
2899
+ The prime to test ``a`` against.
2900
+
2901
+ Returns
2902
+ =======
2903
+
2904
+ int
2905
+ Legendre symbol (a / p).
2906
+
2907
+ """
2908
+ sig = pow(a, (p - 1)//2, p)
2909
+ if sig == 1:
2910
+ return 1
2911
+ elif sig == 0:
2912
+ return 0
2913
+ else:
2914
+ return -1
2915
+
2916
+
2917
+ def _random_coprime_stream(n, seed=None):
2918
+ randrange = _randrange(seed)
2919
+ while True:
2920
+ y = randrange(n)
2921
+ if gcd(y, n) == 1:
2922
+ yield y
2923
+
2924
+
2925
+ def gm_private_key(p, q, a=None):
2926
+ r"""
2927
+ Check if ``p`` and ``q`` can be used as private keys for
2928
+ the Goldwasser-Micali encryption. The method works
2929
+ roughly as follows.
2930
+
2931
+ Explanation
2932
+ ===========
2933
+
2934
+ #. Pick two large primes $p$ and $q$.
2935
+ #. Call their product $N$.
2936
+ #. Given a message as an integer $i$, write $i$ in its bit representation $b_0, \dots, b_n$.
2937
+ #. For each $k$,
2938
+
2939
+ if $b_k = 0$:
2940
+ let $a_k$ be a random square
2941
+ (quadratic residue) modulo $p q$
2942
+ such that ``jacobi_symbol(a, p*q) = 1``
2943
+ if $b_k = 1$:
2944
+ let $a_k$ be a random non-square
2945
+ (non-quadratic residue) modulo $p q$
2946
+ such that ``jacobi_symbol(a, p*q) = 1``
2947
+
2948
+ returns $\left[a_1, a_2, \dots\right]$
2949
+
2950
+ $b_k$ can be recovered by checking whether or not
2951
+ $a_k$ is a residue. And from the $b_k$'s, the message
2952
+ can be reconstructed.
2953
+
2954
+ The idea is that, while ``jacobi_symbol(a, p*q)``
2955
+ can be easily computed (and when it is equal to $-1$ will
2956
+ tell you that $a$ is not a square mod $p q$), quadratic
2957
+ residuosity modulo a composite number is hard to compute
2958
+ without knowing its factorization.
2959
+
2960
+ Moreover, approximately half the numbers coprime to $p q$ have
2961
+ :func:`~.jacobi_symbol` equal to $1$ . And among those, approximately half
2962
+ are residues and approximately half are not. This maximizes the
2963
+ entropy of the code.
2964
+
2965
+ Parameters
2966
+ ==========
2967
+
2968
+ p, q, a
2969
+ Initialization variables.
2970
+
2971
+ Returns
2972
+ =======
2973
+
2974
+ tuple : (p, q)
2975
+ The input value ``p`` and ``q``.
2976
+
2977
+ Raises
2978
+ ======
2979
+
2980
+ ValueError
2981
+ If ``p`` and ``q`` are not distinct odd primes.
2982
+
2983
+ """
2984
+ if p == q:
2985
+ raise ValueError("expected distinct primes, "
2986
+ "got two copies of %i" % p)
2987
+ elif not isprime(p) or not isprime(q):
2988
+ raise ValueError("first two arguments must be prime, "
2989
+ "got %i of %i" % (p, q))
2990
+ elif p == 2 or q == 2:
2991
+ raise ValueError("first two arguments must not be even, "
2992
+ "got %i of %i" % (p, q))
2993
+ return p, q
2994
+
2995
+
2996
+ def gm_public_key(p, q, a=None, seed=None):
2997
+ """
2998
+ Compute public keys for ``p`` and ``q``.
2999
+ Note that in Goldwasser-Micali Encryption,
3000
+ public keys are randomly selected.
3001
+
3002
+ Parameters
3003
+ ==========
3004
+
3005
+ p, q, a : int, int, int
3006
+ Initialization variables.
3007
+
3008
+ Returns
3009
+ =======
3010
+
3011
+ tuple : (a, N)
3012
+ ``a`` is the input ``a`` if it is not ``None`` otherwise
3013
+ some random integer coprime to ``p`` and ``q``.
3014
+
3015
+ ``N`` is the product of ``p`` and ``q``.
3016
+
3017
+ """
3018
+
3019
+ p, q = gm_private_key(p, q)
3020
+ N = p * q
3021
+
3022
+ if a is None:
3023
+ randrange = _randrange(seed)
3024
+ while True:
3025
+ a = randrange(N)
3026
+ if _legendre(a, p) == _legendre(a, q) == -1:
3027
+ break
3028
+ else:
3029
+ if _legendre(a, p) != -1 or _legendre(a, q) != -1:
3030
+ return False
3031
+ return (a, N)
3032
+
3033
+
3034
+ def encipher_gm(i, key, seed=None):
3035
+ """
3036
+ Encrypt integer 'i' using public_key 'key'
3037
+ Note that gm uses random encryption.
3038
+
3039
+ Parameters
3040
+ ==========
3041
+
3042
+ i : int
3043
+ The message to encrypt.
3044
+
3045
+ key : (a, N)
3046
+ The public key.
3047
+
3048
+ Returns
3049
+ =======
3050
+
3051
+ list : list of int
3052
+ The randomized encrypted message.
3053
+
3054
+ """
3055
+ if i < 0:
3056
+ raise ValueError(
3057
+ "message must be a non-negative "
3058
+ "integer: got %d instead" % i)
3059
+ a, N = key
3060
+ bits = []
3061
+ while i > 0:
3062
+ bits.append(i % 2)
3063
+ i //= 2
3064
+
3065
+ gen = _random_coprime_stream(N, seed)
3066
+ rev = reversed(bits)
3067
+ encode = lambda b: next(gen)**2*pow(a, b) % N
3068
+ return [ encode(b) for b in rev ]
3069
+
3070
+
3071
+
3072
+ def decipher_gm(message, key):
3073
+ """
3074
+ Decrypt message 'message' using public_key 'key'.
3075
+
3076
+ Parameters
3077
+ ==========
3078
+
3079
+ message : list of int
3080
+ The randomized encrypted message.
3081
+
3082
+ key : (p, q)
3083
+ The private key.
3084
+
3085
+ Returns
3086
+ =======
3087
+
3088
+ int
3089
+ The encrypted message.
3090
+
3091
+ """
3092
+ p, q = key
3093
+ res = lambda m, p: _legendre(m, p) > 0
3094
+ bits = [res(m, p) * res(m, q) for m in message]
3095
+ m = 0
3096
+ for b in bits:
3097
+ m <<= 1
3098
+ m += not b
3099
+ return m
3100
+
3101
+
3102
+
3103
+ ########### RailFence Cipher #############
3104
+
3105
+ def encipher_railfence(message,rails):
3106
+ """
3107
+ Performs Railfence Encryption on plaintext and returns ciphertext
3108
+
3109
+ Examples
3110
+ ========
3111
+
3112
+ >>> from sympy.crypto.crypto import encipher_railfence
3113
+ >>> message = "hello world"
3114
+ >>> encipher_railfence(message,3)
3115
+ 'horel ollwd'
3116
+
3117
+ Parameters
3118
+ ==========
3119
+
3120
+ message : string, the message to encrypt.
3121
+ rails : int, the number of rails.
3122
+
3123
+ Returns
3124
+ =======
3125
+
3126
+ The Encrypted string message.
3127
+
3128
+ References
3129
+ ==========
3130
+ .. [1] https://en.wikipedia.org/wiki/Rail_fence_cipher
3131
+
3132
+ """
3133
+ r = list(range(rails))
3134
+ p = cycle(r + r[-2:0:-1])
3135
+ return ''.join(sorted(message, key=lambda i: next(p)))
3136
+
3137
+
3138
+ def decipher_railfence(ciphertext,rails):
3139
+ """
3140
+ Decrypt the message using the given rails
3141
+
3142
+ Examples
3143
+ ========
3144
+
3145
+ >>> from sympy.crypto.crypto import decipher_railfence
3146
+ >>> decipher_railfence("horel ollwd",3)
3147
+ 'hello world'
3148
+
3149
+ Parameters
3150
+ ==========
3151
+
3152
+ message : string, the message to encrypt.
3153
+ rails : int, the number of rails.
3154
+
3155
+ Returns
3156
+ =======
3157
+
3158
+ The Decrypted string message.
3159
+
3160
+ """
3161
+ r = list(range(rails))
3162
+ p = cycle(r + r[-2:0:-1])
3163
+
3164
+ idx = sorted(range(len(ciphertext)), key=lambda i: next(p))
3165
+ res = [''] * len(ciphertext)
3166
+ for i, c in zip(idx, ciphertext):
3167
+ res[i] = c
3168
+ return ''.join(res)
3169
+
3170
+
3171
+ ################ Blum-Goldwasser cryptosystem #########################
3172
+
3173
+ def bg_private_key(p, q):
3174
+ """
3175
+ Check if p and q can be used as private keys for
3176
+ the Blum-Goldwasser cryptosystem.
3177
+
3178
+ Explanation
3179
+ ===========
3180
+
3181
+ The three necessary checks for p and q to pass
3182
+ so that they can be used as private keys:
3183
+
3184
+ 1. p and q must both be prime
3185
+ 2. p and q must be distinct
3186
+ 3. p and q must be congruent to 3 mod 4
3187
+
3188
+ Parameters
3189
+ ==========
3190
+
3191
+ p, q
3192
+ The keys to be checked.
3193
+
3194
+ Returns
3195
+ =======
3196
+
3197
+ p, q
3198
+ Input values.
3199
+
3200
+ Raises
3201
+ ======
3202
+
3203
+ ValueError
3204
+ If p and q do not pass the above conditions.
3205
+
3206
+ """
3207
+
3208
+ if not isprime(p) or not isprime(q):
3209
+ raise ValueError("the two arguments must be prime, "
3210
+ "got %i and %i" %(p, q))
3211
+ elif p == q:
3212
+ raise ValueError("the two arguments must be distinct, "
3213
+ "got two copies of %i. " %p)
3214
+ elif (p - 3) % 4 != 0 or (q - 3) % 4 != 0:
3215
+ raise ValueError("the two arguments must be congruent to 3 mod 4, "
3216
+ "got %i and %i" %(p, q))
3217
+ return p, q
3218
+
3219
+ def bg_public_key(p, q):
3220
+ """
3221
+ Calculates public keys from private keys.
3222
+
3223
+ Explanation
3224
+ ===========
3225
+
3226
+ The function first checks the validity of
3227
+ private keys passed as arguments and
3228
+ then returns their product.
3229
+
3230
+ Parameters
3231
+ ==========
3232
+
3233
+ p, q
3234
+ The private keys.
3235
+
3236
+ Returns
3237
+ =======
3238
+
3239
+ N
3240
+ The public key.
3241
+
3242
+ """
3243
+ p, q = bg_private_key(p, q)
3244
+ N = p * q
3245
+ return N
3246
+
3247
+ def encipher_bg(i, key, seed=None):
3248
+ """
3249
+ Encrypts the message using public key and seed.
3250
+
3251
+ Explanation
3252
+ ===========
3253
+
3254
+ ALGORITHM:
3255
+ 1. Encodes i as a string of L bits, m.
3256
+ 2. Select a random element r, where 1 < r < key, and computes
3257
+ x = r^2 mod key.
3258
+ 3. Use BBS pseudo-random number generator to generate L random bits, b,
3259
+ using the initial seed as x.
3260
+ 4. Encrypted message, c_i = m_i XOR b_i, 1 <= i <= L.
3261
+ 5. x_L = x^(2^L) mod key.
3262
+ 6. Return (c, x_L)
3263
+
3264
+ Parameters
3265
+ ==========
3266
+
3267
+ i
3268
+ Message, a non-negative integer
3269
+
3270
+ key
3271
+ The public key
3272
+
3273
+ Returns
3274
+ =======
3275
+
3276
+ Tuple
3277
+ (encrypted_message, x_L)
3278
+
3279
+ Raises
3280
+ ======
3281
+
3282
+ ValueError
3283
+ If i is negative.
3284
+
3285
+ """
3286
+
3287
+ if i < 0:
3288
+ raise ValueError(
3289
+ "message must be a non-negative "
3290
+ "integer: got %d instead" % i)
3291
+
3292
+ enc_msg = []
3293
+ while i > 0:
3294
+ enc_msg.append(i % 2)
3295
+ i //= 2
3296
+ enc_msg.reverse()
3297
+ L = len(enc_msg)
3298
+
3299
+ r = _randint(seed)(2, key - 1)
3300
+ x = r**2 % key
3301
+ x_L = pow(int(x), int(2**L), int(key))
3302
+
3303
+ rand_bits = []
3304
+ for _ in range(L):
3305
+ rand_bits.append(x % 2)
3306
+ x = x**2 % key
3307
+
3308
+ encrypt_msg = [m ^ b for (m, b) in zip(enc_msg, rand_bits)]
3309
+
3310
+ return (encrypt_msg, x_L)
3311
+
3312
+ def decipher_bg(message, key):
3313
+ """
3314
+ Decrypts the message using private keys.
3315
+
3316
+ Explanation
3317
+ ===========
3318
+
3319
+ ALGORITHM:
3320
+ 1. Let, c be the encrypted message, y the second number received,
3321
+ and p and q be the private keys.
3322
+ 2. Compute, r_p = y^((p+1)/4 ^ L) mod p and
3323
+ r_q = y^((q+1)/4 ^ L) mod q.
3324
+ 3. Compute x_0 = (q(q^-1 mod p)r_p + p(p^-1 mod q)r_q) mod N.
3325
+ 4. From, recompute the bits using the BBS generator, as in the
3326
+ encryption algorithm.
3327
+ 5. Compute original message by XORing c and b.
3328
+
3329
+ Parameters
3330
+ ==========
3331
+
3332
+ message
3333
+ Tuple of encrypted message and a non-negative integer.
3334
+
3335
+ key
3336
+ Tuple of private keys.
3337
+
3338
+ Returns
3339
+ =======
3340
+
3341
+ orig_msg
3342
+ The original message
3343
+
3344
+ """
3345
+
3346
+ p, q = key
3347
+ encrypt_msg, y = message
3348
+ public_key = p * q
3349
+ L = len(encrypt_msg)
3350
+ p_t = ((p + 1)/4)**L
3351
+ q_t = ((q + 1)/4)**L
3352
+ r_p = pow(int(y), int(p_t), int(p))
3353
+ r_q = pow(int(y), int(q_t), int(q))
3354
+
3355
+ x = (q * invert(q, p) * r_p + p * invert(p, q) * r_q) % public_key
3356
+
3357
+ orig_bits = []
3358
+ for _ in range(L):
3359
+ orig_bits.append(x % 2)
3360
+ x = x**2 % public_key
3361
+
3362
+ orig_msg = 0
3363
+ for (m, b) in zip(encrypt_msg, orig_bits):
3364
+ orig_msg = orig_msg * 2
3365
+ orig_msg += (m ^ b)
3366
+
3367
+ return orig_msg
lib/python3.12/site-packages/sympy/crypto/tests/__init__.py ADDED
File without changes
lib/python3.12/site-packages/sympy/crypto/tests/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (197 Bytes). View file
 
lib/python3.12/site-packages/sympy/crypto/tests/__pycache__/test_crypto.cpython-312.pyc ADDED
Binary file (31.7 kB). View file
 
lib/python3.12/site-packages/sympy/crypto/tests/test_crypto.py ADDED
@@ -0,0 +1,562 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core import symbols
2
+ from sympy.crypto.crypto import (cycle_list,
3
+ encipher_shift, encipher_affine, encipher_substitution,
4
+ check_and_join, encipher_vigenere, decipher_vigenere,
5
+ encipher_hill, decipher_hill, encipher_bifid5, encipher_bifid6,
6
+ bifid5_square, bifid6_square, bifid5, bifid6,
7
+ decipher_bifid5, decipher_bifid6, encipher_kid_rsa,
8
+ decipher_kid_rsa, kid_rsa_private_key, kid_rsa_public_key,
9
+ decipher_rsa, rsa_private_key, rsa_public_key, encipher_rsa,
10
+ lfsr_connection_polynomial, lfsr_autocorrelation, lfsr_sequence,
11
+ encode_morse, decode_morse, elgamal_private_key, elgamal_public_key,
12
+ encipher_elgamal, decipher_elgamal, dh_private_key, dh_public_key,
13
+ dh_shared_key, decipher_shift, decipher_affine, encipher_bifid,
14
+ decipher_bifid, bifid_square, padded_key, uniq, decipher_gm,
15
+ encipher_gm, gm_public_key, gm_private_key, encipher_bg, decipher_bg,
16
+ bg_private_key, bg_public_key, encipher_rot13, decipher_rot13,
17
+ encipher_atbash, decipher_atbash, NonInvertibleCipherWarning,
18
+ encipher_railfence, decipher_railfence)
19
+ from sympy.external.gmpy import gcd
20
+ from sympy.matrices import Matrix
21
+ from sympy.ntheory import isprime, is_primitive_root
22
+ from sympy.polys.domains import FF
23
+
24
+ from sympy.testing.pytest import raises, warns
25
+
26
+ from sympy.core.random import randrange
27
+
28
+ def test_encipher_railfence():
29
+ assert encipher_railfence("hello world",2) == "hlowrdel ol"
30
+ assert encipher_railfence("hello world",3) == "horel ollwd"
31
+ assert encipher_railfence("hello world",4) == "hwe olordll"
32
+
33
+ def test_decipher_railfence():
34
+ assert decipher_railfence("hlowrdel ol",2) == "hello world"
35
+ assert decipher_railfence("horel ollwd",3) == "hello world"
36
+ assert decipher_railfence("hwe olordll",4) == "hello world"
37
+
38
+
39
+ def test_cycle_list():
40
+ assert cycle_list(3, 4) == [3, 0, 1, 2]
41
+ assert cycle_list(-1, 4) == [3, 0, 1, 2]
42
+ assert cycle_list(1, 4) == [1, 2, 3, 0]
43
+
44
+
45
+ def test_encipher_shift():
46
+ assert encipher_shift("ABC", 0) == "ABC"
47
+ assert encipher_shift("ABC", 1) == "BCD"
48
+ assert encipher_shift("ABC", -1) == "ZAB"
49
+ assert decipher_shift("ZAB", -1) == "ABC"
50
+
51
+ def test_encipher_rot13():
52
+ assert encipher_rot13("ABC") == "NOP"
53
+ assert encipher_rot13("NOP") == "ABC"
54
+ assert decipher_rot13("ABC") == "NOP"
55
+ assert decipher_rot13("NOP") == "ABC"
56
+
57
+
58
+ def test_encipher_affine():
59
+ assert encipher_affine("ABC", (1, 0)) == "ABC"
60
+ assert encipher_affine("ABC", (1, 1)) == "BCD"
61
+ assert encipher_affine("ABC", (-1, 0)) == "AZY"
62
+ assert encipher_affine("ABC", (-1, 1), symbols="ABCD") == "BAD"
63
+ assert encipher_affine("123", (-1, 1), symbols="1234") == "214"
64
+ assert encipher_affine("ABC", (3, 16)) == "QTW"
65
+ assert decipher_affine("QTW", (3, 16)) == "ABC"
66
+
67
+ def test_encipher_atbash():
68
+ assert encipher_atbash("ABC") == "ZYX"
69
+ assert encipher_atbash("ZYX") == "ABC"
70
+ assert decipher_atbash("ABC") == "ZYX"
71
+ assert decipher_atbash("ZYX") == "ABC"
72
+
73
+ def test_encipher_substitution():
74
+ assert encipher_substitution("ABC", "BAC", "ABC") == "BAC"
75
+ assert encipher_substitution("123", "1243", "1234") == "124"
76
+
77
+
78
+ def test_check_and_join():
79
+ assert check_and_join("abc") == "abc"
80
+ assert check_and_join(uniq("aaabc")) == "abc"
81
+ assert check_and_join("ab c".split()) == "abc"
82
+ assert check_and_join("abc", "a", filter=True) == "a"
83
+ raises(ValueError, lambda: check_and_join('ab', 'a'))
84
+
85
+
86
+ def test_encipher_vigenere():
87
+ assert encipher_vigenere("ABC", "ABC") == "ACE"
88
+ assert encipher_vigenere("ABC", "ABC", symbols="ABCD") == "ACA"
89
+ assert encipher_vigenere("ABC", "AB", symbols="ABCD") == "ACC"
90
+ assert encipher_vigenere("AB", "ABC", symbols="ABCD") == "AC"
91
+ assert encipher_vigenere("A", "ABC", symbols="ABCD") == "A"
92
+
93
+
94
+ def test_decipher_vigenere():
95
+ assert decipher_vigenere("ABC", "ABC") == "AAA"
96
+ assert decipher_vigenere("ABC", "ABC", symbols="ABCD") == "AAA"
97
+ assert decipher_vigenere("ABC", "AB", symbols="ABCD") == "AAC"
98
+ assert decipher_vigenere("AB", "ABC", symbols="ABCD") == "AA"
99
+ assert decipher_vigenere("A", "ABC", symbols="ABCD") == "A"
100
+
101
+
102
+ def test_encipher_hill():
103
+ A = Matrix(2, 2, [1, 2, 3, 5])
104
+ assert encipher_hill("ABCD", A) == "CFIV"
105
+ A = Matrix(2, 2, [1, 0, 0, 1])
106
+ assert encipher_hill("ABCD", A) == "ABCD"
107
+ assert encipher_hill("ABCD", A, symbols="ABCD") == "ABCD"
108
+ A = Matrix(2, 2, [1, 2, 3, 5])
109
+ assert encipher_hill("ABCD", A, symbols="ABCD") == "CBAB"
110
+ assert encipher_hill("AB", A, symbols="ABCD") == "CB"
111
+ # message length, n, does not need to be a multiple of k;
112
+ # it is padded
113
+ assert encipher_hill("ABA", A) == "CFGC"
114
+ assert encipher_hill("ABA", A, pad="Z") == "CFYV"
115
+
116
+
117
+ def test_decipher_hill():
118
+ A = Matrix(2, 2, [1, 2, 3, 5])
119
+ assert decipher_hill("CFIV", A) == "ABCD"
120
+ A = Matrix(2, 2, [1, 0, 0, 1])
121
+ assert decipher_hill("ABCD", A) == "ABCD"
122
+ assert decipher_hill("ABCD", A, symbols="ABCD") == "ABCD"
123
+ A = Matrix(2, 2, [1, 2, 3, 5])
124
+ assert decipher_hill("CBAB", A, symbols="ABCD") == "ABCD"
125
+ assert decipher_hill("CB", A, symbols="ABCD") == "AB"
126
+ # n does not need to be a multiple of k
127
+ assert decipher_hill("CFA", A) == "ABAA"
128
+
129
+
130
+ def test_encipher_bifid5():
131
+ assert encipher_bifid5("AB", "AB") == "AB"
132
+ assert encipher_bifid5("AB", "CD") == "CO"
133
+ assert encipher_bifid5("ab", "c") == "CH"
134
+ assert encipher_bifid5("a bc", "b") == "BAC"
135
+
136
+
137
+ def test_bifid5_square():
138
+ A = bifid5
139
+ f = lambda i, j: symbols(A[5*i + j])
140
+ M = Matrix(5, 5, f)
141
+ assert bifid5_square("") == M
142
+
143
+
144
+ def test_decipher_bifid5():
145
+ assert decipher_bifid5("AB", "AB") == "AB"
146
+ assert decipher_bifid5("CO", "CD") == "AB"
147
+ assert decipher_bifid5("ch", "c") == "AB"
148
+ assert decipher_bifid5("b ac", "b") == "ABC"
149
+
150
+
151
+ def test_encipher_bifid6():
152
+ assert encipher_bifid6("AB", "AB") == "AB"
153
+ assert encipher_bifid6("AB", "CD") == "CP"
154
+ assert encipher_bifid6("ab", "c") == "CI"
155
+ assert encipher_bifid6("a bc", "b") == "BAC"
156
+
157
+
158
+ def test_decipher_bifid6():
159
+ assert decipher_bifid6("AB", "AB") == "AB"
160
+ assert decipher_bifid6("CP", "CD") == "AB"
161
+ assert decipher_bifid6("ci", "c") == "AB"
162
+ assert decipher_bifid6("b ac", "b") == "ABC"
163
+
164
+
165
+ def test_bifid6_square():
166
+ A = bifid6
167
+ f = lambda i, j: symbols(A[6*i + j])
168
+ M = Matrix(6, 6, f)
169
+ assert bifid6_square("") == M
170
+
171
+
172
+ def test_rsa_public_key():
173
+ assert rsa_public_key(2, 3, 1) == (6, 1)
174
+ assert rsa_public_key(5, 3, 3) == (15, 3)
175
+
176
+ with warns(NonInvertibleCipherWarning):
177
+ assert rsa_public_key(2, 2, 1) == (4, 1)
178
+ assert rsa_public_key(8, 8, 8) is False
179
+
180
+
181
+ def test_rsa_private_key():
182
+ assert rsa_private_key(2, 3, 1) == (6, 1)
183
+ assert rsa_private_key(5, 3, 3) == (15, 3)
184
+ assert rsa_private_key(23,29,5) == (667,493)
185
+
186
+ with warns(NonInvertibleCipherWarning):
187
+ assert rsa_private_key(2, 2, 1) == (4, 1)
188
+ assert rsa_private_key(8, 8, 8) is False
189
+
190
+
191
+ def test_rsa_large_key():
192
+ # Sample from
193
+ # http://www.herongyang.com/Cryptography/JCE-Public-Key-RSA-Private-Public-Key-Pair-Sample.html
194
+ p = int('101565610013301240713207239558950144682174355406589305284428666'\
195
+ '903702505233009')
196
+ q = int('894687191887545488935455605955948413812376003053143521429242133'\
197
+ '12069293984003')
198
+ e = int('65537')
199
+ d = int('893650581832704239530398858744759129594796235440844479456143566'\
200
+ '6999402846577625762582824202269399672579058991442587406384754958587'\
201
+ '400493169361356902030209')
202
+ assert rsa_public_key(p, q, e) == (p*q, e)
203
+ assert rsa_private_key(p, q, e) == (p*q, d)
204
+
205
+
206
+ def test_encipher_rsa():
207
+ puk = rsa_public_key(2, 3, 1)
208
+ assert encipher_rsa(2, puk) == 2
209
+ puk = rsa_public_key(5, 3, 3)
210
+ assert encipher_rsa(2, puk) == 8
211
+
212
+ with warns(NonInvertibleCipherWarning):
213
+ puk = rsa_public_key(2, 2, 1)
214
+ assert encipher_rsa(2, puk) == 2
215
+
216
+
217
+ def test_decipher_rsa():
218
+ prk = rsa_private_key(2, 3, 1)
219
+ assert decipher_rsa(2, prk) == 2
220
+ prk = rsa_private_key(5, 3, 3)
221
+ assert decipher_rsa(8, prk) == 2
222
+
223
+ with warns(NonInvertibleCipherWarning):
224
+ prk = rsa_private_key(2, 2, 1)
225
+ assert decipher_rsa(2, prk) == 2
226
+
227
+
228
+ def test_mutltiprime_rsa_full_example():
229
+ # Test example from
230
+ # https://iopscience.iop.org/article/10.1088/1742-6596/995/1/012030
231
+ puk = rsa_public_key(2, 3, 5, 7, 11, 13, 7)
232
+ prk = rsa_private_key(2, 3, 5, 7, 11, 13, 7)
233
+ assert puk == (30030, 7)
234
+ assert prk == (30030, 823)
235
+
236
+ msg = 10
237
+ encrypted = encipher_rsa(2 * msg - 15, puk)
238
+ assert encrypted == 18065
239
+ decrypted = (decipher_rsa(encrypted, prk) + 15) / 2
240
+ assert decrypted == msg
241
+
242
+ # Test example from
243
+ # https://www.scirp.org/pdf/JCC_2018032215502008.pdf
244
+ puk1 = rsa_public_key(53, 41, 43, 47, 41)
245
+ prk1 = rsa_private_key(53, 41, 43, 47, 41)
246
+ puk2 = rsa_public_key(53, 41, 43, 47, 97)
247
+ prk2 = rsa_private_key(53, 41, 43, 47, 97)
248
+
249
+ assert puk1 == (4391633, 41)
250
+ assert prk1 == (4391633, 294041)
251
+ assert puk2 == (4391633, 97)
252
+ assert prk2 == (4391633, 455713)
253
+
254
+ msg = 12321
255
+ encrypted = encipher_rsa(encipher_rsa(msg, puk1), puk2)
256
+ assert encrypted == 1081588
257
+ decrypted = decipher_rsa(decipher_rsa(encrypted, prk2), prk1)
258
+ assert decrypted == msg
259
+
260
+
261
+ def test_rsa_crt_extreme():
262
+ p = int(
263
+ '10177157607154245068023861503693082120906487143725062283406501' \
264
+ '54082258226204046999838297167140821364638180697194879500245557' \
265
+ '65445186962893346463841419427008800341257468600224049986260471' \
266
+ '92257248163014468841725476918639415726709736077813632961290911' \
267
+ '0256421232977833028677441206049309220354796014376698325101693')
268
+
269
+ q = int(
270
+ '28752342353095132872290181526607275886182793241660805077850801' \
271
+ '75689512797754286972952273553128181861830576836289738668745250' \
272
+ '34028199691128870676414118458442900035778874482624765513861643' \
273
+ '27966696316822188398336199002306588703902894100476186823849595' \
274
+ '103239410527279605442148285816149368667083114802852804976893')
275
+
276
+ r = int(
277
+ '17698229259868825776879500736350186838850961935956310134378261' \
278
+ '89771862186717463067541369694816245225291921138038800171125596' \
279
+ '07315449521981157084370187887650624061033066022458512942411841' \
280
+ '18747893789972315277160085086164119879536041875335384844820566' \
281
+ '0287479617671726408053319619892052000850883994343378882717849')
282
+
283
+ s = int(
284
+ '68925428438585431029269182233502611027091755064643742383515623' \
285
+ '64321310582896893395529367074942808353187138794422745718419645' \
286
+ '28291231865157212604266903677599180789896916456120289112752835' \
287
+ '98502265889669730331688206825220074713977607415178738015831030' \
288
+ '364290585369150502819743827343552098197095520550865360159439'
289
+ )
290
+
291
+ t = int(
292
+ '69035483433453632820551311892368908779778144568711455301541094' \
293
+ '31487047642322695357696860925747923189635033183069823820910521' \
294
+ '71172909106797748883261493224162414050106920442445896819806600' \
295
+ '15448444826108008217972129130625571421904893252804729877353352' \
296
+ '739420480574842850202181462656251626522910618936534699566291'
297
+ )
298
+
299
+ e = 65537
300
+ puk = rsa_public_key(p, q, r, s, t, e)
301
+ prk = rsa_private_key(p, q, r, s, t, e)
302
+
303
+ plaintext = 1000
304
+ ciphertext_1 = encipher_rsa(plaintext, puk)
305
+ ciphertext_2 = encipher_rsa(plaintext, puk, [p, q, r, s, t])
306
+ assert ciphertext_1 == ciphertext_2
307
+ assert decipher_rsa(ciphertext_1, prk) == \
308
+ decipher_rsa(ciphertext_1, prk, [p, q, r, s, t])
309
+
310
+
311
+ def test_rsa_exhaustive():
312
+ p, q = 61, 53
313
+ e = 17
314
+ puk = rsa_public_key(p, q, e, totient='Carmichael')
315
+ prk = rsa_private_key(p, q, e, totient='Carmichael')
316
+
317
+ for msg in range(puk[0]):
318
+ encrypted = encipher_rsa(msg, puk)
319
+ decrypted = decipher_rsa(encrypted, prk)
320
+ try:
321
+ assert decrypted == msg
322
+ except AssertionError:
323
+ raise AssertionError(
324
+ "The RSA is not correctly decrypted " \
325
+ "(Original : {}, Encrypted : {}, Decrypted : {})" \
326
+ .format(msg, encrypted, decrypted)
327
+ )
328
+
329
+
330
+ def test_rsa_multiprime_exhanstive():
331
+ primes = [3, 5, 7, 11]
332
+ e = 7
333
+ args = primes + [e]
334
+ puk = rsa_public_key(*args, totient='Carmichael')
335
+ prk = rsa_private_key(*args, totient='Carmichael')
336
+ n = puk[0]
337
+
338
+ for msg in range(n):
339
+ encrypted = encipher_rsa(msg, puk)
340
+ decrypted = decipher_rsa(encrypted, prk)
341
+ try:
342
+ assert decrypted == msg
343
+ except AssertionError:
344
+ raise AssertionError(
345
+ "The RSA is not correctly decrypted " \
346
+ "(Original : {}, Encrypted : {}, Decrypted : {})" \
347
+ .format(msg, encrypted, decrypted)
348
+ )
349
+
350
+
351
+ def test_rsa_multipower_exhanstive():
352
+ primes = [5, 5, 7]
353
+ e = 7
354
+ args = primes + [e]
355
+ puk = rsa_public_key(*args, multipower=True)
356
+ prk = rsa_private_key(*args, multipower=True)
357
+ n = puk[0]
358
+
359
+ for msg in range(n):
360
+ if gcd(msg, n) != 1:
361
+ continue
362
+
363
+ encrypted = encipher_rsa(msg, puk)
364
+ decrypted = decipher_rsa(encrypted, prk)
365
+ try:
366
+ assert decrypted == msg
367
+ except AssertionError:
368
+ raise AssertionError(
369
+ "The RSA is not correctly decrypted " \
370
+ "(Original : {}, Encrypted : {}, Decrypted : {})" \
371
+ .format(msg, encrypted, decrypted)
372
+ )
373
+
374
+
375
+ def test_kid_rsa_public_key():
376
+ assert kid_rsa_public_key(1, 2, 1, 1) == (5, 2)
377
+ assert kid_rsa_public_key(1, 2, 2, 1) == (8, 3)
378
+ assert kid_rsa_public_key(1, 2, 1, 2) == (7, 2)
379
+
380
+
381
+ def test_kid_rsa_private_key():
382
+ assert kid_rsa_private_key(1, 2, 1, 1) == (5, 3)
383
+ assert kid_rsa_private_key(1, 2, 2, 1) == (8, 3)
384
+ assert kid_rsa_private_key(1, 2, 1, 2) == (7, 4)
385
+
386
+
387
+ def test_encipher_kid_rsa():
388
+ assert encipher_kid_rsa(1, (5, 2)) == 2
389
+ assert encipher_kid_rsa(1, (8, 3)) == 3
390
+ assert encipher_kid_rsa(1, (7, 2)) == 2
391
+
392
+
393
+ def test_decipher_kid_rsa():
394
+ assert decipher_kid_rsa(2, (5, 3)) == 1
395
+ assert decipher_kid_rsa(3, (8, 3)) == 1
396
+ assert decipher_kid_rsa(2, (7, 4)) == 1
397
+
398
+
399
+ def test_encode_morse():
400
+ assert encode_morse('ABC') == '.-|-...|-.-.'
401
+ assert encode_morse('SMS ') == '...|--|...||'
402
+ assert encode_morse('SMS\n') == '...|--|...||'
403
+ assert encode_morse('') == ''
404
+ assert encode_morse(' ') == '||'
405
+ assert encode_morse(' ', sep='`') == '``'
406
+ assert encode_morse(' ', sep='``') == '````'
407
+ assert encode_morse('!@#$%^&*()_+') == '-.-.--|.--.-.|...-..-|-.--.|-.--.-|..--.-|.-.-.'
408
+ assert encode_morse('12345') == '.----|..---|...--|....-|.....'
409
+ assert encode_morse('67890') == '-....|--...|---..|----.|-----'
410
+
411
+
412
+ def test_decode_morse():
413
+ assert decode_morse('-.-|.|-.--') == 'KEY'
414
+ assert decode_morse('.-.|..-|-.||') == 'RUN'
415
+ raises(KeyError, lambda: decode_morse('.....----'))
416
+
417
+
418
+ def test_lfsr_sequence():
419
+ raises(TypeError, lambda: lfsr_sequence(1, [1], 1))
420
+ raises(TypeError, lambda: lfsr_sequence([1], 1, 1))
421
+ F = FF(2)
422
+ assert lfsr_sequence([F(1)], [F(1)], 2) == [F(1), F(1)]
423
+ assert lfsr_sequence([F(0)], [F(1)], 2) == [F(1), F(0)]
424
+ F = FF(3)
425
+ assert lfsr_sequence([F(1)], [F(1)], 2) == [F(1), F(1)]
426
+ assert lfsr_sequence([F(0)], [F(2)], 2) == [F(2), F(0)]
427
+ assert lfsr_sequence([F(1)], [F(2)], 2) == [F(2), F(2)]
428
+
429
+
430
+ def test_lfsr_autocorrelation():
431
+ raises(TypeError, lambda: lfsr_autocorrelation(1, 2, 3))
432
+ F = FF(2)
433
+ s = lfsr_sequence([F(1), F(0)], [F(0), F(1)], 5)
434
+ assert lfsr_autocorrelation(s, 2, 0) == 1
435
+ assert lfsr_autocorrelation(s, 2, 1) == -1
436
+
437
+
438
+ def test_lfsr_connection_polynomial():
439
+ F = FF(2)
440
+ x = symbols("x")
441
+ s = lfsr_sequence([F(1), F(0)], [F(0), F(1)], 5)
442
+ assert lfsr_connection_polynomial(s) == x**2 + 1
443
+ s = lfsr_sequence([F(1), F(1)], [F(0), F(1)], 5)
444
+ assert lfsr_connection_polynomial(s) == x**2 + x + 1
445
+
446
+
447
+ def test_elgamal_private_key():
448
+ a, b, _ = elgamal_private_key(digit=100)
449
+ assert isprime(a)
450
+ assert is_primitive_root(b, a)
451
+ assert len(bin(a)) >= 102
452
+
453
+
454
+ def test_elgamal():
455
+ dk = elgamal_private_key(5)
456
+ ek = elgamal_public_key(dk)
457
+ P = ek[0]
458
+ assert P - 1 == decipher_elgamal(encipher_elgamal(P - 1, ek), dk)
459
+ raises(ValueError, lambda: encipher_elgamal(P, dk))
460
+ raises(ValueError, lambda: encipher_elgamal(-1, dk))
461
+
462
+
463
+ def test_dh_private_key():
464
+ p, g, _ = dh_private_key(digit = 100)
465
+ assert isprime(p)
466
+ assert is_primitive_root(g, p)
467
+ assert len(bin(p)) >= 102
468
+
469
+
470
+ def test_dh_public_key():
471
+ p1, g1, a = dh_private_key(digit = 100)
472
+ p2, g2, ga = dh_public_key((p1, g1, a))
473
+ assert p1 == p2
474
+ assert g1 == g2
475
+ assert ga == pow(g1, a, p1)
476
+
477
+
478
+ def test_dh_shared_key():
479
+ prk = dh_private_key(digit = 100)
480
+ p, _, ga = dh_public_key(prk)
481
+ b = randrange(2, p)
482
+ sk = dh_shared_key((p, _, ga), b)
483
+ assert sk == pow(ga, b, p)
484
+ raises(ValueError, lambda: dh_shared_key((1031, 14, 565), 2000))
485
+
486
+
487
+ def test_padded_key():
488
+ assert padded_key('b', 'ab') == 'ba'
489
+ raises(ValueError, lambda: padded_key('ab', 'ace'))
490
+ raises(ValueError, lambda: padded_key('ab', 'abba'))
491
+
492
+
493
+ def test_bifid():
494
+ raises(ValueError, lambda: encipher_bifid('abc', 'b', 'abcde'))
495
+ assert encipher_bifid('abc', 'b', 'abcd') == 'bdb'
496
+ raises(ValueError, lambda: decipher_bifid('bdb', 'b', 'abcde'))
497
+ assert encipher_bifid('bdb', 'b', 'abcd') == 'abc'
498
+ raises(ValueError, lambda: bifid_square('abcde'))
499
+ assert bifid5_square("B") == \
500
+ bifid5_square('BACDEFGHIKLMNOPQRSTUVWXYZ')
501
+ assert bifid6_square('B0') == \
502
+ bifid6_square('B0ACDEFGHIJKLMNOPQRSTUVWXYZ123456789')
503
+
504
+
505
+ def test_encipher_decipher_gm():
506
+ ps = [131, 137, 139, 149, 151, 157, 163, 167,
507
+ 173, 179, 181, 191, 193, 197, 199]
508
+ qs = [89, 97, 101, 103, 107, 109, 113, 127,
509
+ 131, 137, 139, 149, 151, 157, 47]
510
+ messages = [
511
+ 0, 32855, 34303, 14805, 1280, 75859, 38368,
512
+ 724, 60356, 51675, 76697, 61854, 18661,
513
+ ]
514
+ for p, q in zip(ps, qs):
515
+ pri = gm_private_key(p, q)
516
+ for msg in messages:
517
+ pub = gm_public_key(p, q)
518
+ enc = encipher_gm(msg, pub)
519
+ dec = decipher_gm(enc, pri)
520
+ assert dec == msg
521
+
522
+
523
+ def test_gm_private_key():
524
+ raises(ValueError, lambda: gm_public_key(13, 15))
525
+ raises(ValueError, lambda: gm_public_key(0, 0))
526
+ raises(ValueError, lambda: gm_public_key(0, 5))
527
+ assert 17, 19 == gm_public_key(17, 19)
528
+
529
+
530
+ def test_gm_public_key():
531
+ assert 323 == gm_public_key(17, 19)[1]
532
+ assert 15 == gm_public_key(3, 5)[1]
533
+ raises(ValueError, lambda: gm_public_key(15, 19))
534
+
535
+ def test_encipher_decipher_bg():
536
+ ps = [67, 7, 71, 103, 11, 43, 107, 47,
537
+ 79, 19, 83, 23, 59, 127, 31]
538
+ qs = qs = [7, 71, 103, 11, 43, 107, 47,
539
+ 79, 19, 83, 23, 59, 127, 31, 67]
540
+ messages = [
541
+ 0, 328, 343, 148, 1280, 758, 383,
542
+ 724, 603, 516, 766, 618, 186,
543
+ ]
544
+
545
+ for p, q in zip(ps, qs):
546
+ pri = bg_private_key(p, q)
547
+ for msg in messages:
548
+ pub = bg_public_key(p, q)
549
+ enc = encipher_bg(msg, pub)
550
+ dec = decipher_bg(enc, pri)
551
+ assert dec == msg
552
+
553
+ def test_bg_private_key():
554
+ raises(ValueError, lambda: bg_private_key(8, 16))
555
+ raises(ValueError, lambda: bg_private_key(8, 8))
556
+ raises(ValueError, lambda: bg_private_key(13, 17))
557
+ assert 23, 31 == bg_private_key(23, 31)
558
+
559
+ def test_bg_public_key():
560
+ assert 5293 == bg_public_key(67, 79)
561
+ assert 713 == bg_public_key(23, 31)
562
+ raises(ValueError, lambda: bg_private_key(13, 17))
lib/python3.12/site-packages/sympy/external/__init__.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Unified place for determining if external dependencies are installed or not.
3
+
4
+ You should import all external modules using the import_module() function.
5
+
6
+ For example
7
+
8
+ >>> from sympy.external import import_module
9
+ >>> numpy = import_module('numpy')
10
+
11
+ If the resulting library is not installed, or if the installed version
12
+ is less than a given minimum version, the function will return None.
13
+ Otherwise, it will return the library. See the docstring of
14
+ import_module() for more information.
15
+
16
+ """
17
+
18
+ from sympy.external.importtools import import_module
19
+
20
+ __all__ = ['import_module']
lib/python3.12/site-packages/sympy/external/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (801 Bytes). View file
 
lib/python3.12/site-packages/sympy/external/__pycache__/gmpy.cpython-312.pyc ADDED
Binary file (7.96 kB). View file
 
lib/python3.12/site-packages/sympy/external/__pycache__/importtools.cpython-312.pyc ADDED
Binary file (6.85 kB). View file
 
lib/python3.12/site-packages/sympy/external/__pycache__/ntheory.cpython-312.pyc ADDED
Binary file (20.9 kB). View file
 
lib/python3.12/site-packages/sympy/external/__pycache__/pythonmpq.cpython-312.pyc ADDED
Binary file (14.2 kB). View file
 
lib/python3.12/site-packages/sympy/external/gmpy.py ADDED
@@ -0,0 +1,341 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from ctypes import c_long, sizeof
3
+ from functools import reduce
4
+ from typing import Tuple as tTuple, Type
5
+ from warnings import warn
6
+
7
+ from sympy.external import import_module
8
+
9
+ from .pythonmpq import PythonMPQ
10
+
11
+ from .ntheory import (
12
+ bit_scan1 as python_bit_scan1,
13
+ bit_scan0 as python_bit_scan0,
14
+ remove as python_remove,
15
+ factorial as python_factorial,
16
+ sqrt as python_sqrt,
17
+ sqrtrem as python_sqrtrem,
18
+ gcd as python_gcd,
19
+ lcm as python_lcm,
20
+ gcdext as python_gcdext,
21
+ is_square as python_is_square,
22
+ invert as python_invert,
23
+ legendre as python_legendre,
24
+ jacobi as python_jacobi,
25
+ kronecker as python_kronecker,
26
+ iroot as python_iroot,
27
+ is_fermat_prp as python_is_fermat_prp,
28
+ is_euler_prp as python_is_euler_prp,
29
+ is_strong_prp as python_is_strong_prp,
30
+ is_fibonacci_prp as python_is_fibonacci_prp,
31
+ is_lucas_prp as python_is_lucas_prp,
32
+ is_selfridge_prp as python_is_selfridge_prp,
33
+ is_strong_lucas_prp as python_is_strong_lucas_prp,
34
+ is_strong_selfridge_prp as python_is_strong_selfridge_prp,
35
+ is_bpsw_prp as python_is_bpsw_prp,
36
+ is_strong_bpsw_prp as python_is_strong_bpsw_prp,
37
+ )
38
+
39
+
40
+ __all__ = [
41
+ # GROUND_TYPES is either 'gmpy' or 'python' depending on which is used. If
42
+ # gmpy is installed then it will be used unless the environment variable
43
+ # SYMPY_GROUND_TYPES is set to something other than 'auto', 'gmpy', or
44
+ # 'gmpy2'.
45
+ 'GROUND_TYPES',
46
+
47
+ # If HAS_GMPY is 0, no supported version of gmpy is available. Otherwise,
48
+ # HAS_GMPY will be 2 for gmpy2 if GROUND_TYPES is 'gmpy'. It used to be
49
+ # possible for HAS_GMPY to be 1 for gmpy but gmpy is no longer supported.
50
+ 'HAS_GMPY',
51
+
52
+ # SYMPY_INTS is a tuple containing the base types for valid integer types.
53
+ # This is either (int,) or (int, type(mpz(0))) depending on GROUND_TYPES.
54
+ 'SYMPY_INTS',
55
+
56
+ # MPQ is either gmpy.mpq or the Python equivalent from
57
+ # sympy.external.pythonmpq
58
+ 'MPQ',
59
+
60
+ # MPZ is either gmpy.mpz or int.
61
+ 'MPZ',
62
+
63
+ 'bit_scan1',
64
+ 'bit_scan0',
65
+ 'remove',
66
+ 'factorial',
67
+ 'sqrt',
68
+ 'is_square',
69
+ 'sqrtrem',
70
+ 'gcd',
71
+ 'lcm',
72
+ 'gcdext',
73
+ 'invert',
74
+ 'legendre',
75
+ 'jacobi',
76
+ 'kronecker',
77
+ 'iroot',
78
+ 'is_fermat_prp',
79
+ 'is_euler_prp',
80
+ 'is_strong_prp',
81
+ 'is_fibonacci_prp',
82
+ 'is_lucas_prp',
83
+ 'is_selfridge_prp',
84
+ 'is_strong_lucas_prp',
85
+ 'is_strong_selfridge_prp',
86
+ 'is_bpsw_prp',
87
+ 'is_strong_bpsw_prp',
88
+ ]
89
+
90
+
91
+ #
92
+ # Tested python-flint version. Future versions might work but we will only use
93
+ # them if explicitly requested by SYMPY_GROUND_TYPES=flint.
94
+ #
95
+ _PYTHON_FLINT_VERSION_NEEDED = ["0.6", "0.7", "0.8", "0.9"]
96
+
97
+
98
+ def _flint_version_okay(flint_version):
99
+ major, minor = flint_version.split('.')[:2]
100
+ flint_ver = f'{major}.{minor}'
101
+ return flint_ver in _PYTHON_FLINT_VERSION_NEEDED
102
+
103
+ #
104
+ # We will only use gmpy2 >= 2.0.0
105
+ #
106
+ _GMPY2_MIN_VERSION = '2.0.0'
107
+
108
+
109
+ def _get_flint(sympy_ground_types):
110
+ if sympy_ground_types not in ('auto', 'flint'):
111
+ return None
112
+
113
+ try:
114
+ import flint
115
+ # Earlier versions of python-flint may not have __version__.
116
+ from flint import __version__ as _flint_version
117
+ except ImportError:
118
+ if sympy_ground_types == 'flint':
119
+ warn("SYMPY_GROUND_TYPES was set to flint but python-flint is not "
120
+ "installed. Falling back to other ground types.")
121
+ return None
122
+
123
+ if _flint_version_okay(_flint_version):
124
+ return flint
125
+ elif sympy_ground_types == 'auto':
126
+ return None
127
+ else:
128
+ warn(f"Using python-flint {_flint_version} because SYMPY_GROUND_TYPES "
129
+ f"is set to flint but this version of SymPy is only tested "
130
+ f"with python-flint versions {_PYTHON_FLINT_VERSION_NEEDED}.")
131
+ return flint
132
+
133
+
134
+ def _get_gmpy2(sympy_ground_types):
135
+ if sympy_ground_types not in ('auto', 'gmpy', 'gmpy2'):
136
+ return None
137
+
138
+ gmpy = import_module('gmpy2', min_module_version=_GMPY2_MIN_VERSION,
139
+ module_version_attr='version', module_version_attr_call_args=())
140
+
141
+ if sympy_ground_types != 'auto' and gmpy is None:
142
+ warn("gmpy2 library is not installed, switching to 'python' ground types")
143
+
144
+ return gmpy
145
+
146
+
147
+ #
148
+ # SYMPY_GROUND_TYPES can be flint, gmpy, gmpy2, python or auto (default)
149
+ #
150
+ _SYMPY_GROUND_TYPES = os.environ.get('SYMPY_GROUND_TYPES', 'auto').lower()
151
+ _flint = None
152
+ _gmpy = None
153
+
154
+ #
155
+ # First handle auto-detection of flint/gmpy2. We will prefer flint if available
156
+ # or otherwise gmpy2 if available and then lastly the python types.
157
+ #
158
+ if _SYMPY_GROUND_TYPES in ('auto', 'flint'):
159
+ _flint = _get_flint(_SYMPY_GROUND_TYPES)
160
+ if _flint is not None:
161
+ _SYMPY_GROUND_TYPES = 'flint'
162
+ else:
163
+ _SYMPY_GROUND_TYPES = 'auto'
164
+
165
+ if _SYMPY_GROUND_TYPES in ('auto', 'gmpy', 'gmpy2'):
166
+ _gmpy = _get_gmpy2(_SYMPY_GROUND_TYPES)
167
+ if _gmpy is not None:
168
+ _SYMPY_GROUND_TYPES = 'gmpy'
169
+ else:
170
+ _SYMPY_GROUND_TYPES = 'python'
171
+
172
+ if _SYMPY_GROUND_TYPES not in ('flint', 'gmpy', 'python'):
173
+ warn("SYMPY_GROUND_TYPES environment variable unrecognised. "
174
+ "Should be 'auto', 'flint', 'gmpy', 'gmpy2' or 'python'.")
175
+ _SYMPY_GROUND_TYPES = 'python'
176
+
177
+ #
178
+ # At this point _SYMPY_GROUND_TYPES is either flint, gmpy or python. The blocks
179
+ # below define the values exported by this module in each case.
180
+ #
181
+
182
+ #
183
+ # In gmpy2 and flint, there are functions that take a long (or unsigned long)
184
+ # argument. That is, it is not possible to input a value larger than that.
185
+ #
186
+ LONG_MAX = (1 << (8*sizeof(c_long) - 1)) - 1
187
+
188
+ #
189
+ # Type checkers are confused by what SYMPY_INTS is. There may be a better type
190
+ # hint for this like Type[Integral] or something.
191
+ #
192
+ SYMPY_INTS: tTuple[Type, ...]
193
+
194
+ if _SYMPY_GROUND_TYPES == 'gmpy':
195
+
196
+ assert _gmpy is not None
197
+
198
+ flint = None
199
+ gmpy = _gmpy
200
+
201
+ HAS_GMPY = 2
202
+ GROUND_TYPES = 'gmpy'
203
+ SYMPY_INTS = (int, type(gmpy.mpz(0)))
204
+ MPZ = gmpy.mpz
205
+ MPQ = gmpy.mpq
206
+
207
+ bit_scan1 = gmpy.bit_scan1
208
+ bit_scan0 = gmpy.bit_scan0
209
+ remove = gmpy.remove
210
+ factorial = gmpy.fac
211
+ sqrt = gmpy.isqrt
212
+ is_square = gmpy.is_square
213
+ sqrtrem = gmpy.isqrt_rem
214
+ gcd = gmpy.gcd
215
+ lcm = gmpy.lcm
216
+ gcdext = gmpy.gcdext
217
+ invert = gmpy.invert
218
+ legendre = gmpy.legendre
219
+ jacobi = gmpy.jacobi
220
+ kronecker = gmpy.kronecker
221
+
222
+ def iroot(x, n):
223
+ # In the latest gmpy2, the threshold for n is ULONG_MAX,
224
+ # but adjust to the older one.
225
+ if n <= LONG_MAX:
226
+ return gmpy.iroot(x, n)
227
+ return python_iroot(x, n)
228
+
229
+ is_fermat_prp = gmpy.is_fermat_prp
230
+ is_euler_prp = gmpy.is_euler_prp
231
+ is_strong_prp = gmpy.is_strong_prp
232
+ is_fibonacci_prp = gmpy.is_fibonacci_prp
233
+ is_lucas_prp = gmpy.is_lucas_prp
234
+ is_selfridge_prp = gmpy.is_selfridge_prp
235
+ is_strong_lucas_prp = gmpy.is_strong_lucas_prp
236
+ is_strong_selfridge_prp = gmpy.is_strong_selfridge_prp
237
+ is_bpsw_prp = gmpy.is_bpsw_prp
238
+ is_strong_bpsw_prp = gmpy.is_strong_bpsw_prp
239
+
240
+ elif _SYMPY_GROUND_TYPES == 'flint':
241
+
242
+ assert _flint is not None
243
+
244
+ flint = _flint
245
+ gmpy = None
246
+
247
+ HAS_GMPY = 0
248
+ GROUND_TYPES = 'flint'
249
+ SYMPY_INTS = (int, flint.fmpz) # type: ignore
250
+ MPZ = flint.fmpz # type: ignore
251
+ MPQ = flint.fmpq # type: ignore
252
+
253
+ bit_scan1 = python_bit_scan1
254
+ bit_scan0 = python_bit_scan0
255
+ remove = python_remove
256
+ factorial = python_factorial
257
+
258
+ def sqrt(x):
259
+ return flint.fmpz(x).isqrt()
260
+
261
+ def is_square(x):
262
+ if x < 0:
263
+ return False
264
+ return flint.fmpz(x).sqrtrem()[1] == 0
265
+
266
+ def sqrtrem(x):
267
+ return flint.fmpz(x).sqrtrem()
268
+
269
+ def gcd(*args):
270
+ return reduce(flint.fmpz.gcd, args, flint.fmpz(0))
271
+
272
+ def lcm(*args):
273
+ return reduce(flint.fmpz.lcm, args, flint.fmpz(1))
274
+
275
+ gcdext = python_gcdext
276
+ invert = python_invert
277
+ legendre = python_legendre
278
+
279
+ def jacobi(x, y):
280
+ if y <= 0 or not y % 2:
281
+ raise ValueError("y should be an odd positive integer")
282
+ return flint.fmpz(x).jacobi(y)
283
+
284
+ kronecker = python_kronecker
285
+
286
+ def iroot(x, n):
287
+ if n <= LONG_MAX:
288
+ y = flint.fmpz(x).root(n)
289
+ return y, y**n == x
290
+ return python_iroot(x, n)
291
+
292
+ is_fermat_prp = python_is_fermat_prp
293
+ is_euler_prp = python_is_euler_prp
294
+ is_strong_prp = python_is_strong_prp
295
+ is_fibonacci_prp = python_is_fibonacci_prp
296
+ is_lucas_prp = python_is_lucas_prp
297
+ is_selfridge_prp = python_is_selfridge_prp
298
+ is_strong_lucas_prp = python_is_strong_lucas_prp
299
+ is_strong_selfridge_prp = python_is_strong_selfridge_prp
300
+ is_bpsw_prp = python_is_bpsw_prp
301
+ is_strong_bpsw_prp = python_is_strong_bpsw_prp
302
+
303
+ elif _SYMPY_GROUND_TYPES == 'python':
304
+
305
+ flint = None
306
+ gmpy = None
307
+
308
+ HAS_GMPY = 0
309
+ GROUND_TYPES = 'python'
310
+ SYMPY_INTS = (int,)
311
+ MPZ = int
312
+ MPQ = PythonMPQ
313
+
314
+ bit_scan1 = python_bit_scan1
315
+ bit_scan0 = python_bit_scan0
316
+ remove = python_remove
317
+ factorial = python_factorial
318
+ sqrt = python_sqrt
319
+ is_square = python_is_square
320
+ sqrtrem = python_sqrtrem
321
+ gcd = python_gcd
322
+ lcm = python_lcm
323
+ gcdext = python_gcdext
324
+ invert = python_invert
325
+ legendre = python_legendre
326
+ jacobi = python_jacobi
327
+ kronecker = python_kronecker
328
+ iroot = python_iroot
329
+ is_fermat_prp = python_is_fermat_prp
330
+ is_euler_prp = python_is_euler_prp
331
+ is_strong_prp = python_is_strong_prp
332
+ is_fibonacci_prp = python_is_fibonacci_prp
333
+ is_lucas_prp = python_is_lucas_prp
334
+ is_selfridge_prp = python_is_selfridge_prp
335
+ is_strong_lucas_prp = python_is_strong_lucas_prp
336
+ is_strong_selfridge_prp = python_is_strong_selfridge_prp
337
+ is_bpsw_prp = python_is_bpsw_prp
338
+ is_strong_bpsw_prp = python_is_strong_bpsw_prp
339
+
340
+ else:
341
+ assert False
lib/python3.12/site-packages/sympy/external/importtools.py ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tools to assist importing optional external modules."""
2
+
3
+ import sys
4
+ import re
5
+
6
+ # Override these in the module to change the default warning behavior.
7
+ # For example, you might set both to False before running the tests so that
8
+ # warnings are not printed to the console, or set both to True for debugging.
9
+
10
+ WARN_NOT_INSTALLED = None # Default is False
11
+ WARN_OLD_VERSION = None # Default is True
12
+
13
+
14
+ def __sympy_debug():
15
+ # helper function from sympy/__init__.py
16
+ # We don't just import SYMPY_DEBUG from that file because we don't want to
17
+ # import all of SymPy just to use this module.
18
+ import os
19
+ debug_str = os.getenv('SYMPY_DEBUG', 'False')
20
+ if debug_str in ('True', 'False'):
21
+ return eval(debug_str)
22
+ else:
23
+ raise RuntimeError("unrecognized value for SYMPY_DEBUG: %s" %
24
+ debug_str)
25
+
26
+ if __sympy_debug():
27
+ WARN_OLD_VERSION = True
28
+ WARN_NOT_INSTALLED = True
29
+
30
+
31
+ _component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE)
32
+
33
+ def version_tuple(vstring):
34
+ # Parse a version string to a tuple e.g. '1.2' -> (1, 2)
35
+ # Simplified from distutils.version.LooseVersion which was deprecated in
36
+ # Python 3.10.
37
+ components = []
38
+ for x in _component_re.split(vstring):
39
+ if x and x != '.':
40
+ try:
41
+ x = int(x)
42
+ except ValueError:
43
+ pass
44
+ components.append(x)
45
+ return tuple(components)
46
+
47
+
48
+ def import_module(module, min_module_version=None, min_python_version=None,
49
+ warn_not_installed=None, warn_old_version=None,
50
+ module_version_attr='__version__', module_version_attr_call_args=None,
51
+ import_kwargs={}, catch=()):
52
+ """
53
+ Import and return a module if it is installed.
54
+
55
+ If the module is not installed, it returns None.
56
+
57
+ A minimum version for the module can be given as the keyword argument
58
+ min_module_version. This should be comparable against the module version.
59
+ By default, module.__version__ is used to get the module version. To
60
+ override this, set the module_version_attr keyword argument. If the
61
+ attribute of the module to get the version should be called (e.g.,
62
+ module.version()), then set module_version_attr_call_args to the args such
63
+ that module.module_version_attr(*module_version_attr_call_args) returns the
64
+ module's version.
65
+
66
+ If the module version is less than min_module_version using the Python <
67
+ comparison, None will be returned, even if the module is installed. You can
68
+ use this to keep from importing an incompatible older version of a module.
69
+
70
+ You can also specify a minimum Python version by using the
71
+ min_python_version keyword argument. This should be comparable against
72
+ sys.version_info.
73
+
74
+ If the keyword argument warn_not_installed is set to True, the function will
75
+ emit a UserWarning when the module is not installed.
76
+
77
+ If the keyword argument warn_old_version is set to True, the function will
78
+ emit a UserWarning when the library is installed, but cannot be imported
79
+ because of the min_module_version or min_python_version options.
80
+
81
+ Note that because of the way warnings are handled, a warning will be
82
+ emitted for each module only once. You can change the default warning
83
+ behavior by overriding the values of WARN_NOT_INSTALLED and WARN_OLD_VERSION
84
+ in sympy.external.importtools. By default, WARN_NOT_INSTALLED is False and
85
+ WARN_OLD_VERSION is True.
86
+
87
+ This function uses __import__() to import the module. To pass additional
88
+ options to __import__(), use the import_kwargs keyword argument. For
89
+ example, to import a submodule A.B, you must pass a nonempty fromlist option
90
+ to __import__. See the docstring of __import__().
91
+
92
+ This catches ImportError to determine if the module is not installed. To
93
+ catch additional errors, pass them as a tuple to the catch keyword
94
+ argument.
95
+
96
+ Examples
97
+ ========
98
+
99
+ >>> from sympy.external import import_module
100
+
101
+ >>> numpy = import_module('numpy')
102
+
103
+ >>> numpy = import_module('numpy', min_python_version=(2, 7),
104
+ ... warn_old_version=False)
105
+
106
+ >>> numpy = import_module('numpy', min_module_version='1.5',
107
+ ... warn_old_version=False) # numpy.__version__ is a string
108
+
109
+ >>> # gmpy does not have __version__, but it does have gmpy.version()
110
+
111
+ >>> gmpy = import_module('gmpy', min_module_version='1.14',
112
+ ... module_version_attr='version', module_version_attr_call_args=(),
113
+ ... warn_old_version=False)
114
+
115
+ >>> # To import a submodule, you must pass a nonempty fromlist to
116
+ >>> # __import__(). The values do not matter.
117
+ >>> p3 = import_module('mpl_toolkits.mplot3d',
118
+ ... import_kwargs={'fromlist':['something']})
119
+
120
+ >>> # matplotlib.pyplot can raise RuntimeError when the display cannot be opened
121
+ >>> matplotlib = import_module('matplotlib',
122
+ ... import_kwargs={'fromlist':['pyplot']}, catch=(RuntimeError,))
123
+
124
+ """
125
+ # keyword argument overrides default, and global variable overrides
126
+ # keyword argument.
127
+ warn_old_version = (WARN_OLD_VERSION if WARN_OLD_VERSION is not None
128
+ else warn_old_version or True)
129
+ warn_not_installed = (WARN_NOT_INSTALLED if WARN_NOT_INSTALLED is not None
130
+ else warn_not_installed or False)
131
+
132
+ import warnings
133
+
134
+ # Check Python first so we don't waste time importing a module we can't use
135
+ if min_python_version:
136
+ if sys.version_info < min_python_version:
137
+ if warn_old_version:
138
+ warnings.warn("Python version is too old to use %s "
139
+ "(%s or newer required)" % (
140
+ module, '.'.join(map(str, min_python_version))),
141
+ UserWarning, stacklevel=2)
142
+ return
143
+
144
+ try:
145
+ mod = __import__(module, **import_kwargs)
146
+
147
+ ## there's something funny about imports with matplotlib and py3k. doing
148
+ ## from matplotlib import collections
149
+ ## gives python's stdlib collections module. explicitly re-importing
150
+ ## the module fixes this.
151
+ from_list = import_kwargs.get('fromlist', ())
152
+ for submod in from_list:
153
+ if submod == 'collections' and mod.__name__ == 'matplotlib':
154
+ __import__(module + '.' + submod)
155
+ except ImportError:
156
+ if warn_not_installed:
157
+ warnings.warn("%s module is not installed" % module, UserWarning,
158
+ stacklevel=2)
159
+ return
160
+ except catch as e:
161
+ if warn_not_installed:
162
+ warnings.warn(
163
+ "%s module could not be used (%s)" % (module, repr(e)),
164
+ stacklevel=2)
165
+ return
166
+
167
+ if min_module_version:
168
+ modversion = getattr(mod, module_version_attr)
169
+ if module_version_attr_call_args is not None:
170
+ modversion = modversion(*module_version_attr_call_args)
171
+ if version_tuple(modversion) < version_tuple(min_module_version):
172
+ if warn_old_version:
173
+ # Attempt to create a pretty string version of the version
174
+ if isinstance(min_module_version, str):
175
+ verstr = min_module_version
176
+ elif isinstance(min_module_version, (tuple, list)):
177
+ verstr = '.'.join(map(str, min_module_version))
178
+ else:
179
+ # Either don't know what this is. Hopefully
180
+ # it's something that has a nice str version, like an int.
181
+ verstr = str(min_module_version)
182
+ warnings.warn("%s version is too old to use "
183
+ "(%s or newer required)" % (module, verstr),
184
+ UserWarning, stacklevel=2)
185
+ return
186
+
187
+ return mod
lib/python3.12/site-packages/sympy/external/ntheory.py ADDED
@@ -0,0 +1,637 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # sympy.external.ntheory
2
+ #
3
+ # This module provides pure Python implementations of some number theory
4
+ # functions that are alternately used from gmpy2 if it is installed.
5
+
6
+ import sys
7
+ import math
8
+
9
+ import mpmath.libmp as mlib
10
+
11
+
12
+ _small_trailing = [0] * 256
13
+ for j in range(1, 8):
14
+ _small_trailing[1 << j :: 1 << (j + 1)] = [j] * (1 << (7 - j))
15
+
16
+
17
+ def bit_scan1(x, n=0):
18
+ if not x:
19
+ return
20
+ x = abs(x >> n)
21
+ low_byte = x & 0xFF
22
+ if low_byte:
23
+ return _small_trailing[low_byte] + n
24
+
25
+ t = 8 + n
26
+ x >>= 8
27
+ # 2**m is quick for z up through 2**30
28
+ z = x.bit_length() - 1
29
+ if x == 1 << z:
30
+ return z + t
31
+
32
+ if z < 300:
33
+ # fixed 8-byte reduction
34
+ while not x & 0xFF:
35
+ x >>= 8
36
+ t += 8
37
+ else:
38
+ # binary reduction important when there might be a large
39
+ # number of trailing 0s
40
+ p = z >> 1
41
+ while not x & 0xFF:
42
+ while x & ((1 << p) - 1):
43
+ p >>= 1
44
+ x >>= p
45
+ t += p
46
+ return t + _small_trailing[x & 0xFF]
47
+
48
+
49
+ def bit_scan0(x, n=0):
50
+ return bit_scan1(x + (1 << n), n)
51
+
52
+
53
+ def remove(x, f):
54
+ if f < 2:
55
+ raise ValueError("factor must be > 1")
56
+ if x == 0:
57
+ return 0, 0
58
+ if f == 2:
59
+ b = bit_scan1(x)
60
+ return x >> b, b
61
+ m = 0
62
+ y, rem = divmod(x, f)
63
+ while not rem:
64
+ x = y
65
+ m += 1
66
+ if m > 5:
67
+ pow_list = [f**2]
68
+ while pow_list:
69
+ _f = pow_list[-1]
70
+ y, rem = divmod(x, _f)
71
+ if not rem:
72
+ m += 1 << len(pow_list)
73
+ x = y
74
+ pow_list.append(_f**2)
75
+ else:
76
+ pow_list.pop()
77
+ y, rem = divmod(x, f)
78
+ return x, m
79
+
80
+
81
+ def factorial(x):
82
+ """Return x!."""
83
+ return int(mlib.ifac(int(x)))
84
+
85
+
86
+ def sqrt(x):
87
+ """Integer square root of x."""
88
+ return int(mlib.isqrt(int(x)))
89
+
90
+
91
+ def sqrtrem(x):
92
+ """Integer square root of x and remainder."""
93
+ s, r = mlib.sqrtrem(int(x))
94
+ return (int(s), int(r))
95
+
96
+
97
+ if sys.version_info[:2] >= (3, 9):
98
+ # As of Python 3.9 these can take multiple arguments
99
+ gcd = math.gcd
100
+ lcm = math.lcm
101
+
102
+ else:
103
+ # Until python 3.8 is no longer supported
104
+ from functools import reduce
105
+
106
+
107
+ def gcd(*args):
108
+ """gcd of multiple integers."""
109
+ return reduce(math.gcd, args, 0)
110
+
111
+
112
+ def lcm(*args):
113
+ """lcm of multiple integers."""
114
+ if 0 in args:
115
+ return 0
116
+ return reduce(lambda x, y: x*y//math.gcd(x, y), args, 1)
117
+
118
+
119
+ def _sign(n):
120
+ if n < 0:
121
+ return -1, -n
122
+ return 1, n
123
+
124
+
125
+ def gcdext(a, b):
126
+ if not a or not b:
127
+ g = abs(a) or abs(b)
128
+ if not g:
129
+ return (0, 0, 0)
130
+ return (g, a // g, b // g)
131
+
132
+ x_sign, a = _sign(a)
133
+ y_sign, b = _sign(b)
134
+ x, r = 1, 0
135
+ y, s = 0, 1
136
+
137
+ while b:
138
+ q, c = divmod(a, b)
139
+ a, b = b, c
140
+ x, r = r, x - q*r
141
+ y, s = s, y - q*s
142
+
143
+ return (a, x * x_sign, y * y_sign)
144
+
145
+
146
+ def is_square(x):
147
+ """Return True if x is a square number."""
148
+ if x < 0:
149
+ return False
150
+
151
+ # Note that the possible values of y**2 % n for a given n are limited.
152
+ # For example, when n=4, y**2 % n can only take 0 or 1.
153
+ # In other words, if x % 4 is 2 or 3, then x is not a square number.
154
+ # Mathematically, it determines if it belongs to the set {y**2 % n},
155
+ # but implementationally, it can be realized as a logical conjunction
156
+ # with an n-bit integer.
157
+ # see https://mersenneforum.org/showpost.php?p=110896
158
+ # def magic(n):
159
+ # s = {y**2 % n for y in range(n)}
160
+ # s = set(range(n)) - s
161
+ # return sum(1 << bit for bit in s)
162
+ # >>> print(hex(magic(128)))
163
+ # 0xfdfdfdedfdfdfdecfdfdfdedfdfcfdec
164
+ # >>> print(hex(magic(99)))
165
+ # 0x5f6f9ffb6fb7ddfcb75befdec
166
+ # >>> print(hex(magic(91)))
167
+ # 0x6fd1bfcfed5f3679d3ebdec
168
+ # >>> print(hex(magic(85)))
169
+ # 0xdef9ae771ffe3b9d67dec
170
+ if 0xfdfdfdedfdfdfdecfdfdfdedfdfcfdec & (1 << (x & 127)):
171
+ return False # e.g. 2, 3
172
+ m = x % 765765 # 765765 = 99 * 91 * 85
173
+ if 0x5f6f9ffb6fb7ddfcb75befdec & (1 << (m % 99)):
174
+ return False # e.g. 17, 68
175
+ if 0x6fd1bfcfed5f3679d3ebdec & (1 << (m % 91)):
176
+ return False # e.g. 97, 388
177
+ if 0xdef9ae771ffe3b9d67dec & (1 << (m % 85)):
178
+ return False # e.g. 793, 1408
179
+ return mlib.sqrtrem(int(x))[1] == 0
180
+
181
+
182
+ def invert(x, m):
183
+ """Modular inverse of x modulo m.
184
+
185
+ Returns y such that x*y == 1 mod m.
186
+
187
+ Uses ``math.pow`` but reproduces the behaviour of ``gmpy2.invert``
188
+ which raises ZeroDivisionError if no inverse exists.
189
+ """
190
+ try:
191
+ return pow(x, -1, m)
192
+ except ValueError:
193
+ raise ZeroDivisionError("invert() no inverse exists")
194
+
195
+
196
+ def legendre(x, y):
197
+ """Legendre symbol (x / y).
198
+
199
+ Following the implementation of gmpy2,
200
+ the error is raised only when y is an even number.
201
+ """
202
+ if y <= 0 or not y % 2:
203
+ raise ValueError("y should be an odd prime")
204
+ x %= y
205
+ if not x:
206
+ return 0
207
+ if pow(x, (y - 1) // 2, y) == 1:
208
+ return 1
209
+ return -1
210
+
211
+
212
+ def jacobi(x, y):
213
+ """Jacobi symbol (x / y)."""
214
+ if y <= 0 or not y % 2:
215
+ raise ValueError("y should be an odd positive integer")
216
+ x %= y
217
+ if not x:
218
+ return int(y == 1)
219
+ if y == 1 or x == 1:
220
+ return 1
221
+ if gcd(x, y) != 1:
222
+ return 0
223
+ j = 1
224
+ while x != 0:
225
+ while x % 2 == 0 and x > 0:
226
+ x >>= 1
227
+ if y % 8 in [3, 5]:
228
+ j = -j
229
+ x, y = y, x
230
+ if x % 4 == y % 4 == 3:
231
+ j = -j
232
+ x %= y
233
+ return j
234
+
235
+
236
+ def kronecker(x, y):
237
+ """Kronecker symbol (x / y)."""
238
+ if gcd(x, y) != 1:
239
+ return 0
240
+ if y == 0:
241
+ return 1
242
+ sign = -1 if y < 0 and x < 0 else 1
243
+ y = abs(y)
244
+ s = bit_scan1(y)
245
+ y >>= s
246
+ if s % 2 and x % 8 in [3, 5]:
247
+ sign = -sign
248
+ return sign * jacobi(x, y)
249
+
250
+
251
+ def iroot(y, n):
252
+ if y < 0:
253
+ raise ValueError("y must be nonnegative")
254
+ if n < 1:
255
+ raise ValueError("n must be positive")
256
+ if y in (0, 1):
257
+ return y, True
258
+ if n == 1:
259
+ return y, True
260
+ if n == 2:
261
+ x, rem = mlib.sqrtrem(y)
262
+ return int(x), not rem
263
+ if n >= y.bit_length():
264
+ return 1, False
265
+ # Get initial estimate for Newton's method. Care must be taken to
266
+ # avoid overflow
267
+ try:
268
+ guess = int(y**(1./n) + 0.5)
269
+ except OverflowError:
270
+ exp = math.log2(y)/n
271
+ if exp > 53:
272
+ shift = int(exp - 53)
273
+ guess = int(2.0**(exp - shift) + 1) << shift
274
+ else:
275
+ guess = int(2.0**exp)
276
+ if guess > 2**50:
277
+ # Newton iteration
278
+ xprev, x = -1, guess
279
+ while 1:
280
+ t = x**(n - 1)
281
+ xprev, x = x, ((n - 1)*x + y//t)//n
282
+ if abs(x - xprev) < 2:
283
+ break
284
+ else:
285
+ x = guess
286
+ # Compensate
287
+ t = x**n
288
+ while t < y:
289
+ x += 1
290
+ t = x**n
291
+ while t > y:
292
+ x -= 1
293
+ t = x**n
294
+ return x, t == y
295
+
296
+
297
+ def is_fermat_prp(n, a):
298
+ if a < 2:
299
+ raise ValueError("is_fermat_prp() requires 'a' greater than or equal to 2")
300
+ if n < 1:
301
+ raise ValueError("is_fermat_prp() requires 'n' be greater than 0")
302
+ if n == 1:
303
+ return False
304
+ if n % 2 == 0:
305
+ return n == 2
306
+ a %= n
307
+ if gcd(n, a) != 1:
308
+ raise ValueError("is_fermat_prp() requires gcd(n,a) == 1")
309
+ return pow(a, n - 1, n) == 1
310
+
311
+
312
+ def is_euler_prp(n, a):
313
+ if a < 2:
314
+ raise ValueError("is_euler_prp() requires 'a' greater than or equal to 2")
315
+ if n < 1:
316
+ raise ValueError("is_euler_prp() requires 'n' be greater than 0")
317
+ if n == 1:
318
+ return False
319
+ if n % 2 == 0:
320
+ return n == 2
321
+ a %= n
322
+ if gcd(n, a) != 1:
323
+ raise ValueError("is_euler_prp() requires gcd(n,a) == 1")
324
+ return pow(a, n >> 1, n) == jacobi(a, n) % n
325
+
326
+
327
+ def _is_strong_prp(n, a):
328
+ s = bit_scan1(n - 1)
329
+ a = pow(a, n >> s, n)
330
+ if a == 1 or a == n - 1:
331
+ return True
332
+ for _ in range(s - 1):
333
+ a = pow(a, 2, n)
334
+ if a == n - 1:
335
+ return True
336
+ if a == 1:
337
+ return False
338
+ return False
339
+
340
+
341
+ def is_strong_prp(n, a):
342
+ if a < 2:
343
+ raise ValueError("is_strong_prp() requires 'a' greater than or equal to 2")
344
+ if n < 1:
345
+ raise ValueError("is_strong_prp() requires 'n' be greater than 0")
346
+ if n == 1:
347
+ return False
348
+ if n % 2 == 0:
349
+ return n == 2
350
+ a %= n
351
+ if gcd(n, a) != 1:
352
+ raise ValueError("is_strong_prp() requires gcd(n,a) == 1")
353
+ return _is_strong_prp(n, a)
354
+
355
+
356
+ def _lucas_sequence(n, P, Q, k):
357
+ r"""Return the modular Lucas sequence (U_k, V_k, Q_k).
358
+
359
+ Explanation
360
+ ===========
361
+
362
+ Given a Lucas sequence defined by P, Q, returns the kth values for
363
+ U and V, along with Q^k, all modulo n. This is intended for use with
364
+ possibly very large values of n and k, where the combinatorial functions
365
+ would be completely unusable.
366
+
367
+ .. math ::
368
+ U_k = \begin{cases}
369
+ 0 & \text{if } k = 0\\
370
+ 1 & \text{if } k = 1\\
371
+ PU_{k-1} - QU_{k-2} & \text{if } k > 1
372
+ \end{cases}\\
373
+ V_k = \begin{cases}
374
+ 2 & \text{if } k = 0\\
375
+ P & \text{if } k = 1\\
376
+ PV_{k-1} - QV_{k-2} & \text{if } k > 1
377
+ \end{cases}
378
+
379
+ The modular Lucas sequences are used in numerous places in number theory,
380
+ especially in the Lucas compositeness tests and the various n + 1 proofs.
381
+
382
+ Parameters
383
+ ==========
384
+
385
+ n : int
386
+ n is an odd number greater than or equal to 3
387
+ P : int
388
+ Q : int
389
+ D determined by D = P**2 - 4*Q is non-zero
390
+ k : int
391
+ k is a nonnegative integer
392
+
393
+ Returns
394
+ =======
395
+
396
+ U, V, Qk : (int, int, int)
397
+ `(U_k \bmod{n}, V_k \bmod{n}, Q^k \bmod{n})`
398
+
399
+ Examples
400
+ ========
401
+
402
+ >>> from sympy.external.ntheory import _lucas_sequence
403
+ >>> N = 10**2000 + 4561
404
+ >>> sol = U, V, Qk = _lucas_sequence(N, 3, 1, N//2); sol
405
+ (0, 2, 1)
406
+
407
+ References
408
+ ==========
409
+
410
+ .. [1] https://en.wikipedia.org/wiki/Lucas_sequence
411
+
412
+ """
413
+ if k == 0:
414
+ return (0, 2, 1)
415
+ D = P**2 - 4*Q
416
+ U = 1
417
+ V = P
418
+ Qk = Q % n
419
+ if Q == 1:
420
+ # Optimization for extra strong tests.
421
+ for b in bin(k)[3:]:
422
+ U = (U*V) % n
423
+ V = (V*V - 2) % n
424
+ if b == "1":
425
+ U, V = U*P + V, V*P + U*D
426
+ if U & 1:
427
+ U += n
428
+ if V & 1:
429
+ V += n
430
+ U, V = U >> 1, V >> 1
431
+ elif P == 1 and Q == -1:
432
+ # Small optimization for 50% of Selfridge parameters.
433
+ for b in bin(k)[3:]:
434
+ U = (U*V) % n
435
+ if Qk == 1:
436
+ V = (V*V - 2) % n
437
+ else:
438
+ V = (V*V + 2) % n
439
+ Qk = 1
440
+ if b == "1":
441
+ # new_U = (U + V) // 2
442
+ # new_V = (5*U + V) // 2 = 2*U + new_U
443
+ U, V = U + V, U << 1
444
+ if U & 1:
445
+ U += n
446
+ U >>= 1
447
+ V += U
448
+ Qk = -1
449
+ Qk %= n
450
+ elif P == 1:
451
+ for b in bin(k)[3:]:
452
+ U = (U*V) % n
453
+ V = (V*V - 2*Qk) % n
454
+ Qk *= Qk
455
+ if b == "1":
456
+ # new_U = (U + V) // 2
457
+ # new_V = new_U - 2*Q*U
458
+ U, V = U + V, (Q*U) << 1
459
+ if U & 1:
460
+ U += n
461
+ U >>= 1
462
+ V = U - V
463
+ Qk *= Q
464
+ Qk %= n
465
+ else:
466
+ # The general case with any P and Q.
467
+ for b in bin(k)[3:]:
468
+ U = (U*V) % n
469
+ V = (V*V - 2*Qk) % n
470
+ Qk *= Qk
471
+ if b == "1":
472
+ U, V = U*P + V, V*P + U*D
473
+ if U & 1:
474
+ U += n
475
+ if V & 1:
476
+ V += n
477
+ U, V = U >> 1, V >> 1
478
+ Qk *= Q
479
+ Qk %= n
480
+ return (U % n, V % n, Qk)
481
+
482
+
483
+ def is_fibonacci_prp(n, p, q):
484
+ d = p**2 - 4*q
485
+ if d == 0 or p <= 0 or q not in [1, -1]:
486
+ raise ValueError("invalid values for p,q in is_fibonacci_prp()")
487
+ if n < 1:
488
+ raise ValueError("is_fibonacci_prp() requires 'n' be greater than 0")
489
+ if n == 1:
490
+ return False
491
+ if n % 2 == 0:
492
+ return n == 2
493
+ return _lucas_sequence(n, p, q, n)[1] == p % n
494
+
495
+
496
+ def is_lucas_prp(n, p, q):
497
+ d = p**2 - 4*q
498
+ if d == 0:
499
+ raise ValueError("invalid values for p,q in is_lucas_prp()")
500
+ if n < 1:
501
+ raise ValueError("is_lucas_prp() requires 'n' be greater than 0")
502
+ if n == 1:
503
+ return False
504
+ if n % 2 == 0:
505
+ return n == 2
506
+ if gcd(n, q*d) not in [1, n]:
507
+ raise ValueError("is_lucas_prp() requires gcd(n,2*q*D) == 1")
508
+ return _lucas_sequence(n, p, q, n - jacobi(d, n))[0] == 0
509
+
510
+
511
+ def _is_selfridge_prp(n):
512
+ """Lucas compositeness test with the Selfridge parameters for n.
513
+
514
+ Explanation
515
+ ===========
516
+
517
+ The Lucas compositeness test checks whether n is a prime number.
518
+ The test can be run with arbitrary parameters ``P`` and ``Q``, which also change the performance of the test.
519
+ So, which parameters are most effective for running the Lucas compositeness test?
520
+ As an algorithm for determining ``P`` and ``Q``, Selfridge proposed method A [1]_ page 1401
521
+ (Since two methods were proposed, referred to simply as A and B in the paper,
522
+ we will refer to one of them as "method A").
523
+
524
+ method A fixes ``P = 1``. Then, ``D`` defined by ``D = P**2 - 4Q`` is varied from 5, -7, 9, -11, 13, and so on,
525
+ with the first ``D`` being ``jacobi(D, n) == -1``. Once ``D`` is determined,
526
+ ``Q`` is determined to be ``(P**2 - D)//4``.
527
+
528
+ References
529
+ ==========
530
+
531
+ .. [1] Robert Baillie, Samuel S. Wagstaff, Lucas Pseudoprimes,
532
+ Math. Comp. Vol 35, Number 152 (1980), pp. 1391-1417,
533
+ https://doi.org/10.1090%2FS0025-5718-1980-0583518-6
534
+ http://mpqs.free.fr/LucasPseudoprimes.pdf
535
+
536
+ """
537
+ for D in range(5, 1_000_000, 2):
538
+ if D & 2: # if D % 4 == 3
539
+ D = -D
540
+ j = jacobi(D, n)
541
+ if j == -1:
542
+ return _lucas_sequence(n, 1, (1-D) // 4, n + 1)[0] == 0
543
+ if j == 0 and D % n:
544
+ return False
545
+ # When j == -1 is hard to find, suspect a square number
546
+ if D == 13 and is_square(n):
547
+ return False
548
+ raise ValueError("appropriate value for D cannot be found in is_selfridge_prp()")
549
+
550
+
551
+ def is_selfridge_prp(n):
552
+ if n < 1:
553
+ raise ValueError("is_selfridge_prp() requires 'n' be greater than 0")
554
+ if n == 1:
555
+ return False
556
+ if n % 2 == 0:
557
+ return n == 2
558
+ return _is_selfridge_prp(n)
559
+
560
+
561
+ def is_strong_lucas_prp(n, p, q):
562
+ D = p**2 - 4*q
563
+ if D == 0:
564
+ raise ValueError("invalid values for p,q in is_strong_lucas_prp()")
565
+ if n < 1:
566
+ raise ValueError("is_selfridge_prp() requires 'n' be greater than 0")
567
+ if n == 1:
568
+ return False
569
+ if n % 2 == 0:
570
+ return n == 2
571
+ if gcd(n, q*D) not in [1, n]:
572
+ raise ValueError("is_strong_lucas_prp() requires gcd(n,2*q*D) == 1")
573
+ j = jacobi(D, n)
574
+ s = bit_scan1(n - j)
575
+ U, V, Qk = _lucas_sequence(n, p, q, (n - j) >> s)
576
+ if U == 0 or V == 0:
577
+ return True
578
+ for _ in range(s - 1):
579
+ V = (V*V - 2*Qk) % n
580
+ if V == 0:
581
+ return True
582
+ Qk = pow(Qk, 2, n)
583
+ return False
584
+
585
+
586
+ def _is_strong_selfridge_prp(n):
587
+ for D in range(5, 1_000_000, 2):
588
+ if D & 2: # if D % 4 == 3
589
+ D = -D
590
+ j = jacobi(D, n)
591
+ if j == -1:
592
+ s = bit_scan1(n + 1)
593
+ U, V, Qk = _lucas_sequence(n, 1, (1-D) // 4, (n + 1) >> s)
594
+ if U == 0 or V == 0:
595
+ return True
596
+ for _ in range(s - 1):
597
+ V = (V*V - 2*Qk) % n
598
+ if V == 0:
599
+ return True
600
+ Qk = pow(Qk, 2, n)
601
+ return False
602
+ if j == 0 and D % n:
603
+ return False
604
+ # When j == -1 is hard to find, suspect a square number
605
+ if D == 13 and is_square(n):
606
+ return False
607
+ raise ValueError("appropriate value for D cannot be found in is_strong_selfridge_prp()")
608
+
609
+
610
+ def is_strong_selfridge_prp(n):
611
+ if n < 1:
612
+ raise ValueError("is_strong_selfridge_prp() requires 'n' be greater than 0")
613
+ if n == 1:
614
+ return False
615
+ if n % 2 == 0:
616
+ return n == 2
617
+ return _is_strong_selfridge_prp(n)
618
+
619
+
620
+ def is_bpsw_prp(n):
621
+ if n < 1:
622
+ raise ValueError("is_bpsw_prp() requires 'n' be greater than 0")
623
+ if n == 1:
624
+ return False
625
+ if n % 2 == 0:
626
+ return n == 2
627
+ return _is_strong_prp(n, 2) and _is_selfridge_prp(n)
628
+
629
+
630
+ def is_strong_bpsw_prp(n):
631
+ if n < 1:
632
+ raise ValueError("is_strong_bpsw_prp() requires 'n' be greater than 0")
633
+ if n == 1:
634
+ return False
635
+ if n % 2 == 0:
636
+ return n == 2
637
+ return _is_strong_prp(n, 2) and _is_strong_selfridge_prp(n)
lib/python3.12/site-packages/sympy/external/pythonmpq.py ADDED
@@ -0,0 +1,341 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ PythonMPQ: Rational number type based on Python integers.
3
+
4
+ This class is intended as a pure Python fallback for when gmpy2 is not
5
+ installed. If gmpy2 is installed then its mpq type will be used instead. The
6
+ mpq type is around 20x faster. We could just use the stdlib Fraction class
7
+ here but that is slower:
8
+
9
+ from fractions import Fraction
10
+ from sympy.external.pythonmpq import PythonMPQ
11
+ nums = range(1000)
12
+ dens = range(5, 1005)
13
+ rats = [Fraction(n, d) for n, d in zip(nums, dens)]
14
+ sum(rats) # <--- 24 milliseconds
15
+ rats = [PythonMPQ(n, d) for n, d in zip(nums, dens)]
16
+ sum(rats) # <--- 7 milliseconds
17
+
18
+ Both mpq and Fraction have some awkward features like the behaviour of
19
+ division with // and %:
20
+
21
+ >>> from fractions import Fraction
22
+ >>> Fraction(2, 3) % Fraction(1, 4)
23
+ 1/6
24
+
25
+ For the QQ domain we do not want this behaviour because there should be no
26
+ remainder when dividing rational numbers. SymPy does not make use of this
27
+ aspect of mpq when gmpy2 is installed. Since this class is a fallback for that
28
+ case we do not bother implementing e.g. __mod__ so that we can be sure we
29
+ are not using it when gmpy2 is installed either.
30
+ """
31
+
32
+
33
+ import operator
34
+ from math import gcd
35
+ from decimal import Decimal
36
+ from fractions import Fraction
37
+ import sys
38
+ from typing import Tuple as tTuple, Type
39
+
40
+
41
+ # Used for __hash__
42
+ _PyHASH_MODULUS = sys.hash_info.modulus
43
+ _PyHASH_INF = sys.hash_info.inf
44
+
45
+
46
+ class PythonMPQ:
47
+ """Rational number implementation that is intended to be compatible with
48
+ gmpy2's mpq.
49
+
50
+ Also slightly faster than fractions.Fraction.
51
+
52
+ PythonMPQ should be treated as immutable although no effort is made to
53
+ prevent mutation (since that might slow down calculations).
54
+ """
55
+ __slots__ = ('numerator', 'denominator')
56
+
57
+ def __new__(cls, numerator, denominator=None):
58
+ """Construct PythonMPQ with gcd computation and checks"""
59
+ if denominator is not None:
60
+ #
61
+ # PythonMPQ(n, d): require n and d to be int and d != 0
62
+ #
63
+ if isinstance(numerator, int) and isinstance(denominator, int):
64
+ # This is the slow part:
65
+ divisor = gcd(numerator, denominator)
66
+ numerator //= divisor
67
+ denominator //= divisor
68
+ return cls._new_check(numerator, denominator)
69
+ else:
70
+ #
71
+ # PythonMPQ(q)
72
+ #
73
+ # Here q can be PythonMPQ, int, Decimal, float, Fraction or str
74
+ #
75
+ if isinstance(numerator, int):
76
+ return cls._new(numerator, 1)
77
+ elif isinstance(numerator, PythonMPQ):
78
+ return cls._new(numerator.numerator, numerator.denominator)
79
+
80
+ # Let Fraction handle Decimal/float conversion and str parsing
81
+ if isinstance(numerator, (Decimal, float, str)):
82
+ numerator = Fraction(numerator)
83
+ if isinstance(numerator, Fraction):
84
+ return cls._new(numerator.numerator, numerator.denominator)
85
+ #
86
+ # Reject everything else. This is more strict than mpq which allows
87
+ # things like mpq(Fraction, Fraction) or mpq(Decimal, any). The mpq
88
+ # behaviour is somewhat inconsistent so we choose to accept only a
89
+ # more strict subset of what mpq allows.
90
+ #
91
+ raise TypeError("PythonMPQ() requires numeric or string argument")
92
+
93
+ @classmethod
94
+ def _new_check(cls, numerator, denominator):
95
+ """Construct PythonMPQ, check divide by zero and canonicalize signs"""
96
+ if not denominator:
97
+ raise ZeroDivisionError(f'Zero divisor {numerator}/{denominator}')
98
+ elif denominator < 0:
99
+ numerator = -numerator
100
+ denominator = -denominator
101
+ return cls._new(numerator, denominator)
102
+
103
+ @classmethod
104
+ def _new(cls, numerator, denominator):
105
+ """Construct PythonMPQ efficiently (no checks)"""
106
+ obj = super().__new__(cls)
107
+ obj.numerator = numerator
108
+ obj.denominator = denominator
109
+ return obj
110
+
111
+ def __int__(self):
112
+ """Convert to int (truncates towards zero)"""
113
+ p, q = self.numerator, self.denominator
114
+ if p < 0:
115
+ return -(-p//q)
116
+ return p//q
117
+
118
+ def __float__(self):
119
+ """Convert to float (approximately)"""
120
+ return self.numerator / self.denominator
121
+
122
+ def __bool__(self):
123
+ """True/False if nonzero/zero"""
124
+ return bool(self.numerator)
125
+
126
+ def __eq__(self, other):
127
+ """Compare equal with PythonMPQ, int, float, Decimal or Fraction"""
128
+ if isinstance(other, PythonMPQ):
129
+ return (self.numerator == other.numerator
130
+ and self.denominator == other.denominator)
131
+ elif isinstance(other, self._compatible_types):
132
+ return self.__eq__(PythonMPQ(other))
133
+ else:
134
+ return NotImplemented
135
+
136
+ def __hash__(self):
137
+ """hash - same as mpq/Fraction"""
138
+ try:
139
+ dinv = pow(self.denominator, -1, _PyHASH_MODULUS)
140
+ except ValueError:
141
+ hash_ = _PyHASH_INF
142
+ else:
143
+ hash_ = hash(hash(abs(self.numerator)) * dinv)
144
+ result = hash_ if self.numerator >= 0 else -hash_
145
+ return -2 if result == -1 else result
146
+
147
+ def __reduce__(self):
148
+ """Deconstruct for pickling"""
149
+ return type(self), (self.numerator, self.denominator)
150
+
151
+ def __str__(self):
152
+ """Convert to string"""
153
+ if self.denominator != 1:
154
+ return f"{self.numerator}/{self.denominator}"
155
+ else:
156
+ return f"{self.numerator}"
157
+
158
+ def __repr__(self):
159
+ """Convert to string"""
160
+ return f"MPQ({self.numerator},{self.denominator})"
161
+
162
+ def _cmp(self, other, op):
163
+ """Helper for lt/le/gt/ge"""
164
+ if not isinstance(other, self._compatible_types):
165
+ return NotImplemented
166
+ lhs = self.numerator * other.denominator
167
+ rhs = other.numerator * self.denominator
168
+ return op(lhs, rhs)
169
+
170
+ def __lt__(self, other):
171
+ """self < other"""
172
+ return self._cmp(other, operator.lt)
173
+
174
+ def __le__(self, other):
175
+ """self <= other"""
176
+ return self._cmp(other, operator.le)
177
+
178
+ def __gt__(self, other):
179
+ """self > other"""
180
+ return self._cmp(other, operator.gt)
181
+
182
+ def __ge__(self, other):
183
+ """self >= other"""
184
+ return self._cmp(other, operator.ge)
185
+
186
+ def __abs__(self):
187
+ """abs(q)"""
188
+ return self._new(abs(self.numerator), self.denominator)
189
+
190
+ def __pos__(self):
191
+ """+q"""
192
+ return self
193
+
194
+ def __neg__(self):
195
+ """-q"""
196
+ return self._new(-self.numerator, self.denominator)
197
+
198
+ def __add__(self, other):
199
+ """q1 + q2"""
200
+ if isinstance(other, PythonMPQ):
201
+ #
202
+ # This is much faster than the naive method used in the stdlib
203
+ # fractions module. Not sure where this method comes from
204
+ # though...
205
+ #
206
+ # Compare timings for something like:
207
+ # nums = range(1000)
208
+ # rats = [PythonMPQ(n, d) for n, d in zip(nums[:-5], nums[5:])]
209
+ # sum(rats) # <-- time this
210
+ #
211
+ ap, aq = self.numerator, self.denominator
212
+ bp, bq = other.numerator, other.denominator
213
+ g = gcd(aq, bq)
214
+ if g == 1:
215
+ p = ap*bq + aq*bp
216
+ q = bq*aq
217
+ else:
218
+ q1, q2 = aq//g, bq//g
219
+ p, q = ap*q2 + bp*q1, q1*q2
220
+ g2 = gcd(p, g)
221
+ p, q = (p // g2), q * (g // g2)
222
+
223
+ elif isinstance(other, int):
224
+ p = self.numerator + self.denominator * other
225
+ q = self.denominator
226
+ else:
227
+ return NotImplemented
228
+
229
+ return self._new(p, q)
230
+
231
+ def __radd__(self, other):
232
+ """z1 + q2"""
233
+ if isinstance(other, int):
234
+ p = self.numerator + self.denominator * other
235
+ q = self.denominator
236
+ return self._new(p, q)
237
+ else:
238
+ return NotImplemented
239
+
240
+ def __sub__(self ,other):
241
+ """q1 - q2"""
242
+ if isinstance(other, PythonMPQ):
243
+ ap, aq = self.numerator, self.denominator
244
+ bp, bq = other.numerator, other.denominator
245
+ g = gcd(aq, bq)
246
+ if g == 1:
247
+ p = ap*bq - aq*bp
248
+ q = bq*aq
249
+ else:
250
+ q1, q2 = aq//g, bq//g
251
+ p, q = ap*q2 - bp*q1, q1*q2
252
+ g2 = gcd(p, g)
253
+ p, q = (p // g2), q * (g // g2)
254
+ elif isinstance(other, int):
255
+ p = self.numerator - self.denominator*other
256
+ q = self.denominator
257
+ else:
258
+ return NotImplemented
259
+
260
+ return self._new(p, q)
261
+
262
+ def __rsub__(self, other):
263
+ """z1 - q2"""
264
+ if isinstance(other, int):
265
+ p = self.denominator * other - self.numerator
266
+ q = self.denominator
267
+ return self._new(p, q)
268
+ else:
269
+ return NotImplemented
270
+
271
+ def __mul__(self, other):
272
+ """q1 * q2"""
273
+ if isinstance(other, PythonMPQ):
274
+ ap, aq = self.numerator, self.denominator
275
+ bp, bq = other.numerator, other.denominator
276
+ x1 = gcd(ap, bq)
277
+ x2 = gcd(bp, aq)
278
+ p, q = ((ap//x1)*(bp//x2), (aq//x2)*(bq//x1))
279
+ elif isinstance(other, int):
280
+ x = gcd(other, self.denominator)
281
+ p = self.numerator*(other//x)
282
+ q = self.denominator//x
283
+ else:
284
+ return NotImplemented
285
+
286
+ return self._new(p, q)
287
+
288
+ def __rmul__(self, other):
289
+ """z1 * q2"""
290
+ if isinstance(other, int):
291
+ x = gcd(self.denominator, other)
292
+ p = self.numerator*(other//x)
293
+ q = self.denominator//x
294
+ return self._new(p, q)
295
+ else:
296
+ return NotImplemented
297
+
298
+ def __pow__(self, exp):
299
+ """q ** z"""
300
+ p, q = self.numerator, self.denominator
301
+
302
+ if exp < 0:
303
+ p, q, exp = q, p, -exp
304
+
305
+ return self._new_check(p**exp, q**exp)
306
+
307
+ def __truediv__(self, other):
308
+ """q1 / q2"""
309
+ if isinstance(other, PythonMPQ):
310
+ ap, aq = self.numerator, self.denominator
311
+ bp, bq = other.numerator, other.denominator
312
+ x1 = gcd(ap, bp)
313
+ x2 = gcd(bq, aq)
314
+ p, q = ((ap//x1)*(bq//x2), (aq//x2)*(bp//x1))
315
+ elif isinstance(other, int):
316
+ x = gcd(other, self.numerator)
317
+ p = self.numerator//x
318
+ q = self.denominator*(other//x)
319
+ else:
320
+ return NotImplemented
321
+
322
+ return self._new_check(p, q)
323
+
324
+ def __rtruediv__(self, other):
325
+ """z / q"""
326
+ if isinstance(other, int):
327
+ x = gcd(self.numerator, other)
328
+ p = self.denominator*(other//x)
329
+ q = self.numerator//x
330
+ return self._new_check(p, q)
331
+ else:
332
+ return NotImplemented
333
+
334
+ _compatible_types: tTuple[Type, ...] = ()
335
+
336
+ #
337
+ # These are the types that PythonMPQ will interoperate with for operations
338
+ # and comparisons such as ==, + etc. We define this down here so that we can
339
+ # include PythonMPQ in the list as well.
340
+ #
341
+ PythonMPQ._compatible_types = (PythonMPQ, int, Decimal, Fraction)
lib/python3.12/site-packages/sympy/external/tests/__init__.py ADDED
File without changes
lib/python3.12/site-packages/sympy/external/tests/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (199 Bytes). View file
 
lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_autowrap.cpython-312.pyc ADDED
Binary file (14.4 kB). View file
 
lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_codegen.cpython-312.pyc ADDED
Binary file (14.1 kB). View file
 
lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_gmpy.cpython-312.pyc ADDED
Binary file (1.29 kB). View file
 
lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_importtools.cpython-312.pyc ADDED
Binary file (1.81 kB). View file
 
lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_ntheory.cpython-312.pyc ADDED
Binary file (15.2 kB). View file
 
lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_numpy.cpython-312.pyc ADDED
Binary file (21.4 kB). View file
 
lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_pythonmpq.cpython-312.pyc ADDED
Binary file (11.7 kB). View file
 
lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_scipy.cpython-312.pyc ADDED
Binary file (1.43 kB). View file
 
lib/python3.12/site-packages/sympy/external/tests/test_autowrap.py ADDED
@@ -0,0 +1,313 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sympy
2
+ import tempfile
3
+ import os
4
+ from sympy.core.mod import Mod
5
+ from sympy.core.relational import Eq
6
+ from sympy.core.symbol import symbols
7
+ from sympy.external import import_module
8
+ from sympy.tensor import IndexedBase, Idx
9
+ from sympy.utilities.autowrap import autowrap, ufuncify, CodeWrapError
10
+ from sympy.testing.pytest import skip
11
+
12
+ numpy = import_module('numpy', min_module_version='1.6.1')
13
+ Cython = import_module('Cython', min_module_version='0.15.1')
14
+ f2py = import_module('numpy.f2py', import_kwargs={'fromlist': ['f2py']})
15
+
16
+ f2pyworks = False
17
+ if f2py:
18
+ try:
19
+ autowrap(symbols('x'), 'f95', 'f2py')
20
+ except (CodeWrapError, ImportError, OSError):
21
+ f2pyworks = False
22
+ else:
23
+ f2pyworks = True
24
+
25
+ a, b, c = symbols('a b c')
26
+ n, m, d = symbols('n m d', integer=True)
27
+ A, B, C = symbols('A B C', cls=IndexedBase)
28
+ i = Idx('i', m)
29
+ j = Idx('j', n)
30
+ k = Idx('k', d)
31
+
32
+
33
+ def has_module(module):
34
+ """
35
+ Return True if module exists, otherwise run skip().
36
+
37
+ module should be a string.
38
+ """
39
+ # To give a string of the module name to skip(), this function takes a
40
+ # string. So we don't waste time running import_module() more than once,
41
+ # just map the three modules tested here in this dict.
42
+ modnames = {'numpy': numpy, 'Cython': Cython, 'f2py': f2py}
43
+
44
+ if modnames[module]:
45
+ if module == 'f2py' and not f2pyworks:
46
+ skip("Couldn't run f2py.")
47
+ return True
48
+ skip("Couldn't import %s." % module)
49
+
50
+ #
51
+ # test runners used by several language-backend combinations
52
+ #
53
+
54
+ def runtest_autowrap_twice(language, backend):
55
+ f = autowrap((((a + b)/c)**5).expand(), language, backend)
56
+ g = autowrap((((a + b)/c)**4).expand(), language, backend)
57
+
58
+ # check that autowrap updates the module name. Else, g gives the same as f
59
+ assert f(1, -2, 1) == -1.0
60
+ assert g(1, -2, 1) == 1.0
61
+
62
+
63
+ def runtest_autowrap_trace(language, backend):
64
+ has_module('numpy')
65
+ trace = autowrap(A[i, i], language, backend)
66
+ assert trace(numpy.eye(100)) == 100
67
+
68
+
69
+ def runtest_autowrap_matrix_vector(language, backend):
70
+ has_module('numpy')
71
+ x, y = symbols('x y', cls=IndexedBase)
72
+ expr = Eq(y[i], A[i, j]*x[j])
73
+ mv = autowrap(expr, language, backend)
74
+
75
+ # compare with numpy's dot product
76
+ M = numpy.random.rand(10, 20)
77
+ x = numpy.random.rand(20)
78
+ y = numpy.dot(M, x)
79
+ assert numpy.sum(numpy.abs(y - mv(M, x))) < 1e-13
80
+
81
+
82
+ def runtest_autowrap_matrix_matrix(language, backend):
83
+ has_module('numpy')
84
+ expr = Eq(C[i, j], A[i, k]*B[k, j])
85
+ matmat = autowrap(expr, language, backend)
86
+
87
+ # compare with numpy's dot product
88
+ M1 = numpy.random.rand(10, 20)
89
+ M2 = numpy.random.rand(20, 15)
90
+ M3 = numpy.dot(M1, M2)
91
+ assert numpy.sum(numpy.abs(M3 - matmat(M1, M2))) < 1e-13
92
+
93
+
94
+ def runtest_ufuncify(language, backend):
95
+ has_module('numpy')
96
+ a, b, c = symbols('a b c')
97
+ fabc = ufuncify([a, b, c], a*b + c, backend=backend)
98
+ facb = ufuncify([a, c, b], a*b + c, backend=backend)
99
+ grid = numpy.linspace(-2, 2, 50)
100
+ b = numpy.linspace(-5, 4, 50)
101
+ c = numpy.linspace(-1, 1, 50)
102
+ expected = grid*b + c
103
+ numpy.testing.assert_allclose(fabc(grid, b, c), expected)
104
+ numpy.testing.assert_allclose(facb(grid, c, b), expected)
105
+
106
+
107
+ def runtest_issue_10274(language, backend):
108
+ expr = (a - b + c)**(13)
109
+ tmp = tempfile.mkdtemp()
110
+ f = autowrap(expr, language, backend, tempdir=tmp,
111
+ helpers=('helper', a - b + c, (a, b, c)))
112
+ assert f(1, 1, 1) == 1
113
+
114
+ for file in os.listdir(tmp):
115
+ if not (file.startswith("wrapped_code_") and file.endswith(".c")):
116
+ continue
117
+
118
+ with open(tmp + '/' + file) as fil:
119
+ lines = fil.readlines()
120
+ assert lines[0] == "/******************************************************************************\n"
121
+ assert "Code generated with SymPy " + sympy.__version__ in lines[1]
122
+ assert lines[2:] == [
123
+ " * *\n",
124
+ " * See http://www.sympy.org/ for more information. *\n",
125
+ " * *\n",
126
+ " * This file is part of 'autowrap' *\n",
127
+ " ******************************************************************************/\n",
128
+ "#include " + '"' + file[:-1]+ 'h"' + "\n",
129
+ "#include <math.h>\n",
130
+ "\n",
131
+ "double helper(double a, double b, double c) {\n",
132
+ "\n",
133
+ " double helper_result;\n",
134
+ " helper_result = a - b + c;\n",
135
+ " return helper_result;\n",
136
+ "\n",
137
+ "}\n",
138
+ "\n",
139
+ "double autofunc(double a, double b, double c) {\n",
140
+ "\n",
141
+ " double autofunc_result;\n",
142
+ " autofunc_result = pow(helper(a, b, c), 13);\n",
143
+ " return autofunc_result;\n",
144
+ "\n",
145
+ "}\n",
146
+ ]
147
+
148
+
149
+ def runtest_issue_15337(language, backend):
150
+ has_module('numpy')
151
+ # NOTE : autowrap was originally designed to only accept an iterable for
152
+ # the kwarg "helpers", but in issue 10274 the user mistakenly thought that
153
+ # if there was only a single helper it did not need to be passed via an
154
+ # iterable that wrapped the helper tuple. There were no tests for this
155
+ # behavior so when the code was changed to accept a single tuple it broke
156
+ # the original behavior. These tests below ensure that both now work.
157
+ a, b, c, d, e = symbols('a, b, c, d, e')
158
+ expr = (a - b + c - d + e)**13
159
+ exp_res = (1. - 2. + 3. - 4. + 5.)**13
160
+
161
+ f = autowrap(expr, language, backend, args=(a, b, c, d, e),
162
+ helpers=('f1', a - b + c, (a, b, c)))
163
+ numpy.testing.assert_allclose(f(1, 2, 3, 4, 5), exp_res)
164
+
165
+ f = autowrap(expr, language, backend, args=(a, b, c, d, e),
166
+ helpers=(('f1', a - b, (a, b)), ('f2', c - d, (c, d))))
167
+ numpy.testing.assert_allclose(f(1, 2, 3, 4, 5), exp_res)
168
+
169
+
170
+ def test_issue_15230():
171
+ has_module('f2py')
172
+
173
+ x, y = symbols('x, y')
174
+ expr = Mod(x, 3.0) - Mod(y, -2.0)
175
+ f = autowrap(expr, args=[x, y], language='F95')
176
+ exp_res = float(expr.xreplace({x: 3.5, y: 2.7}).evalf())
177
+ assert abs(f(3.5, 2.7) - exp_res) < 1e-14
178
+
179
+ x, y = symbols('x, y', integer=True)
180
+ expr = Mod(x, 3) - Mod(y, -2)
181
+ f = autowrap(expr, args=[x, y], language='F95')
182
+ assert f(3, 2) == expr.xreplace({x: 3, y: 2})
183
+
184
+ #
185
+ # tests of language-backend combinations
186
+ #
187
+
188
+ # f2py
189
+
190
+
191
+ def test_wrap_twice_f95_f2py():
192
+ has_module('f2py')
193
+ runtest_autowrap_twice('f95', 'f2py')
194
+
195
+
196
+ def test_autowrap_trace_f95_f2py():
197
+ has_module('f2py')
198
+ runtest_autowrap_trace('f95', 'f2py')
199
+
200
+
201
+ def test_autowrap_matrix_vector_f95_f2py():
202
+ has_module('f2py')
203
+ runtest_autowrap_matrix_vector('f95', 'f2py')
204
+
205
+
206
+ def test_autowrap_matrix_matrix_f95_f2py():
207
+ has_module('f2py')
208
+ runtest_autowrap_matrix_matrix('f95', 'f2py')
209
+
210
+
211
+ def test_ufuncify_f95_f2py():
212
+ has_module('f2py')
213
+ runtest_ufuncify('f95', 'f2py')
214
+
215
+
216
+ def test_issue_15337_f95_f2py():
217
+ has_module('f2py')
218
+ runtest_issue_15337('f95', 'f2py')
219
+
220
+ # Cython
221
+
222
+
223
+ def test_wrap_twice_c_cython():
224
+ has_module('Cython')
225
+ runtest_autowrap_twice('C', 'cython')
226
+
227
+
228
+ def test_autowrap_trace_C_Cython():
229
+ has_module('Cython')
230
+ runtest_autowrap_trace('C99', 'cython')
231
+
232
+
233
+ def test_autowrap_matrix_vector_C_cython():
234
+ has_module('Cython')
235
+ runtest_autowrap_matrix_vector('C99', 'cython')
236
+
237
+
238
+ def test_autowrap_matrix_matrix_C_cython():
239
+ has_module('Cython')
240
+ runtest_autowrap_matrix_matrix('C99', 'cython')
241
+
242
+
243
+ def test_ufuncify_C_Cython():
244
+ has_module('Cython')
245
+ runtest_ufuncify('C99', 'cython')
246
+
247
+
248
+ def test_issue_10274_C_cython():
249
+ has_module('Cython')
250
+ runtest_issue_10274('C89', 'cython')
251
+
252
+
253
+ def test_issue_15337_C_cython():
254
+ has_module('Cython')
255
+ runtest_issue_15337('C89', 'cython')
256
+
257
+
258
+ def test_autowrap_custom_printer():
259
+ has_module('Cython')
260
+
261
+ from sympy.core.numbers import pi
262
+ from sympy.utilities.codegen import C99CodeGen
263
+ from sympy.printing.c import C99CodePrinter
264
+
265
+ class PiPrinter(C99CodePrinter):
266
+ def _print_Pi(self, expr):
267
+ return "S_PI"
268
+
269
+ printer = PiPrinter()
270
+ gen = C99CodeGen(printer=printer)
271
+ gen.preprocessor_statements.append('#include "shortpi.h"')
272
+
273
+ expr = pi * a
274
+
275
+ expected = (
276
+ '#include "%s"\n'
277
+ '#include <math.h>\n'
278
+ '#include "shortpi.h"\n'
279
+ '\n'
280
+ 'double autofunc(double a) {\n'
281
+ '\n'
282
+ ' double autofunc_result;\n'
283
+ ' autofunc_result = S_PI*a;\n'
284
+ ' return autofunc_result;\n'
285
+ '\n'
286
+ '}\n'
287
+ )
288
+
289
+ tmpdir = tempfile.mkdtemp()
290
+ # write a trivial header file to use in the generated code
291
+ with open(os.path.join(tmpdir, 'shortpi.h'), 'w') as f:
292
+ f.write('#define S_PI 3.14')
293
+
294
+ func = autowrap(expr, backend='cython', tempdir=tmpdir, code_gen=gen)
295
+
296
+ assert func(4.2) == 3.14 * 4.2
297
+
298
+ # check that the generated code is correct
299
+ for filename in os.listdir(tmpdir):
300
+ if filename.startswith('wrapped_code') and filename.endswith('.c'):
301
+ with open(os.path.join(tmpdir, filename)) as f:
302
+ lines = f.readlines()
303
+ expected = expected % filename.replace('.c', '.h')
304
+ assert ''.join(lines[7:]) == expected
305
+
306
+
307
+ # Numpy
308
+
309
+ def test_ufuncify_numpy():
310
+ # This test doesn't use Cython, but if Cython works, then there is a valid
311
+ # C compiler, which is needed.
312
+ has_module('Cython')
313
+ runtest_ufuncify('C99', 'numpy')
lib/python3.12/site-packages/sympy/external/tests/test_codegen.py ADDED
@@ -0,0 +1,379 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This tests the compilation and execution of the source code generated with
2
+ # utilities.codegen. The compilation takes place in a temporary directory that
3
+ # is removed after the test. By default the test directory is always removed,
4
+ # but this behavior can be changed by setting the environment variable
5
+ # SYMPY_TEST_CLEAN_TEMP to:
6
+ # export SYMPY_TEST_CLEAN_TEMP=always : the default behavior.
7
+ # export SYMPY_TEST_CLEAN_TEMP=success : only remove the directories of working tests.
8
+ # export SYMPY_TEST_CLEAN_TEMP=never : never remove the directories with the test code.
9
+ # When a directory is not removed, the necessary information is printed on
10
+ # screen to find the files that belong to the (failed) tests. If a test does
11
+ # not fail, py.test captures all the output and you will not see the directories
12
+ # corresponding to the successful tests. Use the --nocapture option to see all
13
+ # the output.
14
+
15
+ # All tests below have a counterpart in utilities/test/test_codegen.py. In the
16
+ # latter file, the resulting code is compared with predefined strings, without
17
+ # compilation or execution.
18
+
19
+ # All the generated Fortran code should conform with the Fortran 95 standard,
20
+ # and all the generated C code should be ANSI C, which facilitates the
21
+ # incorporation in various projects. The tests below assume that the binary cc
22
+ # is somewhere in the path and that it can compile ANSI C code.
23
+
24
+ from sympy.abc import x, y, z
25
+ from sympy.external import import_module
26
+ from sympy.testing.pytest import skip
27
+ from sympy.utilities.codegen import codegen, make_routine, get_code_generator
28
+ import sys
29
+ import os
30
+ import tempfile
31
+ import subprocess
32
+
33
+
34
+ pyodide_js = import_module('pyodide_js')
35
+
36
+ # templates for the main program that will test the generated code.
37
+
38
+ main_template = {}
39
+ main_template['F95'] = """
40
+ program main
41
+ include "codegen.h"
42
+ integer :: result;
43
+ result = 0
44
+
45
+ %(statements)s
46
+
47
+ call exit(result)
48
+ end program
49
+ """
50
+
51
+ main_template['C89'] = """
52
+ #include "codegen.h"
53
+ #include <stdio.h>
54
+ #include <math.h>
55
+
56
+ int main() {
57
+ int result = 0;
58
+
59
+ %(statements)s
60
+
61
+ return result;
62
+ }
63
+ """
64
+ main_template['C99'] = main_template['C89']
65
+ # templates for the numerical tests
66
+
67
+ numerical_test_template = {}
68
+ numerical_test_template['C89'] = """
69
+ if (fabs(%(call)s)>%(threshold)s) {
70
+ printf("Numerical validation failed: %(call)s=%%e threshold=%(threshold)s\\n", %(call)s);
71
+ result = -1;
72
+ }
73
+ """
74
+ numerical_test_template['C99'] = numerical_test_template['C89']
75
+
76
+ numerical_test_template['F95'] = """
77
+ if (abs(%(call)s)>%(threshold)s) then
78
+ write(6,"('Numerical validation failed:')")
79
+ write(6,"('%(call)s=',e15.5,'threshold=',e15.5)") %(call)s, %(threshold)s
80
+ result = -1;
81
+ end if
82
+ """
83
+ # command sequences for supported compilers
84
+
85
+ compile_commands = {}
86
+ compile_commands['cc'] = [
87
+ "cc -c codegen.c -o codegen.o",
88
+ "cc -c main.c -o main.o",
89
+ "cc main.o codegen.o -lm -o test.exe"
90
+ ]
91
+
92
+ compile_commands['gfortran'] = [
93
+ "gfortran -c codegen.f90 -o codegen.o",
94
+ "gfortran -ffree-line-length-none -c main.f90 -o main.o",
95
+ "gfortran main.o codegen.o -o test.exe"
96
+ ]
97
+
98
+ compile_commands['g95'] = [
99
+ "g95 -c codegen.f90 -o codegen.o",
100
+ "g95 -ffree-line-length-huge -c main.f90 -o main.o",
101
+ "g95 main.o codegen.o -o test.exe"
102
+ ]
103
+
104
+ compile_commands['ifort'] = [
105
+ "ifort -c codegen.f90 -o codegen.o",
106
+ "ifort -c main.f90 -o main.o",
107
+ "ifort main.o codegen.o -o test.exe"
108
+ ]
109
+
110
+ combinations_lang_compiler = [
111
+ ('C89', 'cc'),
112
+ ('C99', 'cc'),
113
+ ('F95', 'ifort'),
114
+ ('F95', 'gfortran'),
115
+ ('F95', 'g95')
116
+ ]
117
+
118
+
119
+ def try_run(commands):
120
+ """Run a series of commands and only return True if all ran fine."""
121
+ if pyodide_js:
122
+ return False
123
+ with open(os.devnull, 'w') as null:
124
+ for command in commands:
125
+ retcode = subprocess.call(command, stdout=null, shell=True,
126
+ stderr=subprocess.STDOUT)
127
+ if retcode != 0:
128
+ return False
129
+ return True
130
+
131
+
132
+ def run_test(label, routines, numerical_tests, language, commands, friendly=True):
133
+ """A driver for the codegen tests.
134
+
135
+ This driver assumes that a compiler ifort is present in the PATH and that
136
+ ifort is (at least) a Fortran 90 compiler. The generated code is written in
137
+ a temporary directory, together with a main program that validates the
138
+ generated code. The test passes when the compilation and the validation
139
+ run correctly.
140
+ """
141
+
142
+ # Check input arguments before touching the file system
143
+ language = language.upper()
144
+ assert language in main_template
145
+ assert language in numerical_test_template
146
+
147
+ # Check that environment variable makes sense
148
+ clean = os.getenv('SYMPY_TEST_CLEAN_TEMP', 'always').lower()
149
+ if clean not in ('always', 'success', 'never'):
150
+ raise ValueError("SYMPY_TEST_CLEAN_TEMP must be one of the following: 'always', 'success' or 'never'.")
151
+
152
+ # Do all the magic to compile, run and validate the test code
153
+ # 1) prepare the temporary working directory, switch to that dir
154
+ work = tempfile.mkdtemp("_sympy_%s_test" % language, "%s_" % label)
155
+ oldwork = os.getcwd()
156
+ os.chdir(work)
157
+
158
+ # 2) write the generated code
159
+ if friendly:
160
+ # interpret the routines as a name_expr list and call the friendly
161
+ # function codegen
162
+ codegen(routines, language, "codegen", to_files=True)
163
+ else:
164
+ code_gen = get_code_generator(language, "codegen")
165
+ code_gen.write(routines, "codegen", to_files=True)
166
+
167
+ # 3) write a simple main program that links to the generated code, and that
168
+ # includes the numerical tests
169
+ test_strings = []
170
+ for fn_name, args, expected, threshold in numerical_tests:
171
+ call_string = "%s(%s)-(%s)" % (
172
+ fn_name, ",".join(str(arg) for arg in args), expected)
173
+ if language == "F95":
174
+ call_string = fortranize_double_constants(call_string)
175
+ threshold = fortranize_double_constants(str(threshold))
176
+ test_strings.append(numerical_test_template[language] % {
177
+ "call": call_string,
178
+ "threshold": threshold,
179
+ })
180
+
181
+ if language == "F95":
182
+ f_name = "main.f90"
183
+ elif language.startswith("C"):
184
+ f_name = "main.c"
185
+ else:
186
+ raise NotImplementedError(
187
+ "FIXME: filename extension unknown for language: %s" % language)
188
+
189
+ with open(f_name, "w") as f:
190
+ f.write(
191
+ main_template[language] % {'statements': "".join(test_strings)})
192
+
193
+ # 4) Compile and link
194
+ compiled = try_run(commands)
195
+
196
+ # 5) Run if compiled
197
+ if compiled:
198
+ executed = try_run(["./test.exe"])
199
+ else:
200
+ executed = False
201
+
202
+ # 6) Clean up stuff
203
+ if clean == 'always' or (clean == 'success' and compiled and executed):
204
+ def safe_remove(filename):
205
+ if os.path.isfile(filename):
206
+ os.remove(filename)
207
+ safe_remove("codegen.f90")
208
+ safe_remove("codegen.c")
209
+ safe_remove("codegen.h")
210
+ safe_remove("codegen.o")
211
+ safe_remove("main.f90")
212
+ safe_remove("main.c")
213
+ safe_remove("main.o")
214
+ safe_remove("test.exe")
215
+ os.chdir(oldwork)
216
+ os.rmdir(work)
217
+ else:
218
+ print("TEST NOT REMOVED: %s" % work, file=sys.stderr)
219
+ os.chdir(oldwork)
220
+
221
+ # 7) Do the assertions in the end
222
+ assert compiled, "failed to compile %s code with:\n%s" % (
223
+ language, "\n".join(commands))
224
+ assert executed, "failed to execute %s code from:\n%s" % (
225
+ language, "\n".join(commands))
226
+
227
+
228
+ def fortranize_double_constants(code_string):
229
+ """
230
+ Replaces every literal float with literal doubles
231
+ """
232
+ import re
233
+ pattern_exp = re.compile(r'\d+(\.)?\d*[eE]-?\d+')
234
+ pattern_float = re.compile(r'\d+\.\d*(?!\d*d)')
235
+
236
+ def subs_exp(matchobj):
237
+ return re.sub('[eE]', 'd', matchobj.group(0))
238
+
239
+ def subs_float(matchobj):
240
+ return "%sd0" % matchobj.group(0)
241
+
242
+ code_string = pattern_exp.sub(subs_exp, code_string)
243
+ code_string = pattern_float.sub(subs_float, code_string)
244
+
245
+ return code_string
246
+
247
+
248
+ def is_feasible(language, commands):
249
+ # This test should always work, otherwise the compiler is not present.
250
+ routine = make_routine("test", x)
251
+ numerical_tests = [
252
+ ("test", ( 1.0,), 1.0, 1e-15),
253
+ ("test", (-1.0,), -1.0, 1e-15),
254
+ ]
255
+ try:
256
+ run_test("is_feasible", [routine], numerical_tests, language, commands,
257
+ friendly=False)
258
+ return True
259
+ except AssertionError:
260
+ return False
261
+
262
+ valid_lang_commands = []
263
+ invalid_lang_compilers = []
264
+ for lang, compiler in combinations_lang_compiler:
265
+ commands = compile_commands[compiler]
266
+ if is_feasible(lang, commands):
267
+ valid_lang_commands.append((lang, commands))
268
+ else:
269
+ invalid_lang_compilers.append((lang, compiler))
270
+
271
+ # We test all language-compiler combinations, just to report what is skipped
272
+
273
+ def test_C89_cc():
274
+ if ("C89", 'cc') in invalid_lang_compilers:
275
+ skip("`cc' command didn't work as expected (C89)")
276
+
277
+
278
+ def test_C99_cc():
279
+ if ("C99", 'cc') in invalid_lang_compilers:
280
+ skip("`cc' command didn't work as expected (C99)")
281
+
282
+
283
+ def test_F95_ifort():
284
+ if ("F95", 'ifort') in invalid_lang_compilers:
285
+ skip("`ifort' command didn't work as expected")
286
+
287
+
288
+ def test_F95_gfortran():
289
+ if ("F95", 'gfortran') in invalid_lang_compilers:
290
+ skip("`gfortran' command didn't work as expected")
291
+
292
+
293
+ def test_F95_g95():
294
+ if ("F95", 'g95') in invalid_lang_compilers:
295
+ skip("`g95' command didn't work as expected")
296
+
297
+ # Here comes the actual tests
298
+
299
+
300
+ def test_basic_codegen():
301
+ numerical_tests = [
302
+ ("test", (1.0, 6.0, 3.0), 21.0, 1e-15),
303
+ ("test", (-1.0, 2.0, -2.5), -2.5, 1e-15),
304
+ ]
305
+ name_expr = [("test", (x + y)*z)]
306
+ for lang, commands in valid_lang_commands:
307
+ run_test("basic_codegen", name_expr, numerical_tests, lang, commands)
308
+
309
+
310
+ def test_intrinsic_math1_codegen():
311
+ # not included: log10
312
+ from sympy.core.evalf import N
313
+ from sympy.functions import ln
314
+ from sympy.functions.elementary.exponential import log
315
+ from sympy.functions.elementary.hyperbolic import (cosh, sinh, tanh)
316
+ from sympy.functions.elementary.integers import (ceiling, floor)
317
+ from sympy.functions.elementary.miscellaneous import sqrt
318
+ from sympy.functions.elementary.trigonometric import (acos, asin, atan, cos, sin, tan)
319
+ name_expr = [
320
+ ("test_fabs", abs(x)),
321
+ ("test_acos", acos(x)),
322
+ ("test_asin", asin(x)),
323
+ ("test_atan", atan(x)),
324
+ ("test_cos", cos(x)),
325
+ ("test_cosh", cosh(x)),
326
+ ("test_log", log(x)),
327
+ ("test_ln", ln(x)),
328
+ ("test_sin", sin(x)),
329
+ ("test_sinh", sinh(x)),
330
+ ("test_sqrt", sqrt(x)),
331
+ ("test_tan", tan(x)),
332
+ ("test_tanh", tanh(x)),
333
+ ]
334
+ numerical_tests = []
335
+ for name, expr in name_expr:
336
+ for xval in 0.2, 0.5, 0.8:
337
+ expected = N(expr.subs(x, xval))
338
+ numerical_tests.append((name, (xval,), expected, 1e-14))
339
+ for lang, commands in valid_lang_commands:
340
+ if lang.startswith("C"):
341
+ name_expr_C = [("test_floor", floor(x)), ("test_ceil", ceiling(x))]
342
+ else:
343
+ name_expr_C = []
344
+ run_test("intrinsic_math1", name_expr + name_expr_C,
345
+ numerical_tests, lang, commands)
346
+
347
+
348
+ def test_instrinsic_math2_codegen():
349
+ # not included: frexp, ldexp, modf, fmod
350
+ from sympy.core.evalf import N
351
+ from sympy.functions.elementary.trigonometric import atan2
352
+ name_expr = [
353
+ ("test_atan2", atan2(x, y)),
354
+ ("test_pow", x**y),
355
+ ]
356
+ numerical_tests = []
357
+ for name, expr in name_expr:
358
+ for xval, yval in (0.2, 1.3), (0.5, -0.2), (0.8, 0.8):
359
+ expected = N(expr.subs(x, xval).subs(y, yval))
360
+ numerical_tests.append((name, (xval, yval), expected, 1e-14))
361
+ for lang, commands in valid_lang_commands:
362
+ run_test("intrinsic_math2", name_expr, numerical_tests, lang, commands)
363
+
364
+
365
+ def test_complicated_codegen():
366
+ from sympy.core.evalf import N
367
+ from sympy.functions.elementary.trigonometric import (cos, sin, tan)
368
+ name_expr = [
369
+ ("test1", ((sin(x) + cos(y) + tan(z))**7).expand()),
370
+ ("test2", cos(cos(cos(cos(cos(cos(cos(cos(x + y + z))))))))),
371
+ ]
372
+ numerical_tests = []
373
+ for name, expr in name_expr:
374
+ for xval, yval, zval in (0.2, 1.3, -0.3), (0.5, -0.2, 0.0), (0.8, 2.1, 0.8):
375
+ expected = N(expr.subs(x, xval).subs(y, yval).subs(z, zval))
376
+ numerical_tests.append((name, (xval, yval, zval), expected, 1e-12))
377
+ for lang, commands in valid_lang_commands:
378
+ run_test(
379
+ "complicated_codegen", name_expr, numerical_tests, lang, commands)
lib/python3.12/site-packages/sympy/external/tests/test_gmpy.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.external.gmpy import LONG_MAX, iroot
2
+ from sympy.testing.pytest import raises
3
+
4
+
5
+ def test_iroot():
6
+ assert iroot(2, LONG_MAX) == (1, False)
7
+ assert iroot(2, LONG_MAX + 1) == (1, False)
8
+ for x in range(3):
9
+ assert iroot(x, 1) == (x, True)
10
+ raises(ValueError, lambda: iroot(-1, 1))
11
+ raises(ValueError, lambda: iroot(0, 0))
12
+ raises(ValueError, lambda: iroot(0, -1))
lib/python3.12/site-packages/sympy/external/tests/test_importtools.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.external import import_module
2
+ from sympy.testing.pytest import warns
3
+
4
+ # fixes issue that arose in addressing issue 6533
5
+ def test_no_stdlib_collections():
6
+ '''
7
+ make sure we get the right collections when it is not part of a
8
+ larger list
9
+ '''
10
+ import collections
11
+ matplotlib = import_module('matplotlib',
12
+ import_kwargs={'fromlist': ['cm', 'collections']},
13
+ min_module_version='1.1.0', catch=(RuntimeError,))
14
+ if matplotlib:
15
+ assert collections != matplotlib.collections
16
+
17
+ def test_no_stdlib_collections2():
18
+ '''
19
+ make sure we get the right collections when it is not part of a
20
+ larger list
21
+ '''
22
+ import collections
23
+ matplotlib = import_module('matplotlib',
24
+ import_kwargs={'fromlist': ['collections']},
25
+ min_module_version='1.1.0', catch=(RuntimeError,))
26
+ if matplotlib:
27
+ assert collections != matplotlib.collections
28
+
29
+ def test_no_stdlib_collections3():
30
+ '''make sure we get the right collections with no catch'''
31
+ import collections
32
+ matplotlib = import_module('matplotlib',
33
+ import_kwargs={'fromlist': ['cm', 'collections']},
34
+ min_module_version='1.1.0')
35
+ if matplotlib:
36
+ assert collections != matplotlib.collections
37
+
38
+ def test_min_module_version_python3_basestring_error():
39
+ with warns(UserWarning):
40
+ import_module('mpmath', min_module_version='1000.0.1')
lib/python3.12/site-packages/sympy/external/tests/test_ntheory.py ADDED
@@ -0,0 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from itertools import permutations
2
+
3
+ from sympy.external.ntheory import (bit_scan1, remove, bit_scan0, is_fermat_prp,
4
+ is_euler_prp, is_strong_prp, gcdext, _lucas_sequence,
5
+ is_fibonacci_prp, is_lucas_prp, is_selfridge_prp,
6
+ is_strong_lucas_prp, is_strong_selfridge_prp,
7
+ is_bpsw_prp, is_strong_bpsw_prp)
8
+ from sympy.testing.pytest import raises
9
+
10
+
11
+ def test_bit_scan1():
12
+ assert bit_scan1(0) is None
13
+ assert bit_scan1(1) == 0
14
+ assert bit_scan1(-1) == 0
15
+ assert bit_scan1(2) == 1
16
+ assert bit_scan1(7) == 0
17
+ assert bit_scan1(-7) == 0
18
+ for i in range(100):
19
+ assert bit_scan1(1 << i) == i
20
+ assert bit_scan1((1 << i) * 31337) == i
21
+ for i in range(500):
22
+ n = (1 << 500) + (1 << i)
23
+ assert bit_scan1(n) == i
24
+ assert bit_scan1(1 << 1000001) == 1000001
25
+ assert bit_scan1((1 << 273956)*7**37) == 273956
26
+ # issue 12709
27
+ for i in range(1, 10):
28
+ big = 1 << i
29
+ assert bit_scan1(-big) == bit_scan1(big)
30
+
31
+
32
+ def test_bit_scan0():
33
+ assert bit_scan0(-1) is None
34
+ assert bit_scan0(0) == 0
35
+ assert bit_scan0(1) == 1
36
+ assert bit_scan0(-2) == 0
37
+
38
+
39
+ def test_remove():
40
+ raises(ValueError, lambda: remove(1, 1))
41
+ assert remove(0, 3) == (0, 0)
42
+ for f in range(2, 10):
43
+ for y in range(2, 1000):
44
+ for z in [1, 17, 101, 1009]:
45
+ assert remove(z*f**y, f) == (z, y)
46
+
47
+
48
+ def test_gcdext():
49
+ assert gcdext(0, 0) == (0, 0, 0)
50
+ assert gcdext(3, 0) == (3, 1, 0)
51
+ assert gcdext(0, 4) == (4, 0, 1)
52
+
53
+ for n in range(1, 10):
54
+ assert gcdext(n, 1) == gcdext(-n, 1) == (1, 0, 1)
55
+ assert gcdext(n, -1) == gcdext(-n, -1) == (1, 0, -1)
56
+ assert gcdext(n, n) == gcdext(-n, n) == (n, 0, 1)
57
+ assert gcdext(n, -n) == gcdext(-n, -n) == (n, 0, -1)
58
+
59
+ for n in range(2, 10):
60
+ assert gcdext(1, n) == gcdext(1, -n) == (1, 1, 0)
61
+ assert gcdext(-1, n) == gcdext(-1, -n) == (1, -1, 0)
62
+
63
+ for a, b in permutations([2**5, 3, 5, 7**2, 11], 2):
64
+ g, x, y = gcdext(a, b)
65
+ assert g == a*x + b*y == 1
66
+
67
+
68
+ def test_is_fermat_prp():
69
+ # invalid input
70
+ raises(ValueError, lambda: is_fermat_prp(0, 10))
71
+ raises(ValueError, lambda: is_fermat_prp(5, 1))
72
+
73
+ # n = 1
74
+ assert not is_fermat_prp(1, 3)
75
+
76
+ # n is prime
77
+ assert is_fermat_prp(2, 4)
78
+ assert is_fermat_prp(3, 2)
79
+ assert is_fermat_prp(11, 3)
80
+ assert is_fermat_prp(2**31-1, 5)
81
+
82
+ # A001567
83
+ pseudorpime = [341, 561, 645, 1105, 1387, 1729, 1905, 2047,
84
+ 2465, 2701, 2821, 3277, 4033, 4369, 4371, 4681]
85
+ for n in pseudorpime:
86
+ assert is_fermat_prp(n, 2)
87
+
88
+ # A020136
89
+ pseudorpime = [15, 85, 91, 341, 435, 451, 561, 645, 703, 1105,
90
+ 1247, 1271, 1387, 1581, 1695, 1729, 1891, 1905]
91
+ for n in pseudorpime:
92
+ assert is_fermat_prp(n, 4)
93
+
94
+
95
+ def test_is_euler_prp():
96
+ # invalid input
97
+ raises(ValueError, lambda: is_euler_prp(0, 10))
98
+ raises(ValueError, lambda: is_euler_prp(5, 1))
99
+
100
+ # n = 1
101
+ assert not is_euler_prp(1, 3)
102
+
103
+ # n is prime
104
+ assert is_euler_prp(2, 4)
105
+ assert is_euler_prp(3, 2)
106
+ assert is_euler_prp(11, 3)
107
+ assert is_euler_prp(2**31-1, 5)
108
+
109
+ # A047713
110
+ pseudorpime = [561, 1105, 1729, 1905, 2047, 2465, 3277, 4033,
111
+ 4681, 6601, 8321, 8481, 10585, 12801, 15841]
112
+ for n in pseudorpime:
113
+ assert is_euler_prp(n, 2)
114
+
115
+ # A048950
116
+ pseudorpime = [121, 703, 1729, 1891, 2821, 3281, 7381, 8401,
117
+ 8911, 10585, 12403, 15457, 15841, 16531, 18721]
118
+ for n in pseudorpime:
119
+ assert is_euler_prp(n, 3)
120
+
121
+
122
+ def test_is_strong_prp():
123
+ # invalid input
124
+ raises(ValueError, lambda: is_strong_prp(0, 10))
125
+ raises(ValueError, lambda: is_strong_prp(5, 1))
126
+
127
+ # n = 1
128
+ assert not is_strong_prp(1, 3)
129
+
130
+ # n is prime
131
+ assert is_strong_prp(2, 4)
132
+ assert is_strong_prp(3, 2)
133
+ assert is_strong_prp(11, 3)
134
+ assert is_strong_prp(2**31-1, 5)
135
+
136
+ # A001262
137
+ pseudorpime = [2047, 3277, 4033, 4681, 8321, 15841, 29341,
138
+ 42799, 49141, 52633, 65281, 74665, 80581]
139
+ for n in pseudorpime:
140
+ assert is_strong_prp(n, 2)
141
+
142
+ # A020229
143
+ pseudorpime = [121, 703, 1891, 3281, 8401, 8911, 10585, 12403,
144
+ 16531, 18721, 19345, 23521, 31621, 44287, 47197]
145
+ for n in pseudorpime:
146
+ assert is_strong_prp(n, 3)
147
+
148
+
149
+ def test_lucas_sequence():
150
+ def lucas_u(P, Q, length):
151
+ array = [0] * length
152
+ array[1] = 1
153
+ for k in range(2, length):
154
+ array[k] = P * array[k - 1] - Q * array[k - 2]
155
+ return array
156
+
157
+ def lucas_v(P, Q, length):
158
+ array = [0] * length
159
+ array[0] = 2
160
+ array[1] = P
161
+ for k in range(2, length):
162
+ array[k] = P * array[k - 1] - Q * array[k - 2]
163
+ return array
164
+
165
+ length = 20
166
+ for P in range(-10, 10):
167
+ for Q in range(-10, 10):
168
+ D = P**2 - 4*Q
169
+ if D == 0:
170
+ continue
171
+ us = lucas_u(P, Q, length)
172
+ vs = lucas_v(P, Q, length)
173
+ for n in range(3, 100, 2):
174
+ for k in range(length):
175
+ U, V, Qk = _lucas_sequence(n, P, Q, k)
176
+ assert U == us[k] % n
177
+ assert V == vs[k] % n
178
+ assert pow(Q, k, n) == Qk
179
+
180
+
181
+ def test_is_fibonacci_prp():
182
+ # invalid input
183
+ raises(ValueError, lambda: is_fibonacci_prp(3, 2, 1))
184
+ raises(ValueError, lambda: is_fibonacci_prp(3, -5, 1))
185
+ raises(ValueError, lambda: is_fibonacci_prp(3, 5, 2))
186
+ raises(ValueError, lambda: is_fibonacci_prp(0, 5, -1))
187
+
188
+ # n = 1
189
+ assert not is_fibonacci_prp(1, 3, 1)
190
+
191
+ # n is prime
192
+ assert is_fibonacci_prp(2, 5, 1)
193
+ assert is_fibonacci_prp(3, 6, -1)
194
+ assert is_fibonacci_prp(11, 7, 1)
195
+ assert is_fibonacci_prp(2**31-1, 8, -1)
196
+
197
+ # A005845
198
+ pseudorpime = [705, 2465, 2737, 3745, 4181, 5777, 6721,
199
+ 10877, 13201, 15251, 24465, 29281, 34561]
200
+ for n in pseudorpime:
201
+ assert is_fibonacci_prp(n, 1, -1)
202
+
203
+
204
+ def test_is_lucas_prp():
205
+ # invalid input
206
+ raises(ValueError, lambda: is_lucas_prp(3, 2, 1))
207
+ raises(ValueError, lambda: is_lucas_prp(0, 5, -1))
208
+ raises(ValueError, lambda: is_lucas_prp(15, 3, 1))
209
+
210
+ # n = 1
211
+ assert not is_lucas_prp(1, 3, 1)
212
+
213
+ # n is prime
214
+ assert is_lucas_prp(2, 5, 2)
215
+ assert is_lucas_prp(3, 6, -1)
216
+ assert is_lucas_prp(11, 7, 5)
217
+ assert is_lucas_prp(2**31-1, 8, -3)
218
+
219
+ # A081264
220
+ pseudorpime = [323, 377, 1891, 3827, 4181, 5777, 6601, 6721,
221
+ 8149, 10877, 11663, 13201, 13981, 15251, 17119]
222
+ for n in pseudorpime:
223
+ assert is_lucas_prp(n, 1, -1)
224
+
225
+
226
+ def test_is_selfridge_prp():
227
+ # invalid input
228
+ raises(ValueError, lambda: is_selfridge_prp(0))
229
+
230
+ # n = 1
231
+ assert not is_selfridge_prp(1)
232
+
233
+ # n is prime
234
+ assert is_selfridge_prp(2)
235
+ assert is_selfridge_prp(3)
236
+ assert is_selfridge_prp(11)
237
+ assert is_selfridge_prp(2**31-1)
238
+
239
+ # A217120
240
+ pseudorpime = [323, 377, 1159, 1829, 3827, 5459, 5777, 9071,
241
+ 9179, 10877, 11419, 11663, 13919, 14839, 16109]
242
+ for n in pseudorpime:
243
+ assert is_selfridge_prp(n)
244
+
245
+
246
+ def test_is_strong_lucas_prp():
247
+ # invalid input
248
+ raises(ValueError, lambda: is_strong_lucas_prp(3, 2, 1))
249
+ raises(ValueError, lambda: is_strong_lucas_prp(0, 5, -1))
250
+ raises(ValueError, lambda: is_strong_lucas_prp(15, 3, 1))
251
+
252
+ # n = 1
253
+ assert not is_strong_lucas_prp(1, 3, 1)
254
+
255
+ # n is prime
256
+ assert is_strong_lucas_prp(2, 5, 2)
257
+ assert is_strong_lucas_prp(3, 6, -1)
258
+ assert is_strong_lucas_prp(11, 7, 5)
259
+ assert is_strong_lucas_prp(2**31-1, 8, -3)
260
+
261
+
262
+ def test_is_strong_selfridge_prp():
263
+ # invalid input
264
+ raises(ValueError, lambda: is_strong_selfridge_prp(0))
265
+
266
+ # n = 1
267
+ assert not is_strong_selfridge_prp(1)
268
+
269
+ # n is prime
270
+ assert is_strong_selfridge_prp(2)
271
+ assert is_strong_selfridge_prp(3)
272
+ assert is_strong_selfridge_prp(11)
273
+ assert is_strong_selfridge_prp(2**31-1)
274
+
275
+ # A217255
276
+ pseudorpime = [5459, 5777, 10877, 16109, 18971, 22499, 24569,
277
+ 25199, 40309, 58519, 75077, 97439, 100127, 113573]
278
+ for n in pseudorpime:
279
+ assert is_strong_selfridge_prp(n)
280
+
281
+
282
+ def test_is_bpsw_prp():
283
+ # invalid input
284
+ raises(ValueError, lambda: is_bpsw_prp(0))
285
+
286
+ # n = 1
287
+ assert not is_bpsw_prp(1)
288
+
289
+ # n is prime
290
+ assert is_bpsw_prp(2)
291
+ assert is_bpsw_prp(3)
292
+ assert is_bpsw_prp(11)
293
+ assert is_bpsw_prp(2**31-1)
294
+
295
+
296
+ def test_is_strong_bpsw_prp():
297
+ # invalid input
298
+ raises(ValueError, lambda: is_strong_bpsw_prp(0))
299
+
300
+ # n = 1
301
+ assert not is_strong_bpsw_prp(1)
302
+
303
+ # n is prime
304
+ assert is_strong_bpsw_prp(2)
305
+ assert is_strong_bpsw_prp(3)
306
+ assert is_strong_bpsw_prp(11)
307
+ assert is_strong_bpsw_prp(2**31-1)
lib/python3.12/site-packages/sympy/external/tests/test_numpy.py ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This testfile tests SymPy <-> NumPy compatibility
2
+
3
+ # Don't test any SymPy features here. Just pure interaction with NumPy.
4
+ # Always write regular SymPy tests for anything, that can be tested in pure
5
+ # Python (without numpy). Here we test everything, that a user may need when
6
+ # using SymPy with NumPy
7
+ from sympy.external.importtools import version_tuple
8
+ from sympy.external import import_module
9
+
10
+ numpy = import_module('numpy')
11
+ if numpy:
12
+ array, matrix, ndarray = numpy.array, numpy.matrix, numpy.ndarray
13
+ else:
14
+ #bin/test will not execute any tests now
15
+ disabled = True
16
+
17
+
18
+ from sympy.core.numbers import (Float, Integer, Rational)
19
+ from sympy.core.symbol import (Symbol, symbols)
20
+ from sympy.functions.elementary.trigonometric import sin
21
+ from sympy.matrices.dense import (Matrix, list2numpy, matrix2numpy, symarray)
22
+ from sympy.utilities.lambdify import lambdify
23
+ import sympy
24
+
25
+ import mpmath
26
+ from sympy.abc import x, y, z
27
+ from sympy.utilities.decorator import conserve_mpmath_dps
28
+ from sympy.utilities.exceptions import ignore_warnings
29
+ from sympy.testing.pytest import raises
30
+
31
+
32
+ # first, systematically check, that all operations are implemented and don't
33
+ # raise an exception
34
+
35
+
36
+ def test_systematic_basic():
37
+ def s(sympy_object, numpy_array):
38
+ _ = [sympy_object + numpy_array,
39
+ numpy_array + sympy_object,
40
+ sympy_object - numpy_array,
41
+ numpy_array - sympy_object,
42
+ sympy_object * numpy_array,
43
+ numpy_array * sympy_object,
44
+ sympy_object / numpy_array,
45
+ numpy_array / sympy_object,
46
+ sympy_object ** numpy_array,
47
+ numpy_array ** sympy_object]
48
+ x = Symbol("x")
49
+ y = Symbol("y")
50
+ sympy_objs = [
51
+ Rational(2, 3),
52
+ Float("1.3"),
53
+ x,
54
+ y,
55
+ pow(x, y)*y,
56
+ Integer(5),
57
+ Float(5.5),
58
+ ]
59
+ numpy_objs = [
60
+ array([1]),
61
+ array([3, 8, -1]),
62
+ array([x, x**2, Rational(5)]),
63
+ array([x/y*sin(y), 5, Rational(5)]),
64
+ ]
65
+ for x in sympy_objs:
66
+ for y in numpy_objs:
67
+ s(x, y)
68
+
69
+
70
+ # now some random tests, that test particular problems and that also
71
+ # check that the results of the operations are correct
72
+
73
+ def test_basics():
74
+ one = Rational(1)
75
+ zero = Rational(0)
76
+ assert array(1) == array(one)
77
+ assert array([one]) == array([one])
78
+ assert array([x]) == array([x])
79
+ assert array(x) == array(Symbol("x"))
80
+ assert array(one + x) == array(1 + x)
81
+
82
+ X = array([one, zero, zero])
83
+ assert (X == array([one, zero, zero])).all()
84
+ assert (X == array([one, 0, 0])).all()
85
+
86
+
87
+ def test_arrays():
88
+ one = Rational(1)
89
+ zero = Rational(0)
90
+ X = array([one, zero, zero])
91
+ Y = one*X
92
+ X = array([Symbol("a") + Rational(1, 2)])
93
+ Y = X + X
94
+ assert Y == array([1 + 2*Symbol("a")])
95
+ Y = Y + 1
96
+ assert Y == array([2 + 2*Symbol("a")])
97
+ Y = X - X
98
+ assert Y == array([0])
99
+
100
+
101
+ def test_conversion1():
102
+ a = list2numpy([x**2, x])
103
+ #looks like an array?
104
+ assert isinstance(a, ndarray)
105
+ assert a[0] == x**2
106
+ assert a[1] == x
107
+ assert len(a) == 2
108
+ #yes, it's the array
109
+
110
+
111
+ def test_conversion2():
112
+ a = 2*list2numpy([x**2, x])
113
+ b = list2numpy([2*x**2, 2*x])
114
+ assert (a == b).all()
115
+
116
+ one = Rational(1)
117
+ zero = Rational(0)
118
+ X = list2numpy([one, zero, zero])
119
+ Y = one*X
120
+ X = list2numpy([Symbol("a") + Rational(1, 2)])
121
+ Y = X + X
122
+ assert Y == array([1 + 2*Symbol("a")])
123
+ Y = Y + 1
124
+ assert Y == array([2 + 2*Symbol("a")])
125
+ Y = X - X
126
+ assert Y == array([0])
127
+
128
+
129
+ def test_list2numpy():
130
+ assert (array([x**2, x]) == list2numpy([x**2, x])).all()
131
+
132
+
133
+ def test_Matrix1():
134
+ m = Matrix([[x, x**2], [5, 2/x]])
135
+ assert (array(m.subs(x, 2)) == array([[2, 4], [5, 1]])).all()
136
+ m = Matrix([[sin(x), x**2], [5, 2/x]])
137
+ assert (array(m.subs(x, 2)) == array([[sin(2), 4], [5, 1]])).all()
138
+
139
+
140
+ def test_Matrix2():
141
+ m = Matrix([[x, x**2], [5, 2/x]])
142
+ with ignore_warnings(PendingDeprecationWarning):
143
+ assert (matrix(m.subs(x, 2)) == matrix([[2, 4], [5, 1]])).all()
144
+ m = Matrix([[sin(x), x**2], [5, 2/x]])
145
+ with ignore_warnings(PendingDeprecationWarning):
146
+ assert (matrix(m.subs(x, 2)) == matrix([[sin(2), 4], [5, 1]])).all()
147
+
148
+
149
+ def test_Matrix3():
150
+ a = array([[2, 4], [5, 1]])
151
+ assert Matrix(a) == Matrix([[2, 4], [5, 1]])
152
+ assert Matrix(a) != Matrix([[2, 4], [5, 2]])
153
+ a = array([[sin(2), 4], [5, 1]])
154
+ assert Matrix(a) == Matrix([[sin(2), 4], [5, 1]])
155
+ assert Matrix(a) != Matrix([[sin(0), 4], [5, 1]])
156
+
157
+
158
+ def test_Matrix4():
159
+ with ignore_warnings(PendingDeprecationWarning):
160
+ a = matrix([[2, 4], [5, 1]])
161
+ assert Matrix(a) == Matrix([[2, 4], [5, 1]])
162
+ assert Matrix(a) != Matrix([[2, 4], [5, 2]])
163
+ with ignore_warnings(PendingDeprecationWarning):
164
+ a = matrix([[sin(2), 4], [5, 1]])
165
+ assert Matrix(a) == Matrix([[sin(2), 4], [5, 1]])
166
+ assert Matrix(a) != Matrix([[sin(0), 4], [5, 1]])
167
+
168
+
169
+ def test_Matrix_sum():
170
+ M = Matrix([[1, 2, 3], [x, y, x], [2*y, -50, z*x]])
171
+ with ignore_warnings(PendingDeprecationWarning):
172
+ m = matrix([[2, 3, 4], [x, 5, 6], [x, y, z**2]])
173
+ assert M + m == Matrix([[3, 5, 7], [2*x, y + 5, x + 6], [2*y + x, y - 50, z*x + z**2]])
174
+ assert m + M == Matrix([[3, 5, 7], [2*x, y + 5, x + 6], [2*y + x, y - 50, z*x + z**2]])
175
+ assert M + m == M.add(m)
176
+
177
+
178
+ def test_Matrix_mul():
179
+ M = Matrix([[1, 2, 3], [x, y, x]])
180
+ with ignore_warnings(PendingDeprecationWarning):
181
+ m = matrix([[2, 4], [x, 6], [x, z**2]])
182
+ assert M*m == Matrix([
183
+ [ 2 + 5*x, 16 + 3*z**2],
184
+ [2*x + x*y + x**2, 4*x + 6*y + x*z**2],
185
+ ])
186
+
187
+ assert m*M == Matrix([
188
+ [ 2 + 4*x, 4 + 4*y, 6 + 4*x],
189
+ [ 7*x, 2*x + 6*y, 9*x],
190
+ [x + x*z**2, 2*x + y*z**2, 3*x + x*z**2],
191
+ ])
192
+ a = array([2])
193
+ assert a[0] * M == 2 * M
194
+ assert M * a[0] == 2 * M
195
+
196
+
197
+ def test_Matrix_array():
198
+ class matarray:
199
+ def __array__(self, dtype=object, copy=None):
200
+ if copy is not None and not copy:
201
+ raise TypeError("Cannot implement copy=False when converting Matrix to ndarray")
202
+ from numpy import array
203
+ return array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
204
+ matarr = matarray()
205
+ assert Matrix(matarr) == Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
206
+
207
+
208
+ def test_matrix2numpy():
209
+ a = matrix2numpy(Matrix([[1, x**2], [3*sin(x), 0]]))
210
+ assert isinstance(a, ndarray)
211
+ assert a.shape == (2, 2)
212
+ assert a[0, 0] == 1
213
+ assert a[0, 1] == x**2
214
+ assert a[1, 0] == 3*sin(x)
215
+ assert a[1, 1] == 0
216
+
217
+
218
+ def test_matrix2numpy_conversion():
219
+ a = Matrix([[1, 2, sin(x)], [x**2, x, Rational(1, 2)]])
220
+ b = array([[1, 2, sin(x)], [x**2, x, Rational(1, 2)]])
221
+ assert (matrix2numpy(a) == b).all()
222
+ assert matrix2numpy(a).dtype == numpy.dtype('object')
223
+
224
+ c = matrix2numpy(Matrix([[1, 2], [10, 20]]), dtype='int8')
225
+ d = matrix2numpy(Matrix([[1, 2], [10, 20]]), dtype='float64')
226
+ assert c.dtype == numpy.dtype('int8')
227
+ assert d.dtype == numpy.dtype('float64')
228
+
229
+
230
+ def test_issue_3728():
231
+ assert (Rational(1, 2)*array([2*x, 0]) == array([x, 0])).all()
232
+ assert (Rational(1, 2) + array(
233
+ [2*x, 0]) == array([2*x + Rational(1, 2), Rational(1, 2)])).all()
234
+ assert (Float("0.5")*array([2*x, 0]) == array([Float("1.0")*x, 0])).all()
235
+ assert (Float("0.5") + array(
236
+ [2*x, 0]) == array([2*x + Float("0.5"), Float("0.5")])).all()
237
+
238
+
239
+ @conserve_mpmath_dps
240
+ def test_lambdify():
241
+ mpmath.mp.dps = 16
242
+ sin02 = mpmath.mpf("0.198669330795061215459412627")
243
+ f = lambdify(x, sin(x), "numpy")
244
+ prec = 1e-15
245
+ assert -prec < f(0.2) - sin02 < prec
246
+
247
+ # if this succeeds, it can't be a numpy function
248
+
249
+ if version_tuple(numpy.__version__) >= version_tuple('1.17'):
250
+ with raises(TypeError):
251
+ f(x)
252
+ else:
253
+ with raises(AttributeError):
254
+ f(x)
255
+
256
+
257
+ def test_lambdify_matrix():
258
+ f = lambdify(x, Matrix([[x, 2*x], [1, 2]]), [{'ImmutableMatrix': numpy.array}, "numpy"])
259
+ assert (f(1) == array([[1, 2], [1, 2]])).all()
260
+
261
+
262
+ def test_lambdify_matrix_multi_input():
263
+ M = sympy.Matrix([[x**2, x*y, x*z],
264
+ [y*x, y**2, y*z],
265
+ [z*x, z*y, z**2]])
266
+ f = lambdify((x, y, z), M, [{'ImmutableMatrix': numpy.array}, "numpy"])
267
+
268
+ xh, yh, zh = 1.0, 2.0, 3.0
269
+ expected = array([[xh**2, xh*yh, xh*zh],
270
+ [yh*xh, yh**2, yh*zh],
271
+ [zh*xh, zh*yh, zh**2]])
272
+ actual = f(xh, yh, zh)
273
+ assert numpy.allclose(actual, expected)
274
+
275
+
276
+ def test_lambdify_matrix_vec_input():
277
+ X = sympy.DeferredVector('X')
278
+ M = Matrix([
279
+ [X[0]**2, X[0]*X[1], X[0]*X[2]],
280
+ [X[1]*X[0], X[1]**2, X[1]*X[2]],
281
+ [X[2]*X[0], X[2]*X[1], X[2]**2]])
282
+ f = lambdify(X, M, [{'ImmutableMatrix': numpy.array}, "numpy"])
283
+
284
+ Xh = array([1.0, 2.0, 3.0])
285
+ expected = array([[Xh[0]**2, Xh[0]*Xh[1], Xh[0]*Xh[2]],
286
+ [Xh[1]*Xh[0], Xh[1]**2, Xh[1]*Xh[2]],
287
+ [Xh[2]*Xh[0], Xh[2]*Xh[1], Xh[2]**2]])
288
+ actual = f(Xh)
289
+ assert numpy.allclose(actual, expected)
290
+
291
+
292
+ def test_lambdify_transl():
293
+ from sympy.utilities.lambdify import NUMPY_TRANSLATIONS
294
+ for sym, mat in NUMPY_TRANSLATIONS.items():
295
+ assert sym in sympy.__dict__
296
+ assert mat in numpy.__dict__
297
+
298
+
299
+ def test_symarray():
300
+ """Test creation of numpy arrays of SymPy symbols."""
301
+
302
+ import numpy as np
303
+ import numpy.testing as npt
304
+
305
+ syms = symbols('_0,_1,_2')
306
+ s1 = symarray("", 3)
307
+ s2 = symarray("", 3)
308
+ npt.assert_array_equal(s1, np.array(syms, dtype=object))
309
+ assert s1[0] == s2[0]
310
+
311
+ a = symarray('a', 3)
312
+ b = symarray('b', 3)
313
+ assert not(a[0] == b[0])
314
+
315
+ asyms = symbols('a_0,a_1,a_2')
316
+ npt.assert_array_equal(a, np.array(asyms, dtype=object))
317
+
318
+ # Multidimensional checks
319
+ a2d = symarray('a', (2, 3))
320
+ assert a2d.shape == (2, 3)
321
+ a00, a12 = symbols('a_0_0,a_1_2')
322
+ assert a2d[0, 0] == a00
323
+ assert a2d[1, 2] == a12
324
+
325
+ a3d = symarray('a', (2, 3, 2))
326
+ assert a3d.shape == (2, 3, 2)
327
+ a000, a120, a121 = symbols('a_0_0_0,a_1_2_0,a_1_2_1')
328
+ assert a3d[0, 0, 0] == a000
329
+ assert a3d[1, 2, 0] == a120
330
+ assert a3d[1, 2, 1] == a121
331
+
332
+
333
+ def test_vectorize():
334
+ assert (numpy.vectorize(
335
+ sin)([1, 2, 3]) == numpy.array([sin(1), sin(2), sin(3)])).all()
lib/python3.12/site-packages/sympy/external/tests/test_pythonmpq.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ test_pythonmpq.py
3
+
4
+ Test the PythonMPQ class for consistency with gmpy2's mpq type. If gmpy2 is
5
+ installed run the same tests for both.
6
+ """
7
+ from fractions import Fraction
8
+ from decimal import Decimal
9
+ import pickle
10
+ from typing import Callable, List, Tuple, Type
11
+
12
+ from sympy.testing.pytest import raises
13
+
14
+ from sympy.external.pythonmpq import PythonMPQ
15
+
16
+ #
17
+ # If gmpy2 is installed then run the tests for both mpq and PythonMPQ.
18
+ # That should ensure consistency between the implementation here and mpq.
19
+ #
20
+ rational_types: List[Tuple[Callable, Type, Callable, Type]]
21
+ rational_types = [(PythonMPQ, PythonMPQ, int, int)]
22
+ try:
23
+ from gmpy2 import mpq, mpz
24
+ rational_types.append((mpq, type(mpq(1)), mpz, type(mpz(1))))
25
+ except ImportError:
26
+ pass
27
+
28
+
29
+ def test_PythonMPQ():
30
+ #
31
+ # Test PythonMPQ and also mpq if gmpy/gmpy2 is installed.
32
+ #
33
+ for Q, TQ, Z, TZ in rational_types:
34
+
35
+ def check_Q(q):
36
+ assert isinstance(q, TQ)
37
+ assert isinstance(q.numerator, TZ)
38
+ assert isinstance(q.denominator, TZ)
39
+ return q.numerator, q.denominator
40
+
41
+ # Check construction from different types
42
+ assert check_Q(Q(3)) == (3, 1)
43
+ assert check_Q(Q(3, 5)) == (3, 5)
44
+ assert check_Q(Q(Q(3, 5))) == (3, 5)
45
+ assert check_Q(Q(0.5)) == (1, 2)
46
+ assert check_Q(Q('0.5')) == (1, 2)
47
+ assert check_Q(Q(Fraction(3, 5))) == (3, 5)
48
+
49
+ # https://github.com/aleaxit/gmpy/issues/327
50
+ if Q is PythonMPQ:
51
+ assert check_Q(Q(Decimal('0.6'))) == (3, 5)
52
+
53
+ # Invalid types
54
+ raises(TypeError, lambda: Q([]))
55
+ raises(TypeError, lambda: Q([], []))
56
+
57
+ # Check normalisation of signs
58
+ assert check_Q(Q(2, 3)) == (2, 3)
59
+ assert check_Q(Q(-2, 3)) == (-2, 3)
60
+ assert check_Q(Q(2, -3)) == (-2, 3)
61
+ assert check_Q(Q(-2, -3)) == (2, 3)
62
+
63
+ # Check gcd calculation
64
+ assert check_Q(Q(12, 8)) == (3, 2)
65
+
66
+ # __int__/__float__
67
+ assert int(Q(5, 3)) == 1
68
+ assert int(Q(-5, 3)) == -1
69
+ assert float(Q(5, 2)) == 2.5
70
+ assert float(Q(-5, 2)) == -2.5
71
+
72
+ # __str__/__repr__
73
+ assert str(Q(2, 1)) == "2"
74
+ assert str(Q(1, 2)) == "1/2"
75
+ if Q is PythonMPQ:
76
+ assert repr(Q(2, 1)) == "MPQ(2,1)"
77
+ assert repr(Q(1, 2)) == "MPQ(1,2)"
78
+ else:
79
+ assert repr(Q(2, 1)) == "mpq(2,1)"
80
+ assert repr(Q(1, 2)) == "mpq(1,2)"
81
+
82
+ # __bool__
83
+ assert bool(Q(1, 2)) is True
84
+ assert bool(Q(0)) is False
85
+
86
+ # __eq__/__ne__
87
+ assert (Q(2, 3) == Q(2, 3)) is True
88
+ assert (Q(2, 3) == Q(2, 5)) is False
89
+ assert (Q(2, 3) != Q(2, 3)) is False
90
+ assert (Q(2, 3) != Q(2, 5)) is True
91
+
92
+ # __hash__
93
+ assert hash(Q(3, 5)) == hash(Fraction(3, 5))
94
+
95
+ # __reduce__
96
+ q = Q(2, 3)
97
+ assert pickle.loads(pickle.dumps(q)) == q
98
+
99
+ # __ge__/__gt__/__le__/__lt__
100
+ assert (Q(1, 3) < Q(2, 3)) is True
101
+ assert (Q(2, 3) < Q(2, 3)) is False
102
+ assert (Q(2, 3) < Q(1, 3)) is False
103
+ assert (Q(-2, 3) < Q(1, 3)) is True
104
+ assert (Q(1, 3) < Q(-2, 3)) is False
105
+
106
+ assert (Q(1, 3) <= Q(2, 3)) is True
107
+ assert (Q(2, 3) <= Q(2, 3)) is True
108
+ assert (Q(2, 3) <= Q(1, 3)) is False
109
+ assert (Q(-2, 3) <= Q(1, 3)) is True
110
+ assert (Q(1, 3) <= Q(-2, 3)) is False
111
+
112
+ assert (Q(1, 3) > Q(2, 3)) is False
113
+ assert (Q(2, 3) > Q(2, 3)) is False
114
+ assert (Q(2, 3) > Q(1, 3)) is True
115
+ assert (Q(-2, 3) > Q(1, 3)) is False
116
+ assert (Q(1, 3) > Q(-2, 3)) is True
117
+
118
+ assert (Q(1, 3) >= Q(2, 3)) is False
119
+ assert (Q(2, 3) >= Q(2, 3)) is True
120
+ assert (Q(2, 3) >= Q(1, 3)) is True
121
+ assert (Q(-2, 3) >= Q(1, 3)) is False
122
+ assert (Q(1, 3) >= Q(-2, 3)) is True
123
+
124
+ # __abs__/__pos__/__neg__
125
+ assert abs(Q(2, 3)) == abs(Q(-2, 3)) == Q(2, 3)
126
+ assert +Q(2, 3) == Q(2, 3)
127
+ assert -Q(2, 3) == Q(-2, 3)
128
+
129
+ # __add__/__radd__
130
+ assert Q(2, 3) + Q(5, 7) == Q(29, 21)
131
+ assert Q(2, 3) + 1 == Q(5, 3)
132
+ assert 1 + Q(2, 3) == Q(5, 3)
133
+ raises(TypeError, lambda: [] + Q(1))
134
+ raises(TypeError, lambda: Q(1) + [])
135
+
136
+ # __sub__/__rsub__
137
+ assert Q(2, 3) - Q(5, 7) == Q(-1, 21)
138
+ assert Q(2, 3) - 1 == Q(-1, 3)
139
+ assert 1 - Q(2, 3) == Q(1, 3)
140
+ raises(TypeError, lambda: [] - Q(1))
141
+ raises(TypeError, lambda: Q(1) - [])
142
+
143
+ # __mul__/__rmul__
144
+ assert Q(2, 3) * Q(5, 7) == Q(10, 21)
145
+ assert Q(2, 3) * 1 == Q(2, 3)
146
+ assert 1 * Q(2, 3) == Q(2, 3)
147
+ raises(TypeError, lambda: [] * Q(1))
148
+ raises(TypeError, lambda: Q(1) * [])
149
+
150
+ # __pow__/__rpow__
151
+ assert Q(2, 3) ** 2 == Q(4, 9)
152
+ assert Q(2, 3) ** 1 == Q(2, 3)
153
+ assert Q(-2, 3) ** 2 == Q(4, 9)
154
+ assert Q(-2, 3) ** -1 == Q(-3, 2)
155
+ if Q is PythonMPQ:
156
+ raises(TypeError, lambda: 1 ** Q(2, 3))
157
+ raises(TypeError, lambda: Q(1, 4) ** Q(1, 2))
158
+ raises(TypeError, lambda: [] ** Q(1))
159
+ raises(TypeError, lambda: Q(1) ** [])
160
+
161
+ # __div__/__rdiv__
162
+ assert Q(2, 3) / Q(5, 7) == Q(14, 15)
163
+ assert Q(2, 3) / 1 == Q(2, 3)
164
+ assert 1 / Q(2, 3) == Q(3, 2)
165
+ raises(TypeError, lambda: [] / Q(1))
166
+ raises(TypeError, lambda: Q(1) / [])
167
+ raises(ZeroDivisionError, lambda: Q(1, 2) / Q(0))
168
+
169
+ # __divmod__
170
+ if Q is PythonMPQ:
171
+ raises(TypeError, lambda: Q(2, 3) // Q(1, 3))
172
+ raises(TypeError, lambda: Q(2, 3) % Q(1, 3))
173
+ raises(TypeError, lambda: 1 // Q(1, 3))
174
+ raises(TypeError, lambda: 1 % Q(1, 3))
175
+ raises(TypeError, lambda: Q(2, 3) // 1)
176
+ raises(TypeError, lambda: Q(2, 3) % 1)
lib/python3.12/site-packages/sympy/external/tests/test_scipy.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This testfile tests SymPy <-> SciPy compatibility
2
+
3
+ # Don't test any SymPy features here. Just pure interaction with SciPy.
4
+ # Always write regular SymPy tests for anything, that can be tested in pure
5
+ # Python (without scipy). Here we test everything, that a user may need when
6
+ # using SymPy with SciPy
7
+
8
+ from sympy.external import import_module
9
+
10
+ scipy = import_module('scipy')
11
+ if not scipy:
12
+ #bin/test will not execute any tests now
13
+ disabled = True
14
+
15
+ from sympy.functions.special.bessel import jn_zeros
16
+
17
+
18
+ def eq(a, b, tol=1e-6):
19
+ for x, y in zip(a, b):
20
+ if not (abs(x - y) < tol):
21
+ return False
22
+ return True
23
+
24
+
25
+ def test_jn_zeros():
26
+ assert eq(jn_zeros(0, 4, method="scipy"),
27
+ [3.141592, 6.283185, 9.424777, 12.566370])
28
+ assert eq(jn_zeros(1, 4, method="scipy"),
29
+ [4.493409, 7.725251, 10.904121, 14.066193])
30
+ assert eq(jn_zeros(2, 4, method="scipy"),
31
+ [5.763459, 9.095011, 12.322940, 15.514603])
32
+ assert eq(jn_zeros(3, 4, method="scipy"),
33
+ [6.987932, 10.417118, 13.698023, 16.923621])
34
+ assert eq(jn_zeros(4, 4, method="scipy"),
35
+ [8.182561, 11.704907, 15.039664, 18.301255])
lib/python3.12/site-packages/sympy/integrals/__pycache__/integrals.cpython-312.pyc ADDED
Binary file (65.9 kB). View file
 
lib/python3.12/site-packages/sympy/integrals/__pycache__/meijerint_doc.cpython-312.pyc ADDED
Binary file (1.99 kB). View file
 
lib/python3.12/site-packages/sympy/integrals/__pycache__/rationaltools.cpython-312.pyc ADDED
Binary file (16.3 kB). View file
 
lib/python3.12/site-packages/sympy/integrals/__pycache__/rde.cpython-312.pyc ADDED
Binary file (36.7 kB). View file
 
lib/python3.12/site-packages/sympy/integrals/__pycache__/risch.cpython-312.pyc ADDED
Binary file (87.8 kB). View file
 
lib/python3.12/site-packages/sympy/integrals/__pycache__/singularityfunctions.cpython-312.pyc ADDED
Binary file (2.76 kB). View file
 
lib/python3.12/site-packages/sympy/integrals/benchmarks/__init__.py ADDED
File without changes
lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (205 Bytes). View file
 
lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/bench_integrate.cpython-312.pyc ADDED
Binary file (1.24 kB). View file
 
lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/bench_trigintegrate.cpython-312.pyc ADDED
Binary file (840 Bytes). View file
 
lib/python3.12/site-packages/sympy/integrals/benchmarks/bench_integrate.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.symbol import Symbol
2
+ from sympy.functions.elementary.trigonometric import sin
3
+ from sympy.integrals.integrals import integrate
4
+
5
+ x = Symbol('x')
6
+
7
+
8
+ def bench_integrate_sin():
9
+ integrate(sin(x), x)
10
+
11
+
12
+ def bench_integrate_x1sin():
13
+ integrate(x**1*sin(x), x)
14
+
15
+
16
+ def bench_integrate_x2sin():
17
+ integrate(x**2*sin(x), x)
18
+
19
+
20
+ def bench_integrate_x3sin():
21
+ integrate(x**3*sin(x), x)