Skip to content

Commit 8e54cfa

Browse files
committed
speed up inverse_mod
since the divmod() is comparatively expensive, and inverse_mod() is extensively used, use a slightly different implementation that doesn't use it
1 parent 5ad395e commit 8e54cfa

File tree

2 files changed

+15
-24
lines changed

2 files changed

+15
-24
lines changed

README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ On an Intel Core i7 4790K @ 4.0GHz I'm getting the following performance:
4949

5050
```
5151
siglen keygen keygen/s sign sign/s verify verify/s
52-
NIST192p: 48 0.02193s 45.60 0.01167s 85.71 0.02307s 43.34
53-
NIST224p: 56 0.02993s 33.42 0.01595s 62.71 0.03157s 31.68
54-
NIST256p: 64 0.03937s 25.40 0.02131s 46.92 0.04212s 23.74
55-
NIST384p: 96 0.09177s 10.90 0.04844s 20.64 0.09787s 10.22
56-
NIST521p: 132 0.17622s 5.67 0.09454s 10.58 0.18823s 5.31
57-
SECP256k1: 64 0.03940s 25.38 0.02124s 47.07 0.04137s 24.17
52+
NIST192p: 48 0.01586s 63.05 0.00853s 117.26 0.01624s 61.58
53+
NIST224p: 56 0.02153s 46.46 0.01145s 87.36 0.02307s 43.35
54+
NIST256p: 64 0.02850s 35.09 0.01500s 66.65 0.02925s 34.19
55+
NIST384p: 96 0.06664s 15.01 0.03512s 28.48 0.06887s 14.52
56+
NIST521p: 132 0.13048s 7.66 0.07050s 14.18 0.13673s 7.31
57+
SECP256k1: 64 0.02809s 35.60 0.01531s 65.32 0.03113s 32.12
5858
```
5959

6060
For comparison, a highly optimised implementation (including curve-specific

src/ecdsa/numbertheory.py

+9-18
Original file line numberDiff line numberDiff line change
@@ -202,27 +202,18 @@ def square_root_mod_prime(a, p):
202202

203203

204204
def inverse_mod(a, m):
205-
"""Inverse of a mod m."""
205+
"""Inverse of a mod m."""
206206

207-
if a < 0 or m <= a:
208-
a = a % m
207+
if a == 0:
208+
return 0
209209

210-
# From Ferguson and Schneier, roughly:
210+
lm, hm = 1, 0
211+
low, high = a % m, m
212+
while low > 1:
213+
r = high // low
214+
lm, low, hm, high = hm - lm * r, high - low * r, lm, low
211215

212-
c, d = a, m
213-
uc, vc, ud, vd = 1, 0, 0, 1
214-
while c != 0:
215-
q, c, d = divmod(d, c) + (c,)
216-
uc, vc, ud, vd = ud - q * uc, vd - q * vc, uc, vc
217-
218-
# At this point, d is the GCD, and ud*a+vd*m = d.
219-
# If d == 1, this means that ud is a inverse.
220-
221-
assert d == 1
222-
if ud > 0:
223-
return ud
224-
else:
225-
return ud + m
216+
return lm % m
226217

227218

228219
def gcd2(a, b):

0 commit comments

Comments
 (0)