diff options
author | Torbjorn Granlund <tege@gmplib.org> | 2009-12-23 05:30:08 +0100 |
---|---|---|
committer | Torbjorn Granlund <tege@gmplib.org> | 2009-12-23 05:30:08 +0100 |
commit | 857b60452cc26bd4705a0a0ed5a99e5b7d32539a (patch) | |
tree | 664a8801c854b737df459c8dc725a3a3ae108441 /mpz/powm_sec.c | |
parent | 09103509a876320e3e5b26bc0644a632a0326f6f (diff) | |
download | gmp-857b60452cc26bd4705a0a0ed5a99e5b7d32539a.tar.gz |
Add function mpz_powm_sec.
Diffstat (limited to 'mpz/powm_sec.c')
-rw-r--r-- | mpz/powm_sec.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/mpz/powm_sec.c b/mpz/powm_sec.c new file mode 100644 index 000000000..2432fe498 --- /dev/null +++ b/mpz/powm_sec.c @@ -0,0 +1,90 @@ +/* mpz_powm_sec(res,base,exp,mod) -- Set R to (U^E) mod M. + + Contributed to the GNU project by Torbjorn Granlund. + +Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2002, 2005, 2008, 2009 +Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +The GNU MP Library 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 Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ + + +#include "gmp.h" +#include "gmp-impl.h" + + +void +mpz_powm_sec (mpz_ptr r, mpz_srcptr b, mpz_srcptr e, mpz_srcptr m) +{ + mp_size_t n; + mp_ptr rp, tp; + mp_srcptr bp, ep, mp; + mp_size_t rn, bn, es, en; + TMP_DECL; + + n = ABSIZ(m); + if (n == 0) + DIVIDE_BY_ZERO; + + mp = PTR(m); + + if (mp[0] % 2 == 0) + DIVIDE_BY_ZERO; + + es = SIZ(e); + if (UNLIKELY (es <= 0)) + { + mpz_t new_b; + if (es == 0) + { + /* b^0 mod m, b is anything and m is non-zero. + Result is 1 mod m, i.e., 1 or 0 depending on if m = 1. */ + SIZ(r) = n != 1 || mp[0] != 1; + PTR(r)[0] = 1; + return; + } + DIVIDE_BY_ZERO; + } + + en = es; + bn = ABSIZ(b); + + TMP_MARK; + tp = TMP_ALLOC_LIMBS (n + mpn_powm_sec_itch (bn, en, n)); + + rp = tp; tp += n; + + bp = PTR(b); + ep = PTR(e); + + mpn_powm_sec (rp, bp, bn, ep, en, mp, n, tp); + + rn = n; + + MPN_NORMALIZE (rp, rn); + + if ((ep[0] & 1) && SIZ(b) < 0 && rn != 0) + { + mpn_sub (rp, PTR(m), n, rp, rn); + rn = n; + MPN_NORMALIZE (rp, rn); + } + + MPZ_REALLOC (r, rn); + SIZ(r) = rn; + MPN_COPY (PTR(r), rp, rn); + + TMP_FREE; +} |