Having trouble getting Miller-Rabin primality test in Python - python

I have been trying to implement Miller-Rabin primality test in Python. Unfortunately there seems to be a problem on some prime numbers. Any help is appreciated.
Code:
def _isPrime(n):
if n % 2 == 0:
return False
a = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]
s, d = _Apart(n) # turns it into 2^s x d
print(s, d)
basePrime = False
isPrime = True
for base in a:
if base >= n-2:
break
if isPrime == False and basePrime == False:
return False
witness = pow(base, d)
if (witness % n) == 1 or (witness % n) == (n-1):
basePrime = True
continue
else:
basePrime = False
for r in range(1, s):
witness = pow(base, pow(2, r) * d)
if (witness % n) != ( n - 1 ):
isPrime = False
return True
Test:
isPrime(17)
Expected:
True
Result:
False

I wrote a Miller Rabin test that is deterministic, no need for random numbers. This implementation is for python 3.7. In python 3.8, llinear_diophantinex can be replaced with pow(x, -1, y). Also i used gmpy2 as it's very fast, but you can just replace the gmpy2 statements with normal pow if you can't use that, and just remove the gmpy2.mpz() wrappers since those are just used to overload operators.
import gmpy2
sinn = 2110229697309202254897383305762150945330987087513434511395506048950594976569434432057019507105035289374307720719984431280856161609820548842778454256113246763860786119268583367543952735347969627478873317341364209555365064365565504232770227619462128918701942169785585423104678142850200975026619010035331023744330713985615650556129731348659986462960062760308034462660525448390420668021248422741300646552941285862310410598374242189448623917196191138254637812716211329113836605859918549332304189053950819346551095911511755911832183789503704294770046935064469435830299623205136625543859303686699678929069468518950480476841246805908501510754550017255944080874819287974625925494008373883250410775902993163965873632474224574883242826458163446781002284368017611606202344050570737818087202137703099075773680753707346415849787963446390136517016131227807076254668461445862154978026041507116570585784569893773262639243954090283224759975513502582494002154146757110676408972377044584495342170277522887809749465855954126593100747444378301829661568735873345178089061677917127496915956539418931430313218084338374827152407795095072639044306222222695685778907958272820576498682506540189586657786292950574081739269257159839589987847266550007783514316481286222515710538845836151864127815058116482680058626451349913138908040817800742009650450811565324184631847563730941344941348929727603343965091116543702880556850922077216848669966268219928808236163268726995495688157209747596437162960244538054993785127947211290438554095851924381172697827312534174244295581184309147813790451951453564726742200569263225639113681905176376701339808868274637448606821696026703034737428319530072483125495383057919894902076566679023694181381398377144302767983385253577700652358431959604517728821603076762965129019244904679015099154368058005173028200266632883632953133017055122970338782493475762548347258351148037427739052271661340801912188203749647918379812483260399614599813650518046331670764766419886619324840045611486524123102046413946014624119568013100078163986683199814025915420877588778260860713148420321896163326473203441644820182490479899368048072263481024886708136521847014624735722333931331098969321911443978386868675912141648200500219168920887757573018380579532261231821382787339600631297820996466930957801607217549420247654458172818940238337170577825003408756362106088558651381993611741503374243481167926898332728164900189941804942580426055589622673679047058619682175301326905577843405270203660160407401675700528981573327582844330828861745574031416926871562443652858767649050943181353635950301154441954046214987718582670685455252774874198771086552440702483933126644594300464549471422237478151976561680719370424626162642534252062987911763456822609569209140676822858933588602318066530038691463577379331113471591913447226829868760176810195567325921301390329055242213842898142597360121925124635965685365925901913816717677946911762631634793638450106377437599347740569467683272089859392249351406815344105961234868327316964137925419770514177021722214309784062017826024217906664090209434553785436385765927274067126192143337589109608949427467825999057058702263715338956534536892852849984934736685814891286495169007648767081688963426768409476169071460997622740467533572971356017575900999100928776382541052696124463195981888715845688808970103527288822088031150716134784735332326775370417950625124642515148342694377095213470544739900830244879573205335578256682901821773047071352497997708791157012233232529777513203024818391621220967964874173106990772425289900446640237659116713251437567138729645677868024033209183367071421651937808005637679844370347367922676824239404492688418047080583797577102267329067247758368597488680401670673861120323439239792549053895366970423259196919428554146265587250617656401028722578111927104663315250291888502226235291264834968061065817079511872899991276288365723969841290984981957389126603952133124328219936785870274843554107325931034103072894378438818494802517594594270034007832922248742746517915210656205746338575621725899098414488628833412591266637224507533934158213117522503993423240638893845121918647788013
def llinear_diophantinex(a, b, divmodx=1, x=1, y=0, offset=0, withstats=False, pow_mod_p2=False):
origa, origb = a, gmpy2.mpz(b)
r=a
q = a//b
prevq=1
if a == 1:
return 1
if withstats == True:
print(f"a = {a}, b = {b}, q = {q}, r = {r}")
while r != 0:
prevr = r
a,r,b = b, b, r
q,r = divmod(a,b)
x, y = y, x - q * y
if withstats == True:
print(f"a = {a}, b = {b}, q = {q}, r = {r}, x = {x}, y = {y}")
y = gmpy2.mpz(1 - origb*x // origa - 1)
if withstats == True:
print(f"x = {x}, y = {y}")
x,y=y,x
modx = (-abs(x)*divmodx)%origb
if withstats == True:
print(f"x = {x}, y = {y}, modx = {modx}")
if pow_mod_p2==False:
return (x*divmodx)%origb, y, modx, (origa)%origb
else:
if x < 0: return (modx*divmodx)%origb
else: return (x*divmodx)%origb
def ffs(x):
"""Returns the index, counting from 0, of the
least significant set bit in `x`.
"""
return (x&-x).bit_length()-1
def MillerRabin(arglist):
N = arglist[0]
primetest = arglist[1]
iterx = arglist[2]
powx = arglist[3]
withstats = arglist[4]
primetest = gmpy2.powmod(primetest, powx, N)
if withstats == True:
print("first: ", primetest)
if primetest == 1 or primetest == N - 1:
return True
else:
for x in range(0, iterx):
primetest = gmpy2.powmod(primetest, 2, N)
if withstats == True:
print("else: ", primetest)
if primetest == N - 1: return True
if primetest == 1: return False
return False
def sfactorint_isprime(N, withstats=False):
N = gmpy2.mpz(N)
from multiprocessing import Pool
if N <= 1: return False
if N == 2:
return True
if N % 2 == 0:
return False
if N < 2:
return False
# Add Trial Factoring here to speed up smaller factored number testing
iterx = ffs(N-1)
""" This k test is an algorithmic test builder instead of using
random numbers. The offset of k, from -2 to +2 produces pow tests
that fail or pass instead of having to use random numbers and more
iterations. All you need are those 5 numbers from k to get a
primality answer.
"""
k = llinear_diophantinex(N, 1<<N.bit_length(), pow_mod_p2=True) - 1
t = N >> iterx
tests = [k-2, k-1, k, k+1, k+2]
for primetest in range(len(tests)):
if tests[primetest] >= N:
tests[primetest] %= N
arglist = []
for primetest in range(len(tests)):
if tests[primetest] >= 2:
arglist.append([N, tests[primetest], iterx, t, withstats])
with Pool(5) as p:
s=p.map(MillerRabin, arglist)
if s.count(True) == len(arglist): return True
else: return False
return s

Recently I also tried to implement this algorithm in the deterministic form, as shown in Miller Test, and ran into the same problem. I couldn't figure out why it failed for some numbers so I decided to implement the 'complete' Miller-Rabin Test and it worked.
I should warn that it gets slow quickly as n increases. It's advised to use some numeric library like Numpy to optimize the calculations.
With some tweaks on your code it can be achieved:
import random
def _isPrime(n):
if n % 2 == 0:
return False
rounds = 40 # Determines the accuracy of the test
s, d = _Apart(n) # Turns it into 2^s x d + 1
for _ in range(rounds):
base = random.randrange(2, n-1) # Randomly selects a base
witness = pow(base, d)
if (witness % n) == 1 or (witness % n) == (n-1):
continue
for _ in range(1, s):
witness = pow(witness, 2) % n
if witness == (n-1):
break
else: # if the for-loop is not 'broken', n is not prime
return False
return True

def is_prime(n):
"""returns True if n is prime else False"""
if n < 5 or n & 1 == 0 or n % 3 == 0:
return 2 <= n <= 3
s = ((n - 1) & (1 - n)).bit_length() - 1
d = n >> s
for a in [2, 325, 9375, 28178, 450775, 9780504, 1795265022]:
p = pow(a, d, n)
if p == 1 or p == n - 1 or a % n == 0:
continue
for _ in range(s):
p = (p * p) % n
if p == n - 1:
break
else:
return False
return True

Related

Fastest way to find prime in intervals

I tried searching StackOverflow and some other sources to find the fastest way to get a prime number within some interval but I didn't find any efficient way, so here is my code:
def prime(lower,upper):
prime_num = []
for num in range(lower, upper + 1):
# all prime numbers are greater than 1
if num > 1:
for i in range(2, num):
if (num % i) == 0:
break
else:
prime_num.append(num)
return prime_num
Can I make this more efficient?
I tried finding my answer in Fastest way to find prime number but I didn't find prime numbers in intervals.
I wrote an equation based prime finder using MillerRabin, it's not as fast as a next_prime finder that sieves, but it can create large primes and you get the equation it used to do it. Here is an example. Following that is the code:
In [5]: random_powers_of_2_prime_finder(1700)
Out[5]: 'pow_mod_p2(27667926810353357467837030512965232809390030031226210665153053230366733641224969190749433786036367429621811172950201894317760707656743515868441833458231399831181835090133016121983538940390210139495308488162621251038899539040754356082290519897317296011451440743372490592978807226034368488897495284627000283052473128881567140583900869955672587100845212926471955871127908735971483320243645947895142869961737653915035227117609878654364103786076604155505752302208115738401922695154233285466309546195881192879100630465, 2**1700-1, 2**1700) = 39813813626508820802866840332930483915032503127272745949035409006826553224524022617054655998698265075307606470641844262425466307284799062400415723706121978318083341480570093257346685775812379517688088750320304825524129104843315625728552273405257012724890746036676690819264523213918417013254746343166475026521678315406258681897811019418959153156539529686266438553210337341886173951710073382062000738529177807356144889399957163774682298839265163964939160419147731528735814055956971057054406988006642001090729179713'
or use to get the answer directly:
In [6]: random_powers_of_2_prime_finder(1700, withstats=False)
Out[6]: 4294700745548823167814331026002277003506280507463037204789057278997393231742311262730598677178338843033513290622514923311878829768955491790776416394211091580729947152858233850115018443160652214481910152534141980349815095067950295723412327595876094583434338271661005996561619688026571936782640346943257209115949079332605276629723961466102207851395372367417030036395877110498443231648303290010952093560918409759519145163112934517372716658602133001390012193450373443470282242835941058763834226551786349290424923951
The code:
import random
import math
def primes_sieve2(limit):
a = [True] * limit
a[0] = a[1] = False
for (i, isprime) in enumerate(a):
if isprime:
yield i
for n in range(i*i, limit, i):
a[n] = False
def ltrailing(N):
return len(str(bin(N))) - len(str(bin(N)).rstrip('0'))
def pow_mod_p2(x, y, z):
"4-5 times faster than pow for powers of 2"
number = 1
while y:
if y & 1:
number = modular_powerxz(number * x, z)
y >>= 1
x = modular_powerxz(x * x, z)
return number
def modular_powerxz(num, z, bitlength=1, offset=0):
xpowers = 1<<(z.bit_length()-bitlength)
if ((num+1) & (xpowers-1)) == 0:
return ( num & ( xpowers -bitlength)) + 2
elif offset == -1:
return ( num & ( xpowers -bitlength)) + 1
elif offset == 0:
return ( num & ( xpowers -bitlength))
elif offset == 1:
return ( num & ( xpowers -bitlength)) - 1
elif offset == 2:
return ( num & ( xpowers -bitlength)) - 2
def MillerRabin(N, primetest, iterx, powx, withstats=False):
primetest = pow(primetest, powx, N)
if withstats == True:
print("first: ",primetest)
if primetest == 1 or primetest == N - 1:
return True
else:
for x in range(0, iterx-1):
primetest = pow(primetest, 2, N)
if withstats == True:
print("else: ", primetest)
if primetest == N - 1: return True
if primetest == 1: return False
return False
PRIMES=list(primes_sieve2(1000000))
def mr_isprime(N, withstats=False):
if N == 2:
return True
if N % 2 == 0:
return False
if N < 2:
return False
if N in PRIMES:
return True
for xx in PRIMES:
if N % xx == 0:
return False
iterx = ltrailing(N - 1)
k = pow_mod_p2(N, (1<<N.bit_length())-1, 1<<N.bit_length()) - 1
t = N >> iterx
tests = [k+1, k+2, k, k-2, k-1]
for primetest in tests:
if primetest >= N:
primetest %= N
if primetest >= 2:
if MillerRabin(N, primetest, iterx, t, withstats) == False:
return False
return True
def lars_last_modulus_powers_of_two(hm):
return math.gcd(hm, 1<<hm.bit_length())
def random_powers_of_2_prime_finder(powersnumber, primeanswer=False, withstats=True):
while True:
randnum = random.randrange((1<<(powersnumber-1))-1, (1<<powersnumber)-1,2)
while lars_last_modulus_powers_of_two(randnum) == 2 and mr_isprime(randnum//2) == False:
randnum = random.randrange((1<<(powersnumber-1))-1, (1<<powersnumber)-1,2)
answer = randnum//2
# This option makes the finding of a prime much longer, i would suggest not using it as
# the whole point is a prime answer.
if primeanswer == True:
if mr_isprime(answer) == False:
continue
powers2find = pow_mod_p2(answer, (1<<powersnumber)-1, 1<<powersnumber)
if mr_isprime(powers2find) == True:
break
else:
continue
if withstats == False:
return powers2find
elif withstats == True:
return f"pow_mod_p2({answer}, 2**{powersnumber}-1, 2**{powersnumber}) = {powers2find}"
return powers2find
def nextprime(N):
N+=2
while not mr_isprime(N):
N+=2
return N
def get_primes(lower, upper):
lower = lower|1
upper = upper|1
vv = []
if mr_isprime(lower):
vv.append(lower)
else:
vv=[nextprime(lower)]
while vv[-1] < upper:
vv.append(nextprime(vv[-1]))
return vv
Here is an example like yours:
In [1538]: cc = get_primes(1009732533765201, 1009732533767201)
In [1539]: print(cc)
[1009732533765251, 1009732533765281, 1009732533765289, 1009732533765301, 1009732533765341, 1009732533765379, 1009732533765481, 1009732533765493, 1009732533765509, 1009732533765521, 1009732533765539, 1009732533765547, 1009732533765559, 1009732533765589, 1009732533765623, 1009732533765749, 1009732533765751, 1009732533765757, 1009732533765773, 1009732533765821, 1009732533765859, 1009732533765889, 1009732533765899, 1009732533765929, 1009732533765947, 1009732533766063, 1009732533766069, 1009732533766079, 1009732533766093, 1009732533766109, 1009732533766189, 1009732533766211, 1009732533766249, 1009732533766283, 1009732533766337, 1009732533766343, 1009732533766421, 1009732533766427, 1009732533766457, 1009732533766531, 1009732533766631, 1009732533766643, 1009732533766667, 1009732533766703, 1009732533766727, 1009732533766751, 1009732533766763, 1009732533766807, 1009732533766811, 1009732533766829, 1009732533766843, 1009732533766877, 1009732533766909, 1009732533766933, 1009732533766937, 1009732533766973, 1009732533767029, 1009732533767039, 1009732533767093, 1009732533767101, 1009732533767147, 1009732533767159, 1009732533767161, 1009732533767183, 1009732533767197, 1009732533767233]
Yes. In general, use:
Sieve of Eratosthenes
Miller-Rabin Primality Test
Other options include trying a compiled language, like C++, but I think that isn't what you're looking for, since you've asked about Python.
Yes, you can make it more efficient. As has been mentioned, for very large numbers use Miller-Rabin. For smaller ranges use the Sieve of Eratosthenes. However, apart from that, your prime checker code is very inefficient.
2 is the only even prime number, which can save you doing half the work you do.
You only need to check up to the square root of the number you are testing. In any pair of factors: f and n/f, one is guaranteed to be less then or equal to the square root of the number being tested. Once you find a factor then the number is composite.
My Python is not good, so this is in pseudocode:
isPrime(num)
// Negatives, 0, 1 are not prime.
if (num < 2) return false
// Even numbers: 2 is the only even prime.
if (num % 2 == 0) return (num == 2)
// Odd numbers have only odd factors.
limit <- 1 + sqrt(num)
for (i <- 3 to limit step 2)
if (num % i == 0) return false
// No factors found so num is prime
return true
end isPrime

Is this function i wrote to find prime numbers efficient [duplicate]

This question already has answers here:
Big O, how do you calculate/approximate it?
(24 answers)
Closed 2 years ago.
def is_prime(x):
'''
Function to check if a number is prime
'''
if x == 2:
return True
if x%2 != 0: #Check if number is even since all primes are odd except 2
a = [x % i for i in range(2,x+1)]
b = [i for i in a if i == 0] # Checks to make sure there's only one modulus of 0
if len(b) == 1:
return True
else:
return False
else:
return False
So like yeah please what is the time complexity (all those 0/n things) and how do i find that, a good resource link would be helpful (:
Your complexity is O(x) as you run one loop from 2 to x+1.
You can just check upto sqrt(x). That will bring down the complexity to O(sqrt(x)). (You can break once you find one factor, even though it won't bring down the worst time complexity)
Just change this line -
a = [x % i for i in range(2,math.sqrt(x+1))]
Why up to square root?
You can just google, there are many proofs. The simple one being, if
a = b.c, then the at least there is one divisor of a which is less than sqrt(a), or equal if a is square number a = b*b.
There are many fast heuristic and probabilistic (Miller-Rabin is very famous and frequently used) algorithms for faster prime detection.
Here's one which is deterministic:
The Adleman–Pomerance–Rumely primality test is an algorithm for determining whether a number is prime. Unlike other, more efficient algorithms for this purpose, it avoids the use of random numbers, so it is a deterministic primality test.
It's complexity is log(x)^O(logloglogx)
import copy
import time
from math import gcd # version >= 3.5
# primality test by trial division
def isprime_slow(n):
if n<2:
return False
elif n==2 or n==3:
return True
elif n%2==0:
return False
else:
i = 3
while i*i <= n:
if n%i == 0:
return False
i+=2
return True
# v_q(t): how many time is t divided by q
def v(q, t):
ans = 0
while(t % q == 0):
ans +=1
t//= q
return ans
def prime_factorize(n):
ret = []
p=2
while p*p <= n:
if n%p==0:
num = 0
while n%p==0:
num+=1
n//= p
ret.append((p,num))
p+= 1
if n!=1:
ret.append((n,1))
return ret
# calculate e(t)
def e(t):
s = 1
q_list = []
for q in range(2, t+2):
if t % (q-1) == 0 and isprime_slow(q):
s *= q ** (1+v(q,t))
q_list.append(q)
return 2*s, q_list
# Jacobi sum
class JacobiSum(object):
def __init__(self, p, k, q):
self.p = p
self.k = k
self.q = q
self.m = (p-1)*p**(k-1)
self.pk = p**k
self.coef = [0]*self.m
# 1
def one(self):
self.coef[0] = 1
for i in range(1,self.m):
self.coef[i] = 0
return self
# product of JacobiSum
# jac : JacobiSum
def mul(self, jac):
m = self.m
pk = self.pk
j_ret=JacobiSum(self.p, self.k, self.q)
for i in range(m):
for j in range(m):
if (i+j)% pk < m:
j_ret.coef[(i+j)% pk] += self.coef[i] * jac.coef[j]
else:
r = (i+j) % pk - self.p ** (self.k-1)
while r>=0:
j_ret.coef[r] -= self.coef[i] * jac.coef[j]
r-= self.p ** (self.k-1)
return j_ret
def __mul__(self, right):
if type(right) is int:
# product with integer
j_ret=JacobiSum(self.p, self.k, self.q)
for i in range(self.m):
j_ret.coef[i] = self.coef[i] * right
return j_ret
else:
# product with JacobiSum
return self.mul(right)
# power of JacobiSum(x-th power mod n)
def modpow(self, x, n):
j_ret=JacobiSum(self.p, self.k, self.q)
j_ret.coef[0]=1
j_a = copy.deepcopy(self)
while x>0:
if x%2==1:
j_ret = (j_ret * j_a).mod(n)
j_a = j_a*j_a
j_a.mod(n)
x //= 2
return j_ret
# applying "mod n" to coefficient of self
def mod(self, n):
for i in range(self.m):
self.coef[i] %= n
return self
# operate sigma_x
# verification for sigma_inv
def sigma(self, x):
m = self.m
pk = self.pk
j_ret=JacobiSum(self.p, self.k, self.q)
for i in range(m):
if (i*x) % pk < m:
j_ret.coef[(i*x) % pk] += self.coef[i]
else:
r = (i*x) % pk - self.p ** (self.k-1)
while r>=0:
j_ret.coef[r] -= self.coef[i]
r-= self.p ** (self.k-1)
return j_ret
# operate sigma_x^(-1)
def sigma_inv(self, x):
m = self.m
pk = self.pk
j_ret=JacobiSum(self.p, self.k, self.q)
for i in range(pk):
if i<m:
if (i*x)%pk < m:
j_ret.coef[i] += self.coef[(i*x)%pk]
else:
r = i - self.p ** (self.k-1)
while r>=0:
if (i*x)%pk < m:
j_ret.coef[r] -= self.coef[(i*x)%pk]
r-= self.p ** (self.k-1)
return j_ret
# Is self p^k-th root of unity (mod N)
# if so, return h where self is zeta^h
def is_root_of_unity(self, N):
m = self.m
p = self.p
k = self.k
# case of zeta^h (h<m)
one = 0
for i in range(m):
if self.coef[i]==1:
one += 1
h = i
elif self.coef[i] == 0:
continue
elif (self.coef[i] - (-1)) %N != 0:
return False, None
if one == 1:
return True, h
# case of zeta^h (h>=m)
for i in range(m):
if self.coef[i]!=0:
break
r = i % (p**(k-1))
for i in range(m):
if i % (p**(k-1)) == r:
if (self.coef[i] - (-1))%N != 0:
return False, None
else:
if self.coef[i] !=0:
return False, None
return True, (p-1)*p**(k-1)+ r
# find primitive root
def smallest_primitive_root(q):
for r in range(2, q):
s = set({})
m = 1
for i in range(1, q):
m = (m*r) % q
s.add(m)
if len(s) == q-1:
return r
return None # error
# calculate f_q(x)
def calc_f(q):
g = smallest_primitive_root(q)
m = {}
for x in range(1,q-1):
m[pow(g,x,q)] = x
f = {}
for x in range(1,q-1):
f[x] = m[ (1-pow(g,x,q))%q ]
return f
# sum zeta^(a*x+b*f(x))
def calc_J_ab(p, k, q, a, b):
j_ret = JacobiSum(p,k,q)
f = calc_f(q)
for x in range(1,q-1):
pk = p**k
if (a*x+b*f[x]) % pk < j_ret.m:
j_ret.coef[(a*x+b*f[x]) % pk] += 1
else:
r = (a*x+b*f[x]) % pk - p**(k-1)
while r>=0:
j_ret.coef[r] -= 1
r-= p**(k-1)
return j_ret
# calculate J(p,q)(p>=3 or p,q=2,2)
def calc_J(p, k, q):
return calc_J_ab(p, k, q, 1, 1)
# calculate J_3(q)(p=2 and k>=3)
def calc_J3(p, k, q):
j2q = calc_J(p, k, q)
j21 = calc_J_ab(p, k, q, 2, 1)
j_ret = j2q * j21
return j_ret
# calculate J_2(q)(p=2 and k>=3)
def calc_J2(p, k, q):
j31 = calc_J_ab(2, 3, q, 3, 1)
j_conv = JacobiSum(p, k, q)
for i in range(j31.m):
j_conv.coef[i*(p**k)//8] = j31.coef[i]
j_ret = j_conv * j_conv
return j_ret
# in case of p>=3
def APRtest_step4a(p, k, q, N):
print("Step 4a. (p^k, q = {0}^{1}, {2})".format(p,k,q))
J = calc_J(p, k, q)
# initialize s1=1
s1 = JacobiSum(p,k,q).one()
# J^Theta
for x in range(p**k):
if x % p == 0:
continue
t = J.sigma_inv(x)
t = t.modpow(x, N)
s1 = s1 * t
s1.mod(N)
# r = N mod p^k
r = N % (p**k)
# s2 = s1 ^ (N/p^k)
s2 = s1.modpow(N//(p**k), N)
# J^alpha
J_alpha = JacobiSum(p,k,q).one()
for x in range(p**k):
if x % p == 0:
continue
t = J.sigma_inv(x)
t = t.modpow((r*x)//(p**k), N)
J_alpha = J_alpha * t
J_alpha.mod(N)
# S = s2 * J_alpha
S = (s2 * J_alpha).mod(N)
# Is S root of unity
exist, h = S.is_root_of_unity(N)
if not exist:
# composite!
return False, None
else:
# possible prime
if h%p!=0:
l_p = 1
else:
l_p = 0
return True, l_p
# in case of p=2 and k>=3
def APRtest_step4b(p, k, q, N):
print("Step 4b. (p^k, q = {0}^{1}, {2})".format(p,k,q))
J = calc_J3(p, k, q)
# initialize s1=1
s1 = JacobiSum(p,k,q).one()
# J3^Theta
for x in range(p**k):
if x % 8 not in [1,3]:
continue
t = J.sigma_inv(x)
t = t.modpow(x, N)
s1 = s1 * t
s1.mod(N)
# r = N mod p^k
r = N % (p**k)
# s2 = s1 ^ (N/p^k)
s2 = s1.modpow(N//(p**k), N)
# J3^alpha
J_alpha = JacobiSum(p,k,q).one()
for x in range(p**k):
if x % 8 not in [1,3]:
continue
t = J.sigma_inv(x)
t = t.modpow((r*x)//(p**k), N)
J_alpha = J_alpha * t
J_alpha.mod(N)
# S = s2 * J_alpha * J2^delta
if N%8 in [1,3]:
S = (s2 * J_alpha ).mod(N)
else:
J2_delta = calc_J2(p,k,q)
S = (s2 * J_alpha * J2_delta).mod(N)
# Is S root of unity
exist, h = S.is_root_of_unity(N)
if not exist:
# composite
return False, None
else:
# possible prime
if h%p!=0 and (pow(q,(N-1)//2,N) + 1)%N==0:
l_p = 1
else:
l_p = 0
return True, l_p
# in case of p=2 and k=2
def APRtest_step4c(p, k, q, N):
print("Step 4c. (p^k, q = {0}^{1}, {2})".format(p,k,q))
J2q = calc_J(p, k, q)
# s1 = J(2,q)^2 * q (mod N)
s1 = (J2q * J2q * q).mod(N)
# s2 = s1 ^ (N/4)
s2 = s1.modpow(N//4, N)
if N%4 == 1:
S = s2
elif N%4 == 3:
S = (s2 * J2q * J2q).mod(N)
else:
print("Error")
# Is S root of unity
exist, h = S.is_root_of_unity(N)
if not exist:
# composite
return False, None
else:
# possible prime
if h%p!=0 and (pow(q,(N-1)//2,N) + 1)%N==0:
l_p = 1
else:
l_p = 0
return True, l_p
# in case of p=2 and k=1
def APRtest_step4d(p, k, q, N):
print("Step 4d. (p^k, q = {0}^{1}, {2})".format(p,k,q))
S2q = pow(-q, (N-1)//2, N)
if (S2q-1)%N != 0 and (S2q+1)%N != 0:
# composite
return False, None
else:
# possible prime
if (S2q + 1)%N == 0 and (N-1)%4==0:
l_p=1
else:
l_p=0
return True, l_p
# Step 4
def APRtest_step4(p, k, q, N):
if p>=3:
result, l_p = APRtest_step4a(p, k, q, N)
elif p==2 and k>=3:
result, l_p = APRtest_step4b(p, k, q, N)
elif p==2 and k==2:
result, l_p = APRtest_step4c(p, k, q, N)
elif p==2 and k==1:
result, l_p = APRtest_step4d(p, k, q, N)
else:
print("error")
if not result:
print("Composite")
return result, l_p
def APRtest(N):
t_list = [
2,
12,
60,
180,
840,
1260,
1680,
2520,
5040,
15120,
55440,
110880,
720720,
1441440,
4324320,
24504480,
73513440
]
print("N=", N)
if N<=3:
print("input should be greater than 3")
return False
# Select t
for t in t_list:
et, q_list = e(t)
if N < et*et:
break
else:
print("t not found")
return False
print("t=", t)
print("e(t)=", et, q_list)
# Step 1
print("=== Step 1 ===")
g = gcd(t*et, N)
if g > 1:
print("Composite")
return False
# Step 2
print("=== Step 2 ===")
l = {}
fac_t = prime_factorize(t)
for p, k in fac_t:
if p>=3 and pow(N, p-1, p*p)!=1:
l[p] = 1
else:
l[p] = 0
print("l_p=", l)
# Step 3 & Step 4
print("=== Step 3&4 ===")
for q in q_list:
if q == 2:
continue
fac = prime_factorize(q-1)
for p,k in fac:
# Step 4
result, l_p = APRtest_step4(p, k, q, N)
if not result:
# composite
print("Composite")
return False
elif l_p==1:
l[p] = 1
# Step 5
print("=== Step 5 ===")
print("l_p=", l)
for p, value in l.items():
if value==0:
# try other pair of (p,q)
print("Try other (p,q). p={}".format(p))
count = 0
i = 1
found = False
# try maximum 30 times
while count < 30:
q = p*i+1
if N%q != 0 and isprime_slow(q) and (q not in q_list):
count += 1
k = v(p, q-1)
# Step 4
result, l_p = APRtest_step4(p, k, q, N)
if not result:
# composite
print("Composite")
return False
elif l_p == 1:
found = True
break
i += 1
if not found:
print("error in Step 5")
return False
# Step 6
print("=== Step 6 ===")
r = 1
for t in range(t-1):
r = (r*N) % et
if r!=1 and r!= N and N % r == 0:
print("Composite", r)
return False
# prime!!
print("Prime!")
return True
if __name__ == '__main__':
start_time = time.time()
APRtest(2**521-1) # 157 digit, 18 sec
# APRtest(2**1279-1) # 386 digit, 355 sec
# APRtest(2074722246773485207821695222107608587480996474721117292752992589912196684750549658310084416732550077)
end_time = time.time()
print(end_time - start_time, "sec")
credit: https://github.com/wacchoz/APR_CL/blob/master/APR_CL.py
You only need to test odd numbers, except for 2 which you can test specially before the loop. This doesn't change the complexity, since it's a constant factor, but it reduces the time in half.
You should only test numbers up to math.sqrt(x). This changes the worst case complexity from O(n) to O(sqrt(n)).
You should stop as soon as you find a factor, rather than creating a list of all the x % i. This improves the best case complexity.
import math
def is_prime(x):
'''
Function to check if a number is prime
'''
if x == 2:
return True
if x % 2 == 0:
return False
for i in range(3, int(math.sqrt(x))+1, 2):
if x % i == 0:
return False
return True
Even better than checking all odd numbers is to check only prime numbers, using the Sieve of Eratosthenes.

Python - Algorithm for finding order of cyclic group generator

I wanted to find the order of a generator g chosen from a cyclic group G = Z*q where q is a very large (hundreds of bits long) number. I have tried the following code from Rosetta Code but it is taking too long:
def gcd(a, b):
while b != 0:
a, b = b, a % b
return a
def lcm(a, b):
return (a*b) / gcd(a, b)
def isPrime(p):
return (p > 1) and all(f == p for f,e in factored(p))
primeList = [2,3,5,7]
def primes():
for p in primeList:
yield p
while 1:
p += 2
while not isPrime(p):
p += 2
primeList.append(p)
yield p
def factored( a):
for p in primes():
j = 0
while a%p == 0:
a /= p
j += 1
if j > 0:
yield (p,j)
if a < p*p: break
if a > 1:
yield (a,1)
def multOrdr1(a, (p,e)):
m = p**e
t = (p-1)*(p**(e-1)) # = Phi(p**e) where p prime
qs = [1,]
for f in factored(t):
qs = [ q * f[0]**j for j in range(1+f[1]) for q in qs ]
qs.sort()
for q in qs:
if pow( a, q, m )==1: break
return q
def multOrder(a,m):
assert gcd(a,m) == 1
mofs = (multOrdr1(a,r) for r in factored(m))
return functools.reduce(lcm, mofs, 1)
if __name__ == "__main__":
print(multOrder(37, 1000)) # 100
b = 10**20-1
print(multOrder(2, b)) # 3748806900
print(multOrder(17,b)) # 1499522760
b = 100001
print(multOrder(54,b))
print(pow(54, multOrder(54,b), b))
if any( (1==pow(54,r, b)) for r in range(1,multOrder(54,b)) ):
print('Exists a power r < 9090 where pow(54,r,b)==1')
else:
print('Everything checks.')

Python: represent a number as a sum of prime numbers

I need to write an algorithm, that can represent a number as a min sum of prime numbers:
For example:
8 -> [2, 2, 2, 2], [3, 5], [2, 3, 3]
and I need get min len of this => 2
I've written the code, but it takes a lot of time, because it contains recursion. How can I change it to improve time?
import sys
x = int(sys.stdin.readline())
def is_prime(n):
for i in range(2, n):
if n % i == 0:
return False
return True
def decomposition(x):
result = []
for a in range(2, int(x/2 + 1)):
if x-a >= 2:
b = x - a
pair = [a, b]
result.append(pair)
return result
def f(elem):
list_of_mins = []
if is_prime(elem) == True:
return 1
else:
pairs = decomposition(elem)
print(pairs)
for a,b in pairs:
list_of_mins.append(f(a)+f(b))
return min(list_of_mins)
if str(int(x)).isdigit() and 2 <= int(x) <= 10 ** 9:
sum = []import sys
x = int(sys.stdin.readline())
def is_prime(n):
for i in range(2, n):
if n % i == 0:
return False
return True
def decomposition(x):
result = []
for a in range(2, int(x/2 + 1)):
if x-a >= 2:
b = x - a
pair = [a, b]
result.append(pair)
return result
def f(elem):
list_of_mins = []
if is_prime(elem) == True:
return 1
else:
pairs = decomposition(elem)
print(pairs)
for a,b in pairs:
list_of_mins.append(f(a)+f(b))
return min(list_of_mins)
if str(int(x)).isdigit() and 2 <= int(x) <= 10 ** 9:
sum = []
print(f(x))
Your is_prime function only needs to test divisors up to pow(n, 0.5)+1. This means your code would be:
def is_prime(n):
for i in range(2, int(pow(n, 0.5)+1):
if n % i == 0:
return False
return True
This should speed your algorithm up significantly.
Here's a possible solution:
import math
class Foo():
def __init__(self, n):
self.n = n
self.primes = self.prime_sieve(n)
def prime_sieve(self, sieve_size):
sieve = [True] * sieve_size
sieve[0] = False
sieve[1] = False
for i in range(2, int(math.sqrt(sieve_size)) + 1):
pointer = i * 2
while pointer < sieve_size:
sieve[pointer] = False
pointer += i
primes = []
for i in range(sieve_size):
if sieve[i] == True:
primes.append(i)
return primes
def sum_to_n(self, n, size, limit=None):
if size == 1:
yield [n]
return
if limit is None:
limit = n
start = (n + size - 1) // size
stop = min(limit, n - size + 1) + 1
for i in range(start, stop):
for tail in self.sum_to_n(n - i, size - 1, i):
yield [i] + tail
def possible_sums(self):
for i in range(2, self.n):
result = list(self.sum_to_n(self.n, i))
result = (
[v for v in result if all([(p in self.primes) for p in v])])
if result:
yield result
def result(self):
for i in self.possible_sums():
return i
raise Exception("Not available result!")
if __name__ == '__main__':
obj = Foo(8)
print(list(obj.possible_sums()))
print('-' * 80)
try:
v = obj.result()
print("{} , length = {}".format(v[0], len(v[0])))
except Exception as e:
print(e)
Result:
[[[5, 3]], [[3, 3, 2]], [[2, 2, 2, 2]]]
--------------------------------------------------------------------------------
[5, 3] , length = 2

Is my math or my variables wrong in my RSA example?

I was reading up on cryptography, specifically RSA(https://www.khanacademy.org/computing/computer-science/cryptography/modern-crypt/v/rsa-encryption-part-4), and decided to make an example for myself. However, even though I'm pretty sure I got my variables right, I think I got my math wrong. Can someone help me find the error? I tried to put comments everywhere I thought needed an explanation. Written in Python 3.5.2
#m^phi(n) mod n == 1 where m & n dont share a common factor
#since 1^k = 1, m^(k * phi(n)) mod n == 1, too.
#since 1*m = m, m* (m^(k * phi(n)) mod n) == m
#^^^^simplifies to m^(k * phi(n) + 1) mod n == m
#b/c m^(e*d) mod n = m
#m^(e*d) mod n == m^(k * phi(n) + 1) mod n
#e*d = k * phi(n) + 1
#d = (k * phi(n) + 1)/e
from fractions import gcd
import random
i = 1
j = 1
t = 1
def is_prime(a):
return all(a % i for i in range(2, a))
while True:
p1 = random.randrange(10.00000)#gens the 1st random prime
if is_prime(p1):
if p1 == 0 or p1 == 1:
i+=1
continue
else:
print("First Random Prime Found on attempt "+str(i)+": "+str(p1))
break
i+=1
while True:
p2 = random.randrange(10.00000)#gens the 1st random prime
if is_prime(p2):
if p2 == 0 or p2 == 1:
j+=1
continue
else:
print("First Random Prime Found on attempt "+str(j)+": "+str(p2))
break
j+=1
n = p1 * p2
print("n = p1 * p2 = "+str(n))
phi_n = (p1 - 1) * (p2 - 1)#phi(n) = how many numbers below n share no factors w/ n. Given Definition of a prime, phi(any_prime_num) is always any_prime_num - 1.
print("phi_n = (p1 - 1) * (p2 - 1) = "+str(phi_n))
while True:
e = random.randrange(10)#gens the 3rd random prime
if e % 2 != 0:
if phi_n % e == 0:
k+=1
continue
else:
print("Public Random Prime(is e)Found on attempt "+str(t)+": "+str(e))
break
k = random.randrange(e)
print("num used to find d(is k): "+str(k))
d = (k * phi_n + 1)/e
print("PRIVATE key(is d): "+str(d))
#pub_key = [n, e]
#priv_key = [d, k, p1, p2, phi_n]
m = input("Type an int: ")
if gcd(int(m), n) != 1:
quit() #b/c m & n must not share a common factor(apparently)
c = (int(m)**e) % n #cipher text(nums)
print("Encrypted: "+str(c))
u = (c**d) % n #SHOULD be decrypted text(more nums)
print("Decrypted: "+str(u))
if int(m) == int(u):
print("Successful!!")
else:
print("Unsuccessful....")

Categories

Resources