Coverage for src\pqlattice\integer\_modring.py: 84%

1 from typing import overload

2

3 from ..typing import Array

4 from ._integer import eea

5

6

7@overload

8 def mod(a: int, modulus: int) -> int: ...

9

10

11@overload

12 def mod(a: Array, modulus: int) -> Array: ...

13

14

15 def mod(a: int | Array, modulus: int) -> int | Array:

16 """_summary_

17

18 Parameters

19 ----------

20 a : int | Array

21 _description_

22 modulus : int

23 _description_

24

25 Returns

26 -------

27 int | Array

28 _description_

29 """

30 return a % abs(modulus)

31

32

33@overload

34 def cmodl(a: int, modulus: int) -> int: ...

35

36

37@overload

38 def cmodl(a: Array, modulus: int) -> Array: ...

39

40

41 def cmodl(a: int | Array, modulus: int) -> int | Array:

42 """_summary_

43

44 Parameters

45 ----------

46 a : int | Array

47 _description_

48 modulus : int

49 _description_

50

51 Returns

52 -------

53 int | Array

54 _description_

55 """

56 return mod(a, modulus) - modulus // 2

57

58

59@overload

60 def cmodr(a: int, modulus: int) -> int: ...

61

62

63@overload

64 def cmodr(a: Array, modulus: int) -> Array: ...

65

66

67 def cmodr(a: int | Array, modulus: int) -> int | Array:

68 """_summary_

69

70 Parameters

71 ----------

72 a : int | Array

73 _description_

74 modulus : int

75 _description_

76

77 Returns

78 -------

79 int | Array

80 _description_

81 """

82 return mod(a, modulus) - int(modulus / 2 - 0.1)

83

84

85@overload

86 def modinv(a: int, modulus: int) -> int: ...

87

88

89@overload

90 def modinv(a: Array, modulus: int) -> Array: ...

91

92

93 def modinv(a: int | Array, modulus: int) -> int | Array:

94 """_summary_

95

96 Parameters

97 ----------

98 a : int | Array

99 _description_

100 modulus : int

101 _description_

102

103 Returns

104 -------

105 int | Array

106 _description_

107

108 Raises

109 ------

110 ValueError

111 _description_

112 ValueError

113 _description_

114 """

115 if isinstance(a, int):

116 if mod(a, modulus) == 0:

117 raise ValueError(f"{a} mod {modulus} is zero; Modular inverse does not exist")

118 gcd, a_inv, _ = eea(a, modulus)

119 if gcd != 1:

120 raise ValueError(f"Modular inverse of {a} mod {modulus} does not exist; gcd is equal to {gcd}")

121 else:

122 if (mod(a, modulus) == 0).all():

123 raise ValueError(f"{a} mod {modulus} is zero; Modular inverse does not exist")

124 gcd, a_inv, _ = eea(a, modulus)

125 if (gcd != 1).any():

126 raise ValueError(f"Modular inverse of {a} mod {modulus} does not exist; gcd is equal to {gcd}")

127

128 return mod(a_inv, modulus)

129

130

131@overload

132 def modpow(a: Array, r: int, modulus: int) -> Array: ...

133

134

135@overload

136 def modpow(a: int, r: int, modulus: int) -> int: ...

137

138

139 def modpow(a: int | Array, r: int, modulus: int) -> int | Array:

140 """_summary_

141

142 Parameters

143 ----------

144 a : int | Array

145 _description_

146 r : int

147 _description_

148 modulus : int

149 _description_

150

151 Returns

152 -------

153 int | Array

154 _description_

155 """

156 if r < 0:

157 return modpow(modinv(a, modulus), -r, modulus)

158

159 y, z = 1, a

160 while r != 0:

161 if r % 2 == 1:

162 y = mod(y * z, modulus)

163 r //= 2

164 z = mod(z * z, modulus)

165 return y