mirror of
https://github.com/boostorg/integer.git
synced 2025-07-29 20:27:14 +02:00
[ci skip] Modular exponentiation, modular multiplicative inverse, extended Euclidean algorithm, discrete logarithm.
This commit is contained in:
97
doc/modular_arithmetic/discrete_log.qbk
Normal file
97
doc/modular_arithmetic/discrete_log.qbk
Normal file
@ -0,0 +1,97 @@
|
||||
[section:discrete_log Discrete Log]
|
||||
|
||||
[section Introduction]
|
||||
|
||||
The discrete log is the inverse of modular exponentiation.
|
||||
To wit, if /a/[sup /x/] = /b/ mod /p/, then we write /x/ = log[sub a](/b/).
|
||||
Fast algorithms for modular exponentiation exists, but currently there are no polynomial time algorithms known for the discrete logarithm,
|
||||
a fact which is the basis for the security of Diffie-Hellman key exchange.
|
||||
|
||||
Despite having exponential complexity in the number of bits, the algorithms for discrete logarithm provided by Boost are still useful,
|
||||
for there are many uses of the discrete logarithm outside of cryptography which do not require massive inputs.
|
||||
The algorithms provided by Boost should be acceptable up to roughly 64 bits.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Synopsis]
|
||||
|
||||
#include <boost/integer/discrete_log.hpp>
|
||||
|
||||
namespace boost { namespace integer {
|
||||
|
||||
template<class Z>
|
||||
boost::optional<Z> trial_multiplication_discrete_log(Z base, Z arg, Z p);
|
||||
|
||||
|
||||
template<class Z>
|
||||
class baby_step_giant_step_discrete_log
|
||||
{
|
||||
public:
|
||||
baby_step_giant_step_discrete_log(Z base, Z p);
|
||||
|
||||
Z operator()(Z arg) const;
|
||||
|
||||
};
|
||||
}}
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Usage]
|
||||
|
||||
|
||||
Boost provides two algorithms for the discrete log: Trial multiplication and the "baby-step giant step" algorithm.
|
||||
Basic usage is shown below:
|
||||
|
||||
auto logarithm = trial_multiplication_discrete_log(2, 3, 5);
|
||||
if (logarithm)
|
||||
{
|
||||
std::cout << "log_2(3) mod 5 = " << l.value() << std::endl;
|
||||
}
|
||||
|
||||
auto bsgs = baby_step_giant_step_discrete_log(2, 5);
|
||||
int log = bsgs(3);
|
||||
std::cout << "log_2(3) mod 5 = " << log << std::endl;
|
||||
|
||||
|
||||
Of these, trial multiplication is more general, requires O(/p/) time and O(1) storage.
|
||||
The baby-step giant step algorithm requires O([radic] p) time and O([radic] p) storage, and is slightly less general as the generator must be coprime to the the modulus.
|
||||
Let's illustrate this with a few examples: Suppose we wish to compute log[sub 2](3) mod 4.
|
||||
Since 2[sup x] = 3 mod 4 has no solution, the result is undefined.
|
||||
|
||||
boost::optional<int> l = trial_multiplication_discrete_log(2, 3, 4);
|
||||
if (!l)
|
||||
{
|
||||
std::cout << "log_2(3) mod 4 is undefined!\n";
|
||||
}
|
||||
|
||||
The baby-step giant-step algorithm is less polite when the base and the modulus are not coprime:
|
||||
|
||||
try
|
||||
{
|
||||
auto bsgs = baby_step_giant_step_discrete_log(2, 4);
|
||||
}
|
||||
catch(std::exception const & e)
|
||||
{
|
||||
// e.what() is gonna tell you 2 and 4 are not coprime:
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
|
||||
|
||||
The baby-step giant-step discrete log will *never* compute a logarithm when the generator and modulus are not coprime, because it relies on the existence of modular multiplicative inverses.
|
||||
However, discrete logarithms can exist even when the generator and modulus share a common divisor greater than 1.
|
||||
For example, since 2[sup 1] = 2 mod 4, log[sub 2](2) = 1.
|
||||
Trial multiplication successfully recovers this value, and `baby_step_giant_step_discrete_log` blows up.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section References]
|
||||
Wagstaff, Samuel S., ['The Joy of Factoring], Vol. 68. American Mathematical Soc., 2013.
|
||||
[endsect]
|
||||
[endsect]
|
||||
[/
|
||||
Copyright 2018 Nick Thompson.
|
||||
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).
|
||||
]
|
47
doc/modular_arithmetic/extended_euclidean.qbk
Normal file
47
doc/modular_arithmetic/extended_euclidean.qbk
Normal file
@ -0,0 +1,47 @@
|
||||
[section:extended_euclidean Extended Euclidean Algorithm]
|
||||
|
||||
[section Introduction]
|
||||
|
||||
The extended Euclidean algorithm solves the integer relation /mx + ny/ = gcd(/m/, /n/) for /x/ and /y/.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Synopsis]
|
||||
|
||||
#include <boost/integer/extended_euclidean.hpp>
|
||||
|
||||
namespace boost { namespace integer {
|
||||
|
||||
template<class Z>
|
||||
std::tuple<Z, Z, Z> extended_euclidean(Z m, Z n);
|
||||
|
||||
}}
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Usage]
|
||||
|
||||
The tuple returned by the extended Euclidean algorithm contains, the greatest common divisor, /x/, and /y/, in that order:
|
||||
|
||||
int m = 12;
|
||||
int n = 15;
|
||||
auto tup = extended_euclidean(m, n);
|
||||
|
||||
int gcd = std::get<0>(tup);
|
||||
int x = std::get<1>(tup);
|
||||
int y = std::get<2>(tup);
|
||||
// mx + ny = gcd(m,n)
|
||||
|
||||
[endsect]
|
||||
|
||||
[section References]
|
||||
Wagstaff, Samuel S., ['The Joy of Factoring], Vol. 68. American Mathematical Soc., 2013.
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
[/
|
||||
Copyright 2018 Nick Thompson.
|
||||
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).
|
||||
]
|
51
doc/modular_arithmetic/modular_multiplicative_inverse.qbk
Normal file
51
doc/modular_arithmetic/modular_multiplicative_inverse.qbk
Normal file
@ -0,0 +1,51 @@
|
||||
[section:modular_multiplicative_inverse Modular Multiplicative Inverse]
|
||||
|
||||
[section Introduction]
|
||||
|
||||
The modular multiplicative inverse of a number /a/ is that number /x/ which satisfied /ax/ = 1 mod /p/.
|
||||
A fast algorithm for computing modular multiplicative inverses based on the extended Euclidean algorithm exists and is provided by Boost.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Synopsis]
|
||||
|
||||
#include <boost/integer/modular_multiplicative_inverse.hpp>
|
||||
|
||||
namespace boost { namespace integer {
|
||||
|
||||
template<class Z>
|
||||
boost::optional<Z> modular_multiplicative_inverse(Z a, Z p);
|
||||
|
||||
}}
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Usage]
|
||||
|
||||
Multiplicative modular inverses exist if and only if /a/ and /p/ are coprime.
|
||||
So for example
|
||||
|
||||
auto x = modular_multiplicative_inverse(2, 5);
|
||||
if (x)
|
||||
{
|
||||
int should_be_three = x.value();
|
||||
}
|
||||
auto y = modular_multiplicative_inverse(2, 4);
|
||||
if (!y)
|
||||
{
|
||||
std::cout << "There is no inverse of 2 mod 4\n";
|
||||
}
|
||||
|
||||
[endsect]
|
||||
|
||||
[section References]
|
||||
Wagstaff, Samuel S., ['The Joy of Factoring], Vol. 68. American Mathematical Soc., 2013.
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
[/
|
||||
Copyright 2018 Nick Thompson.
|
||||
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).
|
||||
]
|
Reference in New Issue
Block a user