lucas_factorization_method.sf 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. #!/usr/bin/ruby
  2. # Author: Daniel "Trizen" Șuteu
  3. # Date: 30 September 2018
  4. # https://github.com/trizen
  5. # A new integer factorization method, using the Lucas U and V sequences.
  6. # Inspired by the BPSW primality test.
  7. # See also:
  8. # https://en.wikipedia.org/wiki/Lucas_sequence
  9. # https://en.wikipedia.org/wiki/Lucas_pseudoprime
  10. # https://en.wikipedia.org/wiki/Baillie%E2%80%93PSW_primality_test
  11. func lucas_factorization(n, B = n.ilog2**2) {
  12. return n if (n <= 3)
  13. if (n.is_power) {
  14. return n.perfect_root
  15. }
  16. var Q
  17. for k in (2 .. Inf) {
  18. var D = ((-1)**k * (2*k + 1))
  19. if (D.kronecker(n) == -1) {
  20. Q = (1 - D)/4
  21. break
  22. }
  23. }
  24. var check_factor = {|a|
  25. var g = gcd(a, n)
  26. if ((g > 1) && (g < n)) {
  27. return g
  28. }
  29. }
  30. var d = B.consecutive_lcm
  31. var s = d.valuation(2)
  32. var(U1 = 1)
  33. var(V1 = 2, V2 = 1)
  34. var(Q1 = 1, Q2 = 1)
  35. for bit in ((d>>(s+1)).as_bin.chars) {
  36. Q1 = mulmod(Q1, Q2, n)
  37. if (bit) {
  38. Q2 = mulmod(Q1, Q, n)
  39. U1 = mulmod(U1, V2, n)
  40. V1 = mulsubmod(V1, V2, Q1, n)
  41. V2 = mulsubmulmod(V2, V2, 2, Q2, n)
  42. }
  43. else {
  44. Q2 = Q1
  45. U1 = mulsubmod(U1, V1, Q1, n)
  46. V2 = mulsubmod(V2, V1, Q1, n)
  47. V1 = mulsubmulmod(V1, V1, 2, Q2, n)
  48. }
  49. }
  50. Q1 = mulmod(Q1, Q2, n)
  51. Q2 = mulmod(Q1, Q, n)
  52. U1 = mulsubmod(U1, V1, Q1, n)
  53. V1 = mulsubmod(V2, V1, Q1, n)
  54. Q1 = mulmod(Q1, Q2, n)
  55. check_factor(U1)
  56. check_factor(V1)
  57. s.times {
  58. U1 = mulmod(U1, V1, n)
  59. V1 = mulsubmulmod(V1, V1, 2, Q1, n)
  60. Q1 = mulmod(Q1, Q1, n)
  61. check_factor(U1)
  62. check_factor(V1)
  63. }
  64. return 1
  65. }
  66. say lucas_factorization(257221 * 470783, 700); #=> 470783 (p+1 is 700-smooth)
  67. say lucas_factorization(333732865481 * 1632480277613, 3000); #=> 333732865481 (p-1 is 3000-smooth)
  68. say lucas_factorization(1124075136413 * 3556516507813, 4000); #=> 1124075136413 (p+1 is 4000-smooth)
  69. say lucas_factorization(6555457852399 * 7864885571993, 700); #=> 6555457852399 (p-1 is 700-smooth)
  70. say lucas_factorization(7553377229 * 588103349, 800); #=> 7553377229 (p+1 is 800-smooth)
  71. for k in (2..20) {
  72. var n = 2.of { random_nbit_prime(k) }.prod
  73. var p = lucas_factorization(n, 2 * n.ilog2**2)
  74. if (p.is_prime) {
  75. say "#{n} = #{p} * #{n/p}"
  76. }
  77. }