_IntegerGMP.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. # ===================================================================
  2. #
  3. # Copyright (c) 2014, Legrandin <helderijs@gmail.com>
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions
  8. # are met:
  9. #
  10. # 1. Redistributions of source code must retain the above copyright
  11. # notice, this list of conditions and the following disclaimer.
  12. # 2. Redistributions in binary form must reproduce the above copyright
  13. # notice, this list of conditions and the following disclaimer in
  14. # the documentation and/or other materials provided with the
  15. # distribution.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25. # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  27. # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. # POSSIBILITY OF SUCH DAMAGE.
  29. # ===================================================================
  30. import sys
  31. from Crypto.Util.py3compat import tobytes, is_native_int
  32. from Crypto.Util._raw_api import (backend, load_lib,
  33. get_raw_buffer, get_c_string,
  34. null_pointer, create_string_buffer,
  35. c_ulong, c_size_t)
  36. from ._IntegerBase import IntegerBase
  37. gmp_defs = """typedef unsigned long UNIX_ULONG;
  38. typedef struct { int a; int b; void *c; } MPZ;
  39. typedef MPZ mpz_t[1];
  40. typedef UNIX_ULONG mp_bitcnt_t;
  41. void __gmpz_init (mpz_t x);
  42. void __gmpz_init_set (mpz_t rop, const mpz_t op);
  43. void __gmpz_init_set_ui (mpz_t rop, UNIX_ULONG op);
  44. int __gmp_sscanf (const char *s, const char *fmt, ...);
  45. void __gmpz_set (mpz_t rop, const mpz_t op);
  46. int __gmp_snprintf (uint8_t *buf, size_t size, const char *fmt, ...);
  47. void __gmpz_add (mpz_t rop, const mpz_t op1, const mpz_t op2);
  48. void __gmpz_add_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2);
  49. void __gmpz_sub_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2);
  50. void __gmpz_addmul (mpz_t rop, const mpz_t op1, const mpz_t op2);
  51. void __gmpz_addmul_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2);
  52. void __gmpz_submul_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2);
  53. void __gmpz_import (mpz_t rop, size_t count, int order, size_t size,
  54. int endian, size_t nails, const void *op);
  55. void * __gmpz_export (void *rop, size_t *countp, int order,
  56. size_t size,
  57. int endian, size_t nails, const mpz_t op);
  58. size_t __gmpz_sizeinbase (const mpz_t op, int base);
  59. void __gmpz_sub (mpz_t rop, const mpz_t op1, const mpz_t op2);
  60. void __gmpz_mul (mpz_t rop, const mpz_t op1, const mpz_t op2);
  61. void __gmpz_mul_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2);
  62. int __gmpz_cmp (const mpz_t op1, const mpz_t op2);
  63. void __gmpz_powm (mpz_t rop, const mpz_t base, const mpz_t exp, const
  64. mpz_t mod);
  65. void __gmpz_powm_ui (mpz_t rop, const mpz_t base, UNIX_ULONG exp,
  66. const mpz_t mod);
  67. void __gmpz_pow_ui (mpz_t rop, const mpz_t base, UNIX_ULONG exp);
  68. void __gmpz_sqrt(mpz_t rop, const mpz_t op);
  69. void __gmpz_mod (mpz_t r, const mpz_t n, const mpz_t d);
  70. void __gmpz_neg (mpz_t rop, const mpz_t op);
  71. void __gmpz_abs (mpz_t rop, const mpz_t op);
  72. void __gmpz_and (mpz_t rop, const mpz_t op1, const mpz_t op2);
  73. void __gmpz_ior (mpz_t rop, const mpz_t op1, const mpz_t op2);
  74. void __gmpz_clear (mpz_t x);
  75. void __gmpz_tdiv_q_2exp (mpz_t q, const mpz_t n, mp_bitcnt_t b);
  76. void __gmpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d);
  77. void __gmpz_mul_2exp (mpz_t rop, const mpz_t op1, mp_bitcnt_t op2);
  78. int __gmpz_tstbit (const mpz_t op, mp_bitcnt_t bit_index);
  79. int __gmpz_perfect_square_p (const mpz_t op);
  80. int __gmpz_jacobi (const mpz_t a, const mpz_t b);
  81. void __gmpz_gcd (mpz_t rop, const mpz_t op1, const mpz_t op2);
  82. UNIX_ULONG __gmpz_gcd_ui (mpz_t rop, const mpz_t op1,
  83. UNIX_ULONG op2);
  84. void __gmpz_lcm (mpz_t rop, const mpz_t op1, const mpz_t op2);
  85. int __gmpz_invert (mpz_t rop, const mpz_t op1, const mpz_t op2);
  86. int __gmpz_divisible_p (const mpz_t n, const mpz_t d);
  87. int __gmpz_divisible_ui_p (const mpz_t n, UNIX_ULONG d);
  88. """
  89. if sys.platform == "win32":
  90. raise ImportError("Not using GMP on Windows")
  91. lib = load_lib("gmp", gmp_defs)
  92. implementation = {"library": "gmp", "api": backend}
  93. if hasattr(lib, "__mpir_version"):
  94. raise ImportError("MPIR library detected")
  95. # In order to create a function that returns a pointer to
  96. # a new MPZ structure, we need to break the abstraction
  97. # and know exactly what ffi backend we have
  98. if implementation["api"] == "ctypes":
  99. from ctypes import Structure, c_int, c_void_p, byref
  100. class _MPZ(Structure):
  101. _fields_ = [('_mp_alloc', c_int),
  102. ('_mp_size', c_int),
  103. ('_mp_d', c_void_p)]
  104. def new_mpz():
  105. return byref(_MPZ())
  106. else:
  107. # We are using CFFI
  108. from Crypto.Util._raw_api import ffi
  109. def new_mpz():
  110. return ffi.new("MPZ*")
  111. # Lazy creation of GMP methods
  112. class _GMP(object):
  113. def __getattr__(self, name):
  114. if name.startswith("mpz_"):
  115. func_name = "__gmpz_" + name[4:]
  116. elif name.startswith("gmp_"):
  117. func_name = "__gmp_" + name[4:]
  118. else:
  119. raise AttributeError("Attribute %s is invalid" % name)
  120. func = getattr(lib, func_name)
  121. setattr(self, name, func)
  122. return func
  123. _gmp = _GMP()
  124. class IntegerGMP(IntegerBase):
  125. """A fast, arbitrary precision integer"""
  126. _zero_mpz_p = new_mpz()
  127. _gmp.mpz_init_set_ui(_zero_mpz_p, c_ulong(0))
  128. def __init__(self, value):
  129. """Initialize the integer to the given value."""
  130. self._mpz_p = new_mpz()
  131. self._initialized = False
  132. if isinstance(value, float):
  133. raise ValueError("A floating point type is not a natural number")
  134. self._initialized = True
  135. if is_native_int(value):
  136. _gmp.mpz_init(self._mpz_p)
  137. result = _gmp.gmp_sscanf(tobytes(str(value)), b"%Zd", self._mpz_p)
  138. if result != 1:
  139. raise ValueError("Error converting '%d'" % value)
  140. elif isinstance(value, IntegerGMP):
  141. _gmp.mpz_init_set(self._mpz_p, value._mpz_p)
  142. else:
  143. raise NotImplementedError
  144. # Conversions
  145. def __int__(self):
  146. # buf will contain the integer encoded in decimal plus the trailing
  147. # zero, and possibly the negative sign.
  148. # dig10(x) < log10(x) + 1 = log2(x)/log2(10) + 1 < log2(x)/3 + 1
  149. buf_len = _gmp.mpz_sizeinbase(self._mpz_p, 2) // 3 + 3
  150. buf = create_string_buffer(buf_len)
  151. _gmp.gmp_snprintf(buf, c_size_t(buf_len), b"%Zd", self._mpz_p)
  152. return int(get_c_string(buf))
  153. def __str__(self):
  154. return str(int(self))
  155. def __repr__(self):
  156. return "Integer(%s)" % str(self)
  157. # Only Python 2.x
  158. def __hex__(self):
  159. return hex(int(self))
  160. # Only Python 3.x
  161. def __index__(self):
  162. return int(self)
  163. def to_bytes(self, block_size=0):
  164. """Convert the number into a byte string.
  165. This method encodes the number in network order and prepends
  166. as many zero bytes as required. It only works for non-negative
  167. values.
  168. :Parameters:
  169. block_size : integer
  170. The exact size the output byte string must have.
  171. If zero, the string has the minimal length.
  172. :Returns:
  173. A byte string.
  174. :Raise ValueError:
  175. If the value is negative or if ``block_size`` is
  176. provided and the length of the byte string would exceed it.
  177. """
  178. if self < 0:
  179. raise ValueError("Conversion only valid for non-negative numbers")
  180. buf_len = (_gmp.mpz_sizeinbase(self._mpz_p, 2) + 7) // 8
  181. if buf_len > block_size > 0:
  182. raise ValueError("Number is too big to convert to byte string"
  183. "of prescribed length")
  184. buf = create_string_buffer(buf_len)
  185. _gmp.mpz_export(
  186. buf,
  187. null_pointer, # Ignore countp
  188. 1, # Big endian
  189. c_size_t(1), # Each word is 1 byte long
  190. 0, # Endianess within a word - not relevant
  191. c_size_t(0), # No nails
  192. self._mpz_p)
  193. return b'\x00' * max(0, block_size - buf_len) + get_raw_buffer(buf)
  194. @staticmethod
  195. def from_bytes(byte_string):
  196. """Convert a byte string into a number.
  197. :Parameters:
  198. byte_string : byte string
  199. The input number, encoded in network order.
  200. It can only be non-negative.
  201. :Return:
  202. The ``Integer`` object carrying the same value as the input.
  203. """
  204. result = IntegerGMP(0)
  205. _gmp.mpz_import(
  206. result._mpz_p,
  207. c_size_t(len(byte_string)), # Amount of words to read
  208. 1, # Big endian
  209. c_size_t(1), # Each word is 1 byte long
  210. 0, # Endianess within a word - not relevant
  211. c_size_t(0), # No nails
  212. byte_string)
  213. return result
  214. # Relations
  215. def _apply_and_return(self, func, term):
  216. if not isinstance(term, IntegerGMP):
  217. term = IntegerGMP(term)
  218. return func(self._mpz_p, term._mpz_p)
  219. def __eq__(self, term):
  220. if not (isinstance(term, IntegerGMP) or is_native_int(term)):
  221. return False
  222. return self._apply_and_return(_gmp.mpz_cmp, term) == 0
  223. def __ne__(self, term):
  224. if not (isinstance(term, IntegerGMP) or is_native_int(term)):
  225. return True
  226. return self._apply_and_return(_gmp.mpz_cmp, term) != 0
  227. def __lt__(self, term):
  228. return self._apply_and_return(_gmp.mpz_cmp, term) < 0
  229. def __le__(self, term):
  230. return self._apply_and_return(_gmp.mpz_cmp, term) <= 0
  231. def __gt__(self, term):
  232. return self._apply_and_return(_gmp.mpz_cmp, term) > 0
  233. def __ge__(self, term):
  234. return self._apply_and_return(_gmp.mpz_cmp, term) >= 0
  235. def __nonzero__(self):
  236. return _gmp.mpz_cmp(self._mpz_p, self._zero_mpz_p) != 0
  237. __bool__ = __nonzero__
  238. def is_negative(self):
  239. return _gmp.mpz_cmp(self._mpz_p, self._zero_mpz_p) < 0
  240. # Arithmetic operations
  241. def __add__(self, term):
  242. result = IntegerGMP(0)
  243. if not isinstance(term, IntegerGMP):
  244. try:
  245. term = IntegerGMP(term)
  246. except NotImplementedError:
  247. return NotImplemented
  248. _gmp.mpz_add(result._mpz_p,
  249. self._mpz_p,
  250. term._mpz_p)
  251. return result
  252. def __sub__(self, term):
  253. result = IntegerGMP(0)
  254. if not isinstance(term, IntegerGMP):
  255. try:
  256. term = IntegerGMP(term)
  257. except NotImplementedError:
  258. return NotImplemented
  259. _gmp.mpz_sub(result._mpz_p,
  260. self._mpz_p,
  261. term._mpz_p)
  262. return result
  263. def __mul__(self, term):
  264. result = IntegerGMP(0)
  265. if not isinstance(term, IntegerGMP):
  266. try:
  267. term = IntegerGMP(term)
  268. except NotImplementedError:
  269. return NotImplemented
  270. _gmp.mpz_mul(result._mpz_p,
  271. self._mpz_p,
  272. term._mpz_p)
  273. return result
  274. def __floordiv__(self, divisor):
  275. if not isinstance(divisor, IntegerGMP):
  276. divisor = IntegerGMP(divisor)
  277. if _gmp.mpz_cmp(divisor._mpz_p,
  278. self._zero_mpz_p) == 0:
  279. raise ZeroDivisionError("Division by zero")
  280. result = IntegerGMP(0)
  281. _gmp.mpz_fdiv_q(result._mpz_p,
  282. self._mpz_p,
  283. divisor._mpz_p)
  284. return result
  285. def __mod__(self, divisor):
  286. if not isinstance(divisor, IntegerGMP):
  287. divisor = IntegerGMP(divisor)
  288. comp = _gmp.mpz_cmp(divisor._mpz_p,
  289. self._zero_mpz_p)
  290. if comp == 0:
  291. raise ZeroDivisionError("Division by zero")
  292. if comp < 0:
  293. raise ValueError("Modulus must be positive")
  294. result = IntegerGMP(0)
  295. _gmp.mpz_mod(result._mpz_p,
  296. self._mpz_p,
  297. divisor._mpz_p)
  298. return result
  299. def inplace_pow(self, exponent, modulus=None):
  300. if modulus is None:
  301. if exponent < 0:
  302. raise ValueError("Exponent must not be negative")
  303. # Normal exponentiation
  304. if exponent > 256:
  305. raise ValueError("Exponent is too big")
  306. _gmp.mpz_pow_ui(self._mpz_p,
  307. self._mpz_p, # Base
  308. c_ulong(int(exponent))
  309. )
  310. else:
  311. # Modular exponentiation
  312. if not isinstance(modulus, IntegerGMP):
  313. modulus = IntegerGMP(modulus)
  314. if not modulus:
  315. raise ZeroDivisionError("Division by zero")
  316. if modulus.is_negative():
  317. raise ValueError("Modulus must be positive")
  318. if is_native_int(exponent):
  319. if exponent < 0:
  320. raise ValueError("Exponent must not be negative")
  321. if exponent < 65536:
  322. _gmp.mpz_powm_ui(self._mpz_p,
  323. self._mpz_p,
  324. c_ulong(exponent),
  325. modulus._mpz_p)
  326. return self
  327. exponent = IntegerGMP(exponent)
  328. elif exponent.is_negative():
  329. raise ValueError("Exponent must not be negative")
  330. _gmp.mpz_powm(self._mpz_p,
  331. self._mpz_p,
  332. exponent._mpz_p,
  333. modulus._mpz_p)
  334. return self
  335. def __pow__(self, exponent, modulus=None):
  336. result = IntegerGMP(self)
  337. return result.inplace_pow(exponent, modulus)
  338. def __abs__(self):
  339. result = IntegerGMP(0)
  340. _gmp.mpz_abs(result._mpz_p, self._mpz_p)
  341. return result
  342. def sqrt(self, modulus=None):
  343. """Return the largest Integer that does not
  344. exceed the square root"""
  345. if modulus is None:
  346. if self < 0:
  347. raise ValueError("Square root of negative value")
  348. result = IntegerGMP(0)
  349. _gmp.mpz_sqrt(result._mpz_p,
  350. self._mpz_p)
  351. else:
  352. if modulus <= 0:
  353. raise ValueError("Modulus must be positive")
  354. modulus = int(modulus)
  355. result = IntegerGMP(self._tonelli_shanks(int(self) % modulus, modulus))
  356. return result
  357. def __iadd__(self, term):
  358. if is_native_int(term):
  359. if 0 <= term < 65536:
  360. _gmp.mpz_add_ui(self._mpz_p,
  361. self._mpz_p,
  362. c_ulong(term))
  363. return self
  364. if -65535 < term < 0:
  365. _gmp.mpz_sub_ui(self._mpz_p,
  366. self._mpz_p,
  367. c_ulong(-term))
  368. return self
  369. term = IntegerGMP(term)
  370. _gmp.mpz_add(self._mpz_p,
  371. self._mpz_p,
  372. term._mpz_p)
  373. return self
  374. def __isub__(self, term):
  375. if is_native_int(term):
  376. if 0 <= term < 65536:
  377. _gmp.mpz_sub_ui(self._mpz_p,
  378. self._mpz_p,
  379. c_ulong(term))
  380. return self
  381. if -65535 < term < 0:
  382. _gmp.mpz_add_ui(self._mpz_p,
  383. self._mpz_p,
  384. c_ulong(-term))
  385. return self
  386. term = IntegerGMP(term)
  387. _gmp.mpz_sub(self._mpz_p,
  388. self._mpz_p,
  389. term._mpz_p)
  390. return self
  391. def __imul__(self, term):
  392. if is_native_int(term):
  393. if 0 <= term < 65536:
  394. _gmp.mpz_mul_ui(self._mpz_p,
  395. self._mpz_p,
  396. c_ulong(term))
  397. return self
  398. if -65535 < term < 0:
  399. _gmp.mpz_mul_ui(self._mpz_p,
  400. self._mpz_p,
  401. c_ulong(-term))
  402. _gmp.mpz_neg(self._mpz_p, self._mpz_p)
  403. return self
  404. term = IntegerGMP(term)
  405. _gmp.mpz_mul(self._mpz_p,
  406. self._mpz_p,
  407. term._mpz_p)
  408. return self
  409. def __imod__(self, divisor):
  410. if not isinstance(divisor, IntegerGMP):
  411. divisor = IntegerGMP(divisor)
  412. comp = _gmp.mpz_cmp(divisor._mpz_p,
  413. divisor._zero_mpz_p)
  414. if comp == 0:
  415. raise ZeroDivisionError("Division by zero")
  416. if comp < 0:
  417. raise ValueError("Modulus must be positive")
  418. _gmp.mpz_mod(self._mpz_p,
  419. self._mpz_p,
  420. divisor._mpz_p)
  421. return self
  422. # Boolean/bit operations
  423. def __and__(self, term):
  424. result = IntegerGMP(0)
  425. if not isinstance(term, IntegerGMP):
  426. term = IntegerGMP(term)
  427. _gmp.mpz_and(result._mpz_p,
  428. self._mpz_p,
  429. term._mpz_p)
  430. return result
  431. def __or__(self, term):
  432. result = IntegerGMP(0)
  433. if not isinstance(term, IntegerGMP):
  434. term = IntegerGMP(term)
  435. _gmp.mpz_ior(result._mpz_p,
  436. self._mpz_p,
  437. term._mpz_p)
  438. return result
  439. def __rshift__(self, pos):
  440. result = IntegerGMP(0)
  441. if pos < 0:
  442. raise ValueError("negative shift count")
  443. if pos > 65536:
  444. if self < 0:
  445. return -1
  446. else:
  447. return 0
  448. _gmp.mpz_tdiv_q_2exp(result._mpz_p,
  449. self._mpz_p,
  450. c_ulong(int(pos)))
  451. return result
  452. def __irshift__(self, pos):
  453. if pos < 0:
  454. raise ValueError("negative shift count")
  455. if pos > 65536:
  456. if self < 0:
  457. return -1
  458. else:
  459. return 0
  460. _gmp.mpz_tdiv_q_2exp(self._mpz_p,
  461. self._mpz_p,
  462. c_ulong(int(pos)))
  463. return self
  464. def __lshift__(self, pos):
  465. result = IntegerGMP(0)
  466. if not 0 <= pos < 65536:
  467. raise ValueError("Incorrect shift count")
  468. _gmp.mpz_mul_2exp(result._mpz_p,
  469. self._mpz_p,
  470. c_ulong(int(pos)))
  471. return result
  472. def __ilshift__(self, pos):
  473. if not 0 <= pos < 65536:
  474. raise ValueError("Incorrect shift count")
  475. _gmp.mpz_mul_2exp(self._mpz_p,
  476. self._mpz_p,
  477. c_ulong(int(pos)))
  478. return self
  479. def get_bit(self, n):
  480. """Return True if the n-th bit is set to 1.
  481. Bit 0 is the least significant."""
  482. if self < 0:
  483. raise ValueError("no bit representation for negative values")
  484. if n < 0:
  485. raise ValueError("negative bit count")
  486. if n > 65536:
  487. return 0
  488. return bool(_gmp.mpz_tstbit(self._mpz_p,
  489. c_ulong(int(n))))
  490. # Extra
  491. def is_odd(self):
  492. return _gmp.mpz_tstbit(self._mpz_p, 0) == 1
  493. def is_even(self):
  494. return _gmp.mpz_tstbit(self._mpz_p, 0) == 0
  495. def size_in_bits(self):
  496. """Return the minimum number of bits that can encode the number."""
  497. if self < 0:
  498. raise ValueError("Conversion only valid for non-negative numbers")
  499. return _gmp.mpz_sizeinbase(self._mpz_p, 2)
  500. def size_in_bytes(self):
  501. """Return the minimum number of bytes that can encode the number."""
  502. return (self.size_in_bits() - 1) // 8 + 1
  503. def is_perfect_square(self):
  504. return _gmp.mpz_perfect_square_p(self._mpz_p) != 0
  505. def fail_if_divisible_by(self, small_prime):
  506. """Raise an exception if the small prime is a divisor."""
  507. if is_native_int(small_prime):
  508. if 0 < small_prime < 65536:
  509. if _gmp.mpz_divisible_ui_p(self._mpz_p,
  510. c_ulong(small_prime)):
  511. raise ValueError("The value is composite")
  512. return
  513. small_prime = IntegerGMP(small_prime)
  514. if _gmp.mpz_divisible_p(self._mpz_p,
  515. small_prime._mpz_p):
  516. raise ValueError("The value is composite")
  517. def multiply_accumulate(self, a, b):
  518. """Increment the number by the product of a and b."""
  519. if not isinstance(a, IntegerGMP):
  520. a = IntegerGMP(a)
  521. if is_native_int(b):
  522. if 0 < b < 65536:
  523. _gmp.mpz_addmul_ui(self._mpz_p,
  524. a._mpz_p,
  525. c_ulong(b))
  526. return self
  527. if -65535 < b < 0:
  528. _gmp.mpz_submul_ui(self._mpz_p,
  529. a._mpz_p,
  530. c_ulong(-b))
  531. return self
  532. b = IntegerGMP(b)
  533. _gmp.mpz_addmul(self._mpz_p,
  534. a._mpz_p,
  535. b._mpz_p)
  536. return self
  537. def set(self, source):
  538. """Set the Integer to have the given value"""
  539. if not isinstance(source, IntegerGMP):
  540. source = IntegerGMP(source)
  541. _gmp.mpz_set(self._mpz_p,
  542. source._mpz_p)
  543. return self
  544. def inplace_inverse(self, modulus):
  545. """Compute the inverse of this number in the ring of
  546. modulo integers.
  547. Raise an exception if no inverse exists.
  548. """
  549. if not isinstance(modulus, IntegerGMP):
  550. modulus = IntegerGMP(modulus)
  551. comp = _gmp.mpz_cmp(modulus._mpz_p,
  552. self._zero_mpz_p)
  553. if comp == 0:
  554. raise ZeroDivisionError("Modulus cannot be zero")
  555. if comp < 0:
  556. raise ValueError("Modulus must be positive")
  557. result = _gmp.mpz_invert(self._mpz_p,
  558. self._mpz_p,
  559. modulus._mpz_p)
  560. if not result:
  561. raise ValueError("No inverse value can be computed")
  562. return self
  563. def inverse(self, modulus):
  564. result = IntegerGMP(self)
  565. result.inplace_inverse(modulus)
  566. return result
  567. def gcd(self, term):
  568. """Compute the greatest common denominator between this
  569. number and another term."""
  570. result = IntegerGMP(0)
  571. if is_native_int(term):
  572. if 0 < term < 65535:
  573. _gmp.mpz_gcd_ui(result._mpz_p,
  574. self._mpz_p,
  575. c_ulong(term))
  576. return result
  577. term = IntegerGMP(term)
  578. _gmp.mpz_gcd(result._mpz_p, self._mpz_p, term._mpz_p)
  579. return result
  580. def lcm(self, term):
  581. """Compute the least common multiplier between this
  582. number and another term."""
  583. result = IntegerGMP(0)
  584. if not isinstance(term, IntegerGMP):
  585. term = IntegerGMP(term)
  586. _gmp.mpz_lcm(result._mpz_p, self._mpz_p, term._mpz_p)
  587. return result
  588. @staticmethod
  589. def jacobi_symbol(a, n):
  590. """Compute the Jacobi symbol"""
  591. if not isinstance(a, IntegerGMP):
  592. a = IntegerGMP(a)
  593. if not isinstance(n, IntegerGMP):
  594. n = IntegerGMP(n)
  595. if n <= 0 or n.is_even():
  596. raise ValueError("n must be positive even for the Jacobi symbol")
  597. return _gmp.mpz_jacobi(a._mpz_p, n._mpz_p)
  598. # Clean-up
  599. def __del__(self):
  600. try:
  601. if self._mpz_p is not None:
  602. if self._initialized:
  603. _gmp.mpz_clear(self._mpz_p)
  604. self._mpz_p = None
  605. except AttributeError:
  606. pass