Skip to main content

vdf_classgroup/gmp/
mpz.rs

1#![allow(unsafe_code)]
2use super::sign::Sign;
3use libc::{c_char, c_double, c_int, c_long, c_ulong, c_void, size_t, strnlen};
4use num_traits::{One, Zero};
5use std::cmp::Ordering::{self, Equal, Greater, Less};
6use std::convert::From;
7use std::error::Error;
8use std::ffi::CString;
9use std::mem::{size_of, uninitialized};
10use std::ops::{
11    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
12    Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
13};
14use std::str::FromStr;
15use std::{fmt, hash};
16use std::{i32, u32, usize};
17
18use super::ffi::*;
19
20#[repr(C)]
21pub struct mpz_struct {
22    _mp_alloc: c_int,
23    _mp_size: c_int,
24    _mp_d: *mut c_void,
25}
26
27pub type mp_limb_t = usize; // TODO: Find a way to use __gmp_bits_per_limb instead.
28pub type mp_bitcnt_t = c_ulong;
29pub type mpz_srcptr = *const mpz_struct;
30pub type mpz_ptr = *mut mpz_struct;
31
32#[link(name = "gmp")]
33extern "C" {
34    static __gmp_bits_per_limb: c_int;
35    fn __gmpz_init(x: mpz_ptr);
36    fn __gmpz_init2(x: mpz_ptr, n: mp_bitcnt_t);
37    fn __gmpz_init_set(rop: mpz_ptr, op: mpz_srcptr);
38    fn __gmpz_init_set_ui(rop: mpz_ptr, op: c_ulong);
39    fn __gmpz_init_set_str(rop: mpz_ptr, s: *const c_char, base: c_int) -> c_int;
40    fn __gmpz_clear(x: mpz_ptr);
41    fn __gmpz_realloc2(x: mpz_ptr, n: mp_bitcnt_t);
42    fn __gmpz_set(rop: mpz_ptr, op: mpz_srcptr);
43    fn __gmpz_set_str(rop: mpz_ptr, s: *const c_char, base: c_int) -> c_int;
44    fn __gmpz_get_str(s: *mut c_char, base: c_int, op: mpz_srcptr) -> *mut c_char;
45    fn __gmpz_get_ui(op: mpz_srcptr) -> c_ulong;
46    fn __gmpz_fits_ulong_p(op: mpz_srcptr) -> c_int;
47    fn __gmpz_get_si(op: mpz_srcptr) -> c_ulong;
48    fn __gmpz_get_d(op: mpz_srcptr) -> c_double;
49    fn __gmpz_fits_slong_p(op: mpz_srcptr) -> c_long;
50    fn __gmpz_sizeinbase(op: mpz_srcptr, base: c_int) -> size_t;
51    fn __gmpz_cmp(op1: mpz_srcptr, op2: mpz_srcptr) -> c_int;
52    fn __gmpz_cmp_ui(op1: mpz_srcptr, op2: c_ulong) -> c_int;
53    fn __gmpz_add(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
54    fn __gmpz_add_ui(rop: mpz_ptr, op1: mpz_srcptr, op2: c_ulong);
55    fn __gmpz_sub(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
56    fn __gmpz_sub_ui(rop: mpz_ptr, op1: mpz_srcptr, op2: c_ulong);
57    fn __gmpz_ui_sub(rop: mpz_ptr, op1: c_ulong, op2: mpz_srcptr);
58    fn __gmpz_mul(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
59    fn __gmpz_mul_ui(rop: mpz_ptr, op1: mpz_srcptr, op2: c_ulong);
60    fn __gmpz_mul_si(rop: mpz_ptr, op1: mpz_srcptr, op2: c_long);
61    fn __gmpz_mul_2exp(rop: mpz_ptr, op1: mpz_srcptr, op2: mp_bitcnt_t);
62    fn __gmpz_neg(rop: mpz_ptr, op: mpz_srcptr);
63    fn __gmpz_abs(rop: mpz_ptr, op: mpz_srcptr);
64    fn __gmpz_tdiv_q(q: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr);
65    fn __gmpz_tdiv_r(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr);
66    fn __gmpz_tdiv_q_ui(q: mpz_ptr, n: mpz_srcptr, d: c_ulong);
67    fn __gmpz_tdiv_r_ui(r: mpz_ptr, n: mpz_srcptr, d: c_ulong);
68    fn __gmpz_fdiv_r(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr);
69    fn __gmpz_fdiv_q_2exp(q: mpz_ptr, n: mpz_srcptr, b: mp_bitcnt_t);
70    fn __gmpz_mod(r: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr);
71    fn __gmpz_divisible_p(n: mpz_srcptr, d: mpz_srcptr) -> c_int;
72    fn __gmpz_and(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
73    fn __gmpz_ior(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
74    fn __gmpz_xor(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
75    fn __gmpz_com(rop: mpz_ptr, op: mpz_srcptr);
76    fn __gmpz_popcount(op: mpz_srcptr) -> mp_bitcnt_t;
77    fn __gmpz_pow_ui(rop: mpz_ptr, base: mpz_srcptr, exp: c_ulong);
78    fn __gmpz_ui_pow_ui(rop: mpz_ptr, base: c_ulong, exp: c_ulong);
79    fn __gmpz_powm(rop: mpz_ptr, base: mpz_srcptr, exp: mpz_srcptr, modulo: mpz_srcptr);
80    fn __gmpz_powm_sec(rop: mpz_ptr, base: mpz_srcptr, exp: mpz_srcptr, modulo: mpz_srcptr);
81    fn __gmpz_hamdist(op1: mpz_srcptr, op2: mpz_srcptr) -> mp_bitcnt_t;
82    fn __gmpz_setbit(rop: mpz_ptr, bit_index: mp_bitcnt_t);
83    fn __gmpz_clrbit(rop: mpz_ptr, bit_index: mp_bitcnt_t);
84    fn __gmpz_combit(rop: mpz_ptr, bit_index: mp_bitcnt_t);
85    fn __gmpz_tstbit(rop: mpz_srcptr, bit_index: mp_bitcnt_t) -> c_int;
86    fn __gmpz_probab_prime_p(n: mpz_srcptr, reps: c_int) -> c_int;
87    fn __gmpz_nextprime(rop: mpz_ptr, op: mpz_srcptr);
88    fn __gmpz_gcd(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
89    fn __gmpz_gcdext(g: mpz_ptr, s: mpz_ptr, t: mpz_ptr, a: mpz_srcptr, b: mpz_srcptr);
90    fn __gmpz_lcm(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr);
91    fn __gmpz_invert(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr) -> c_int;
92    fn __gmpz_import(
93        rop: mpz_ptr,
94        count: size_t,
95        order: c_int,
96        size: size_t,
97        endian: c_int,
98        nails: size_t,
99        op: *const c_void,
100    );
101    fn __gmpz_export(
102        rop: *mut c_void,
103        countp: *mut size_t,
104        order: c_int,
105        size: size_t,
106        endian: c_int,
107        nails: size_t,
108        op: mpz_srcptr,
109    );
110    fn __gmpz_root(rop: mpz_ptr, op: mpz_srcptr, n: c_ulong) -> c_int;
111    fn __gmpz_sqrt(rop: mpz_ptr, op: mpz_srcptr);
112    fn __gmpz_millerrabin(n: mpz_srcptr, reps: c_int) -> c_int;
113}
114
115#[repr(transparent)]
116pub struct Mpz {
117    mpz: mpz_struct,
118}
119
120unsafe impl Send for Mpz {}
121unsafe impl Sync for Mpz {}
122
123impl Drop for Mpz {
124    fn drop(&mut self) {
125        unsafe { __gmpz_clear(&mut self.mpz) }
126    }
127}
128
129/// The result of running probab_prime
130#[derive(PartialEq)]
131pub enum ProbabPrimeResult {
132    NotPrime,
133    ProbablyPrime,
134    Prime,
135}
136
137impl Mpz {
138    #[inline]
139    pub unsafe fn inner(&self) -> mpz_srcptr {
140        &self.mpz
141    }
142
143    #[inline]
144    pub unsafe fn inner_mut(&mut self) -> mpz_ptr {
145        &mut self.mpz
146    }
147
148    #[inline]
149    pub fn new() -> Mpz {
150        unsafe {
151            let mut mpz = uninitialized();
152            __gmpz_init(&mut mpz);
153            Mpz { mpz }
154        }
155    }
156
157    #[inline]
158    pub fn new_reserve(n: usize) -> Mpz {
159        unsafe {
160            let mut mpz = uninitialized();
161            __gmpz_init2(&mut mpz, n as c_ulong);
162            Mpz { mpz }
163        }
164    }
165
166    #[inline]
167    pub fn reserve(&mut self, n: usize) {
168        if self.bit_length() < n {
169            unsafe { __gmpz_realloc2(&mut self.mpz, n as c_ulong) }
170        }
171    }
172
173    #[inline]
174    pub fn size_in_base(&self, base: u8) -> usize {
175        unsafe { __gmpz_sizeinbase(&self.mpz, base as c_int) as usize }
176    }
177
178    // TODO: fail on an invalid base
179    // FIXME: Unfortunately it isn't currently possible to use the fmt::RadixFmt
180    //        machinery for a custom type.
181    pub fn to_str_radix(&self, base: u8) -> String {
182        unsafe {
183            assert!(base >= 2 && base <= 36, "invalid base");
184            // Extra two bytes are for possible minus sign and null terminator
185            let len = {
186                let len = __gmpz_sizeinbase(&self.mpz, base as c_int) as usize;
187                assert!(usize::MAX - len >= 2, "capacity overflow");
188                len + 2
189            };
190
191            // Allocate and write into a raw *c_char of the correct length
192            let mut vector: Vec<u8> = Vec::with_capacity(len);
193            __gmpz_get_str(vector.as_mut_ptr() as *mut _, base as c_int, &self.mpz);
194            let string_len = strnlen(vector.as_ptr() as *const _, len);
195            assert!(string_len < len);
196            vector.set_len(string_len);
197            // FIXME is this actually a problem?
198            String::from_utf8(vector).expect("GMP returned invalid UTF-8!")
199        }
200    }
201
202    pub fn from_str_radix(s: &str, base: u8) -> Result<Mpz, ParseMpzError> {
203        let s = CString::new(s.to_string()).map_err(|_| ParseMpzError { _priv: () })?;
204        unsafe {
205            assert!(base == 0 || (base >= 2 && base <= 62));
206            let mut mpz = uninitialized();
207            let r = __gmpz_init_set_str(&mut mpz, s.as_ptr(), base as c_int);
208            if r == 0 {
209                Ok(Mpz { mpz })
210            } else {
211                __gmpz_clear(&mut mpz);
212                Err(ParseMpzError { _priv: () })
213            }
214        }
215    }
216
217    #[inline]
218    pub fn set(&mut self, other: &Mpz) {
219        unsafe { __gmpz_set(&mut self.mpz, &other.mpz) }
220    }
221
222    // TODO: too easy to forget to check this return value - rename?
223    pub fn set_from_str_radix(&mut self, s: &str, base: u8) -> bool {
224        assert!(base == 0 || (base >= 2 && base <= 62));
225        let s = CString::new(s.to_string()).unwrap();
226        unsafe { __gmpz_set_str(&mut self.mpz, s.as_ptr(), base as c_int) == 0 }
227    }
228
229    #[inline]
230    pub fn bit_length(&self) -> usize {
231        unsafe { __gmpz_sizeinbase(&self.mpz, 2) as usize }
232    }
233
234    #[inline]
235    pub fn compl(&self) -> Mpz {
236        unsafe {
237            let mut res = Mpz::new();
238            __gmpz_com(&mut res.mpz, &self.mpz);
239            res
240        }
241    }
242
243    #[inline]
244    pub fn abs(&self) -> Mpz {
245        unsafe {
246            let mut res = Mpz::new();
247            __gmpz_abs(&mut res.mpz, &self.mpz);
248            res
249        }
250    }
251
252    #[inline]
253    pub fn div_floor(&self, other: &Mpz) -> Mpz {
254        unsafe {
255            if other.is_zero() {
256                panic!("divide by zero")
257            }
258
259            let mut res = Mpz::new();
260            __gmpz_fdiv_q(&mut res.mpz, &self.mpz, &other.mpz);
261            res
262        }
263    }
264
265    #[inline]
266    pub fn mod_floor(&self, other: &Mpz) -> Mpz {
267        unsafe {
268            if other.is_zero() {
269                panic!("divide by zero")
270            }
271
272            let mut res = Mpz::new();
273            __gmpz_fdiv_r(&mut res.mpz, &self.mpz, &other.mpz);
274            res
275        }
276    }
277
278    /// Determine whether n is prime.
279    ///
280    /// This function performs some trial divisions, then reps Miller-Rabin probabilistic primality tests. A higher reps value will reduce the chances of a non-prime being identified as “probably prime”. A composite number will be identified as a prime with a probability of less than 4^(-reps). Reasonable values of reps are between 15 and 50.
281    pub fn probab_prime(&self, reps: i32) -> ProbabPrimeResult {
282        match unsafe { __gmpz_probab_prime_p(&self.mpz, reps as c_int) as u8 } {
283            2 => ProbabPrimeResult::Prime,
284            1 => ProbabPrimeResult::ProbablyPrime,
285            0 => ProbabPrimeResult::NotPrime,
286            x => panic!("Undocumented return value {} from __gmpz_probab_prime_p", x),
287        }
288    }
289
290    #[inline]
291    pub fn nextprime(&self) -> Mpz {
292        unsafe {
293            let mut res = Mpz::new();
294            __gmpz_nextprime(&mut res.mpz, &self.mpz);
295            res
296        }
297    }
298
299    #[inline]
300    pub fn gcd(&self, other: &Mpz) -> Mpz {
301        unsafe {
302            let mut res = Mpz::new();
303            __gmpz_gcd(&mut res.mpz, &self.mpz, &other.mpz);
304            res
305        }
306    }
307
308    /// Given (a, b), return (g, s, t) such that g = gcd(a, b) = s*a + t*b.
309    pub fn gcdext(&self, other: &Mpz) -> (Mpz, Mpz, Mpz) {
310        unsafe {
311            let mut g = Mpz::new();
312            let mut s = Mpz::new();
313            let mut t = Mpz::new();
314            __gmpz_gcdext(&mut g.mpz, &mut s.mpz, &mut t.mpz, &self.mpz, &other.mpz);
315            (g, s, t)
316        }
317    }
318
319    #[inline]
320    pub fn lcm(&self, other: &Mpz) -> Mpz {
321        unsafe {
322            let mut res = Mpz::new();
323            __gmpz_lcm(&mut res.mpz, &self.mpz, &other.mpz);
324            res
325        }
326    }
327
328    #[inline]
329    pub fn is_multiple_of(&self, other: &Mpz) -> bool {
330        unsafe { __gmpz_divisible_p(&self.mpz, &other.mpz) != 0 }
331    }
332
333    #[inline]
334    pub fn divides(&self, other: &Mpz) -> bool {
335        other.is_multiple_of(self)
336    }
337
338    pub fn modulus(&self, modulo: &Mpz) -> Mpz {
339        unsafe {
340            if modulo.is_zero() {
341                panic!("divide by zero")
342            }
343
344            let mut res = Mpz::new();
345            __gmpz_mod(&mut res.mpz, &self.mpz, &modulo.mpz);
346            res
347        }
348    }
349
350    // TODO: handle a zero modulo
351    pub fn invert(&self, modulo: &Mpz) -> Option<Mpz> {
352        unsafe {
353            let mut res = Mpz::new();
354            if __gmpz_invert(&mut res.mpz, &self.mpz, &modulo.mpz) == 0 {
355                None
356            } else {
357                Some(res)
358            }
359        }
360    }
361
362    #[inline]
363    pub fn popcount(&self) -> usize {
364        unsafe { __gmpz_popcount(&self.mpz) as usize }
365    }
366
367    #[inline]
368    pub fn pow(&self, exp: u32) -> Mpz {
369        unsafe {
370            let mut res = Mpz::new();
371            __gmpz_pow_ui(&mut res.mpz, &self.mpz, exp as c_ulong);
372            res
373        }
374    }
375
376    #[inline]
377    pub fn powm(&self, exp: &Mpz, modulus: &Mpz) -> Mpz {
378        unsafe {
379            let mut res = Mpz::new();
380            __gmpz_powm(&mut res.mpz, &self.mpz, &exp.mpz, &modulus.mpz);
381            res
382        }
383    }
384
385    #[inline]
386    pub fn powm_sec(&self, exp: &Mpz, modulus: &Mpz) -> Mpz {
387        unsafe {
388            let mut res = Mpz::new();
389            __gmpz_powm_sec(&mut res.mpz, &self.mpz, &exp.mpz, &modulus.mpz);
390            res
391        }
392    }
393
394    #[inline]
395    pub fn ui_pow_ui(x: u32, y: u32) -> Mpz {
396        unsafe {
397            let mut res = Mpz::new();
398            __gmpz_ui_pow_ui(&mut res.mpz, x as c_ulong, y as c_ulong);
399            res
400        }
401    }
402
403    #[inline]
404    pub fn hamdist(&self, other: &Mpz) -> usize {
405        unsafe { __gmpz_hamdist(&self.mpz, &other.mpz) as usize }
406    }
407
408    #[inline]
409    pub fn setbit(&mut self, bit_index: usize) {
410        unsafe { __gmpz_setbit(&mut self.mpz, bit_index as c_ulong) }
411    }
412
413    #[inline]
414    pub fn clrbit(&mut self, bit_index: usize) {
415        unsafe { __gmpz_clrbit(&mut self.mpz, bit_index as c_ulong) }
416    }
417
418    #[inline]
419    pub fn combit(&mut self, bit_index: usize) {
420        unsafe { __gmpz_combit(&mut self.mpz, bit_index as c_ulong) }
421    }
422
423    #[inline]
424    pub fn tstbit(&self, bit_index: usize) -> bool {
425        unsafe { __gmpz_tstbit(&self.mpz, bit_index as c_ulong) == 1 }
426    }
427
428    pub fn root(&self, n: u32) -> Mpz {
429        assert!(self.mpz._mp_size >= 0);
430        unsafe {
431            let mut res = Mpz::new();
432            let _perfect_root = match __gmpz_root(&mut res.mpz, &self.mpz, n as c_ulong) {
433                0 => false,
434                _ => true,
435            };
436            // TODO: consider returning `_perfect_root`
437            res
438        }
439    }
440
441    pub fn sqrt(&self) -> Mpz {
442        assert!(self.mpz._mp_size >= 0);
443        unsafe {
444            let mut res = Mpz::new();
445            __gmpz_sqrt(&mut res.mpz, &self.mpz);
446            res
447        }
448    }
449
450    pub fn millerrabin(&self, reps: i32) -> i32 {
451        unsafe { __gmpz_millerrabin(&self.mpz, reps as c_int) }
452    }
453
454    pub fn sign(&self) -> Sign {
455        let size = self.mpz._mp_size;
456        if size == 0 {
457            Sign::Zero
458        } else if size > 0 {
459            Sign::Positive
460        } else {
461            Sign::Negative
462        }
463    }
464
465    pub fn one() -> Mpz {
466        unsafe {
467            let mut mpz = uninitialized();
468            __gmpz_init_set_ui(&mut mpz, 1);
469            Mpz { mpz }
470        }
471    }
472
473    pub fn zero() -> Mpz {
474        Mpz::new()
475    }
476
477    pub fn is_zero(&self) -> bool {
478        self.mpz._mp_size == 0
479    }
480}
481
482#[derive(Debug)]
483pub struct ParseMpzError {
484    _priv: (),
485}
486
487impl fmt::Display for ParseMpzError {
488    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
489        f.write_str("invalid integer")
490    }
491}
492
493impl Error for ParseMpzError {}
494
495impl Clone for Mpz {
496    fn clone(&self) -> Mpz {
497        unsafe {
498            let mut mpz = uninitialized();
499            __gmpz_init_set(&mut mpz, &self.mpz);
500            Mpz { mpz }
501        }
502    }
503}
504
505impl Eq for Mpz {}
506
507impl PartialEq for Mpz {
508    fn eq(&self, other: &Mpz) -> bool {
509        unsafe { __gmpz_cmp(&self.mpz, &other.mpz) == 0 }
510    }
511}
512
513impl Ord for Mpz {
514    fn cmp(&self, other: &Mpz) -> Ordering {
515        let cmp = unsafe { __gmpz_cmp(&self.mpz, &other.mpz) };
516        if cmp == 0 {
517            Equal
518        } else if cmp < 0 {
519            Less
520        } else {
521            Greater
522        }
523    }
524}
525
526impl PartialOrd for Mpz {
527    fn partial_cmp(&self, other: &Mpz) -> Option<Ordering> {
528        Some(self.cmp(other))
529    }
530}
531
532// Implementation of operators
533
534// This macro inserts a guard against division by 0 for Div and Rem implementations
535macro_rules! div_guard {
536    (Div, $is_zero: expr) => {
537        if $is_zero {
538            panic!("divide by zero")
539        }
540    };
541    (Rem, $is_zero: expr) => {
542        if $is_zero {
543            panic!("divide by zero")
544        }
545    };
546    ($tr: ident, $is_zero: expr) => {};
547}
548
549// On Windows c_long and c_ulong are only 32-bit - in order to implement operations for
550// 64-bit types we need some workarounds
551macro_rules! bit_guard {
552    (u64, $what: ident, $e1: expr, $e2: expr) => {
553        if size_of::<c_ulong>() == 8 || $what <= u32::MAX as u64 {
554            $e1
555        } else {
556            $e2
557        }
558    };
559
560    (i64, $what: ident, $e1: expr, $e2: expr) => {
561        if size_of::<c_long>() == 8 || $what <= i32::MAX as i64 {
562            $e1
563        } else {
564            $e2
565        }
566    };
567
568    (u32, $what: ident, $e1: expr, $e2: expr) => {
569        $e1
570    };
571
572    (i32, $what: ident, $e1: expr, $e2: expr) => {
573        $e1
574    };
575}
576
577macro_rules! impl_oper {
578	($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => {
579		impl $tr<Mpz> for Mpz {
580			type Output = Mpz;
581			#[inline]
582			fn $meth(self, other: Mpz) -> Mpz {
583				self.$meth(&other)
584			}
585		}
586
587		impl<'a> $tr<&'a Mpz> for Mpz {
588			type Output = Mpz;
589			#[inline]
590			fn $meth(mut self, other: &Mpz) -> Mpz {
591				self.$meth_assign(other);
592				self
593			}
594		}
595
596		impl<'a> $tr<Mpz> for &'a Mpz {
597			type Output = Mpz;
598			#[inline]
599			fn $meth(self, mut other: Mpz) -> Mpz {
600				unsafe {
601					div_guard!($tr, other.is_zero());
602					$fun(&mut other.mpz, &self.mpz, &other.mpz);
603					other
604				}
605			}
606		}
607
608		impl<'a, 'b> $tr<&'b Mpz> for &'a Mpz {
609			type Output = Mpz;
610			fn $meth(self, other: &Mpz) -> Mpz {
611				unsafe {
612					div_guard!($tr, other.is_zero());
613					let mut res = Mpz::new();
614					$fun(&mut res.mpz, &self.mpz, &other.mpz);
615					res
616				}
617			}
618		}
619
620		impl $tr_assign<Mpz> for Mpz {
621			#[inline]
622			fn $meth_assign(&mut self, other: Mpz) {
623				self.$meth_assign(&other)
624			}
625		}
626
627		impl<'a> $tr_assign<&'a Mpz> for Mpz {
628			#[inline]
629			fn $meth_assign(&mut self, other: &Mpz) {
630				unsafe {
631					div_guard!($tr, other.is_zero());
632					$fun(&mut self.mpz, &self.mpz, &other.mpz);
633				}
634			}
635		}
636	};
637
638	(both $num: ident, $cnum: ident, $tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => {
639		impl_oper!(normal $num, $cnum, $tr, $meth, $tr_assign, $meth_assign, $fun);
640
641		impl $tr<Mpz> for $num {
642			type Output = Mpz;
643			#[inline]
644			fn $meth(self, mut other: Mpz) -> Mpz {
645				unsafe {
646					bit_guard!($num, self, {
647		            	$fun(&mut other.mpz, &other.mpz, self as $cnum);
648		            	other
649		        	}, other.$meth(Mpz::from(self)))
650				}
651			}
652		}
653
654		impl<'a> $tr<&'a Mpz> for $num {
655			type Output = Mpz;
656			fn $meth(self, other: &'a Mpz) -> Mpz {
657				unsafe {
658					bit_guard!($num, self, {
659			            let mut res = Mpz::new();
660			            $fun(&mut res.mpz, &other.mpz, self as $cnum);
661			            res
662		            }, other.$meth(Mpz::from(self)))
663				}
664			}
665		}
666	};
667
668	(normal $num: ident, $cnum: ident, $tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => {
669		impl $tr<$num> for Mpz {
670			type Output = Mpz;
671			#[inline]
672			fn $meth(mut self, other: $num) -> Mpz {
673				self.$meth_assign(other);
674				self
675			}
676		}
677
678		impl<'a> $tr<$num> for &'a Mpz {
679			type Output = Mpz;
680			fn $meth(self, other: $num) -> Mpz {
681		        unsafe {
682					div_guard!($tr, other == 0);
683		        	bit_guard!($num, other, {
684			            let mut res = Mpz::new();
685			            $fun(&mut res.mpz, &self.mpz, other as $cnum);
686			            res
687		            }, self.$meth(Mpz::from(other)))
688		        }
689			}
690		}
691
692		impl $tr_assign<$num> for Mpz {
693			#[inline]
694			fn $meth_assign(&mut self, other: $num) {
695				unsafe {
696					div_guard!($tr, other == 0);
697					bit_guard!($num, other,
698						$fun(&mut self.mpz, &self.mpz, other as $cnum),
699						self.$meth_assign(Mpz::from(other)))
700				}
701			}
702		}
703	};
704
705	(reverse $num: ident, $cnum: ident, $tr: ident, $meth: ident, $fun: ident) => {
706		impl $tr<Mpz> for $num {
707			type Output = Mpz;
708			#[inline]
709			fn $meth(self, mut other: Mpz) -> Mpz {
710				unsafe {
711					bit_guard!($num, self, {
712		            	$fun(&mut other.mpz, self as $cnum, &other.mpz);
713		            	other
714		        	}, Mpz::from(self).$meth(other))
715				}
716			}
717		}
718
719		impl<'a> $tr<&'a Mpz> for $num {
720			type Output = Mpz;
721			fn $meth(self, other: &'a Mpz) -> Mpz {
722				unsafe {
723					bit_guard!($num, self, {
724			            let mut res = Mpz::new();
725			            $fun(&mut res.mpz, self as $cnum, &other.mpz);
726			            res
727		            }, Mpz::from(self).$meth(other))
728				}
729			}
730		}
731	};
732
733}
734
735impl_oper!(Add, add, AddAssign, add_assign, __gmpz_add);
736impl_oper!(both u64, c_ulong, Add, add, AddAssign, add_assign, __gmpz_add_ui);
737
738impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpz_sub);
739impl_oper!(normal u64, c_ulong, Sub, sub, SubAssign, sub_assign, __gmpz_sub_ui);
740impl_oper!(reverse u64, c_ulong, Sub, sub, __gmpz_ui_sub);
741
742impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpz_mul);
743impl_oper!(both i64, c_long, Mul, mul, MulAssign, mul_assign, __gmpz_mul_si);
744impl_oper!(both u64, c_ulong, Mul, mul, MulAssign, mul_assign, __gmpz_mul_ui);
745
746impl_oper!(Div, div, DivAssign, div_assign, __gmpz_tdiv_q);
747impl_oper!(normal u64, c_ulong, Div, div, DivAssign, div_assign, __gmpz_tdiv_q_ui);
748
749impl_oper!(Rem, rem, RemAssign, rem_assign, __gmpz_tdiv_r);
750impl_oper!(normal u64, c_ulong, Rem, rem, RemAssign, rem_assign, __gmpz_tdiv_r_ui);
751
752impl<'b> Neg for &'b Mpz {
753    type Output = Mpz;
754    fn neg(self) -> Mpz {
755        unsafe {
756            let mut res = Mpz::new();
757            __gmpz_neg(&mut res.mpz, &self.mpz);
758            res
759        }
760    }
761}
762
763impl Neg for Mpz {
764    type Output = Mpz;
765    #[inline]
766    fn neg(mut self) -> Mpz {
767        unsafe {
768            __gmpz_neg(&mut self.mpz, &self.mpz);
769            self
770        }
771    }
772}
773
774impl<'b> Not for &'b Mpz {
775    type Output = Mpz;
776    fn not(self) -> Mpz {
777        unsafe {
778            let mut res = Mpz::new();
779            __gmpz_com(&mut res.mpz, &self.mpz);
780            res
781        }
782    }
783}
784
785impl Not for Mpz {
786    type Output = Mpz;
787    #[inline]
788    fn not(mut self) -> Mpz {
789        unsafe {
790            __gmpz_com(&mut self.mpz, &self.mpz);
791            self
792        }
793    }
794}
795
796// Similarly to mpz_export, this does not preserve the sign of the input.
797impl<'b> From<&'b Mpz> for Vec<u8> {
798    fn from(other: &Mpz) -> Vec<u8> {
799        unsafe {
800            let bit_size = size_of::<u8>() * 8;
801            let size = (__gmpz_sizeinbase(&other.mpz, 2) + bit_size - 1) / bit_size;
802            let mut result: Vec<u8> = vec![0; size];
803            __gmpz_export(
804                result.as_mut_ptr() as *mut c_void,
805                0 as *mut size_t,
806                1,
807                size_of::<u8>() as size_t,
808                0,
809                0,
810                &other.mpz,
811            );
812            result
813        }
814    }
815}
816
817impl<'b> From<&'b Mpz> for Option<i64> {
818    fn from(other: &Mpz) -> Option<i64> {
819        unsafe {
820            let negative = other.mpz._mp_size < 0;
821            let mut to_export = Mpz::new();
822
823            if negative {
824                __gmpz_com(&mut to_export.mpz, &other.mpz);
825            } else {
826                __gmpz_set(&mut to_export.mpz, &other.mpz);
827            }
828
829            if __gmpz_sizeinbase(&to_export.mpz, 2) <= 63 {
830                let mut result: i64 = 0;
831                __gmpz_export(
832                    &mut result as *mut i64 as *mut c_void,
833                    0 as *mut size_t,
834                    -1,
835                    size_of::<i64>() as size_t,
836                    0,
837                    0,
838                    &to_export.mpz,
839                );
840                if negative {
841                    Some(result ^ -1i64)
842                } else {
843                    Some(result)
844                }
845            } else {
846                return None;
847            }
848        }
849    }
850}
851
852impl<'b> From<&'b Mpz> for Option<u64> {
853    fn from(other: &Mpz) -> Option<u64> {
854        unsafe {
855            if __gmpz_sizeinbase(&other.mpz, 2) <= 64 && other.mpz._mp_size >= 0 {
856                let mut result: u64 = 0;
857                __gmpz_export(
858                    &mut result as *mut u64 as *mut c_void,
859                    0 as *mut size_t,
860                    -1,
861                    size_of::<u64>() as size_t,
862                    0,
863                    0,
864                    &other.mpz,
865                );
866                Some(result)
867            } else {
868                None
869            }
870        }
871    }
872}
873
874impl<'a> From<&'a Mpz> for f64 {
875    fn from(other: &Mpz) -> f64 {
876        unsafe { __gmpz_get_d(&other.mpz) as f64 }
877    }
878}
879
880impl<'a> From<&'a [u8]> for Mpz {
881    fn from(other: &'a [u8]) -> Mpz {
882        unsafe {
883            let mut res = Mpz::new();
884            __gmpz_import(
885                &mut res.mpz,
886                other.len(),
887                1,
888                size_of::<u8>() as size_t,
889                0,
890                0,
891                other.as_ptr() as *const c_void,
892            );
893            res
894        }
895    }
896}
897
898impl From<u64> for Mpz {
899    fn from(other: u64) -> Mpz {
900        unsafe {
901            let mut res = Mpz::new();
902            __gmpz_import(
903                &mut res.mpz,
904                1,
905                -1,
906                size_of::<u64>() as size_t,
907                0,
908                0,
909                &other as *const u64 as *const c_void,
910            );
911            res
912        }
913    }
914}
915
916impl From<u32> for Mpz {
917    fn from(other: u32) -> Mpz {
918        unsafe {
919            let mut res = Mpz::new();
920            __gmpz_import(
921                &mut res.mpz,
922                1,
923                -1,
924                size_of::<u32>() as size_t,
925                0,
926                0,
927                &other as *const u32 as *const c_void,
928            );
929            res
930        }
931    }
932}
933
934impl From<i64> for Mpz {
935    fn from(other: i64) -> Mpz {
936        unsafe {
937            let mut res = Mpz::new();
938
939            if other.is_negative() {
940                __gmpz_import(
941                    &mut res.mpz,
942                    1,
943                    -1,
944                    size_of::<i64>() as size_t,
945                    0,
946                    0,
947                    &(other ^ -1i64) as *const i64 as *const c_void,
948                );
949                __gmpz_com(&mut res.mpz, &res.mpz);
950            } else {
951                __gmpz_import(
952                    &mut res.mpz,
953                    1,
954                    -1,
955                    size_of::<i64>() as size_t,
956                    0,
957                    0,
958                    &other as *const i64 as *const c_void,
959                );
960            }
961            res
962        }
963    }
964}
965
966impl From<i32> for Mpz {
967    fn from(other: i32) -> Mpz {
968        unsafe {
969            let mut res = Mpz::new();
970
971            if other.is_negative() {
972                __gmpz_import(
973                    &mut res.mpz,
974                    1,
975                    -1,
976                    size_of::<i32>() as size_t,
977                    0,
978                    0,
979                    &(other ^ -1i32) as *const i32 as *const c_void,
980                );
981                __gmpz_com(&mut res.mpz, &res.mpz);
982            } else {
983                __gmpz_import(
984                    &mut res.mpz,
985                    1,
986                    -1,
987                    size_of::<i32>() as size_t,
988                    0,
989                    0,
990                    &other as *const i32 as *const c_void,
991                );
992            }
993            res
994        }
995    }
996}
997
998impl_oper!(BitAnd, bitand, BitAndAssign, bitand_assign, __gmpz_and);
999impl_oper!(BitOr, bitor, BitOrAssign, bitor_assign, __gmpz_ior);
1000impl_oper!(BitXor, bitxor, BitXorAssign, bitxor_assign, __gmpz_xor);
1001
1002impl<'b> Shl<usize> for &'b Mpz {
1003    type Output = Mpz;
1004    fn shl(self, other: usize) -> Mpz {
1005        unsafe {
1006            let mut res = Mpz::new();
1007            __gmpz_mul_2exp(&mut res.mpz, &self.mpz, other as c_ulong);
1008            res
1009        }
1010    }
1011}
1012
1013impl<'b> Shr<usize> for &'b Mpz {
1014    type Output = Mpz;
1015    fn shr(self, other: usize) -> Mpz {
1016        unsafe {
1017            let mut res = Mpz::new();
1018            __gmpz_fdiv_q_2exp(&mut res.mpz, &self.mpz, other as c_ulong);
1019            res
1020        }
1021    }
1022}
1023
1024impl Shl<usize> for Mpz {
1025    type Output = Mpz;
1026    fn shl(self, other: usize) -> Mpz {
1027        unsafe {
1028            let mut res = Mpz::new();
1029            __gmpz_mul_2exp(&mut res.mpz, &self.mpz, other as c_ulong);
1030            res
1031        }
1032    }
1033}
1034
1035impl Shr<usize> for Mpz {
1036    type Output = Mpz;
1037    fn shr(self, other: usize) -> Mpz {
1038        unsafe {
1039            let mut res = Mpz::new();
1040            __gmpz_fdiv_q_2exp(&mut res.mpz, &self.mpz, other as c_ulong);
1041            res
1042        }
1043    }
1044}
1045
1046impl ShlAssign<usize> for Mpz {
1047    fn shl_assign(&mut self, other: usize) {
1048        unsafe {
1049            __gmpz_mul_2exp(&mut self.mpz, &self.mpz, other as c_ulong);
1050        }
1051    }
1052}
1053
1054impl ShrAssign<usize> for Mpz {
1055    fn shr_assign(&mut self, other: usize) {
1056        unsafe {
1057            __gmpz_fdiv_q_2exp(&mut self.mpz, &self.mpz, other as c_ulong);
1058        }
1059    }
1060}
1061
1062impl FromStr for Mpz {
1063    type Err = ParseMpzError;
1064    fn from_str(s: &str) -> Result<Self, Self::Err> {
1065        Mpz::from_str_radix(s, 10)
1066    }
1067}
1068
1069impl fmt::Display for Mpz {
1070    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1071        write!(f, "{}", self.to_str_radix(10))
1072    }
1073}
1074
1075impl fmt::Debug for Mpz {
1076    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1077        write!(f, "{}", self.to_str_radix(10))
1078    }
1079}
1080
1081impl hash::Hash for Mpz {
1082    fn hash<S: hash::Hasher>(&self, state: &mut S) {
1083        unsafe {
1084            for i in 0..self.mpz._mp_size.abs() {
1085                let limb = self.mpz._mp_d as *const mp_limb_t;
1086                let limb = *(limb.offset(i as isize));
1087                limb.hash(state);
1088            }
1089        }
1090    }
1091}
1092
1093impl Zero for Mpz {
1094    #[inline]
1095    fn zero() -> Mpz {
1096        Mpz::zero()
1097    }
1098
1099    #[inline]
1100    fn is_zero(&self) -> bool {
1101        self.is_zero()
1102    }
1103}
1104
1105impl One for Mpz {
1106    #[inline]
1107    fn one() -> Mpz {
1108        Mpz::one()
1109    }
1110}