| 
									
										
										
										
											2014-09-09 07:55:20 +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. | 
					
						
							|  |  |  | # =================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-01 21:18:05 +01:00
										 |  |  | from Crypto.Util.py3compat import tobytes, b, bchr | 
					
						
							| 
									
										
										
										
											2014-09-09 07:55:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-01 21:18:05 +01:00
										 |  |  | from Crypto.Util._raw_api import (load_lib, | 
					
						
							|  |  |  |                                   get_raw_buffer, get_c_string, | 
					
						
							|  |  |  |                                   null_pointer, create_string_buffer, | 
					
						
							|  |  |  |                                   c_ulong, c_size_t) | 
					
						
							| 
									
										
										
										
											2014-09-21 22:07:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-09 12:19:52 +01:00
										 |  |  | gmp_defs = """
 | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         typedef struct { int a; int b; void *c; } MPZ; | 
					
						
							|  |  |  |         typedef MPZ mpz_t[1]; | 
					
						
							|  |  |  |         typedef unsigned long        mp_bitcnt_t; | 
					
						
							|  |  |  |         void __gmpz_init_set (mpz_t rop, const mpz_t op); | 
					
						
							|  |  |  |         void __gmpz_init_set_ui (mpz_t rop, unsigned long op); | 
					
						
							|  |  |  |         int __gmpz_init_set_str (mpz_t rop, const char *str, int base); | 
					
						
							|  |  |  |         void __gmpz_set (mpz_t rop, const mpz_t op); | 
					
						
							|  |  |  |         int __gmpz_set_str (mpz_t rop, const char *str, int base); | 
					
						
							|  |  |  |         int __gmp_snprintf (char *buf, size_t size, const char *fmt, ...); | 
					
						
							|  |  |  |         void __gmpz_add (mpz_t rop, const mpz_t op1, const mpz_t op2); | 
					
						
							|  |  |  |         void __gmpz_add_ui (mpz_t rop, const mpz_t op1, unsigned long op2); | 
					
						
							|  |  |  |         void __gmpz_sub_ui (mpz_t rop, const mpz_t op1, unsigned long op2); | 
					
						
							|  |  |  |         void __gmpz_addmul (mpz_t rop, const mpz_t op1, const mpz_t op2); | 
					
						
							|  |  |  |         void __gmpz_addmul_ui (mpz_t rop, const mpz_t op1, unsigned long op2); | 
					
						
							|  |  |  |         void __gmpz_submul_ui (mpz_t rop, const mpz_t op1, unsigned long op2); | 
					
						
							|  |  |  |         void __gmpz_import (mpz_t rop, size_t count, int order, size_t size, | 
					
						
							|  |  |  |                             int endian, size_t nails, const void *op); | 
					
						
							| 
									
										
										
										
											2015-02-01 21:18:05 +01:00
										 |  |  |         void * __gmpz_export (void *rop, size_t *countp, int order, | 
					
						
							|  |  |  |                               size_t size, | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |                               int endian, size_t nails, const mpz_t op); | 
					
						
							|  |  |  |         size_t __gmpz_sizeinbase (const mpz_t op, int base); | 
					
						
							|  |  |  |         void __gmpz_sub (mpz_t rop, const mpz_t op1, const mpz_t op2); | 
					
						
							|  |  |  |         void __gmpz_mul (mpz_t rop, const mpz_t op1, const mpz_t op2); | 
					
						
							| 
									
										
										
										
											2015-01-15 19:11:51 +00:00
										 |  |  |         void __gmpz_mul_ui (mpz_t rop, const mpz_t op1, unsigned long op2); | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         int __gmpz_cmp (const mpz_t op1, const mpz_t op2); | 
					
						
							|  |  |  |         void __gmpz_powm (mpz_t rop, const mpz_t base, const mpz_t exp, const | 
					
						
							|  |  |  |                           mpz_t mod); | 
					
						
							|  |  |  |         void __gmpz_powm_ui (mpz_t rop, const mpz_t base, unsigned long exp, | 
					
						
							|  |  |  |                              const mpz_t mod); | 
					
						
							|  |  |  |         void __gmpz_pow_ui (mpz_t rop, const mpz_t base, unsigned long exp); | 
					
						
							|  |  |  |         void __gmpz_mod (mpz_t r, const mpz_t n, const mpz_t d); | 
					
						
							|  |  |  |         void __gmpz_neg (mpz_t rop, const mpz_t op); | 
					
						
							|  |  |  |         void __gmpz_and (mpz_t rop, const mpz_t op1, const mpz_t op2); | 
					
						
							|  |  |  |         void __gmpz_ior (mpz_t rop, const mpz_t op1, const mpz_t op2); | 
					
						
							|  |  |  |         void __gmpz_clear (mpz_t x); | 
					
						
							|  |  |  |         void __gmpz_tdiv_q_2exp (mpz_t q, const mpz_t n, mp_bitcnt_t b); | 
					
						
							|  |  |  |         void __gmpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d); | 
					
						
							|  |  |  |         void __gmpz_mul_2exp (mpz_t rop, const mpz_t op1, mp_bitcnt_t op2); | 
					
						
							|  |  |  |         int __gmpz_tstbit (const mpz_t op, mp_bitcnt_t bit_index); | 
					
						
							|  |  |  |         int __gmpz_perfect_square_p (const mpz_t op); | 
					
						
							|  |  |  |         int __gmpz_jacobi (const mpz_t a, const mpz_t b); | 
					
						
							|  |  |  |         void __gmpz_gcd (mpz_t rop, const mpz_t op1, const mpz_t op2); | 
					
						
							| 
									
										
										
										
											2015-02-01 21:18:05 +01:00
										 |  |  |         unsigned long __gmpz_gcd_ui (mpz_t rop, const mpz_t op1, | 
					
						
							|  |  |  |                                      unsigned long op2); | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         int __gmpz_invert (mpz_t rop, const mpz_t op1, const mpz_t op2); | 
					
						
							|  |  |  |         int __gmpz_divisible_p (const mpz_t n, const mpz_t d); | 
					
						
							|  |  |  |         int __gmpz_divisible_ui_p (const mpz_t n, unsigned long d); | 
					
						
							| 
									
										
										
										
											2015-02-09 12:19:52 +01:00
										 |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  |     lib = load_lib("gmp", gmp_defs) | 
					
						
							|  |  |  | except OSError: | 
					
						
							|  |  |  |     lib = load_lib("mpir", gmp_defs) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-01 21:18:05 +01:00
										 |  |  | # In order to create a function that returns a pointer to | 
					
						
							|  |  |  | # a new MPZ structure, we need to break the abstraction | 
					
						
							|  |  |  | # and know exactly what ffi backend we have | 
					
						
							|  |  |  | from ctypes import c_ulong as _c_ulong | 
					
						
							|  |  |  | if c_ulong is _c_ulong: | 
					
						
							|  |  |  |     # We are using ctypes | 
					
						
							|  |  |  |     from ctypes import Structure, c_int, c_void_p, byref | 
					
						
							| 
									
										
										
										
											2014-09-09 07:55:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |     class _MPZ(Structure): | 
					
						
							|  |  |  |         _fields_ = [('_mp_alloc', c_int), | 
					
						
							|  |  |  |                     ('_mp_size', c_int), | 
					
						
							|  |  |  |                     ('_mp_d', c_void_p)] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def new_mpz(): | 
					
						
							|  |  |  |         return byref(_MPZ()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-01 21:18:05 +01:00
										 |  |  | else: | 
					
						
							|  |  |  |     # We are using CFFI | 
					
						
							|  |  |  |     from Crypto.Util._raw_api import ffi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def new_mpz(): | 
					
						
							|  |  |  |         return ffi.new("MPZ*") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | # Unfortunately, all symbols exported by the GMP library start with "__" | 
					
						
							|  |  |  | # and have no trailing underscore. | 
					
						
							|  |  |  | # You cannot directly refer to them as members of the ctypes' library | 
					
						
							|  |  |  | # object from within any class because Python will replace the double | 
					
						
							|  |  |  | # underscore with "_classname_". | 
					
						
							| 
									
										
										
										
											2015-02-01 21:18:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _GMP(object): | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | _gmp = _GMP() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | _gmp = _GMP() | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  | _gmp.mpz_init_set = lib.__gmpz_init_set | 
					
						
							|  |  |  | _gmp.mpz_init_set_ui = lib.__gmpz_init_set_ui | 
					
						
							|  |  |  | _gmp.mpz_init_set_str = lib.__gmpz_init_set_str | 
					
						
							|  |  |  | _gmp.mpz_set = lib.__gmpz_set | 
					
						
							|  |  |  | _gmp.mpz_set_str = lib.__gmpz_set_str | 
					
						
							|  |  |  | _gmp.gmp_snprintf = lib.__gmp_snprintf | 
					
						
							|  |  |  | _gmp.mpz_add = lib.__gmpz_add | 
					
						
							|  |  |  | _gmp.mpz_add_ui = lib.__gmpz_add_ui | 
					
						
							|  |  |  | _gmp.mpz_sub_ui = lib.__gmpz_sub_ui | 
					
						
							|  |  |  | _gmp.mpz_addmul = lib.__gmpz_addmul | 
					
						
							|  |  |  | _gmp.mpz_addmul_ui = lib.__gmpz_addmul_ui | 
					
						
							|  |  |  | _gmp.mpz_submul_ui = lib.__gmpz_submul_ui | 
					
						
							|  |  |  | _gmp.mpz_import = lib.__gmpz_import | 
					
						
							|  |  |  | _gmp.mpz_export = lib.__gmpz_export | 
					
						
							|  |  |  | _gmp.mpz_sizeinbase = lib.__gmpz_sizeinbase | 
					
						
							|  |  |  | _gmp.mpz_sub = lib.__gmpz_sub | 
					
						
							|  |  |  | _gmp.mpz_mul = lib.__gmpz_mul | 
					
						
							| 
									
										
										
										
											2015-01-09 22:35:11 +01:00
										 |  |  | _gmp.mpz_mul_ui = lib.__gmpz_mul_ui | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  | _gmp.mpz_cmp = lib.__gmpz_cmp | 
					
						
							|  |  |  | _gmp.mpz_powm = lib.__gmpz_powm | 
					
						
							|  |  |  | _gmp.mpz_powm_ui = lib.__gmpz_powm_ui | 
					
						
							|  |  |  | _gmp.mpz_pow_ui = lib.__gmpz_pow_ui | 
					
						
							|  |  |  | _gmp.mpz_mod = lib.__gmpz_mod | 
					
						
							|  |  |  | _gmp.mpz_neg = lib.__gmpz_neg | 
					
						
							|  |  |  | _gmp.mpz_and = lib.__gmpz_and | 
					
						
							|  |  |  | _gmp.mpz_ior = lib.__gmpz_ior | 
					
						
							|  |  |  | _gmp.mpz_clear = lib.__gmpz_clear | 
					
						
							|  |  |  | _gmp.mpz_tdiv_q_2exp = lib.__gmpz_tdiv_q_2exp | 
					
						
							|  |  |  | _gmp.mpz_fdiv_q = lib.__gmpz_fdiv_q | 
					
						
							|  |  |  | _gmp.mpz_mul_2exp = lib.__gmpz_mul_2exp | 
					
						
							|  |  |  | _gmp.mpz_tstbit = lib.__gmpz_tstbit | 
					
						
							|  |  |  | _gmp.mpz_perfect_square_p = lib.__gmpz_perfect_square_p | 
					
						
							|  |  |  | _gmp.mpz_jacobi = lib.__gmpz_jacobi | 
					
						
							|  |  |  | _gmp.mpz_gcd = lib.__gmpz_gcd | 
					
						
							|  |  |  | _gmp.mpz_gcd_ui = lib.__gmpz_gcd_ui | 
					
						
							|  |  |  | _gmp.mpz_invert = lib.__gmpz_invert | 
					
						
							|  |  |  | _gmp.mpz_divisible_p = lib.__gmpz_divisible_p | 
					
						
							|  |  |  | _gmp.mpz_divisible_ui_p = lib.__gmpz_divisible_ui_p | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  | class Integer(object): | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |     _zero_mpz_p = new_mpz() | 
					
						
							|  |  |  |     _gmp.mpz_init_set_ui(_zero_mpz_p, c_ulong(0)) | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         self._mpz_p = new_mpz() | 
					
						
							| 
									
										
										
										
											2015-01-15 19:12:25 +00:00
										 |  |  |         self._initialized = False | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if isinstance(value, float): | 
					
						
							|  |  |  |             raise ValueError("A floating point type is not a natural number") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         if isinstance(value, (int, long)): | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |             if 0 <= value < 65536: | 
					
						
							|  |  |  |                 _gmp.mpz_init_set_ui(self._mpz_p, c_ulong(value)) | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |                 if _gmp.mpz_init_set_str(self._mpz_p, | 
					
						
							|  |  |  |                                          tobytes(str(abs(value))), | 
					
						
							|  |  |  |                                          10) != 0: | 
					
						
							|  |  |  |                     _gmp.mpz_clear(self._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  |                     raise ValueError("Error converting '%d'" % value) | 
					
						
							|  |  |  |                 if value < 0: | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |                     _gmp.mpz_neg(self._mpz_p, self._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |             _gmp.mpz_init_set(self._mpz_p, value._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-15 19:12:25 +00:00
										 |  |  |         self._initialized = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     # Conversions | 
					
						
							|  |  |  |     def __int__(self): | 
					
						
							| 
									
										
										
										
											2014-10-12 18:54:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         # buf will contain the integer encoded in decimal plus the trailing | 
					
						
							|  |  |  |         # zero, and possibly the negative sign. | 
					
						
							|  |  |  |         # dig10(x) < log10(x) + 1 = log2(x)/log2(10) + 1 < log2(x)/3 + 1 | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         buf_len = _gmp.mpz_sizeinbase(self._mpz_p, 2) // 3 + 3 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         buf = create_string_buffer(buf_len) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.gmp_snprintf(buf, c_size_t(buf_len), b("%Zd"), self._mpz_p) | 
					
						
							|  |  |  |         return int(get_c_string(buf)) | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return str(int(self)) | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return "Integer(%s)" % str(self) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  |     def to_bytes(self, block_size=0): | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         """Convert the number into a byte string.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This method encodes the number in network order and prepends | 
					
						
							|  |  |  |         as many zero bytes as required. It only works for non-negative | 
					
						
							|  |  |  |         values. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :Parameters: | 
					
						
							|  |  |  |           block_size : integer | 
					
						
							|  |  |  |             The exact size the output byte string must have. | 
					
						
							|  |  |  |             If zero, the string has the minimal length. | 
					
						
							|  |  |  |         :Returns: | 
					
						
							|  |  |  |           A byte string. | 
					
						
							|  |  |  |         :Raises: | 
					
						
							|  |  |  |           ``ValueError`` if the value is negative or if ``block_size`` is | 
					
						
							|  |  |  |           provided and the length of the byte string would exceed it. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         if self < 0: | 
					
						
							|  |  |  |             raise ValueError("Conversion only valid for non-negative numbers") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         buf_len = (_gmp.mpz_sizeinbase(self._mpz_p, 2) + 7) // 8 | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  |         if buf_len > block_size > 0: | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |             raise ValueError("Number is too big to convert to byte string" | 
					
						
							|  |  |  |                              "of prescribed length") | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  |         buf = create_string_buffer(buf_len) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         _gmp.mpz_export( | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |                 buf, | 
					
						
							|  |  |  |                 null_pointer,  # Ignore countp | 
					
						
							|  |  |  |                 1,             # Big endian | 
					
						
							|  |  |  |                 c_size_t(1),   # Each word is 1 byte long | 
					
						
							|  |  |  |                 0,             # Endianess within a word - not relevant | 
					
						
							|  |  |  |                 c_size_t(0),   # No nails | 
					
						
							|  |  |  |                 self._mpz_p) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return bchr(0) * max(0, block_size - buf_len) + get_raw_buffer(buf) | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def from_bytes(byte_string): | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         """Convert a byte string into a number.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :Parameters: | 
					
						
							|  |  |  |           byte_string : byte string | 
					
						
							|  |  |  |             The input number, encoded in network order. | 
					
						
							|  |  |  |             It can only be non-negative. | 
					
						
							|  |  |  |         :Return: | 
					
						
							|  |  |  |           The ``Integer`` object carrying the same value as the input. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         result = Integer(0) | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  |         _gmp.mpz_import( | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |                         result._mpz_p, | 
					
						
							| 
									
										
										
										
											2014-09-19 22:30:15 +02:00
										 |  |  |                         c_size_t(len(byte_string)),  # Amount of words to read | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |                         1,            # Big endian | 
					
						
							| 
									
										
										
										
											2014-09-19 22:30:15 +02:00
										 |  |  |                         c_size_t(1),  # Each word is 1 byte long | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |                         0,            # Endianess within a word - not relevant | 
					
						
							| 
									
										
										
										
											2014-09-19 22:30:15 +02:00
										 |  |  |                         c_size_t(0),  # No nails | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  |                         byte_string) | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     # Relations | 
					
						
							|  |  |  |     def _apply_and_return(self, func, term): | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         if not isinstance(term, Integer): | 
					
						
							|  |  |  |             term = Integer(term) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         return func(self._mpz_p, term._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def __eq__(self, term): | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         if not isinstance(term, (Integer, int, long)): | 
					
						
							|  |  |  |             return False | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         return self._apply_and_return(_gmp.mpz_cmp, term) == 0 | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def __ne__(self, term): | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         if not isinstance(term, (Integer, int, long)): | 
					
						
							|  |  |  |             return True | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         return self._apply_and_return(_gmp.mpz_cmp, term) != 0 | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def __lt__(self, term): | 
					
						
							|  |  |  |         return self._apply_and_return(_gmp.mpz_cmp, term) < 0 | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def __le__(self, term): | 
					
						
							|  |  |  |         return self._apply_and_return(_gmp.mpz_cmp, term) <= 0 | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def __gt__(self, term): | 
					
						
							|  |  |  |         return self._apply_and_return(_gmp.mpz_cmp, term) > 0 | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def __ge__(self, term): | 
					
						
							|  |  |  |         return self._apply_and_return(_gmp.mpz_cmp, term) >= 0 | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def __nonzero__(self): | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         return _gmp.mpz_cmp(self._mpz_p, self._zero_mpz_p) != 0 | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |     def is_negative(self): | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         return _gmp.mpz_cmp(self._mpz_p, self._zero_mpz_p) < 0 | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     # Arithmetic operations | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |     def __add__(self, term): | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         result = Integer(0) | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         if not isinstance(term, Integer): | 
					
						
							|  |  |  |             term = Integer(term) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_add(result._mpz_p, | 
					
						
							|  |  |  |                      self._mpz_p, | 
					
						
							|  |  |  |                      term._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def __sub__(self, term): | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         result = Integer(0) | 
					
						
							|  |  |  |         if not isinstance(term, Integer): | 
					
						
							|  |  |  |             term = Integer(term) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_sub(result._mpz_p, | 
					
						
							|  |  |  |                      self._mpz_p, | 
					
						
							|  |  |  |                      term._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         return result | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def __mul__(self, term): | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         result = Integer(0) | 
					
						
							|  |  |  |         if not isinstance(term, Integer): | 
					
						
							|  |  |  |             term = Integer(term) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_mul(result._mpz_p, | 
					
						
							|  |  |  |                      self._mpz_p, | 
					
						
							|  |  |  |                      term._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         return result | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |     def __floordiv__(self, divisor): | 
					
						
							|  |  |  |         if not isinstance(divisor, Integer): | 
					
						
							|  |  |  |             divisor = Integer(divisor) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         if _gmp.mpz_cmp(divisor._mpz_p, | 
					
						
							|  |  |  |                         self._zero_mpz_p) == 0: | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |             raise ZeroDivisionError("Division by zero") | 
					
						
							|  |  |  |         result = Integer(0) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_fdiv_q(result._mpz_p, | 
					
						
							|  |  |  |                         self._mpz_p, | 
					
						
							|  |  |  |                         divisor._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def __mod__(self, divisor): | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         if not isinstance(divisor, Integer): | 
					
						
							|  |  |  |             divisor = Integer(divisor) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         comp = _gmp.mpz_cmp(divisor._mpz_p, | 
					
						
							|  |  |  |                             self._zero_mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         if comp == 0: | 
					
						
							|  |  |  |             raise ZeroDivisionError("Division by zero") | 
					
						
							|  |  |  |         if comp < 0: | 
					
						
							|  |  |  |             raise ValueError("Modulus must be positive") | 
					
						
							|  |  |  |         result = Integer(0) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_mod(result._mpz_p, | 
					
						
							|  |  |  |                      self._mpz_p, | 
					
						
							|  |  |  |                      divisor._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         return result | 
					
						
							| 
									
										
										
										
											2014-09-21 21:28:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def __pow__(self, exponent, modulus=None): | 
					
						
							| 
									
										
										
										
											2014-09-21 21:28:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |         result = Integer(0) | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         if modulus is None: | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |             if exponent < 0: | 
					
						
							|  |  |  |                 raise ValueError("Exponent must not be negative") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             # Normal exponentiation | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |             result = Integer(0) | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             if exponent > 256: | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |                 raise ValueError("Exponent is too big") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |             _gmp.mpz_pow_ui(result._mpz_p, | 
					
						
							|  |  |  |                             self._mpz_p,   # Base | 
					
						
							|  |  |  |                             c_ulong(int(exponent)) | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |                             ) | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             return result | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |             # Modular exponentiation | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |             if not isinstance(modulus, Integer): | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |                 modulus = Integer(modulus) | 
					
						
							|  |  |  |             if not modulus: | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |                 raise ZeroDivisionError("Division by zero") | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |             if modulus.is_negative(): | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |                 raise ValueError("Modulus must be positive") | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |             if isinstance(exponent, (int, long)): | 
					
						
							|  |  |  |                 if exponent < 0: | 
					
						
							|  |  |  |                     raise ValueError("Exponent must not be negative") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |                 if exponent < 65536: | 
					
						
							|  |  |  |                     _gmp.mpz_powm_ui(result._mpz_p, | 
					
						
							|  |  |  |                                      self._mpz_p, | 
					
						
							|  |  |  |                                      c_ulong(exponent), | 
					
						
							|  |  |  |                                      modulus._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |                     return result | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |                 exponent = Integer(exponent) | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |             elif exponent.is_negative(): | 
					
						
							|  |  |  |                 raise ValueError("Exponent must not be negative") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |             _gmp.mpz_powm(result._mpz_p, | 
					
						
							|  |  |  |                           self._mpz_p, | 
					
						
							|  |  |  |                           exponent._mpz_p, | 
					
						
							|  |  |  |                           modulus._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |             return result | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |     def __iadd__(self, term): | 
					
						
							|  |  |  |         if isinstance(term, (int, long)): | 
					
						
							| 
									
										
										
										
											2015-01-09 22:35:11 +01:00
										 |  |  |             if 0 <= term < 65536: | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |                 _gmp.mpz_add_ui(self._mpz_p, | 
					
						
							|  |  |  |                                 self._mpz_p, | 
					
						
							| 
									
										
										
										
											2015-01-09 22:35:11 +01:00
										 |  |  |                                 c_ulong(term)) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |                 return self | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |             if -65535 < term < 0: | 
					
						
							|  |  |  |                 _gmp.mpz_sub_ui(self._mpz_p, | 
					
						
							|  |  |  |                                 self._mpz_p, | 
					
						
							| 
									
										
										
										
											2015-01-09 22:35:11 +01:00
										 |  |  |                                 c_ulong(-term)) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |                 return self | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |             term = Integer(term) | 
					
						
							|  |  |  |         _gmp.mpz_add(self._mpz_p, | 
					
						
							|  |  |  |                      self._mpz_p, | 
					
						
							|  |  |  |                      term._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __imul__(self, term): | 
					
						
							|  |  |  |         if isinstance(term, (int, long)): | 
					
						
							| 
									
										
										
										
											2015-01-09 22:35:11 +01:00
										 |  |  |             if 0 <= term < 65536: | 
					
						
							|  |  |  |                 _gmp.mpz_mul_ui(self._mpz_p, | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |                                 self._mpz_p, | 
					
						
							| 
									
										
										
										
											2015-01-09 22:35:11 +01:00
										 |  |  |                                 c_ulong(term)) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |                 return self | 
					
						
							| 
									
										
										
										
											2015-01-09 22:35:11 +01:00
										 |  |  |             if -65535 < term < 0: | 
					
						
							|  |  |  |                 _gmp.mpz_mul_ui(self._mpz_p, | 
					
						
							|  |  |  |                                 self._mpz_p, | 
					
						
							|  |  |  |                                 c_ulong(-term)) | 
					
						
							|  |  |  |                 _gmp.mpz_neg(self._mpz_p, self._mpz_p) | 
					
						
							|  |  |  |                 return self | 
					
						
							|  |  |  |             term = Integer(term) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_mul(self._mpz_p, | 
					
						
							|  |  |  |                      self._mpz_p, | 
					
						
							|  |  |  |                      term._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __imod__(self, divisor): | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         if not isinstance(divisor, Integer): | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |             divisor = Integer(divisor) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         comp = _gmp.mpz_cmp(divisor._mpz_p, | 
					
						
							|  |  |  |                             divisor._zero_mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |         if comp == 0: | 
					
						
							|  |  |  |             raise ZeroDivisionError("Division by zero") | 
					
						
							|  |  |  |         if comp < 0: | 
					
						
							|  |  |  |             raise ValueError("Modulus must be positive") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_mod(self._mpz_p, | 
					
						
							|  |  |  |                      self._mpz_p, | 
					
						
							|  |  |  |                      divisor._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |         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): | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         result = Integer(0) | 
					
						
							|  |  |  |         if not isinstance(term, Integer): | 
					
						
							|  |  |  |             term = Integer(term) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_and(result._mpz_p, | 
					
						
							|  |  |  |                      self._mpz_p, | 
					
						
							|  |  |  |                      term._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         return result | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-16 22:05:16 +01:00
										 |  |  |     def __or__(self, term): | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         result = Integer(0) | 
					
						
							|  |  |  |         if not isinstance(term, Integer): | 
					
						
							|  |  |  |             term = Integer(term) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_ior(result._mpz_p, | 
					
						
							|  |  |  |                      self._mpz_p, | 
					
						
							|  |  |  |                      term._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         return result | 
					
						
							| 
									
										
										
										
											2014-11-16 22:05:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |     def __rshift__(self, pos): | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         result = Integer(0) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         if not 0 <= pos < 65536: | 
					
						
							| 
									
										
										
										
											2014-11-25 22:13:59 +01:00
										 |  |  |             raise ValueError("Incorrect shift count") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_tdiv_q_2exp(result._mpz_p, | 
					
						
							|  |  |  |                              self._mpz_p, | 
					
						
							| 
									
										
										
										
											2015-01-09 22:46:21 +01:00
										 |  |  |                              c_ulong(int(pos))) | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |     def __irshift__(self, pos): | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         if not 0 <= pos < 65536: | 
					
						
							| 
									
										
										
										
											2014-11-25 22:13:59 +01:00
										 |  |  |             raise ValueError("Incorrect shift count") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_tdiv_q_2exp(self._mpz_p, | 
					
						
							|  |  |  |                              self._mpz_p, | 
					
						
							| 
									
										
										
										
											2015-01-09 22:46:21 +01:00
										 |  |  |                              c_ulong(int(pos))) | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |     def __lshift__(self, pos): | 
					
						
							|  |  |  |         result = Integer(0) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         if not 0 <= pos < 65536: | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |             raise ValueError("Incorrect shift count") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_mul_2exp(result._mpz_p, | 
					
						
							|  |  |  |                           self._mpz_p, | 
					
						
							| 
									
										
										
										
											2015-01-09 22:46:21 +01:00
										 |  |  |                           c_ulong(int(pos))) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __ilshift__(self, pos): | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         if not 0 <= pos < 65536: | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |             raise ValueError("Incorrect shift count") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_mul_2exp(self._mpz_p, | 
					
						
							|  |  |  |                           self._mpz_p, | 
					
						
							| 
									
										
										
										
											2015-01-09 22:46:21 +01:00
										 |  |  |                           c_ulong(int(pos))) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |     def get_bit(self, n): | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         """Return True if the n-th bit is set to 1.
 | 
					
						
							|  |  |  |         Bit 0 is the least significant."""
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         if not 0 <= n < 65536: | 
					
						
							| 
									
										
										
										
											2014-11-25 22:13:59 +01:00
										 |  |  |             raise ValueError("Incorrect bit position") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         return bool(_gmp.mpz_tstbit(self._mpz_p, | 
					
						
							| 
									
										
										
										
											2015-01-09 22:46:21 +01:00
										 |  |  |                                     c_ulong(int(n)))) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     # Extra | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  |     def is_odd(self): | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         return _gmp.mpz_tstbit(self._mpz_p, 0) == 1 | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def is_even(self): | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         return _gmp.mpz_tstbit(self._mpz_p, 0) == 0 | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     def size_in_bits(self): | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         """Return the minimum number of bits that can encode the number.""" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         if self < 0: | 
					
						
							|  |  |  |             raise ValueError("Conversion only valid for non-negative numbers") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         return _gmp.mpz_sizeinbase(self._mpz_p, 2) | 
					
						
							| 
									
										
										
										
											2014-10-05 18:53:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-12 14:55:38 +02:00
										 |  |  |     def is_perfect_square(self): | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         return _gmp.mpz_perfect_square_p(self._mpz_p) != 0 | 
					
						
							| 
									
										
										
										
											2014-10-12 14:55:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |     def fail_if_divisible_by(self, small_prime): | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         """Raise an exception if the small prime is a divisor.""" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |         if isinstance(small_prime, (int, long)): | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |             if 0 < small_prime < 65536: | 
					
						
							|  |  |  |                 if _gmp.mpz_divisible_ui_p(self._mpz_p, | 
					
						
							|  |  |  |                                            c_ulong(small_prime)): | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |                     raise ValueError("The value is composite") | 
					
						
							| 
									
										
										
										
											2014-11-26 12:06:39 +01:00
										 |  |  |                 return | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |             small_prime = Integer(small_prime) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         if _gmp.mpz_divisible_p(self._mpz_p, | 
					
						
							|  |  |  |                                 small_prime._mpz_p): | 
					
						
							| 
									
										
										
										
											2014-11-29 21:58:49 +01:00
										 |  |  |             raise ValueError("The value is composite") | 
					
						
							| 
									
										
										
										
											2014-11-19 20:54:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |     def multiply_accumulate(self, a, b): | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         """Increment the number by the product of a and b.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if not isinstance(a, Integer): | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |             a = Integer(a) | 
					
						
							|  |  |  |         if isinstance(b, (int, long)): | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |             if 0 < b < 65536: | 
					
						
							|  |  |  |                 _gmp.mpz_addmul_ui(self._mpz_p, | 
					
						
							|  |  |  |                                    a._mpz_p, | 
					
						
							|  |  |  |                                    c_ulong(b)) | 
					
						
							|  |  |  |                 return self | 
					
						
							|  |  |  |             if -65535 < b < 0: | 
					
						
							|  |  |  |                 _gmp.mpz_submul_ui(self._mpz_p, | 
					
						
							|  |  |  |                                    a._mpz_p, | 
					
						
							|  |  |  |                                    c_ulong(-b)) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |                 return self | 
					
						
							|  |  |  |             b = Integer(b) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_addmul(self._mpz_p, | 
					
						
							|  |  |  |                         a._mpz_p, | 
					
						
							|  |  |  |                         b._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set(self, source): | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         if not isinstance(source, Integer): | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |             source = Integer(source) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_set(self._mpz_p, | 
					
						
							|  |  |  |                      source._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-22 18:43:24 +01:00
										 |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |     def inverse(self, modulus): | 
					
						
							|  |  |  |         """Compute the inverse of this number in the ring of
 | 
					
						
							|  |  |  |         modulo integers. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Raise an exception if no inverse exists. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if not isinstance(modulus, Integer): | 
					
						
							|  |  |  |             modulus = Integer(modulus) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         comp = _gmp.mpz_cmp(modulus._mpz_p, | 
					
						
							|  |  |  |                             self._zero_mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |         if comp == 0: | 
					
						
							|  |  |  |             raise ZeroDivisionError("Modulus cannot be zero") | 
					
						
							|  |  |  |         if comp < 0: | 
					
						
							|  |  |  |             raise ValueError("Modulus must be positive") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |         result = Integer(0) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_invert(result._mpz_p, | 
					
						
							|  |  |  |                         self._mpz_p, | 
					
						
							|  |  |  |                         modulus._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |         if not result: | 
					
						
							|  |  |  |             raise ValueError("No inverse value can be computed") | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def gcd(self, term): | 
					
						
							|  |  |  |         """Compute the greatest common denominator between this
 | 
					
						
							|  |  |  |         number and another term."""
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         result = Integer(0) | 
					
						
							|  |  |  |         if isinstance(term, (int, long)): | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |             if 0 < term < 65535: | 
					
						
							|  |  |  |                 _gmp.mpz_gcd_ui(result._mpz_p, | 
					
						
							|  |  |  |                                 self._mpz_p, | 
					
						
							|  |  |  |                                 c_ulong(term)) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |                 return result | 
					
						
							|  |  |  |             term = Integer(term) | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         _gmp.mpz_gcd(result._mpz_p, self._mpz_p, term._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-11-28 10:06:03 -05:00
										 |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |     @staticmethod | 
					
						
							|  |  |  |     def jacobi_symbol(a, n): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |         if not isinstance(a, Integer): | 
					
						
							|  |  |  |             a = Integer(a) | 
					
						
							|  |  |  |         if not isinstance(n, Integer): | 
					
						
							|  |  |  |             n = Integer(n) | 
					
						
							|  |  |  |         if n <= 0 or n.is_even(): | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  |             raise ValueError("n must be positive even for the Jacobi symbol") | 
					
						
							| 
									
										
										
										
											2015-01-06 22:00:34 +01:00
										 |  |  |         return _gmp.mpz_jacobi(a._mpz_p, n._mpz_p) | 
					
						
							| 
									
										
										
										
											2014-10-12 21:45:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-05 22:07:14 +01:00
										 |  |  |     # Clean-up | 
					
						
							| 
									
										
										
										
											2014-09-10 07:47:08 +02:00
										 |  |  |     def __del__(self): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |         try: | 
					
						
							|  |  |  |             if self._mpz_p is not None: | 
					
						
							| 
									
										
										
										
											2015-01-15 19:12:25 +00:00
										 |  |  |                 if self._initialized: | 
					
						
							|  |  |  |                     _gmp.mpz_clear(self._mpz_p) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-27 20:45:23 +01:00
										 |  |  |             self._mpz_p = None | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             pass |