// // This file is part of // // CTBignum // // C++ Library for Compile-Time and Run-Time Multi-Precision and Modular Arithmetic // // // This file is distributed under the Apache License, Version 2.0. See the LICENSE // file for details. #ifndef CT_MODULAR_EXP_HPP #define CT_MODULAR_EXP_HPP #include #include #include #include #include #include #include namespace cbn { template constexpr auto mod_exp(big_int a, big_int exp, std::integer_sequence modulus) { // modular exponentiation using Montgomery multiplication constexpr auto N = modulus.size(); constexpr big_int m{Modulus...}; constexpr auto R_mod_m = div(detail::unary_encoding(), m).remainder; constexpr auto Rsq_mod_m = div(detail::unary_encoding<2 * N, 2 * N + 1>(), m).remainder; auto result = R_mod_m; auto base = montgomery_mul(a, Rsq_mod_m, modulus); big_int zero{}; if (exp == zero) return big_int{1}; if (m == big_int{1}) return big_int{0}; while (true) { auto lsb = exp[0] & 1; exp = shift_right(exp, 1); if (lsb) { result = montgomery_mul(base, result, modulus); if (exp == zero) break; } base = montgomery_mul(base, base, modulus); } return montgomery_mul(result, big_int{1}, modulus); } template constexpr auto mod_exp(big_int a, big_int exp, big_int m) { // modular exponentiation using Montgomery multiplication with runtime modulus auto R_mod_m = div(detail::unary_encoding(), m).remainder; auto Rsq_mod_m = div(detail::unary_encoding<2 * N, 2 * N + 1, T>(), m).remainder; T mprime = -detail::inverse_mod(m[0]); auto result = R_mod_m; auto base = montgomery_mul(a, Rsq_mod_m, m, mprime); big_int zero{}; if (exp == zero) return big_int{1}; if (m == big_int{1}) return big_int{0}; while (true) { auto lsb = exp[0] & 1; exp = shift_right(exp, 1); if (lsb) { result = montgomery_mul(base, result, m, mprime); if (exp == zero) break; } base = montgomery_mul(base, base, m, mprime); } return montgomery_mul(result, big_int{1}, m, mprime); } } #endif