/* -*-c++-*- */ /* $Id: bigint.h,v 1.25 2001/12/19 23:11:22 dm Exp $ */ /* * * Copyright (C) 1998 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #ifndef _SFS_BIGINT_H_ #define _SFS_BIGINT_H_ 1 #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #undef ABS #define ABS(a) ((a) < 0 ? -(a) : (a)) enum { mpz_bitsperlimb = sizeof (mp_limb_t) * 8 }; int mpz_getbit (const MP_INT *, size_t); void mpz_xor (MP_INT *, const MP_INT *, const MP_INT *); void mpz_square (MP_INT *, const MP_INT *); void mpz_umod_2exp (MP_INT *r, const MP_INT *a, unsigned long b); size_t mpz_sizeinbase2 (const MP_INT *mp); size_t mpz_rawsize (const MP_INT *); void mpz_get_raw (char *buf, size_t size, const MP_INT *mp); void mpz_set_raw (MP_INT *mp, const char *buf, size_t size); void mpz_get_rawmag_le (char *buf, size_t size, const MP_INT *mp); void mpz_get_rawmag_be (char *buf, size_t size, const MP_INT *mp); void mpz_set_rawmag_le (MP_INT *mp, const char *buf, size_t size); void mpz_set_rawmag_be (MP_INT *mp, const char *buf, size_t size); void _mpz_fixsize (MP_INT *r); #ifdef CHECK_BOUNDS #define _mpz_assert(mp) \ assert (!(mp)->_mp_size || (mp)->_mp_d[ABS((mp)->_mp_size)-1]) #else /* !CHECK_BOUNDS */ #define _mpz_assert(mp) ((void) 0) #endif #ifdef _ARPC_XDRMISC_H_ extern bool_t xdr_mpz_t (register XDR *, MP_INT *); #endif /* _ARPC_XDRMISC_H_ */ #ifdef __cplusplus } #include "str.h" template class mpdelayed; class bigint : public MP_INT { struct mutablestr { mutable str s; mutablestr () {} }; public: // operator MP_INT *() { return this; } // operator const MP_INT *() const { return this; } bigint () { mpz_init (this); } bigint (const bigint &b) { mpz_init_set (this, &b); } explicit bigint (const MP_INT *bp) { mpz_init_set (this, bp); } bigint (long si) { mpz_init_set_si (this, si); } bigint (u_long ui) { mpz_init_set_ui (this, ui); } bigint (int si) { mpz_init_set_si (this, si); } bigint (u_int ui) { mpz_init_set_ui (this, ui); } explicit bigint (const char *s, int base = 0) { mpz_init_set_str (this, s, base); } //explicit bigint (str s, int base = 0) { mpz_init_set_str (this, s, base); } template bigint (const mpdelayed &d) { mpz_init (this); d.getres (this); } ~bigint () { mpz_clear (this); } bigint &operator= (const bigint &b) { mpz_set (this, &b); return *this; } bigint &operator= (const MP_INT *bp) { mpz_set (this, bp); return *this; } bigint &operator= (int si) { mpz_set_si (this, si); return *this; } bigint &operator= (long si) { mpz_set_si (this, si); return *this; } bigint &operator= (u_long ui) { mpz_set_ui (this, ui); return *this; } bigint &operator= (const char *s) { mpz_set_str (this, s, 0); return *this; } template bigint &operator= (const mpdelayed &d) { d.getres (this); return *this; } void swap (MP_INT *a) { MP_INT t = *a; *a = *static_cast (this); *static_cast (this) = t; } void swap (bigint &b) { swap (&b); } long getsi () const { return mpz_get_si (this); } u_long getui () const { return mpz_get_ui (this); } str getstr (const int base = 16) const { mstr m (mpz_sizeinbase (this, base) + 1); mpz_get_str (m, base, this); m.setlen (strlen (m.cstr ())); return m; } const char *cstr (const int base = 16, const mutablestr &ms = mutablestr ()) const { return ms.s = getstr (base); } str getraw () const { size_t size = mpz_rawsize (this); mstr ret (size); mpz_get_raw (ret, size, this); return ret; }; void setraw (str s) { mpz_set_raw (this, s, s.len ()); } #define ASSOPX(X, fn) \ bigint &operator X (const bigint &b) \ { fn (this, this, &b); return *this; } \ bigint &operator X (const MP_INT *bp) \ { fn (this, this, bp); return *this; } \ bigint &operator X (u_long ui) \ { fn##_ui (this, this, ui); return *this; } ASSOPX (+=, mpz_add); ASSOPX (-=, mpz_sub); ASSOPX (*=, mpz_mul); ASSOPX (/=, mpz_tdiv_q); ASSOPX (%=, mpz_tdiv_r); #undef ASSOPX #define ASSOPX(X, fn) \ bigint &operator X (const bigint &b) \ { fn (this, this, &b); return *this; } \ bigint &operator X (const MP_INT *bp) \ { fn (this, this, bp); return *this; } ASSOPX (&=, mpz_and); ASSOPX (^=, mpz_xor); ASSOPX (|=, mpz_ior); #undef ASSOPX bigint &operator<<= (u_long ui) { mpz_mul_2exp (this, this, ui); return *this; } bigint &operator>>= (u_long ui) { mpz_tdiv_q_2exp (this, this, ui); return *this; } #ifdef BIGINT_BOOLOP operator bool () const { return *this != 0; } #endif /* BIGINT_BOOLOP */ const bigint &operator++ () { return *this += 1; } const bigint &operator-- () { return *this -= 1; } mpdelayed operator++ (int); mpdelayed operator-- (int); #if 0 mpdelayed invert (const bigint &) const; mpdelayed pow (u_long) const; mpdelayed powm (const bigint &, const bigint &) const; mpdelayed powm (const bigint &, const MP_INT *) const; mpdelayed powm (u_long, const bigint &) const; mpdelayed powm (u_long, const MP_INT *) const; #endif size_t nbits () const { return mpz_sizeinbase2 (this); } void (setbit) (u_long bitno, bool val) { if (val) mpz_setbit (this, bitno); else mpz_clrbit (this, bitno); } bool (getbit) (u_long bitno) const { return mpz_getbit (this, bitno); } void trunc (u_long size) { mpz_tdiv_r_2exp (this, this, size); } bool probab_prime (int reps = 25) const { return mpz_probab_prime_p (this, reps); } u_long popcount () const { return mpz_popcount (this); } }; inline const strbuf & strbuf_cat (const strbuf &sb, const bigint &b, const int base = 16) { int size = mpz_sizeinbase (&b, base) + 2; char *p = sb.tosuio ()->getspace (size); mpz_get_str (p, base, &b); sb.tosuio ()->print (p, strlen (p)); return sb; } template inline const strbuf & strbuf_cat (const strbuf &sb, const mpdelayed &b, const int base = 16) { return strbuf_cat (sb, bigint (b), base); } #ifdef BIGINT_BOOLOP #define MPDELAY_BOOLOP \ public: \ operator bool() const { return bigint (*this); } \ private: \ operator int() const; \ public: #else /* !BIGINT_BOOLOP */ #define MPDELAY_BOOLOP #endif /* !BIGINT_BOOLOP */ template<> class mpdelayed { typedef const MP_INT *A; typedef void (*fn_t) (MP_INT *, A); fn_t f; const A a; public: mpdelayed (fn_t ff, A aa) : f (ff), a (aa) {} void getres (MP_INT *r) const { f (r, a); } MPDELAY_BOOLOP }; template class mpdelayed > { typedef mpdelayed A; typedef void (*fn_t) (MP_INT *, const MP_INT *); fn_t f; const A &a; public: mpdelayed (fn_t ff, const A &aa) : f (ff), a (aa) {} void getres (MP_INT *r) const { a.getres (r); f (r, r); } MPDELAY_BOOLOP }; template class mpdelayed { typedef const MP_INT *A; typedef void (*fn_t) (MP_INT *, A, B); fn_t f; const A a; const B b; public: mpdelayed (fn_t ff, A aa, B bb) : f (ff), a (aa), b (bb) {} void getres (MP_INT *r) const { f (r, a, b); } MPDELAY_BOOLOP }; template class mpdelayed > { typedef const MP_INT *A; typedef mpdelayed B; typedef void (*fn_t) (MP_INT *, const MP_INT *, const MP_INT *); fn_t f; const A a; const B &b; public: mpdelayed (fn_t ff, A aa, const B &bb) : f (ff), a (aa), b (bb) {} void getres (MP_INT *r) const { if (r == a) { bigint t = b; f (r, a, &t); } else { b.getres (r); f (r, a, r); } } MPDELAY_BOOLOP }; template class mpdelayed, const MP_INT *> { typedef mpdelayed A; typedef const MP_INT *B; typedef void (*fn_t) (MP_INT *, const MP_INT *, B); fn_t f; const A &a; const B b; public: mpdelayed (fn_t ff, const A &aa, B bb) : f (ff), a (aa), b (bb) {} void getres (MP_INT *r) const { if (r == b) { bigint t = a; f (r, &t, b); } else { a.getres (r); f (r, r, b); } } MPDELAY_BOOLOP }; template class mpdelayed, u_long> { typedef mpdelayed A; typedef const u_long B; typedef void (*fn_t) (MP_INT *, const MP_INT *, B); fn_t f; const A &a; const B b; public: mpdelayed (fn_t ff, const A &aa, B bb) : f (ff), a (aa), b (bb) {} void getres (MP_INT *r) const { a.getres (r); f (r, r, b); } MPDELAY_BOOLOP }; template class mpdelayed > { typedef bigint A; typedef mpdelayed B; typedef void (*fn_t) (MP_INT *, const MP_INT *, const MP_INT *); fn_t f; const A a; const B &b; public: mpdelayed (fn_t ff, const A &aa, const B &bb) : f (ff), a (aa), b (bb) {} template mpdelayed (fn_t ff, const mpdelayed &aa, const B &bb) : f (ff), a (aa), b (bb) {} void getres (MP_INT *r) const { b.getres (r); f (r, a, r); } MPDELAY_BOOLOP }; template class mpdelayed { typedef void (*fn_t) (MP_INT *, A, B); fn_t f; const A a; const B b; public: mpdelayed (fn_t ff, A aa, B bb) : f (ff), a (aa), b (bb) {} void getres (MP_INT *r) const { f (r, a, b); } MPDELAY_BOOLOP }; template class mpdelayed { typedef void (*fn_t) (MP_INT *, A, B, C); fn_t f; const A a; const B b; const C c; public: mpdelayed (fn_t ff, A aa, B bb, C cc) : f (ff), a (aa), b (bb), c (cc) {} void getres (MP_INT *r) const { f (r, a, b, c); } MPDELAY_BOOLOP }; #undef MPDELAY_BOOLOP #define MPMPOP(X, F) \ inline mpdelayed \ X (const bigint &a, const bigint &b) \ { \ return mpdelayed (F, &a, &b); \ } \ inline mpdelayed \ X (const bigint &a, const MP_INT *b) \ { \ return mpdelayed (F, &a, b); \ } \ inline mpdelayed \ X (const MP_INT *a, const bigint &b) \ { \ return mpdelayed (F, a, &b); \ } \ template \ inline mpdelayed > \ X (const bigint &a, const mpdelayed &b) \ { \ return mpdelayed > (F, &a, b); \ } \ template \ inline mpdelayed, const MP_INT *> \ X (const mpdelayed &a, const bigint &b) \ { \ return mpdelayed, const MP_INT *> (F, a, &b); \ } \ template \ inline mpdelayed > \ X (const mpdelayed &a, const mpdelayed &b) \ { \ return mpdelayed > (F, a, b); \ } #define MPUIOP(X, F) \ inline mpdelayed \ X (const bigint &a, u_long b) \ { \ return mpdelayed (F, &a, b); \ } \ template \ inline mpdelayed, u_long> \ X (const mpdelayed &a, u_long b) \ { \ return mpdelayed, u_long> (F, a, b); \ } #define MPUICOP(X, F) \ MPUIOP (X, F) \ inline mpdelayed \ X (u_long b, const bigint &a) \ { \ return mpdelayed (F, &a, b); \ } \ template \ inline mpdelayed, u_long> \ X (u_long b, const mpdelayed &a) \ { \ return mpdelayed, u_long> (F, a, b); \ } #define UNOP(X, F) \ inline mpdelayed \ X (const bigint &a) \ { \ return mpdelayed (F, &a); \ } \ template \ inline mpdelayed > \ X (const mpdelayed &a) \ { \ return mpdelayed > (F, a); \ } #define BINOP(X, F) MPMPOP (X, F) MPUIOP (X, F##_ui) #define CBINOP(X, F) MPMPOP (X, F) MPUICOP (X, F##_ui) #define CMPOPX(X) \ inline bool \ operator X (const bigint &a, const bigint &b) \ { \ return mpz_cmp (&a, &b) X 0; \ } \ inline bool \ operator X (const bigint &a, const MP_INT *bp) \ { \ return mpz_cmp (&a, bp) X 0; \ } \ inline bool \ operator X (const bigint &a, u_long ui) \ { \ return mpz_cmp_ui (&a, ui) X 0; \ } \ inline bool \ operator X (const bigint &a, long si) \ { \ return mpz_cmp_si (&a, si) X 0; \ } \ inline bool \ operator X (const bigint &a, u_int ui) \ { \ return mpz_cmp_ui (&a, ui) X 0; \ } \ inline bool \ operator X (const bigint &a, int si) \ { \ return mpz_cmp_si (&a, si) X 0; \ } \ inline bool \ operator X (const MP_INT *bp, const bigint &b) \ { \ return mpz_cmp (bp, &b) X 0; \ } \ template inline bool \ operator X (const mpdelayed &_a, const B &b) \ { \ bigint a (_a); \ return a X b; \ } \ template inline bool \ operator X (const bigint &a, const mpdelayed &_b) \ { \ bigint b (_b); \ return a X b; \ } CBINOP (operator*, mpz_mul) CBINOP (operator+, mpz_add) BINOP (operator-, mpz_sub) /* Need to get rid of return values for GMP version 3 */ MPMPOP (operator/, mpz_tdiv_q) inline void mpz_tdiv_q_ui_void (MP_INT *r, const MP_INT *a, u_long b) { mpz_tdiv_q_ui (r, a, b); } MPUIOP (operator/, mpz_tdiv_q_ui_void) MPMPOP (operator%, mpz_tdiv_r) inline void mpz_tdiv_r_ui_void (MP_INT *r, const MP_INT *a, u_long b) { mpz_tdiv_r_ui (r, a, b); } /* Note: mod(bigint, u_long) is more efficient (but has result always >= 0) */ MPUIOP (operator%, mpz_tdiv_r_ui_void) MPMPOP (mod, mpz_mod) MPMPOP (operator&, mpz_and) MPMPOP (operator^, mpz_xor) MPMPOP (operator|, mpz_ior) MPMPOP (gcd, mpz_gcd) MPUIOP (operator<<, mpz_mul_2exp) MPUIOP (operator>>, mpz_tdiv_q_2exp) UNOP (operator-, mpz_neg) UNOP (operator~, mpz_com) UNOP (abs, mpz_abs) UNOP (sqrt, mpz_sqrt) CMPOPX (<) CMPOPX (>) CMPOPX (<=) CMPOPX (>=) CMPOPX (==) CMPOPX (!=) #undef MPMPOP #undef MPUIOP #undef MPUICOP #undef BINOP #undef CBINOP #undef UNOP #undef CMOPOPX inline int sgn (const bigint &a) { return mpz_sgn (&a); } inline bool operator! (const bigint &a) { return !sgn (a); } inline const bigint & operator+ (const bigint &a) { return a; } inline void _invert0 (MP_INT *r, const MP_INT *a, const MP_INT *b) { bigint gcd; mpz_gcdext (&gcd, r, NULL, a, b); if (gcd._mp_size != 1 || gcd._mp_d[0] != 1) r->_mp_size = 0; else if (r->_mp_size < 0) mpz_add (r, r, b); } inline mpdelayed invert (const bigint &a, const bigint &mod) { return mpdelayed (&_invert0, &a, &mod); } inline mpdelayed pow (const bigint &a, u_long ui) { return mpdelayed (mpz_pow_ui, &a, ui); } inline mpdelayed powm (const bigint &base, const bigint &exp, const bigint &mod) { return mpdelayed (mpz_powm, &base, &exp, &mod); } inline mpdelayed powm (const bigint &base, const bigint &exp, const MP_INT *mod) { return mpdelayed (mpz_powm, &base, &exp, mod); } inline mpdelayed powm (const bigint &base, u_long ui, const bigint &mod) { return mpdelayed (mpz_powm_ui, &base, ui, &mod); } inline mpdelayed powm (const bigint &base, u_long ui, const MP_INT *mod) { return mpdelayed (mpz_powm_ui, &base, ui, mod); } inline mpdelayed bigint::operator++ (int) { return mpdelayed (mpz_sub_ui, &++*this, 1); } inline mpdelayed bigint::operator-- (int) { return mpdelayed (mpz_add_ui, &--*this, 1); } inline u_long mod (const bigint &a, u_long b) { static bigint junk; return mpz_mod_ui (&junk, &a, b); } inline u_long gcd (const bigint &a, u_long b) { return mpz_gcd_ui (NULL, &a, b); } inline u_long gcd (u_long b, const bigint &a) { return mpz_gcd_ui (NULL, &a, b); } inline u_long hamdist (const bigint &a, const bigint &b) { return mpz_hamdist (&a, &b); } inline int jacobi (const bigint &a, const bigint &b) { return mpz_jacobi (&a, &b); } inline int legendre (const bigint &a, const bigint &b) { return mpz_legendre (&a, &b); } #ifdef _ARPC_XDRMISC_H_ inline bool rpc_traverse (XDR *xdrs, bigint &obj) { return xdr_mpz_t (xdrs, &obj); } inline bool rpc_traverse (const stompcast_t, bigint &obj) { return true; } #define xdr_bigint reinterpret_cast (xdr_mpz_t) // XXX RPC_TYPE2STR_DECL (bigint) inline RPC_PRINT_GEN (bigint, sb << obj) inline bool xdr_putbigint (XDR *xdrs, const bigint &obj) { assert (xdrs->x_op == XDR_ENCODE); return xdr_mpz_t (xdrs, const_cast (&obj)); } inline bool xdr_getbigint (XDR *xdrs, bigint &obj) { assert (xdrs->x_op == XDR_DECODE); return xdr_mpz_t (xdrs, &obj); } #endif /* _ARPC_XDRMISC_H_ */ inline void swap (bigint &a, bigint &b) { a.swap (b); } #endif /* __cplusplus */ #endif /* _SFS_BIGINT_H_ */