// // 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_BARRETT_HPP #define CT_BARRETT_HPP #include #include // std::size_t #include #include #include #include #include #include #include namespace cbn { namespace detail { template constexpr auto precompute_mu() { big_int modulus = {Modulus...}; const std::size_t twoN = 2 * sizeof...(Modulus); auto quot_rem = div(detail::unary_encoding(), modulus); return quot_rem.quotient; } } // end namespace detail template constexpr auto barrett_reduction(big_int x, std::integer_sequence) { // Barrett reduction, modulus as a template parameter. using detail::skip; using detail::first; using detail::unary_encoding; using detail::pad; auto mu = detail::precompute_mu(); const std::size_t N2 = sizeof...(Modulus); constexpr auto L = std::max(static_cast(0), static_cast(N2)+1-static_cast(N1)); auto y = pad(x); big_int modulus = {Modulus...}; auto q2approx = mul(skip(y), // skip(mu)); // approximation as suggested in Ch.14 // of "Handbook of Applied Cryptography", // by Menezes and van Oorschot auto q3 = skip<3>(q2approx); // //auto q3 = skip(mul(skip(x),mu)); // this would be the exact version auto r1 = first(y); auto r2 = partial_mul(q3, modulus); auto r_with_carry = subtract(r1, r2); auto r = first(r_with_carry); if (r_with_carry[N2 + 1]) r = add_ignore_carry(r, unary_encoding()); auto padded_mod = pad<1>(modulus); if (r >= padded_mod) r = subtract_ignore_carry(r, padded_mod); if (r >= padded_mod) r = subtract_ignore_carry(r, padded_mod); return first(r); } // specialization for length one template constexpr auto barrett_reduction(big_int<1, T> x, std::integer_sequence) { return big_int<1,T>{ x[0] % Modulus }; } template constexpr auto barrett_reduction(big_int x, big_int modulus, big_int mu) { // Barrett reduction, when given modulus and precomputed value mu that depends // on modulus as ordinary parameters. using detail::skip; using detail::first; using detail::unary_encoding; using detail::pad; auto q2approx = mul(skip(x), skip(mu)); auto q3 = skip<3>(q2approx); auto r1 = first(x); auto r2 = partial_mul(q3, modulus); auto r_with_carry = subtract(r1, r2); auto r = first(r_with_carry); if (r_with_carry[N2 + 1]) r = add_ignore_carry(r, unary_encoding()); auto padded_mod = pad<1>(modulus); if (r >= padded_mod) r = subtract_ignore_carry(r, padded_mod); if (r >= padded_mod) r = subtract_ignore_carry(r, padded_mod); return first(r); } } #endif