Congruence relation
For a positive integer
it can also be proven that
Which means that
Reordering the equation
Since
Properties
- Reflexive:
since is a multiple of any - Symetric:
(the same as multiplying by ) - Transitive: if
and then
Rules
Let
The following rules apply
Addition/subtraction rule
proof: let
Multiplication rule
proof: let
multiplying both equations
Exponentiation rule
Since
Where
Implementation based on Binary Exponentiation
/**
*
* Computes
*
* a^k % m
*
* Given the fact that a^k can be computed in O(log k) using
* binary exponentiation
*
* @param {int} a
* @param {int} k
* @param {int} m
* @return {int}
*/
int binary_exponentiation_modulo_m(int a, int k, int m) {
if (k == 0) {
// a^0 = 1
return 1;
}
if (k % 2 == 1) {
return (binary_exponentiation_modulo_m(a, k - 1, m) * a) % m;
} else {
int t = binary_exponentiation_modulo_m(a, k / 2, m);
return (t * t) % m;
}
}
Modular multiplicative inverse
Extended Euclidean Algorithm
The multiplicative inverse of a number
Such a number exists only if
The number
Rearranging
This is the exact form of the equation that the Extended Euclidean Algorithm solves where
/**
* Computes the modular mutiplicative inverse of the number `a` in the ring
* of integers modulo `m`
*
* ax ≡ 1 (mod m)
*
* `x` only exists if `a` and `m` are coprimes
*
* @param {int} a
* @param {int} m
* @param {int} x
* @returns {bool} True if the number `a` has a modular multiplicative
* inverse, false otherwise
*/
bool modular_multiplicative_inverse(int a, int m, int &x) {
// the value multiplying `y` is never used
int y;
int gcd = extended_euclidean(a, m, x, y);
if (gcd != 1) {
// `a` and `m` are not coprime
return false;
}
// ensure that the value of `x` is positive
x = (x % m + m) % m;
return true;
}
/**
* Same as above but throws an error if the `a` and `m` are not coprimes
*
* @param {int} a
* @param {int} m
* @returns {int} The modular multiplicative inverse of a
*/
int modular_multiplicative_inverse(int a, int m) {
// the value multiplying `y` is never used
int x, y;
int gcd = extended_euclidean(a, m, x, y);
if (gcd != 1) {
// `a` and `m` are not coprime
throw std::invalid_argument("a and m are not relative primes");
}
// ensure that the value of `x` is positive
x = (x % m + m) % m;
return x;
}
Euler’s Theorem
The modular multiplicative inverse can be also found using Euler’s theorem, if
Where
In the special case where
/**
* Computes the modular multiplicative inverse of `a` in the ring
* of integers modulo `m` using Euler's theorem,
* it assumes that `m` is a prime number and that is relatively prime to `a`
*
* a^{-1} ≡ a^{m - 2} (mod m)
*
* @param {int} a
* @param {int} m
* @returns {int} The modular multiplicative inverse of a
*/
int modular_multiplicative_inverse(int a, int m) {
return binary_exponentiation_modulo_m(a, m - 2, m);
}