| 
									
										
										
										
											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. | 
					
						
							|  |  |  | # =================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 22:03:40 +01:00
										 |  |  | from ._IntegerBase import IntegerBase | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  | from Crypto.Util.number import long_to_bytes, bytes_to_long | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 22:03:40 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | class IntegerNative(IntegerBase): | 
					
						
							| 
									
										
										
										
											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") | 
					
						
							| 
									
										
										
										
											2015-02-03 17:41:30 +01:00
										 |  |  |         try: | 
					
						
							|  |  |  |             self._value = value._value | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             self._value = value | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 12:12:41 +01:00
										 |  |  |     def __hex__(self): | 
					
						
							|  |  |  |         return hex(self._value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 22:03:40 +01:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_bytes(cls, byte_string): | 
					
						
							|  |  |  |         return cls(bytes_to_long(byte_string)) | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Relations | 
					
						
							|  |  |  |     def __eq__(self, term): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         if term is None: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |         return self._value == int(term) | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __ne__(self, term): | 
					
						
							|  |  |  |         return not self.__eq__(term) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __lt__(self, term): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         return self._value < int(term) | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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 | 
					
						
							| 
									
										
										
										
											2018-11-04 11:31:40 +01:00
										 |  |  |     __bool__ = __nonzero__ | 
					
						
							| 
									
										
										
										
											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): | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |         return self.__class__(self._value + int(term)) | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __sub__(self, term): | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |         return self.__class__(self._value - int(term)) | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |     def __mul__(self, factor): | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |         return self.__class__(self._value * int(factor)) | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |     def __floordiv__(self, divisor): | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |         return self.__class__(self._value // int(divisor)) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  |     def __mod__(self, divisor): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         divisor_value = int(divisor) | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         if divisor_value < 0: | 
					
						
							|  |  |  |             raise ValueError("Modulus must be positive") | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |         return self.__class__(self._value % divisor_value) | 
					
						
							| 
									
										
										
										
											2014-07-15 18:32:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-11 08:33:00 +01:00
										 |  |  |     def inplace_pow(self, exponent, modulus=None): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         exp_value = int(exponent) | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |         if exp_value < 0: | 
					
						
							|  |  |  |             raise ValueError("Exponent must not be negative") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         if modulus is not None: | 
					
						
							|  |  |  |             mod_value = int(modulus) | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             if mod_value < 0: | 
					
						
							|  |  |  |                 raise ValueError("Modulus must be positive") | 
					
						
							|  |  |  |             if mod_value == 0: | 
					
						
							|  |  |  |                 raise ZeroDivisionError("Modulus cannot be zero") | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         else: | 
					
						
							|  |  |  |             mod_value = None | 
					
						
							| 
									
										
										
										
											2016-01-11 08:33:00 +01:00
										 |  |  |         self._value = pow(self._value, exp_value, mod_value) | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __pow__(self, exponent, modulus=None): | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |         result = self.__class__(self) | 
					
						
							| 
									
										
										
										
											2016-01-11 08:33:00 +01:00
										 |  |  |         return result.inplace_pow(exponent, modulus) | 
					
						
							| 
									
										
										
										
											2014-09-21 21:28:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-27 22:46:39 +01:00
										 |  |  |     def __abs__(self): | 
					
						
							|  |  |  |         return abs(self._value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 23:49:54 +01:00
										 |  |  |     def sqrt(self, modulus=None): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         value = self._value | 
					
						
							|  |  |  |         if modulus is None: | 
					
						
							|  |  |  |             if value < 0: | 
					
						
							|  |  |  |                 raise ValueError("Square root of negative value") | 
					
						
							|  |  |  |             # http://stackoverflow.com/questions/15390807/integer-square-root-in-python | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             x = value | 
					
						
							|  |  |  |             y = (x + 1) // 2 | 
					
						
							|  |  |  |             while y < x: | 
					
						
							|  |  |  |                 x = y | 
					
						
							|  |  |  |                 y = (x + value // x) // 2 | 
					
						
							|  |  |  |             result = x | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             if modulus <= 0: | 
					
						
							|  |  |  |                 raise ValueError("Modulus must be positive") | 
					
						
							| 
									
										
										
										
											2018-02-16 23:43:06 +01:00
										 |  |  |             result = self._tonelli_shanks(self % modulus, modulus) | 
					
						
							| 
									
										
										
										
											2018-02-14 23:49:54 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return self.__class__(result) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-11 22:33:41 +01:00
										 |  |  |     def __iadd__(self, term): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         self._value += int(term) | 
					
						
							| 
									
										
										
										
											2016-01-11 22:33:41 +01:00
										 |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __isub__(self, term): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         self._value -= int(term) | 
					
						
							| 
									
										
										
										
											2016-01-11 22:33:41 +01:00
										 |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __imul__(self, term): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         self._value *= int(term) | 
					
						
							| 
									
										
										
										
											2016-01-11 22:33:41 +01:00
										 |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __imod__(self, term): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         modulus = int(term) | 
					
						
							| 
									
										
										
										
											2016-01-11 22:33:41 +01:00
										 |  |  |         if modulus == 0: | 
					
						
							|  |  |  |             raise ZeroDivisionError("Division by zero") | 
					
						
							|  |  |  |         if modulus < 0: | 
					
						
							|  |  |  |             raise ValueError("Modulus must be positive") | 
					
						
							|  |  |  |         self._value %= modulus | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     # Boolean/bit operations | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |     def __and__(self, term): | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |         return self.__class__(self._value & int(term)) | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-16 22:05:16 +01:00
										 |  |  |     def __or__(self, term): | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |         return self.__class__(self._value | int(term)) | 
					
						
							| 
									
										
										
										
											2014-11-16 22:05:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |     def __rshift__(self, pos): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |             return self.__class__(self._value >> int(pos)) | 
					
						
							| 
									
										
										
										
											2014-11-25 22:13:59 +01:00
										 |  |  |         except OverflowError: | 
					
						
							| 
									
										
										
										
											2018-01-08 12:01:49 +01:00
										 |  |  |             if self._value >= 0: | 
					
						
							|  |  |  |                 return 0 | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 return -1 | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |     def __irshift__(self, pos): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |             self._value >>= int(pos) | 
					
						
							| 
									
										
										
										
											2014-11-25 22:13:59 +01:00
										 |  |  |         except OverflowError: | 
					
						
							| 
									
										
										
										
											2018-01-08 12:01:49 +01:00
										 |  |  |             if self._value >= 0: | 
					
						
							|  |  |  |                 return 0 | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 return -1 | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |     def __lshift__(self, pos): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |             return self.__class__(self._value << int(pos)) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |         except OverflowError: | 
					
						
							|  |  |  |             raise ValueError("Incorrect shift count") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ilshift__(self, pos): | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |             self._value <<= int(pos) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |         except OverflowError: | 
					
						
							|  |  |  |             raise ValueError("Incorrect shift count") | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |     def get_bit(self, n): | 
					
						
							| 
									
										
										
										
											2018-01-08 11:49:10 +01:00
										 |  |  |         if self._value < 0: | 
					
						
							|  |  |  |             raise ValueError("no bit representation for negative values") | 
					
						
							| 
									
										
										
										
											2014-11-25 22:13:59 +01:00
										 |  |  |         try: | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2018-01-08 11:49:10 +01:00
										 |  |  |                 result = (self._value >> n._value) & 1 | 
					
						
							|  |  |  |                 if n._value < 0: | 
					
						
							|  |  |  |                     raise ValueError("negative bit count") | 
					
						
							| 
									
										
										
										
											2014-11-25 22:13:59 +01:00
										 |  |  |             except AttributeError: | 
					
						
							| 
									
										
										
										
											2018-01-08 11:49:10 +01:00
										 |  |  |                 result = (self._value >> n) & 1 | 
					
						
							|  |  |  |                 if n < 0: | 
					
						
							|  |  |  |                     raise ValueError("negative bit count") | 
					
						
							| 
									
										
										
										
											2014-11-25 22:13:59 +01:00
										 |  |  |         except OverflowError: | 
					
						
							| 
									
										
										
										
											2018-01-08 11:49:10 +01:00
										 |  |  |             result = 0 | 
					
						
							|  |  |  |         return result | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-24 22:49:24 +01:00
										 |  |  |     def size_in_bytes(self): | 
					
						
							|  |  |  |         return (self.size_in_bits() - 1) // 8 + 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         if (self._value % int(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): | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |         self._value += int(a) * int(b) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set(self, source): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         self._value = int(source) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-11 22:55:39 +01:00
										 |  |  |     def inplace_inverse(self, modulus): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         modulus = int(modulus) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |         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 | 
					
						
							| 
									
										
										
										
											2016-01-11 22:55:39 +01:00
										 |  |  |         self._value = s_p | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def inverse(self, modulus): | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |         result = self.__class__(self) | 
					
						
							| 
									
										
										
										
											2016-01-11 22:55:39 +01:00
										 |  |  |         result.inplace_inverse(modulus) | 
					
						
							|  |  |  |         return result | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def gcd(self, term): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         r_p, r_n = abs(self._value), abs(int(term)) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |         while r_n > 0: | 
					
						
							|  |  |  |             q = r_p // r_n | 
					
						
							|  |  |  |             r_p, r_n = r_n, r_p - q * r_n | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |         return self.__class__(r_p) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-27 22:46:39 +01:00
										 |  |  |     def lcm(self, term): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         term = int(term) | 
					
						
							| 
									
										
										
										
											2015-02-27 22:46:39 +01:00
										 |  |  |         if self._value == 0 or term == 0: | 
					
						
							| 
									
										
										
										
											2018-01-13 00:12:03 +01:00
										 |  |  |             return self.__class__(0) | 
					
						
							|  |  |  |         return self.__class__(abs((self._value * term) // self.gcd(term)._value)) | 
					
						
							| 
									
										
										
										
											2015-02-27 22:46:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |     @staticmethod | 
					
						
							|  |  |  |     def jacobi_symbol(a, n): | 
					
						
							| 
									
										
										
										
											2018-01-22 00:37:47 +01:00
										 |  |  |         a = int(a) | 
					
						
							|  |  |  |         n = int(n) | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-10 12:58:41 +02:00
										 |  |  |         if n <= 0: | 
					
						
							|  |  |  |             raise ValueError("n must be a positive integer") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |         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 | 
					
						
							| 
									
										
										
										
											2018-11-08 22:03:40 +01:00
										 |  |  |         return s * IntegerNative.jacobi_symbol(n1, a1) |