utils.py 1.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940
  1. def extended_euclidean_algorithm(a, b):
  2. """
  3. Returns a three-tuple (gcd, x, y) such that
  4. a * x + b * y == gcd, where gcd is the greatest
  5. common divisor of a and b.
  6. This function implements the extended Euclidean
  7. algorithm and runs in O(log b) in the worst case.
  8. """
  9. s, old_s = 0, 1
  10. t, old_t = 1, 0
  11. r, old_r = b, a
  12. while r != 0:
  13. quotient = old_r // r
  14. old_r, r = r, old_r - quotient * r
  15. old_s, s = s, old_s - quotient * s
  16. old_t, t = t, old_t - quotient * t
  17. return old_r, old_s, old_t
  18. def inverse_of(n, p):
  19. """
  20. Returns the multiplicative inverse of
  21. n modulo p.
  22. This function returns an integer m such that
  23. (n * m) % p == 1.
  24. """
  25. gcd, x, y = extended_euclidean_algorithm(n, p)
  26. assert (n * x + p * y) % p == gcd
  27. if gcd != 1:
  28. # Either n is 0, or p is not a prime number.
  29. raise ValueError(
  30. '{} has no multiplicative inverse '
  31. 'modulo {}'.format(n, p))
  32. else:
  33. return x % p