-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use extended Euclidean algorithm for modular inverse #7
Conversation
div = b | ||
while True: | ||
if div == 0: | ||
return u |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be 4 space indented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, might be easier to write this as while div != 0
and put return u
outside the loop. I don't have a strong opinion on that, but it's how I've seen most reference implementations write it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
Important to ask, Are you OK with this code being licensed as in #6 that PR is just waiting on the OK from the other contributor before i merge it. |
while True: | ||
if div == 0: | ||
return u | ||
qq, div, d = d // div, d % div, div |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
d // div, d %div
might be better implemented with divmod(d, div)
, might save a few cycles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I forgot about divmod
. I'll double check, but you're probably right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least on pypy, divmod actually saves instructions (both div and mod are
implemented in terms of divmod), I assume this is true on CPython as well
On Fri, Oct 4, 2013 at 9:56 PM, Christopher Swenson <
notifications@github.com> wrote:
In ed25519.py:
are both quadratic, so this is likely the fastest way to do this.
See, for example, H. Cohen, A Course in Computational Algebraic Number
Theory, Algorithm 1.3.6
- """
- a, b = z, q
- if b == 0:
return 1
- u = 1
- d = a
- r = 0
- div = b
- while True:
if div == 0:
return u
qq, div, d = d // div, d % div, div
Ah, I forgot about divmod. I'll double check, but you're probably right.
—
Reply to this email directly or view it on GitHubhttps://github.com//pull/7/files#r6782936
.
"I disapprove of what you say, but I will defend to the death your right to
say it." -- Evelyn Beatrice Hall (summarizing Voltaire)
"The people's good is the highest law." -- Cicero
GPG Key fingerprint: 125F 5C67 DFE9 4084
@dstufft I left a comment on the license PR -- I'm actually not okay with that license, but mostly because it is contradictory. |
* Fix docstring formatting * Use divmod for a speedup * Cleanup 2-spacing * Remove unused variables
Updated, now even faster: Time generate 1.10641002655 Time create signature 2.36265206337 Time verify signature 3.46614480019 |
""" | ||
d, div = z, q | ||
if div == 0: | ||
return 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
q
will never be 0, so we can just drop this case, as far as I can tell.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right.
Modulo that comment, and the licensing issue, I think this looks good. I want to get another set of eyes on it though. |
This change seems to have caused it to recurse infinetly, and I don't understand why. |
@@ -92,7 +90,7 @@ def scalarmult(P, e): | |||
if e == 0: | |||
return (0, 1) | |||
|
|||
Q = scalarmult(P, e // 2) | |||
Q = scalarmult(P, e / 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure how that wound up in there. I'll change it back.
@@ -39,22 +39,20 @@ def pow2(x, p): | |||
p -= 1 | |||
return x |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pow2
can be deleted now
Great that this is faster! Glad to see more eyes on the crypto algorithms here. The algorithm looks right, and standard. The one drawback, which is important in some contexts, is that it introduces branches, which means it's vulnerable to timing attacks. This is the reason why DJB didn't use this algorithm for Curve25519, a precursor of this system, and presumably also why he and his collaborators didn't for Ed25519. The Curve25519 paper explains:
http://cr.yp.to/ecdh/curve25519-20060209.pdf (This version isn't randomized to protect against timing attacks, and I don't think we'd want to implement such a version.) The Ed25519 paper just says it does inversion the same way as in Curve25519. This is no problem as long as this code is only used for verifying signatures on public data. It's a serious problem for making signatures. We should use this algorithm only if we remove the signing code from this pure-Python fallback, to make sure nobody unwittingly falls into that vulnerability. Or if we use this algorithm for verifying signatures, and another one for making them. Either way, there should also be a comment warning of the danger. Our existing and previous implementations haven't been carefully secured against branches or loads that depend on potentially secret data -- there might well be such things hidden in the implementation of e.g. long multiplication -- but I believe in principle they could be. At the Python level they're free of such things. |
@gnprice Great point. We can definitely look into reviving the other |
Nice catch @gnprice. I seriously doubt any of this code is timing attack safe (I'm pretty suspicious that you can reliably writing timing attack safe code which runs on CPython or PyPy in general). At a minimum starting to clearly document this would be valuable. |
So for the use case of why I wanted to make ed25519 fast verifying signatures is all we needed. However I do think it'd be nice to have the other operations just for completeness sake. I don't understand the PR itself but if it makes sense to have two implementations for different use cases I think that's reasonable? |
In that case, I think it would make more sense to have a separate file, say, Or, alternatively, make And maybe make a note that if you want it safe and fast, that you should use a C library. :) |
I think before we delve into having multiple APIs, we really need to establish if a) this is remotely timing attack safe now, or b) it has any hope of being so in pure-python. |
@alex I'm not sure it is timing attack resistant at all right -- the |
I'm assuming the word "now" is missing there? On Sat, Oct 5, 2013 at 9:37 AM, Christopher Swenson <
"I disapprove of what you say, but I will defend to the death your right to |
Yup. Right now.
|
I started documenting this in #11 |
Superceded by homogeneous coordinate version. |
This roughly doubles the speed of the ed25519 implementation in Python.
For whatever reason, this is faster than the previous squaring method.
Before:
After: