00001 00002 /* 00003 The Extended Integer (XInt) Library 00004 A fast, portable C++ library for multi-precision integer math 00005 Copyright 2010 by Chad Nelson 00006 00007 Distributed under the Boost Software License, Version 1.0. 00008 See accompanying file LICENSE_1_0.txt or copy at 00009 http://www.boost.org/LICENSE_1_0.txt 00010 00011 See http://www.boost.org/libs/xint for library home page. 00012 */ 00013 00020 #ifndef BOOST_INCLUDED_XINT_MODULAR_HPP 00021 #define BOOST_INCLUDED_XINT_MODULAR_HPP 00022 00024 namespace boost { 00025 namespace xint { 00026 namespace detail { 00027 00028 BOOST_XINT_RAWINT_TPL 00029 BOOST_XINT_RAWINT mulmod(const BOOST_XINT_RAWINT n, const BOOST_XINT_RAWINT by, 00030 const BOOST_XINT_RAWINT modulus) 00031 { 00032 return n * by % modulus; 00033 } 00034 00035 BOOST_XINT_RAWINT_TPL 00036 BOOST_XINT_RAWINT sqrmod(const BOOST_XINT_RAWINT n, const BOOST_XINT_RAWINT 00037 modulus) 00038 { 00039 return square(n) % modulus; 00040 } 00041 00042 BOOST_XINT_RAWINT_TPL 00043 BOOST_XINT_RAWINT powmod(const BOOST_XINT_RAWINT n, const BOOST_XINT_RAWINT e, 00044 const BOOST_XINT_RAWINT m, bool no_montgomery = false) 00045 { 00046 if (m.is_zero() || m.negative) exception_handler<>::call(__FILE__, __LINE__, 00047 exceptions::invalid_modulus()); 00048 if (e.is_zero()) return 1; 00049 00050 bool neg = (n.negative && e.is_odd()); 00051 00052 // Montgomery's method is often noticeably faster, but only works if the 00053 // m is odd. 00054 if (m.is_odd() && !no_montgomery) { 00055 return montgomeryPowerMod(n.abs() % m, e.abs(), m); 00056 } else { 00057 BOOST_XINT_RAWINT answer(1), p(n.abs()); 00058 00059 std::size_t lastBitCount = 0; 00060 detail::digit_t ee(e[e.length - 1]); 00061 while (ee != 0) { ee >>= 1; ++lastBitCount; } 00062 00063 for (std::size_t eIndex = 0; eIndex < e.length; ++eIndex) { 00064 detail::digit_t ee(e[eIndex]); 00065 00066 int bitCount(int(eIndex == e.length - 1 ? lastBitCount : 00067 detail::bits_per_digit)); 00068 while (bitCount-- > 0) { 00069 if (ee & 0x01) answer = mulmod(answer, p, m); 00070 p = sqrmod(p, m); 00071 ee >>= 1; 00072 } 00073 } 00074 answer.negative = neg; 00075 answer.trim(); 00076 00077 return answer; 00078 } 00079 } 00080 00081 } // namespace detail 00082 } // namespace xint 00083 } // namespace boost 00085 00086 #endif // BOOST_INCLUDED_XINT_MODULAR_HPP
© Copyright Chad Nelson, 2010-2011. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)