Skip to content

Commit adcdbec

Browse files
committed
add lenstra eliptic curve factoring
1 parent 0cb178e commit adcdbec

File tree

1 file changed

+71
-44
lines changed

1 file changed

+71
-44
lines changed

src/Primes.jl

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,9 @@ isprime(n::Int128) = n < 2 ? false :
233233

234234

235235
# Trial division of small (< 2^16) precomputed primes +
236-
# Pollard rho's algorithm with Richard P. Brent optimizations
236+
# Lenstra elliptic curve algorithm
237237
# https://en.wikipedia.org/wiki/Trial_division
238-
# https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
239-
# http://maths-people.anu.edu.au/~brent/pub/pub051.html
238+
# https://en.wikipedia.org/wiki/Lenstra_elliptic-curve_factorization
240239
#
241240
function factor!(n::T, h::AbstractDict{K,Int}) where {T<:Integer,K<:Integer}
242241
# check for special cases
@@ -271,7 +270,7 @@ function factor!(n::T, h::AbstractDict{K,Int}) where {T<:Integer,K<:Integer}
271270
end
272271
end
273272
isprime(n) && (h[n]=1; return h)
274-
T <: BigInt || widemul(n - 1, n - 1) typemax(n) ? pollardfactors!(n, h) : pollardfactors!(widen(n), h)
273+
T <: BigInt || widemul(n - 1, n - 1) typemax(n) ? lenstrafactors!(n, h) : lenstrafactors!(widen(n), h)
275274
end
276275

277276

@@ -389,52 +388,80 @@ julia> radical(2*2*3)
389388
"""
390389
radical(n) = prod(factor(Set, n))
391390

392-
function pollardfactors!(n::T, h::AbstractDict{K,Int}) where {T<:Integer,K<:Integer}
393-
while true
394-
c::T = rand(1:(n - 1))
395-
G::T = 1
396-
r::K = 1
397-
y::T = rand(0:(n - 1))
398-
m::K = 1900
399-
ys::T = 0
400-
q::T = 1
401-
x::T = 0
402-
while c == n - 2
403-
c = rand(1:(n - 1))
391+
function inthroot(n::Integer, r::Int)
392+
ans = BigInt()
393+
ccall((:__gmpz_root, :libgmp), Cvoid, (Ref{BigInt}, Ref{BigInt}, Culong), ans, BigInt(n), r)
394+
return ans
395+
end
396+
397+
function lenstrafactors!(n::T, h::AbstractDict{K,Int}, plimit=10000) where{T<:Integer,K<:Integer}
398+
isprime(n) && (h[n] = get(h, n, 0)+1; return h)
399+
r = ceil(Int, inv(log(n, Primes.PRIMES[end])))+1
400+
root = inthroot(n, r)
401+
while r >= 2
402+
if root^r == n
403+
isprime(root) ? h[root] = get(h, root, 0) + 1 : lenstrafactors!(root, h)
404+
return lenstrafactors!(div(n, root), h)
404405
end
405-
while G == 1
406-
x = y
407-
for i in 1:r
408-
y = y^2 % n
409-
y = (y + c) % n
406+
r -= 1
407+
root = inthroot(n, r)
408+
end
409+
small_primes = primes(plimit)
410+
for a in zero(T):(n>>1)
411+
for p in (-1, 1)
412+
res = lenstra_get_factor(n, p*a, small_primes, plimit)
413+
if res != 1
414+
isprime(res) ? h[res] = get(h, res, 0) + 1 : lenstrafactors!(res, h)
415+
res2 = div(n,res)
416+
isprime(res2) ? h[res2] = get(h, res2, 0) + 1 : lenstrafactors!(res2, h)
417+
return h
410418
end
411-
k::K = 0
412-
G = 1
413-
while k < r && G == 1
414-
for i in 1:(m > (r - k) ? (r - k) : m)
415-
ys = y
416-
y = y^2 % n
417-
y = (y + c) % n
418-
q = (q * (x > y ? x - y : y - x)) % n
419+
end
420+
end
421+
end
422+
423+
function lenstra_get_factor(N::T, a, small_primes, plimit) where T <: Integer
424+
x = T(0)
425+
y = T(1)
426+
427+
for B in small_primes
428+
t = B^trunc(Int64, log(B, plimit))
429+
xn, yn = T(0), T(0)
430+
sx, sy = x, y
431+
432+
first = true
433+
while t > 0
434+
if isodd(t)
435+
if first
436+
xn, yn = sx, sy
437+
first = false
438+
else
439+
g, u, _ = gcdx(sx-xn, N)
440+
g > 1 && (g == N ? break : return g)
441+
u += N
442+
L = (u*(sy-yn)) % N
443+
xs = (L*L - xn - sx) % N
444+
445+
yn = (L*(xn - xs) - yn) % N
446+
xn = xs
419447
end
420-
G = gcd(q, n)
421-
k += m
422448
end
423-
r *= 2
424-
end
425-
G == n && (G = 1)
426-
while G == 1
427-
ys = ys^2 % n
428-
ys = (ys + c) % n
429-
G = gcd(x > ys ? x - ys : ys - x, n)
430-
end
431-
if G != n
432-
isprime(G) ? h[G] = get(h, G, 0) + 1 : pollardfactors!(G, h)
433-
G2 = div(n,G)
434-
isprime(G2) ? h[G2] = get(h, G2, 0) + 1 : pollardfactors!(G2, h)
435-
return h
449+
g, u, _ = gcdx(2*sy, N)
450+
g > 1 && (g == N ? break : return g)
451+
u += N
452+
453+
L = (u*(3*sx*sx + a)) % N
454+
x2 = (L*L - 2*sx) % N
455+
456+
sy = (L*(sx - x2) - sy) % N
457+
sx = x2
458+
459+
sy == 0 && return T(1)
460+
t >>= 1
436461
end
462+
x, y = xn, yn
437463
end
464+
return T(1)
438465
end
439466

440467
"""

0 commit comments

Comments
 (0)