# lenstra's algorithm
from random import randint
from fractions import gcd
def primes(n):
b, p, ps = [True] * (n+1), 2, []
for p in xrange(2, n+1):
if b[p]:
ps.append(p)
for i in xrange(p, n+1, p):
b[i] = False
return ps
def bezout(a, b):
if b == 0: return 1, 0, a
q, r = divmod(a, b)
x, y, g = bezout(b, r)
return y, x-q*y, g
def add(p, q, a, b, m):
if p[2] == 0: return q
if q[2] == 0: return p
if p[0] == q[0]:
if (p[1] + q[1]) % m == 0:
return 0, 1, 0 # infinity
n = (3 * p[0] * p[0] + a) % m
d = (2 * p[1]) % m
else:
n = (q[1] - p[1]) % m
d = (q[0] - p[0]) % m
x, y, g = bezout(d, m)
if g > 1: return 0, 0, d # failure
z = (n*x*n*x - p[0] - q[0]) % m
return z, (n * x * (p[0] - z) - p[1]) % m, 1
def mul(k, p, a, b, m):
r = (0,1,0)
while k > 0:
if k % 2 == 1:
r = add(p, r, a, b, m)
if r[2] > 1: return r
k = k // 2
p = add(p, p, a, b, m)
if p[2] > 1: return p
return r
def lenstra(n, limit):
g = n
while g == n:
q = randint(0, n-1), randint(0, n-1), 1
a = randint(0, n-1)
b = (q[1]*q[1] - q[0]*q[0]*q[0] - a*q[0]) % n
g = gcd(4*a*a*a + 27*b*b, n)
if g > 1: return g # lucky factor
for p in primes(limit):
pp = p
while pp < limit:
q = mul(p, q, a, b, n)
if q[2] > 1:
return gcd(q[2], n)
pp = p * pp
return False
# 523 * 769
print lenstra(402187, 25)
print lenstra(402187, 25)
print lenstra(402187, 25)
print lenstra(402187, 25)
print lenstra(402187, 25)
print lenstra(402187, 25)
print lenstra(402187, 25)
print lenstra(402187, 25)
print lenstra(402187, 25)
print lenstra(402187, 25)
print ""
# 4723 * 82193
print lenstra(388197539, 100)
print lenstra(388197539, 100)
print lenstra(388197539, 100)
print lenstra(388197539, 100)
print lenstra(388197539, 100)
print lenstra(388197539, 100)
print lenstra(388197539, 100)
print lenstra(388197539, 100)
print lenstra(388197539, 100)
print lenstra(388197539, 100)
print ""
# 678413 * 49153471
print lenstra(33346353721523, 1000)
print lenstra(33346353721523, 1000)
print lenstra(33346353721523, 1000)
print lenstra(33346353721523, 1000)
print lenstra(33346353721523, 1000)
print lenstra(33346353721523, 1000)
print lenstra(33346353721523, 1000)
print lenstra(33346353721523, 1000)
print lenstra(33346353721523, 1000)
print lenstra(33346353721523, 1000)
IyBsZW5zdHJhJ3MgYWxnb3JpdGhtCgpmcm9tIHJhbmRvbSBpbXBvcnQgcmFuZGludApmcm9tIGZyYWN0aW9ucyBpbXBvcnQgZ2NkCgpkZWYgcHJpbWVzKG4pOgogICAgYiwgcCwgcHMgPSBbVHJ1ZV0gKiAobisxKSwgMiwgW10KICAgIGZvciBwIGluIHhyYW5nZSgyLCBuKzEpOgogICAgICAgIGlmIGJbcF06CiAgICAgICAgICAgIHBzLmFwcGVuZChwKQogICAgICAgICAgICBmb3IgaSBpbiB4cmFuZ2UocCwgbisxLCBwKToKICAgICAgICAgICAgICAgIGJbaV0gPSBGYWxzZQogICAgcmV0dXJuIHBzCgpkZWYgYmV6b3V0KGEsIGIpOgogICAgaWYgYiA9PSAwOiByZXR1cm4gMSwgMCwgYQogICAgcSwgciA9IGRpdm1vZChhLCBiKQogICAgeCwgeSwgZyA9IGJlem91dChiLCByKQogICAgcmV0dXJuIHksIHgtcSp5LCBnCgpkZWYgYWRkKHAsIHEsIGEsIGIsIG0pOgogICAgaWYgcFsyXSA9PSAwOiByZXR1cm4gcQogICAgaWYgcVsyXSA9PSAwOiByZXR1cm4gcAogICAgaWYgcFswXSA9PSBxWzBdOgogICAgICAgIGlmIChwWzFdICsgcVsxXSkgJSBtID09IDA6CiAgICAgICAgICAgIHJldHVybiAwLCAxLCAwICMgaW5maW5pdHkKICAgICAgICBuID0gKDMgKiBwWzBdICogcFswXSArIGEpICUgbQogICAgICAgIGQgPSAoMiAqIHBbMV0pICUgbQogICAgZWxzZToKICAgICAgICBuID0gKHFbMV0gLSBwWzFdKSAlIG0KICAgICAgICBkID0gKHFbMF0gLSBwWzBdKSAlIG0KICAgIHgsIHksIGcgPSBiZXpvdXQoZCwgbSkKICAgIGlmIGcgPiAxOiByZXR1cm4gMCwgMCwgZCAjIGZhaWx1cmUKICAgIHogPSAobip4Km4qeCAtIHBbMF0gLSBxWzBdKSAlIG0KICAgIHJldHVybiB6LCAobiAqIHggKiAocFswXSAtIHopIC0gcFsxXSkgJSBtLCAxCgpkZWYgbXVsKGssIHAsIGEsIGIsIG0pOgogICAgciA9ICgwLDEsMCkKICAgIHdoaWxlIGsgPiAwOgogICAgICAgIGlmIGsgJSAyID09IDE6CiAgICAgICAgICAgIHIgPSBhZGQocCwgciwgYSwgYiwgbSkKICAgICAgICAgICAgaWYgclsyXSA+IDE6IHJldHVybiByCiAgICAgICAgayA9IGsgLy8gMgogICAgICAgIHAgPSBhZGQocCwgcCwgYSwgYiwgbSkKICAgICAgICBpZiBwWzJdID4gMTogcmV0dXJuIHAKICAgIHJldHVybiByCgpkZWYgbGVuc3RyYShuLCBsaW1pdCk6CiAgICBnID0gbgogICAgd2hpbGUgZyA9PSBuOgogICAgICAgIHEgPSByYW5kaW50KDAsIG4tMSksIHJhbmRpbnQoMCwgbi0xKSwgMQogICAgICAgIGEgPSByYW5kaW50KDAsIG4tMSkKICAgICAgICBiID0gKHFbMV0qcVsxXSAtIHFbMF0qcVswXSpxWzBdIC0gYSpxWzBdKSAlIG4KICAgICAgICBnID0gZ2NkKDQqYSphKmEgKyAyNypiKmIsIG4pCiAgICBpZiBnID4gMTogcmV0dXJuIGcgIyBsdWNreSBmYWN0b3IKICAgIGZvciBwIGluIHByaW1lcyhsaW1pdCk6CiAgICAgICAgcHAgPSBwCiAgICAgICAgd2hpbGUgcHAgPCBsaW1pdDoKICAgICAgICAgICAgcSA9IG11bChwLCBxLCBhLCBiLCBuKQogICAgICAgICAgICBpZiBxWzJdID4gMToKICAgICAgICAgICAgICAgIHJldHVybiBnY2QocVsyXSwgbikKICAgICAgICAgICAgcHAgPSBwICogcHAKICAgIHJldHVybiBGYWxzZQoKIyA1MjMgKiA3NjkKcHJpbnQgbGVuc3RyYSg0MDIxODcsIDI1KQpwcmludCBsZW5zdHJhKDQwMjE4NywgMjUpCnByaW50IGxlbnN0cmEoNDAyMTg3LCAyNSkKcHJpbnQgbGVuc3RyYSg0MDIxODcsIDI1KQpwcmludCBsZW5zdHJhKDQwMjE4NywgMjUpCnByaW50IGxlbnN0cmEoNDAyMTg3LCAyNSkKcHJpbnQgbGVuc3RyYSg0MDIxODcsIDI1KQpwcmludCBsZW5zdHJhKDQwMjE4NywgMjUpCnByaW50IGxlbnN0cmEoNDAyMTg3LCAyNSkKcHJpbnQgbGVuc3RyYSg0MDIxODcsIDI1KQoKcHJpbnQgIiIKCiMgNDcyMyAqIDgyMTkzCnByaW50IGxlbnN0cmEoMzg4MTk3NTM5LCAxMDApCnByaW50IGxlbnN0cmEoMzg4MTk3NTM5LCAxMDApCnByaW50IGxlbnN0cmEoMzg4MTk3NTM5LCAxMDApCnByaW50IGxlbnN0cmEoMzg4MTk3NTM5LCAxMDApCnByaW50IGxlbnN0cmEoMzg4MTk3NTM5LCAxMDApCnByaW50IGxlbnN0cmEoMzg4MTk3NTM5LCAxMDApCnByaW50IGxlbnN0cmEoMzg4MTk3NTM5LCAxMDApCnByaW50IGxlbnN0cmEoMzg4MTk3NTM5LCAxMDApCnByaW50IGxlbnN0cmEoMzg4MTk3NTM5LCAxMDApCnByaW50IGxlbnN0cmEoMzg4MTk3NTM5LCAxMDApCgpwcmludCAiIgoKIyA2Nzg0MTMgKiA0OTE1MzQ3MQpwcmludCBsZW5zdHJhKDMzMzQ2MzUzNzIxNTIzLCAxMDAwKQpwcmludCBsZW5zdHJhKDMzMzQ2MzUzNzIxNTIzLCAxMDAwKQpwcmludCBsZW5zdHJhKDMzMzQ2MzUzNzIxNTIzLCAxMDAwKQpwcmludCBsZW5zdHJhKDMzMzQ2MzUzNzIxNTIzLCAxMDAwKQpwcmludCBsZW5zdHJhKDMzMzQ2MzUzNzIxNTIzLCAxMDAwKQpwcmludCBsZW5zdHJhKDMzMzQ2MzUzNzIxNTIzLCAxMDAwKQpwcmludCBsZW5zdHJhKDMzMzQ2MzUzNzIxNTIzLCAxMDAwKQpwcmludCBsZW5zdHJhKDMzMzQ2MzUzNzIxNTIzLCAxMDAwKQpwcmludCBsZW5zdHJhKDMzMzQ2MzUzNzIxNTIzLCAxMDAwKQpwcmludCBsZW5zdHJhKDMzMzQ2MzUzNzIxNTIzLCAxMDAwKQ==