| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  | # =================================================================== | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Copyright (c) 2014, Legrandin <helderijs@gmail.com> | 
					
						
							|  |  |  | # All rights reserved. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  | # modification, are permitted provided that the following conditions | 
					
						
							|  |  |  | # are met: | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # 1. Redistributions of source code must retain the above copyright | 
					
						
							|  |  |  | #    notice, this list of conditions and the following disclaimer. | 
					
						
							|  |  |  | # 2. Redistributions in binary form must reproduce the above copyright | 
					
						
							|  |  |  | #    notice, this list of conditions and the following disclaimer in | 
					
						
							|  |  |  | #    the documentation and/or other materials provided with the | 
					
						
							|  |  |  | #    distribution. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
					
						
							|  |  |  | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
					
						
							|  |  |  | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 
					
						
							|  |  |  | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 
					
						
							|  |  |  | # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 
					
						
							|  |  |  | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 
					
						
							|  |  |  | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 
					
						
							|  |  |  | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | 
					
						
							|  |  |  | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
					
						
							|  |  |  | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | 
					
						
							|  |  |  | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 
					
						
							|  |  |  | # POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  | # =================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from Crypto.Util.number import long_to_bytes, bytes_to_long | 
					
						
							| 
									
										
										
										
											2014-11-19 20:54:54 +01:00
										 |  |  | from Crypto.Util.py3compat import maxint | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  | class Integer(object): | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  |     """A class to model a natural integer (including zero)""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value): | 
					
						
							|  |  |  |         if isinstance(value, float): | 
					
						
							|  |  |  |             raise ValueError("A floating point type is not a natural number") | 
					
						
							|  |  |  |         self._value = value | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     # Conversions | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  |     def __int__(self): | 
					
						
							|  |  |  |         return self._value | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return str(int(self)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return "Integer(%s)" % str(self) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def to_bytes(self, block_size=0): | 
					
						
							|  |  |  |         if self._value < 0: | 
					
						
							|  |  |  |             raise ValueError("Conversion only valid for non-negative numbers") | 
					
						
							|  |  |  |         result = long_to_bytes(self._value, block_size) | 
					
						
							|  |  |  |         if len(result) > block_size > 0: | 
					
						
							|  |  |  |             raise ValueError("Value too large to encode") | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  |     @staticmethod | 
					
						
							|  |  |  |     def from_bytes(byte_string): | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         return Integer(bytes_to_long(byte_string)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Relations | 
					
						
							|  |  |  |     def __eq__(self, term): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             result = self._value == term._value | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             result = self._value == term | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ne__(self, term): | 
					
						
							|  |  |  |         return not self.__eq__(term) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __lt__(self, term): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             result = self._value < term._value | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             result = self._value < term | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __le__(self, term): | 
					
						
							|  |  |  |         return self.__lt__(term) or self.__eq__(term) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __gt__(self, term): | 
					
						
							|  |  |  |         return not self.__le__(term) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ge__(self, term): | 
					
						
							|  |  |  |         return not self.__lt__(term) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __nonzero__(self): | 
					
						
							|  |  |  |         return self._value != 0 | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |     def is_negative(self): | 
					
						
							|  |  |  |         return self._value < 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  |     # Arithmetic operations | 
					
						
							|  |  |  |     def __add__(self, term): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             return Integer(self._value + term._value) | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  |         except AttributeError: | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             return Integer(self._value + term) | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __sub__(self, term): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             diff = self._value - term._value | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             diff = self._value - term | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         return Integer(diff) | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |     def __mul__(self, factor): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             return Integer(self._value * factor._value) | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |         except AttributeError: | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             return Integer(self._value * factor) | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |     def __floordiv__(self, divisor): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             divisor_value = divisor._value | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             divisor_value = divisor | 
					
						
							|  |  |  |         return Integer(self._value // divisor_value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  |     def __mod__(self, divisor): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             divisor_value = divisor._value | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  |         except AttributeError: | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             divisor_value = divisor | 
					
						
							|  |  |  |         if divisor_value < 0: | 
					
						
							|  |  |  |             raise ValueError("Modulus must be positive") | 
					
						
							|  |  |  |         return Integer(self._value % divisor_value) | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |     def __pow__(self, exponent, modulus=None): | 
					
						
							| 
									
										
										
										
											2014-09-21 21:28:59 +02:00
										 |  |  |         try: | 
					
						
							|  |  |  |             exp_value = exponent._value | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             exp_value = exponent | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |         if exp_value < 0: | 
					
						
							|  |  |  |             raise ValueError("Exponent must not be negative") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-21 21:28:59 +02:00
										 |  |  |         try: | 
					
						
							|  |  |  |             mod_value = modulus._value | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             mod_value = modulus | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         if mod_value is not None: | 
					
						
							|  |  |  |             if mod_value < 0: | 
					
						
							|  |  |  |                 raise ValueError("Modulus must be positive") | 
					
						
							|  |  |  |             if mod_value == 0: | 
					
						
							|  |  |  |                 raise ZeroDivisionError("Modulus cannot be zero") | 
					
						
							| 
									
										
										
										
											2014-09-21 21:28:59 +02:00
										 |  |  |         return pow(self._value, exp_value, mod_value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     # Boolean/bit operations | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |     def __and__(self, term): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             return Integer(self._value & term._value) | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |         except AttributeError: | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             return Integer(self._value & term) | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-16 22:05:16 +01:00
										 |  |  |     def __or__(self, term): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return Integer(self._value | term._value) | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             return Integer(self._value | term) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |     def __rshift__(self, pos): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2014-11-25 22:13:59 +01:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 return Integer(self._value >> pos._value) | 
					
						
							|  |  |  |             except AttributeError: | 
					
						
							|  |  |  |                 return Integer(self._value >> pos) | 
					
						
							|  |  |  |         except OverflowError: | 
					
						
							|  |  |  |             raise ValueError("Incorrect shift count") | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |     def __irshift__(self, pos): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2014-11-25 22:13:59 +01:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 self._value >>= pos._value | 
					
						
							|  |  |  |             except AttributeError: | 
					
						
							|  |  |  |                 self._value >>= pos | 
					
						
							|  |  |  |         except OverflowError: | 
					
						
							|  |  |  |             raise ValueError("Incorrect shift count") | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |     def __lshift__(self, pos): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 return Integer(self._value << pos._value) | 
					
						
							|  |  |  |             except AttributeError: | 
					
						
							|  |  |  |                 return Integer(self._value << pos) | 
					
						
							|  |  |  |         except OverflowError: | 
					
						
							|  |  |  |             raise ValueError("Incorrect shift count") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ilshift__(self, pos): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 self._value <<= pos._value | 
					
						
							|  |  |  |             except AttributeError: | 
					
						
							|  |  |  |                 self._value <<= pos | 
					
						
							|  |  |  |         except OverflowError: | 
					
						
							|  |  |  |             raise ValueError("Incorrect shift count") | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |     def get_bit(self, n): | 
					
						
							| 
									
										
										
										
											2014-11-25 22:13:59 +01:00
										 |  |  |         try: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 return (self._value >> n._value) & 1 | 
					
						
							|  |  |  |             except AttributeError: | 
					
						
							|  |  |  |                 return (self._value >> n) & 1 | 
					
						
							|  |  |  |         except OverflowError: | 
					
						
							|  |  |  |             raise ValueError("Incorrect bit position") | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     # Extra | 
					
						
							|  |  |  |     def is_odd(self): | 
					
						
							|  |  |  |         return (self._value & 1) == 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_even(self): | 
					
						
							|  |  |  |         return (self._value & 1) == 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |     def size_in_bits(self): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         if self._value < 0: | 
					
						
							|  |  |  |             raise ValueError("Conversion only valid for non-negative numbers") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |         if self._value == 0: | 
					
						
							|  |  |  |             return 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bit_size = 0 | 
					
						
							|  |  |  |         tmp = self._value | 
					
						
							|  |  |  |         while tmp: | 
					
						
							|  |  |  |             tmp >>= 1 | 
					
						
							|  |  |  |             bit_size += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return bit_size | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-12 14:55:38 +02:00
										 |  |  |     def is_perfect_square(self): | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         if self._value < 0: | 
					
						
							|  |  |  |             return False | 
					
						
							| 
									
										
										
										
											2014-10-12 14:55:38 +02:00
										 |  |  |         if self._value in (0, 1): | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         x = self._value // 2 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         square_x = x ** 2 | 
					
						
							| 
									
										
										
										
											2014-10-12 14:55:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         while square_x > self._value: | 
					
						
							|  |  |  |             x = (square_x + self._value) // (2 * x) | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             square_x = x ** 2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return self._value == x ** 2 | 
					
						
							| 
									
										
										
										
											2014-10-12 14:55:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |     def fail_if_divisible_by(self, small_prime): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             if (self._value % small_prime._value) == 0: | 
					
						
							|  |  |  |                 raise ValueError("Value is composite") | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             if (self._value % small_prime) == 0: | 
					
						
							|  |  |  |                 raise ValueError("Value is composite") | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |     def multiply_accumulate(self, a, b): | 
					
						
							|  |  |  |         if type(a) == Integer: | 
					
						
							|  |  |  |             a = a._value | 
					
						
							|  |  |  |         if type(b) == Integer: | 
					
						
							|  |  |  |             b = b._value | 
					
						
							|  |  |  |         self._value += a * b | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set(self, source): | 
					
						
							|  |  |  |         if type(source) == Integer: | 
					
						
							|  |  |  |             self._value = source._value | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self._value = source | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |     def inverse(self, modulus): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             modulus = modulus._value | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         if modulus == 0: | 
					
						
							|  |  |  |             raise ZeroDivisionError("Modulus cannot be zero") | 
					
						
							|  |  |  |         if modulus < 0: | 
					
						
							|  |  |  |             raise ValueError("Modulus cannot be negative") | 
					
						
							|  |  |  |         r_p, r_n = self._value, modulus | 
					
						
							|  |  |  |         s_p, s_n = 1, 0 | 
					
						
							|  |  |  |         while r_n > 0: | 
					
						
							|  |  |  |             q = r_p // r_n | 
					
						
							|  |  |  |             r_p, r_n = r_n, r_p - q * r_n | 
					
						
							|  |  |  |             s_p, s_n = s_n, s_p - q * s_n | 
					
						
							|  |  |  |         if r_p != 1: | 
					
						
							|  |  |  |             raise ValueError("No inverse value can be computed" + str(r_p)) | 
					
						
							|  |  |  |         while s_p < 0: | 
					
						
							|  |  |  |             s_p += modulus | 
					
						
							|  |  |  |         return s_p | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def gcd(self, term): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             term = term._value | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         r_p, r_n = abs(self._value), abs(term) | 
					
						
							|  |  |  |         while r_n > 0: | 
					
						
							|  |  |  |             q = r_p // r_n | 
					
						
							|  |  |  |             r_p, r_n = r_n, r_p - q * r_n | 
					
						
							|  |  |  |         return r_p | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |     @staticmethod | 
					
						
							|  |  |  |     def jacobi_symbol(a, n): | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         if isinstance(a, Integer): | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |             a = a._value | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         if isinstance(n, Integer): | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |             n = n._value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (n & 1) == 0: | 
					
						
							|  |  |  |             raise ValueError("n must be even for the Jacobi symbol") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Step 1 | 
					
						
							|  |  |  |         a = a % n | 
					
						
							|  |  |  |         # Step 2 | 
					
						
							|  |  |  |         if a == 1 or n == 1: | 
					
						
							|  |  |  |             return 1 | 
					
						
							|  |  |  |         # Step 3 | 
					
						
							|  |  |  |         if a == 0: | 
					
						
							|  |  |  |             return 0 | 
					
						
							|  |  |  |         # Step 4 | 
					
						
							|  |  |  |         e = 0 | 
					
						
							|  |  |  |         a1 = a | 
					
						
							|  |  |  |         while (a1 & 1) == 0: | 
					
						
							|  |  |  |             a1 >>= 1 | 
					
						
							|  |  |  |             e += 1 | 
					
						
							|  |  |  |         # Step 5 | 
					
						
							|  |  |  |         if (e & 1) == 0: | 
					
						
							|  |  |  |             s = 1 | 
					
						
							|  |  |  |         elif n % 8 in (1, 7): | 
					
						
							|  |  |  |             s = 1 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             s = -1 | 
					
						
							|  |  |  |         # Step 6 | 
					
						
							|  |  |  |         if n % 4 == 3 and a1 % 4 == 3: | 
					
						
							|  |  |  |             s = -s | 
					
						
							|  |  |  |         # Step 7 | 
					
						
							|  |  |  |         n1 = n % a1 | 
					
						
							|  |  |  |         # Step 8 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         return s * Integer.jacobi_symbol(n1, a1) |