modular_elliptic-curve_arithmetic.sf 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #!/usr/bin/ruby
  2. # Modular Elliptic curve arithmetic (without validation).
  3. # See also:
  4. # https://rosettacode.org/wiki/Elliptic_curve_arithmetic
  5. class EllipticCurveMod(x, y, N, A = 0) {
  6. method to_s {
  7. "EC Point at x=#{x}, y=#{y}"
  8. }
  9. method is_zero {
  10. x == 0
  11. }
  12. method neg {
  13. EllipticCurveMod(x, -y)
  14. }
  15. method -(EllipticCurveMod p) {
  16. self + -p
  17. }
  18. method +(EllipticCurveMod p) {
  19. if (p.is_zero) {
  20. return self
  21. }
  22. if (x == p.x) {
  23. return self*2 if (y == p.y)
  24. return EllipticCurveMod(0, 0, N, A)
  25. }
  26. else {
  27. var u = invmod(p.x - x, N) || die gcd(p.x - x, N)
  28. var slope = mulmod(p.y - y, u, N)
  29. var x2 = submod(mulmod(slope, slope, N) - x, p.x, N)
  30. var y2 = submod(mulmod(slope, x - x2, N), y, N)
  31. EllipticCurveMod(x2, y2, N, A)
  32. }
  33. }
  34. method *((0)) {
  35. EllipticCurveMod(0, 0, N, A)
  36. }
  37. method *((1)) {
  38. self
  39. }
  40. method *((2)) {
  41. var l = divmod(3*mulmod(x, x, N) + A, 2*y, N)
  42. var x2 = submod(mulmod(l, l, N), 2*x, N)
  43. var y2 = submod(mulmod(l, x - x2, N), y, N)
  44. EllipticCurveMod(x2, y2, N, A)
  45. }
  46. method *(Number n) {
  47. 2*(self * (n>>1)) + self*(n % 2)
  48. }
  49. }
  50. class Number {
  51. method +(EllipticCurveMod p) {
  52. p + self
  53. }
  54. method -(EllipticCurveMod p) {
  55. -p + self
  56. }
  57. method *(EllipticCurveMod p) {
  58. p * self
  59. }
  60. }
  61. func elliptic_curve_factorization(N, alimit = 100, B = 10000) {
  62. for a in (-alimit .. alimit) {
  63. say "Testing: #{a}"
  64. var curve = EllipticCurveMod(0, 1, N, a)
  65. B.each_prime {|p|
  66. var pp = p**B.ilog(p)
  67. try {
  68. curve *= pp
  69. }
  70. catch { |v|
  71. if (v =~ /^(\d+)/) {|m|
  72. return Num(m[0])
  73. }
  74. }
  75. }
  76. }
  77. return 1
  78. }
  79. say ("Found factor: ", elliptic_curve_factorization(14304849576137459)) #=> 16100431
  80. say ("Found factor: ", elliptic_curve_factorization(314159265358979323)) #=> 990371647
  81. #say ("Found factor: ", elliptic_curve_factorization(2**64 + 1)) # takes ~2 seconds
  82. #say ("Found factor: ", elliptic_curve_factorization(2**128 + 1)) # takes ~1 minute