square_root_modulo_n_tonelli-shanks.sf 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 28 October 2017
  4. # https://github.com/trizen
  5. # Find all the solutions to the congruence equation:
  6. # x^2 = a (mod n)
  7. # Defined for any values of `a` and `n` for which `kronecker(a, n) = 1`.
  8. # When `kronecker(a, n) != 1`, for example:
  9. #
  10. # a = 472
  11. # n = 972
  12. #
  13. # which represents:
  14. # x^2 = 472 (mod 972)
  15. #
  16. # this algorithm is not able to find a solution, although there exist four solutions:
  17. # x = {38, 448, 524, 934}
  18. # Code inspired from:
  19. # https://github.com/Magtheridon96/Square-Root-Modulo-N
  20. func tonelli(n, p) {
  21. var q = p-1
  22. var s = valuation(q, 2)
  23. s == 1 && return powmod(n, (p + 1) >> 2, p)
  24. q >>= s
  25. var c = powmod(2 ..^ p -> first {|z| legendre(z, p) == -1 }, q, p)
  26. var r = powmod(n, (q + 1) >> 1, p)
  27. var t = powmod(n, q, p)
  28. while (!p.divides(t - 1)) {
  29. var b = 1
  30. var t2 = (t*t % p)
  31. for i in (1 ..^ s) {
  32. if (p.divides(t2 - 1)) {
  33. b = powmod(c, 1 << (s - i - 1), p)
  34. s = i
  35. break
  36. }
  37. t2 = (t2*t2 % p)
  38. }
  39. r = (r*b % p)
  40. c = (b*b % p)
  41. t = (t*c % p)
  42. }
  43. return r
  44. }
  45. func sqrt_mod_n(a, n) is cached {
  46. kronecker(a, n) == 1 || return []
  47. a = (a % n)
  48. if ((n & (n - 1)) == 0) { # n is a power of 2
  49. if (a % 8 == 1) {
  50. var k = n.valuation(2)
  51. k == 1 && return [1]
  52. k == 2 && return [1, 3]
  53. k == 3 && return [1, 3, 5, 7]
  54. if (a == 1) {
  55. return [1, (n>>1) - 1, (n>>1) + 1, n - 1]
  56. }
  57. return gather {
  58. for s in (sqrt_mod_n(a, n >> 1)) {
  59. var i = (((s*s - a) >> (k - 1)) % 2)
  60. var r = (s + (i << (k - 2)))
  61. take(r, n - r)
  62. }
  63. }.uniq.sort
  64. }
  65. return []
  66. }
  67. if (n.is_prime) { # n is a prime
  68. return gather {
  69. var r = tonelli(a, n)
  70. take(r, n - r)
  71. }.sort
  72. }
  73. var pe = n.factor_exp # factorize `n` into prime powers
  74. if (pe.len == 1) { # `n` is an odd prime power
  75. var p = pe[0][0]
  76. var k = pe[0][1]
  77. kronecker(a, p) == 1 || return []
  78. var roots = gather {
  79. var r = tonelli(a, p)
  80. take(r, n - r)
  81. }
  82. var pk = p
  83. var pi = p*p
  84. (k-1).times {
  85. var x = roots[0]
  86. var y = (invmod(2, pk) * invmod(x, pk))
  87. roots[0] = ((pi + x - y*(x*x - a + pi)) % pi)
  88. roots[1] = (pi - roots[0])
  89. pk *= p
  90. pi *= p
  91. }
  92. return roots.sort
  93. }
  94. var solutions = []
  95. for p,e in (pe) {
  96. var m = p**e
  97. var r = sqrt_mod_n(a, m)
  98. solutions.append(r.map {|r0| [r0, m] })
  99. }
  100. gather {
  101. solutions.cartesian {|*a|
  102. take(Math.chinese(a...))
  103. }
  104. }.uniq.sort
  105. }
  106. for n in (1..1000) {
  107. var a = irand(2, n)
  108. var solutions = sqrt_mod_n(a, n) || next
  109. say "x^2 = #{a} (mod #{n}); x = {#{solutions.join(', ')}}"
  110. }
  111. __END__
  112. x^2 = 455 (mod 838); x = {413, 425}
  113. x^2 = 425 (mod 842); x = {419, 423}
  114. x^2 = 97 (mod 849); x = {83, 200, 649, 766}
  115. x^2 = 202 (mod 859); x = {283, 576}
  116. x^2 = 551 (mod 862); x = {219, 643}
  117. x^2 = 742 (mod 869); x = {128, 425, 444, 741}
  118. x^2 = 628 (mod 871); x = {206, 340, 531, 665}
  119. x^2 = 607 (mod 877); x = {153, 724}
  120. x^2 = 126 (mod 887); x = {112, 775}
  121. x^2 = 841 (mod 905); x = {29, 391, 514, 876}
  122. x^2 = 310 (mod 911); x = {76, 835}
  123. x^2 = 83 (mod 919); x = {177, 742}
  124. x^2 = 441 (mod 920); x = {21, 71, 159, 209, 251, 301, 389, 439, 481, 531, 619, 669, 711, 761, 849, 899}
  125. x^2 = 576 (mod 923); x = {24, 379, 544, 899}
  126. x^2 = 99 (mod 929); x = {429, 500}
  127. x^2 = 884 (mod 937); x = {126, 811}
  128. x^2 = 88 (mod 941); x = {111, 830}
  129. x^2 = 875 (mod 949); x = {119, 392, 557, 830}
  130. x^2 = 836 (mod 953); x = {115, 838}
  131. x^2 = 415 (mod 959); x = {276, 409, 550, 683}
  132. x^2 = 450 (mod 961); x = {779, 182}
  133. x^2 = 289 (mod 974); x = {17, 957}
  134. x^2 = 821 (mod 977); x = {306, 671}
  135. x^2 = 439 (mod 983); x = {173, 810}
  136. x^2 = 574 (mod 991); x = {430, 561}
  137. x^2 = 289 (mod 992); x = {17, 79, 417, 479, 513, 575, 913, 975}
  138. x^2 = 464 (mod 995); x = {128, 327, 668, 867}