1#!/usr/bin/env python3
2#
3#============================================================================
4#
5# NAME
6#
7# millerRabin.py
8#
9# DESCRIPTION
10#
11# Miller-Rabin test for primality.
12#
13# USAGE
14#
15# To test n for primality using random number a,
16#
17# python millerRabin.py n a 1
18#
19# EXAMPLES
20#
21# python millerRabin.py 104729 47340 1
22# Testing n = 104729 for primality using random integer x = 47340
23# Remove powers of 2
24# k = 1 n1 = 52364
25# k = 2 n1 = 26182
26# k = 3 n1 = 13091
27# q = 3 k = 13091
28# Generate and test the sequence x^(q^k) mod n.
29# j = 0 y = 87711
30# j = 1 y = 36639
31# j = 2 y = 104728
32# Probably prime. Found y = n-1 or j = 0 and y = 1 y = 104728 j = 2
33#
34# python millerRabin.py 9999612 32423 1
35# Testing n = 9999612 for primality using random integer x = 32423
36# Remove powers of 2
37# q = 0 k = 9999611
38# Generate and test the sequence x^(q^k) mod n.
39# Definitely composite. Fell off the end of the loop.
40#
41# ./millerRabin.py 8398 1884460498967805432001612672369307101507474835976431925948333387748670120353629453261347843140212808\
42# 570505767386771290423087216156597588216186445958479269565424431335013281 122 1
43# Testing n = 188446049896780543200161267236930710150747483597643192594833338774867012035362945326134784314021280857050576\
44# 7386771290423087216156597588216186445958479269565424431335013281 for primality using random integer x = 122
45# Remove powers of 2
46# k = 1 n1 = 942230249483902716000806336184653550753737417988215962974166693874335060176814726630673921570106404285252883693\
47# 385645211543608078298794108093222979239634782712215667506640
48# k = 2 n1 = 47111512474195135800040316809232677537686870899410798148708334693716753008840736331533696078505320214262644184\
49# 6692822605771804039149397054046611489619817391356107833753320
50# k = 3 n1 = 235557562370975679000201584046163387688434354497053990743541673468583765044203681657668480392526601071313220923\
51# 346411302885902019574698527023305744809908695678053916876660
52# k = 4 n1 = 1177787811854878395001007920230816938442171772485269953717708367342918825221018408288342401962633005356566104616\
53# 73205651442951009787349263511652872404954347839026958438330
54# k = 5 n1 = 5888939059274391975005039601154084692210858862426349768588541836714594126105092041441712009813165026782830523083\
55# 6602825721475504893674631755826436202477173919513479219165
56# q = 5 k = 5888939059274391975005039601154084692210858862426349768588541836714594126105092041441712009813165026782830523083\
57# 6602825721475504893674631755826436202477173919513479219165
58# Generate and test the sequence x^(q^k) mod n.
59# j = 0 y = 4562627375418921997495128389472904369506849162624397308228643567229422125069828207111411946939507039364910257582\
60# 53679056110147196100972654986996407565104255499753038631160
61# j = 1 y = 181921118629873824198891977536932720607952192628256115040458970624355555142399332847486840509884746125806162856\
62# 2013490792783220259040379029588830209459993575609245826016160
63# j = 2 y = 1675291436909496660109561278257723410018131370324303168442668644288721609236515790057247572821758832994480351123\
64# 772012853725200818096891590375783891432523321208439264772913
65# j = 3 y = 1884460498967805432001612672369307101507474835976431925948333387748670120353629453261347843140212808570505767386\
66# 771290423087216156597588216186445958479269565424431335013280
67# Probably prime. Found y = n-1 or j = 0 and y = 1 y = 18844604989678054320016126723693071015074748359764319259483333877486\
68# 70120353629453261347843140212808570505767386771290423087216156597588216186445958479269565424431335013280 j = 3
69#
70# AUTHOR
71#
72# Sean E. O'Connor 3 Apr 2015 Version 1.0 released.
73#
74# NOTES
75#
76# Python interpreter: https://www.python.org/
77# Python tutorial and reference: htttp://docs.python.org/lib/lib.html
78# Python regular expression howto: https://docs.python.org/3.7/howto/regex.html
79#
80# LEGAL
81#
82# millerRabin.py Version 1.0 - A Python program to do the Miller-Rabin test for primality.
83# Copyright (C) 2017-2024 by Sean Erik O'Connor. All Rights Reserved.
84#
85# This program is free software: you can redistribute it and/or modify
86# it under the terms of the GNU General Public License as published by
87# the Free Software Foundation, either version 3 of the License, or
88# (at your option) any later version.
89#
90# This program is distributed in the hope that it will be useful,
91# but WITHOUT ANY WARRANTY; without even the implied warranty of
92# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
93# GNU General Public License for more details.
94#
95# You should have received a copy of the GNU General Public License
96# along with this program. If not, see <http://www.gnu.org/licenses/>.
97#
98# The author's address is seanerikoconnor!AT!gmail!DOT!com
99# with !DOT! replaced by . and the !AT! replaced by @
100#
101#============================================================================
102
103import sys
104
105def main():
106
107 print( "Running Python Version {0:d}.{1:d}.{2:d}".format( sys.version_info[ 0 ], sys.version_info[ 1 ], sys.version_info[ 2 ] ) )
108
109 if len( sys.argv ) != 4:
110 print( "Usage: python MillerRabin.py n x d" )
111 print( " n the number to be tested for primality" )
112 print( " x any random number" )
113 print( " d nonzero turns on debug prints" )
114 sys.exit()
115 else:
116 n = int( sys.argv[ 1 ] )
117 x = int( sys.argv[ 2 ] )
118 if int( sys.argv[ 3 ] ) == 0:
119 debug = False
120 else:
121 debug = True
122
123 if debug:
124 print( "Testing n = {0:d} for primality using random integer x = {1:d}".format( n, x ) )
125
126 if MillerRabin( n, x, debug ):
127 print( "Probably prime" )
128 else:
129 print( "Definitely composite" )
130
131 sys.exit( 0 )
132
133def MillerRabin( n, x, debug ):
134 n1 = n - 1
135
136 # Remove powers of 2.
137 k = 0
138 even = True
139
140 if debug:
141 print( "Remove powers of 2" )
142
143 while n1 % 2 == 0:
144 n1 //= 2
145 k += 1
146 if debug:
147 print( "k = {0:d} n1 = {1:d}".format( k, n1 ))
148
149 q = n1
150
151 if debug:
152 print( "q = {0:d} k = {1:d}".format( k, n1 ) )
153
154 y = pow( x, q, n )
155
156 if debug:
157 if debug:
158 print( "Generate and test the sequence x^(q^k) mod n. " ) ;
159
160 for j in range (0,k):
161 if debug:
162 print( "j = {0:d} y = {1:d}".format( j, y ))
163
164 if (j == 0 and y == 1) or y == n-1:
165 if debug:
166 print( "Probably prime. Found y = n-1 or j = 0 and y = 1 y = {0:d} j = {1:d}".format( y, j ) )
167 return True
168
169 if j > 0 and y == 1:
170 if debug:
171 print( "Definitely composite. Found j > 0 and y = 1" )
172 return False
173
174 y = pow( y, 2, n )
175
176 if debug:
177 print( "Definitely composite. Fell off the end of the loop." )
178 return False
179
180# Call the main.
181if __name__ == '__main__':
182 main()