@@ -1068,6 +1068,14 @@ iterator `..<`*(a, b: BigInt): BigInt =
10681068 yield res
10691069 inc res
10701070
1071+
1072+ func modulo (a, modulus: BigInt ): BigInt =
1073+ # # Like `mod`, but the result is always in the range `[0, modulus-1]`.
1074+ # # `modulus` should be greater than zero.
1075+ result = a mod modulus
1076+ if result < 0 :
1077+ result += modulus
1078+
10711079func fastLog2 * (a: BigInt ): int =
10721080 # # Computes the logarithm in base 2 of `a`.
10731081 # # If `a` is negative, returns the logarithm of `abs(a)`.
@@ -1076,6 +1084,7 @@ func fastLog2*(a: BigInt): int =
10761084 return - 1
10771085 bitops.fastLog2 (a.limbs[^ 1 ]) + 32 * (a.limbs.high)
10781086
1087+
10791088func invmod * (a, modulus: BigInt ): BigInt =
10801089 # # Compute the modular inverse of `a` modulo `modulus`.
10811090 # # The return value is always in the range `[1, modulus-1]`
@@ -1091,23 +1100,22 @@ func invmod*(a, modulus: BigInt): BigInt =
10911100 raise newException (DivByZeroDefect , " 0 has no modular inverse" )
10921101 else :
10931102 var
1094- r0 = ((a mod modulus) + modulus) mod modulus
1095- r1 = modulus
1096- s0 = one
1097- s1 = zero
1103+ r0 = modulus
1104+ r1 = a.modulo (modulus)
1105+ t0 = zero
1106+ t1 = one
1107+ var rk, tk: BigInt # otherwise t1 is incorrectly inferred as cursor (https://github.com/nim-lang/Nim/issues/19457)
10981108 while r1 > 0 :
1099- let
1100- q = r0 div r1
1101- # the `q.isZero` check is needed because of an ARC/ORC bug (see https://github.com/nim-lang/bigints/issues/88)
1102- rk = if q.isZero: r0 else : r0 - q * r1
1103- sk = if q.isZero: s0 else : s0 - q * s1
1109+ let q = r0 div r1
1110+ rk = r0 - q * r1
1111+ tk = t0 - q * t1
11041112 r0 = r1
11051113 r1 = rk
1106- s0 = s1
1107- s1 = sk
1114+ t0 = t1
1115+ t1 = tk
11081116 if r0 != one:
11091117 raise newException (ValueError , $ a & " has no modular inverse modulo " & $ modulus)
1110- result = ((s0 mod modulus) + modulus) mod modulus
1118+ result = t0. modulo ( modulus)
11111119
11121120func powmod * (base, exponent, modulus: BigInt ): BigInt =
11131121 # # Compute modular exponentation of `base` with power `exponent` modulo `modulus`.
@@ -1127,8 +1135,7 @@ func powmod*(base, exponent, modulus: BigInt): BigInt =
11271135 if exponent < 0 :
11281136 base = invmod (base, modulus)
11291137 exponent = - exponent
1130- var
1131- basePow = ((base mod modulus) + modulus) mod modulus # Base stays in [0, m-1]
1138+ var basePow = base.modulo (modulus)
11321139 result = one
11331140 while not exponent.isZero:
11341141 if (exponent.limbs[0 ] and 1 ) != 0 :
0 commit comments