Skip to content

Commit c5f8c04

Browse files
committed
add lenstra eliptic curve factoring minor tidy
1 parent 23df5b3 commit c5f8c04

File tree

1 file changed

+67
-45
lines changed

1 file changed

+67
-45
lines changed

src/Primes.jl

Lines changed: 67 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,20 @@ function iterate(f::FactorIterator{T}, state=(f.n, T(3))) where T
387387
if n <= 2^32 || isprime(n)
388388
return (n, 1), (T(1), n)
389389
end
390+
# check for n=root^r
391+
r = cld(ndigits(n, base=2), ndigits(Primes.PRIMES[end], base=2))
392+
root = inthroot(n, r)
393+
while r >= 2
394+
if root^r == n
395+
isprime(root) && return (root, r), (n, root+2)
396+
397+
end
398+
r -= 1
399+
root = inthroot(n, r)
400+
end
401+
390402
should_widen = T <: BigInt || widemul(n - 1, n - 1) typemax(n)
391-
p = should_widen ? pollardfactor(n) : pollardfactor(widen(n))
403+
p = should_widen ? lenstrafactor(n) : lenstrafactor(widen(n))
392404
num_p = 0
393405
while true
394406
q, r = divrem(n, p)
@@ -520,55 +532,65 @@ julia> radical(2*2*3)
520532
"""
521533
radical(n) = n==1 ? one(n) : prod(p for (p, num_p) in eachfactor(n))
522534

523-
function pollardfactor(n::T) where {T<:Integer}
524-
while true
525-
c::T = rand(1:(n - 1))
526-
G::T = 1
527-
r::T = 1
528-
y::T = rand(0:(n - 1))
529-
m::T = 100
530-
ys::T = 0
531-
q::T = 1
532-
x::T = 0
533-
while c == n - 2
534-
c = rand(1:(n - 1))
535-
end
536-
while G == 1
537-
x = y
538-
for i in 1:r
539-
y = y^2 % n
540-
y = (y + c) % n
541-
end
542-
k::T = 0
543-
G = 1
544-
while k < r && G == 1
545-
ys = y
546-
for i in 1:(m > (r - k) ? (r - k) : m)
547-
y = y^2 % n
548-
y = (y + c) % n
549-
q = (q * (x > y ? x - y : y - x)) % n
550-
end
551-
G = gcd(q, n)
552-
k += m
535+
function lenstrafactor(n::T) where{T<:Integer}
536+
# bounds and runs per bound taken from
537+
# https://www.rieselprime.de/ziki/Elliptic_curve_method
538+
B1s = Int[2e3, 11e3, 5e4, 25e4, 1e6, 3e6, 11e6,
539+
43e6, 11e7, 26e7, 85e7, 29e8, 76e8, 25e9]
540+
runs = (74, 221, 453, 984, 2541, 4949, 8266, 20158,
541+
47173, 77666, 42057, 69471, 102212, 188056, 265557)
542+
for (B1, run) in zip(B1s, runs)
543+
small_primes = primes(B1)
544+
for a in -run:run
545+
res = lenstra_get_factor(n, a, small_primes, B1)
546+
if res != 1
547+
return isprime(res) ? res : lenstrafactor(res)
553548
end
554-
r *= 2
555-
end
556-
G == n && (G = 1)
557-
while G == 1
558-
ys = ys^2 % n
559-
ys = (ys + c) % n
560-
G = gcd(x > ys ? x - ys : ys - x, n)
561549
end
562-
if G != n
563-
G2 = div(n,G)
564-
f = min(G, G2)
565-
_gcd = gcd(G, G2)
566-
if _gcd != 1
567-
f = _gcd
550+
end
551+
throw(ArgumentError("This number is too big to be factored with this algorith effectively"))
552+
end
553+
554+
function lenstra_get_factor(N::T, a, small_primes, plimit) where T <: Integer
555+
x, y = T(0), T(1)
556+
for B in small_primes
557+
t = B^trunc(Int64, log(B, plimit))
558+
xn, yn = T(0), T(0)
559+
sx, sy = x, y
560+
561+
first = true
562+
while t > 0
563+
if isodd(t)
564+
if first
565+
xn, yn = sx, sy
566+
first = false
567+
else
568+
g, u, _ = gcdx(sx-xn, N)
569+
g > 1 && (g == N ? break : return g)
570+
u += N
571+
L = (u*(sy-yn)) % N
572+
xs = (L*L - xn - sx) % N
573+
574+
yn = (L*(xn - xs) - yn) % N
575+
xn = xs
576+
end
568577
end
569-
return isprime(f) ? f : pollardfactor(f)
578+
g, u, _ = gcdx(2*sy, N)
579+
g > 1 && (g == N ? break : return g)
580+
u += N
581+
582+
L = (u*(3*sx*sx + a)) % N
583+
x2 = (L*L - 2*sx) % N
584+
585+
sy = (L*(sx - x2) - sy) % N
586+
sx = x2
587+
588+
sy == 0 && return T(1)
589+
t >>= 1
570590
end
591+
x, y = xn, yn
571592
end
593+
return T(1)
572594
end
573595

574596
"""

0 commit comments

Comments
 (0)