def pm1_pollard(n,B,nbRM=20,verbose=False): """Pollard's p-1 factoring algorithm. Args: - *n (int)*: an integer - *B (int)*: smooth boundary Optional Args: - *nbRM (int)*: number of repeats of Rabin-Miller primality test. - *verbose (bool)*: set to True if you want a display. Returns: - *(int)*: a subfactor p of n such that p-1 is B-smooth if it exists. 0 if attack failed. """ lB = itools.ilog(B,2) primes = itools.get_primes(1,B,nbRM) a = random.randint(1,n) for q in primes: e = lB//itools.ilog(q,2) a = itools.exp_mod(a,q**e,n) #q**e ~ B g = itools.gcd(a-1,n) if g>1 and g<n: if(verbose): print("pm1_pollard :\n",n,"=",g,"x",n//g) return g else: if(verbose): print("pm1_pollard failed with", B, ":(") return 0
def pm1_pollard_auto(n,Bmax,verbose=False): """Pollard's p-1 factoring algorithm with automatic Boundary adjustment. Args: - *n (int)*: an integer - *Bmax (int)*: Maximum smooth boundary Optional Args: - *verbose (bool)*: set to True if you want a display. Returns: - *(int)*: a subfactor p of n such that p-1 is B-smooth if it exists. 0 if attack failed. """ #optimized parameters B = 16000 nbRM = 10 alternate = False g = 1 while(g==1 and B<=Bmax): lB = itools.ilog(B,2) primes = itools.get_primes(1,B,nbRM) g = n while(g==n): a = random.randint(1,n) for q in primes: e = lB//itools.ilog(q,2) a = itools.exp_mod(a,q**e,n) #q**e ~ B g = itools.gcd(a-1,n) if(g==n and verbose): print("N reached, resuming...") if(g==1): c = a primes = itools.get_primes(B,2*B,nbRM) d = primes[0] a = itools.exp_mod(c,d,n) for i in range(1,len(primes)): g = itools.gcd(a-1,n) if(g!=1): alternate=True break d = primes[i]-primes[i-1] a *= itools.exp_mod(c,d,n) #peut être amélioré en mémorisant les c**(2k) dans une table if(g==1): B *= 4 if(g!=1 and g!=n): if(verbose): if(alternate): print("pm1_pollard_auto ( B' =",2*B,") :\n",n,"=",g,"x",n//g) else: print("pm1_pollard_auto ( B =",B,") :\n",n,"=",g,"x",n//g) return g else: if(verbose): print("pm1_pollard_auto failed with", Bmax, ":(") return 0
def pp1_williams(n,B,nbRM=20,verbose=False): """Williams' p+1 factoring algorithm. Args: - *n (int)*: an integer - *B (int)*: smooth boundary Optional Args: - *nbRM (int)*: number of repeats of Rabin-Miller primality test. - *verbose (bool)*: set to True if you want a display. Returns: - *(int)*: a subfactor p of n such that p+1 is B-smooth if it exists. 0 if attack failed. """ lB = itools.ilog(B,2) primes = itools.get_primes(3,B,nbRM) a = random.randint(1,n) v = a i=0 for q in primes: e = lB//itools.ilog(q,2) #plus efficace que : for i in range(e): v = lucal_mul(v,q,n) #évite de calculer e fois la décomposition binaire de q et d'appeler e fonctions, au prix d'une exponentiation entière v = lucas_mul(v,q**e,n) #q**e ~ B g = itools.gcd(v-2,n) if(g!=1 and g!=n): break if(g>1 and g<n): if(verbose): print("pp1_williams :\n",n,"=",g,"x",n//g) return g else: if(verbose): print("pp1_williams failed with", B, ":(") return 0
def pp1_williams_auto(n,Bmax,verbose=False): """Williams' p+1 factoring algorithm with automatic Boundary adjustment. Args: - *n (int)*: an integer - *Bmax (int)*: Maximum smooth boundary Optional Args: - *verbose (bool)*: set to True if you want a display. Returns: - *(int)*: a subfactor p of n such that p+1 is B-smooth if it exists. 0 if attack failed. """ B = 1000 nbRM = 10 alternate = False g = 1 while(g==1 and B<=Bmax): lB = itools.ilog(B,2) B2 = (10 ** (itools.ilog(B,10)//5))*B #tiré de resultats expérimentaux : http://www.loria.fr/~zimmerma/records/Pplus1.html primes = itools.get_primes(3,B,nbRM) g = n #Step 1 while(g==n): a = random.randint(1,n) v = a for q in primes: e = lB//itools.ilog(q,2) #plus efficace que : for i in range(e): v = lucal_mul(v,q,n) #évite de calculer e fois la décomposition binaire de q et d'appeler e fonctions, au prix d'une exponentiation entière v = lucas_mul(v,q**e,n) #q**e ~ B #les valeurs atteintes par g sont croissantes et stagent à n lorsqu'atteints #=> pas besoin de les évaluer à chaque multiplication de l'indice #si g == n -> on a dépassé les facteurs, il faut recommencer avec la même borne (voire plus petite ?) #le tirage de a sera déterminant #si g==1 la borne n'est pas suffisante, on passe au Step 2 puis on augmente g = itools.gcd(v-2,n) if(g==n and verbose): print("N reached, resuming...") #Step 2 TODO : optimal? L'idée des multiples de 6 peut-elle être reprise pour p-1 Pollard ? if(g==1): c = (B//6)*6 v6 = lucas_mul(v,6,n) Vl = [] Vl.append(lucas_mul(v,c,n)) Vl.append(lucas_mul(v,c+6,n)) i = 2 c = c+12 while(c<B2): Vl.append( (Vl[i-1]*v6 - Vl[i-2]) % n ) c += 6 i += 1 produit = 1 for vi in Vl: produit = ( produit * (vi-v) ) % n g = itools.gcd(produit,n) if(g==1): B *= 10 else: alternate = True if(g!=1 and g!=n): if(verbose): if(alternate): print("pp1_williams_auto ( B' =",B2,") :\n",n,"=",g,"x",n//g) else: print("pp1_williams_auto ( B =",B,") :\n",n,"=",g,"x",n//g) return g else: if(verbose): print("pp1_williams_auto failed with", Bmax, ":(") return 0