modp.py 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. from .euclidean import *
  2. from .numbertype import *
  3. # so all IntegersModP are instances of the same base class
  4. class _Modular(FieldElement):
  5. pass
  6. @memoize
  7. def IntegersModP(p):
  8. # assume p is prime
  9. class IntegerModP(_Modular):
  10. def __init__(self, n):
  11. try:
  12. self.n = int(n) % IntegerModP.p
  13. except:
  14. raise TypeError("Can't cast type %s to %s in __init__" %
  15. (type(n).__name__, type(self).__name__))
  16. self.field = IntegerModP
  17. @typecheck
  18. def __add__(self, other):
  19. return IntegerModP(self.n + other.n)
  20. @typecheck
  21. def __sub__(self, other):
  22. return IntegerModP(self.n - other.n)
  23. @typecheck
  24. def __mul__(self, other):
  25. return IntegerModP(self.n * other.n)
  26. def __neg__(self):
  27. return IntegerModP(-self.n)
  28. @typecheck
  29. def __eq__(self, other):
  30. return isinstance(other, IntegerModP) and self.n == other.n
  31. @typecheck
  32. def __ne__(self, other):
  33. return isinstance(other, IntegerModP) is False or self.n != other.n
  34. @typecheck
  35. def __divmod__(self, divisor):
  36. q,r = divmod(self.n, divisor.n)
  37. return (IntegerModP(q), IntegerModP(r))
  38. def inverse(self):
  39. # need to use the division algorithm *as integers* because we're
  40. # doing it on the modulus itself (which would otherwise be zero)
  41. x,y,d = extendedEuclideanAlgorithm(self.n, self.p)
  42. if d != 1:
  43. raise Exception("Error: p is not prime in %s!" % (self.__name__))
  44. return IntegerModP(x)
  45. def __abs__(self):
  46. return abs(self.n)
  47. def __str__(self):
  48. return str(self.n)
  49. def __repr__(self):
  50. return '%d (mod %d)' % (self.n, self.p)
  51. def __int__(self):
  52. return self.n
  53. def __hash__(self):
  54. return hash((self.n, self.p))
  55. IntegerModP.p = p
  56. IntegerModP.__name__ = 'Z/%d' % (p)
  57. IntegerModP.englishName = 'IntegersMod%d' % (p)
  58. return IntegerModP
  59. if __name__ == "__main__":
  60. mod7 = IntegersModP(7)