# # New things are on the top... # # Paul Garrett, 1998-... # import math # use sqrt, log, exp, ceil import __main__ ###################################################################### def lg( n ): return math.log(0.0+n)/math.log(0.0+2) def hamming_weight( n ): wt = 0 while n > 0: wt = wt + ( n % 2 ) n = n/2 return wt def wt( n ): return hamming_weight( n ) def entropy( p ): return -p * lg(p) - (1-p)*lg(1-p) def H(p): return entropy(p) def channel_capacity( p ): return 1 - H(p) def cap(p): return channel_capacity(p) ##################################################################### def is_prime( n ): if (factors(n) == [n]): return 1 else: return 0 def binomial_coefficient( n , k ): out = n + 0L for i in range(1,k): out = out * (n-i) for i in range(1,k+1): out = out/i return out def inverse( x, n ): """ Usage: inverse( x, n ) computes inverse of x modulo n, assuming gcd(b,n)=1 via Euclidean algorithm If n=0, returns rational number inverse...""" if n != 0: n = abs(n) return (full_euclid(n,x)[1] + n) % n else: return 1.0/x def sgn( n ): if n > 0: return 1 elif n < 0: return -1 else: return 0 def full_euclid( x,y): # # Hmmm. Note that divmod(17,-3) == (-6,-1) Rrrr... # """ Usage: full_euclid( x, y ) Returns [a,b,g] so that a.x + b.n = g = gcd(x,n) """ a,b,c,d = 1L,0L,0L,1L sgnx = sgn(x) sgny = sgn(y) x = abs(x) y = abs(y) while y != 0: [q,r] = divmod(x,y) x,y = y,r a,b,c,d = c,d,a-c*q,b-q*d # now a.x_abs + b.y_abs = gcd return a*sgnx, b*sgny, x # now x is the gcd def sqrt( n ): """ Usage: sqrt( n ) Is infinite-precision long-integer square-root evaluator Uses Newton's method, not floating-point """ if n < 1000000: return int(math.sqrt(n)) digits = len( repr(n) ) - 1 if digits <= 0: digits = 1 x = 10L ** (digits/2) ## smaller than actual sqrt decr = (x - n/x)/2 while decr >= 1 or decr <= -1: x = x - decr decr = (x - n/x)/2 return x ###################################################################### def find_last_index( bound, List ): """ Usage: find_index_in_ordered_list( bound, List ) finds highest index i so that List[i] <= bound Uses divide-and-conquer (binary expansion) search """ lg = int( math.log( len(List)-1 )/ math.log( 2 ) ) now = pow(2, lg) - 1 while ( lg > 0 and (List[now] > bound or ( now+1 < len(List) and List[now+1] <= bound ))): lg = lg - 1 inc = pow(2,lg) if List[now] > bound: # guess is too high now = now - inc else: # too low if now + inc < len(List): now = now + inc else: pass return now ###################################################################### def _mr(power_of_2, m, b, n): # private function called by "public" miller_rabin() t = 0 m = m + 0L n = n + 0L b = b + 0L Y = pow( b, m, n) if (Y == 1): return 1 else: while ( t < power_of_2 ): if (Y == n-1): return 1 Y = Y * Y % n if (Y == 1): return 0 t = t + 1 return 0 def standard( n ): ## commercial pseudoprimality test bases_list = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,73] return miller_rabin( n , bases = bases_list ) # # In the latter, there seems to be no point in trial division first.... !?!? # # (as indicated by naive benchmarking tests on 100-digit numbers) # def miller_rabin( n , bases = [2] ): """ Usage: miller_rabin( n, bases = [2] ) Performs Miller-Rabin test on n with list "bases" returns 0 for composite, 1 for probable prime """ if n < 2 : n = 2 m = n-1L n = n + 0L power_of_2 = 0L while (m % 2 == 0): power_of_2 = 1 + power_of_2 m = m/2 for b in bases: if ( _mr(power_of_2, m, b, n) == 0 ): return 0 return 1 def factors( m, verbose = 0 ): """ Usage: factors( m, verbose = 0 ) returns [list_of_factors]""" list_of_factors = [] sq = sqrt(m) while m % 2 == 0: list_of_factors.append( 2 ) m = m/2 sq = sqrt(m) if verbose: print 2 d = 3 while d <= sq: if m % d == 0: list_of_factors.append( d ) m = m/d sq = sqrt(m) if verbose: print d else: d = d+2 if m > 1: list_of_factors.append( m ) if verbose: print m return list_of_factors def gcd(x,y): """ Usage: gcd(x,y) \n returns gcd""" while ( y>0 ): x = x % y (x,y) = (y,x) return x def trial_division( n, bound = 1000): """ Usage trial_division( bound, n ) returns smallest divisor d with 1 < d <= n, or 1 if none such""" bound = bound + 2L if ( n % 2 == 0 ): return 2 d = 3L while ( d <= bound ): if ( n % d == 0 ): return d d = d + 2 return 1 def trial_division_by_list( n, the_list ): """ Usage: trial_division_by_list( n, the_list ) returns smallest divisor >1 on the list, or 1 """ for tester in the_list: if n % tester == 0: return tester return 1 def naive( n ): """ Usage: naive( n ) returns smallest factor <= sqrt(n), or 1 if none such""" sq = sqrt( n ) + 0L return trial_division( n, sq ) def sophie_germain( n, ptest = naive ): # "ptest" should be a primality test """ Usage: sophie_germain( n, ptest = naive ) finds next sophie germain prime above n (so that 2n+1 also prime) using given primality test, with default "naive" test""" if n % 2 == 0: n = n + 1 while ( ptest( n ) == 0 or ptest( 2*n+1 ) == 0 ): n = n+2 return [n, 2*n+1] def fermat( n, bases = [2] ): """ Usage: fermat( n, bases = [2] ) with n odd returns 0 for composite, 1 for probably prime""" sq = sqrt ( n ) ######## this is local, long-valued "sqrt" for b in bases: if ( b > sq ): return 1 b = 0L + b if gcd(b, n) > 1: pass ################# else "carmichael" becomes vacuous! elif pow(b, n, n) != b: return 0 return 1 def _rho_random_function(x,n): """ Usage: _rho_random_function(x,n) it is x*x+1 % n """ return (x * x + 1L) % n def rho(n, bound = 0, verbose = 0 ): """ Usage: rho(n, bound = 0, verbose = 0 ) This is Pollard's rho method with some specific choices: uses _rho_random_function() which by default is x^2+1 % n prints number of cycles every 10,000 if verbose == true if bound is set >0 then limits number of cycles before return Returns [factor, cycle-count]""" y = 2L ## edit value here?! x = _rho_random_function( y,n ) count = 0 if verbose == 0 and bound == 0: while 1: count = count + 1 g = gcd(n, x-y) if g > 1 and g < n: return [g, count] else: # may never return... x = _rho_random_function( _rho_random_function( x,n ), n) y = _rho_random_function( y,n ) elif verbose == 0 and bound > 0: while count < bound: count = count + 1 g = gcd(n, x-y) if g > 1 and g < n: return [g, count] else: # may never return... x = _rho_random_function( _rho_random_function( x,n ), n) y = _rho_random_function( y,n ) return [1,count] elif verbose == 1 and bound == 0: while 1: count = count + 1 g = gcd(n, x-y) if g > 1 and g < n: print " count = " + `count` print g return [g, count] else: x = _rho_random_function( _rho_random_function( x,n ), n) y = _rho_random_function( y,n ) if (count % 10000 == 0): # this block is missing in non-verbose print "count = " + `count` count = count + 1 else: # verbose and bounded case while count < bound: count = count + 1 g = gcd(n, x-y) if g > 1 and g < n: print " count = " + `count` print g return [g, count] else: x = _rho_random_function( _rho_random_function( x,n ), n) y = _rho_random_function( y,n ) if (count % 10000 == 0): # this block is missing in non-verbose print " count = " + `count` count = count + 1 print " No factor found in " + `bound` + " tries " return [1, count] class small_primes: """ Usage: small_primes( bound ) Initializes object "sp" so that len(sp) = number primes under bound and sp[i] retrieves the i-th prime (under the bound) """ def __init__(self, bound): self.plist = [] self.plist.append( 2 ) t = 3 sq = sqrt(bound) while (t < bound): if is_prime(t): self.plist.append( t ) t = t + 2 def get( self ): return self.plist def __len__( self ): return len( self.plist ) def __getitem__( self, i ): return self.plist[i] ###################################################################### def carmichael(lower=500L, upper=3000L, verbose = 0): List = [] if lower < 100: lower = 500L primes_bound = sqrt( upper ) sp = small_primes( primes_bound ) # primes_bound = long(math.ceil( math.exp( math.log(upper)/3 ) ) ) # th = small_primes( primes_bound ) # # Note: since a carmichael number is divisible by at least 3 distinct # primes (!), we need only search for prime factors up through the # cube root, rather than square root. # # This would have ramifications for rho-test, too, I guess... ? # if ( lower % 2 == 0 ): lower = lower + 1L else: lower = lower + 0L for t in xrange(lower, upper, 2L): if ( fermat( t, [2L]) == 1 and is_prime( t ) == 0 and fermat( t, sp.plist ) == 1): List.append(t) if verbose: print t else: pass print List ###################################################################### # # Lucas-Lehmer test for Mersenne numbers to be prime # def lucas_lehmer( s ): """ Usage lucas_lehmer( s ) Applies Lucas-Lehmer test to assess primality of 2^s-1""" if s == 1: return 0 if s == 2: return 1 n = pow(2L, s) - 1 for t in xrange(2, sqrt(s)+1, 2): if s % t == 0: return 0 # composite exponent u = 4 for i in xrange(0,s-2): u = (u * u - 2) % n if u == 0: return 1 else: return 0 def man( obj ): """ Usage: man( obj ) Prints the document string obj.__doc__ attached to an object, function, method, ... named "obj" """ print obj.__doc__ def is_primitive_root( modulus, b = 2L ): """ Usage: is_primitive_root( modulus, b = 2 ) Returns 1 if b is a primitive root modulo, else 0""" less_one = modulus - 1 list_of_factors = distinct_factors( modulus - 1 ) for factor in list_of_factors: if pow(b, less_one/factor, modulus) == 1: return 0 return 1 def primitive_root( modulus ): """ Usage: primitive_root( modulus ) Returns smallest primitive root modulo modulus""" b = 2 while ( is_primitive_root( modulus, b) == 0): b = b+1 return b def next_prime( start, test = naive, increment = 2 ): """ Usage: next_prime( start, test = naive ) Returns next prime above "start" Uses primality test specified, defaults to "naive", which is simply trial division """ if ( start % 2 == 0 ): start = start + 1 else: start = start + increment test_outcome = test( start ) while ( test_outcome == 0 or (test_outcome < start and test_outcome > 1 )): start = start + increment test_outcome = test( start ) return start def p_minus( n, bound = 100000 ): """ Usage p_minus( n, bound = 100000 ) Applies Pollard's p-1 test with smoothness bound "bound" Returns factor, which is proper if successful """ plist = [2,3,5] ## ,5,7,11,13,17,19,23,29,31] # sp = small_primes( bound+1 ) a = 3 print ("n = " + `n`) print ("Use a = " + `a`) for p in plist: ## sp.plist: expr = long( math.log( n )/math.log( p ) ) print("exp for " + `p` + " is " + `expr`) a = pow( a, pow(p+0L, expr), n) print("a^that mod " + `n` + " is " + `a`) # # for t in xrange(0, expr+1): #### don't eval gcd's so often!? # a = pow( a, p, n) # g = gcd( n, a - 1 ) print("gcd(n=" + `n` + ", a-1=" + `a-1` + ") is " + `g`) if (g > 1 and g < n): return g return gcd( n, a - 1 ) def small_factors( n, bound = 1000000, verbose = 0 ): ## 29 Dec 98 """ Usage: small_factors( n, bound = 1000000 ) If stdout is unbuffered (with -u switch in interpreter) then factors under bound are printed as they're found. Return value is compound list [ list-of-factors, leftover ] """ sq = sqrt( n ) if sq < bound: bound = sq List = [] for p in __main__.primes: if p > bound or n == 1: if verbose: print "\n got all the factors", break while n % p == 0: n = n/p List.append(p) sq = sqrt( n ) if sq < bound: bound = sq if verbose: print p, return [List, n] def small_attack( n, cycle_bound = 200000, verbose = 1 ): """ Usage: small_attack( n, cycle_bound = 200000, verbose = 1 ) If stdout is unbuffered (with -u switch in interpreter) then factors are printed as they're found. Return value is compound list [ list-of-factors, leftover, 0 or 1 ] where last indicates probable prime or not First uses list of primes under 1,000,000, then Pollard's rho test for "cycle_bound" cycles """ if verbose: print "... doing trial division ..." [smallFactors, n] = small_factors( n, 1000000, verbose ) if n == 1: return [smallFactors, n, 1] if miller_rabin( n, [2,3,5,7,11,13,17,19,23]) == 1: if verbose: print "\n ... didn't do rho ... " return [smallFactors, n, 1] if verbose: print "\n ... doing rho now ..." [div, cycles_used] = rho( n, cycle_bound, verbose ) n = n/div if verbose == 0: # non-verbose case while div > 1 and miller_rabin( n, [2,3,5,7,11,13,17,19,23]) == 0: smallFactors.append( div ) [div, cycles_used] = rho( n, cycle_bound) n = n / div probable_prime = miller_rabin( n, [2,3,5,7,11,13,17,19,23] ) return [smallFactors, n, probable_prime] else: # verbose case while div > 1 and miller_rabin( n, [2,3,5,7,11,13,17,19,23]) == 0: smallFactors.append( div ) [div, cycles_used] = rho( n, cycle_bound, verbose ) n = n / div probable_prime = miller_rabin( n, [2,3,5,7,11,13,17,19,23] ) return [smallFactors, n, probable_prime] def distinct_factors( m, verbose = 0): """ Usage: distinct_factors( m, verbose = 0 ) returns [list_of_factors]""" list_of_factors = [] sq = sqrt(m) while m % 2 == 0: list_of_factors.append( 2 ) m = m/2 sq = sqrt(m) if verbose: print 2 d = 3 while d <= sq: if m % d == 0: list_of_factors.append( d ) while m % d == 0: m = m/d sq = sqrt(m) if verbose: print d else: d = d+2 if m > 1: list_of_factors.append( m ) if verbose: print m return list_of_factors ######################################################################