| #include "BigIntegerAlgorithms.hh" | |
| BigUnsigned gcd(BigUnsigned a, BigUnsigned b) { | |
| BigUnsigned trash; | |
| // Neat in-place alternating technique. | |
| for (;;) { | |
| if (b.isZero()) | |
| return a; | |
| a.divideWithRemainder(b, trash); | |
| if (a.isZero()) | |
| return b; | |
| b.divideWithRemainder(a, trash); | |
| } | |
| } | |
| void extendedEuclidean(BigInteger m, BigInteger n, | |
| BigInteger &g, BigInteger &r, BigInteger &s) { | |
| if (&g == &r || &g == &s || &r == &s) | |
| throw "BigInteger extendedEuclidean: Outputs are aliased"; | |
| BigInteger r1(1), s1(0), r2(0), s2(1), q; | |
| /* Invariants: | |
| * r1*m(orig) + s1*n(orig) == m(current) | |
| * r2*m(orig) + s2*n(orig) == n(current) */ | |
| for (;;) { | |
| if (n.isZero()) { | |
| r = r1; s = s1; g = m; | |
| return; | |
| } | |
| // Subtract q times the second invariant from the first invariant. | |
| m.divideWithRemainder(n, q); | |
| r1 -= q*r2; s1 -= q*s2; | |
| if (m.isZero()) { | |
| r = r2; s = s2; g = n; | |
| return; | |
| } | |
| // Subtract q times the first invariant from the second invariant. | |
| n.divideWithRemainder(m, q); | |
| r2 -= q*r1; s2 -= q*s1; | |
| } | |
| } | |
| BigUnsigned modinv(const BigInteger &x, const BigUnsigned &n) { | |
| BigInteger g, r, s; | |
| extendedEuclidean(x, n, g, r, s); | |
| if (g == 1) | |
| // r*x + s*n == 1, so r*x === 1 (mod n), so r is the answer. | |
| return (r % n).getMagnitude(); // (r % n) will be nonnegative | |
| else | |
| throw "BigInteger modinv: x and n have a common factor"; | |
| } | |
| BigUnsigned modexp(const BigInteger &base, const BigUnsigned &exponent, | |
| const BigUnsigned &modulus) { | |
| BigUnsigned ans = 1, base2 = (base % modulus).getMagnitude(); | |
| BigUnsigned::Index i = exponent.bitLength(); | |
| // For each bit of the exponent, most to least significant... | |
| while (i > 0) { | |
| i--; | |
| // Square. | |
| ans *= ans; | |
| ans %= modulus; | |
| // And multiply if the bit is a 1. | |
| if (exponent.getBit(i)) { | |
| ans *= base2; | |
| ans %= modulus; | |
| } | |
| } | |
| return ans; | |
| } |