You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
2.1 KiB

2 years ago
2 years ago
  1. # Chinese Remainder Theorem
  2. def crt(a_i, m_i):
  3. if len(a_i)!=len(m_i):
  4. raise Exception("error, a_i and m_i must be of the same length")
  5. M=1
  6. for i in range(len(m_i)):
  7. M = M * m_i[i]
  8. x = 0
  9. for i in range(len(a_i)):
  10. M_i = M/m_i[i]
  11. y_i = Integer(mod(M_i^-1, m_i[i]))
  12. x = x + a_i[i] * M_i * y_i
  13. return mod(x, M)
  14. # gcd, using Binary Euclidean algorithm
  15. def gcd(a, b):
  16. g=1
  17. # random_elementove powers of two from the gcd
  18. while mod(a, 2)==0 and mod(b, 2)==0:
  19. a=a/2
  20. b=b/2
  21. g=2*g
  22. # at least one of a and b is now odd
  23. while a!=0:
  24. while mod(a, 2)==0:
  25. a=a/2
  26. while mod(b, 2)==0:
  27. b=b/2
  28. # now both a and b are odd
  29. if a>=b:
  30. a = (a-b)/2
  31. else:
  32. b = (b-a)/2
  33. return g*b
  34. def gcd_recursive(a, b):
  35. if mod(a, b)==0:
  36. return b
  37. return gcd_recursive(b, mod(a,b))
  38. # Extended Euclidean algorithm
  39. # Inputs: a, b
  40. # Outputs: r, x, y, such that r = gcd(a, b) = x*a + y*b
  41. def egcd(a, b):
  42. s=0
  43. s_=1
  44. t=1
  45. t_=0
  46. r=b
  47. r_=a
  48. while r!=0:
  49. q = r_ // r
  50. (r_,r) = (r,r_ - q*r)
  51. (s_,s) = (s,s_ - q*s)
  52. (t_,t) = (t,t_ - q*t)
  53. d = r_
  54. x = s_
  55. y = t_
  56. return d, x, y
  57. def egcd_recursive(a, b):
  58. if b==0:
  59. return a, 1, 0
  60. g, x, y = egcd_recursive(b, a%b)
  61. return g, y, x - (a//b) * y
  62. # Inverse modulo N, using the Extended Euclidean algorithm
  63. def inv_mod(a, N):
  64. g, x, y = egcd(a, N)
  65. if g != 1:
  66. raise Exception("inv_mod err, g!=1")
  67. return mod(x, N)
  68. # Tests
  69. #####
  70. # Chinese Remainder Theorem tests
  71. a_i = [5, 3, 10]
  72. m_i = [7, 11, 13]
  73. assert crt(a_i, m_i) == 894
  74. a_i = [3, 8]
  75. m_i = [13, 17]
  76. assert crt(a_i, m_i) == 42
  77. #####
  78. # gcd, using Binary Euclidean algorithm tests
  79. assert gcd(21, 12) == 3
  80. assert gcd(1_426_668_559_730, 810_653_094_756) == 1_417_082
  81. assert gcd_recursive(21, 12) == 3
  82. #####
  83. # Extended Euclidean algorithm tests
  84. assert egcd(7, 19) == (1, -8, 3)
  85. assert egcd_recursive(7, 19) == (1, -8, 3)
  86. #####
  87. # Inverse modulo N tests
  88. assert inv_mod(7, 19) == 11