-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Faster const-time modinv divsteps #1031
Conversation
Wowwow, calm down! |
See https://github.com/sipa/secp256k1/commits/pr1031 for two commits on top of this. One renames your delta to theta (as the variable operated on is really defined as delta-1/2 compared to delta as defined in the paper). The other updates the writeup to reflect the improvements here. Concept ACK in any case. I'll look over the code in more detail, but at least this convinces me it's correct. |
As I understand, this should always be faster and we don't need lots of benchmarks to confirm.
Nice, I wanted to ask for this. |
Updated my branch with additional assertions and a few more improvements to the documentation. Code review ACK. I'm happy to do my changes on top in a separate PR, though it's probably better to include them, as a few code comments are out of that as-is in this PR. Feel free to cherry-pick or otherwise include my suggested changes. |
@sipa Never! So, after I PR'ed this, I sat there looking at the code and thinking: you know, there's a lot of low zeros in u/v/q/r... you could almost fit an f/g in there... (a few moments later) https://github.com/peterdettman/secp256k1/tree/vec_modinv I won't spoiler it, but you might like to benchmark const-time inverses in that branch... |
@peterdettman Nice! Benchmarks on Ryzen 5950x (default compilation options, GCC 11.2.0,
This seems to at least suggest the option of throwing out the vartime matrix computation code, and using this new constant-time code for both? The last option (if someone else wants to benchmark) is simply this on top of https://github.com/peterdettman/secp256k1/tree/vec_modinv: @@ -568,7 +568,7 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
while (1) {
/* Compute transition matrix and new eta after 62 divsteps. */
secp256k1_modinv64_trans2x2 t;
- eta = secp256k1_modinv64_divsteps_62_var(eta, f.v[0], g.v[0], &t);
+ eta = secp256k1_modinv64_divsteps_59(eta, f.v[0], g.v[0], &t);
/* Update d,e using that transition matrix. */ |
Wow, that's even more improvement than on my machine. Around 4900 cycles, right? For the _var version, if copying the vec approach at minimum the vartime version would want to escape at the halfway mark if g1 is 0 (mod remaining steps) already, so I think there would still be a separate version. I haven't really looked at it though. |
@peterdettman A vartime version of the vec matrix code could perhaps also do more than 59 iterations. |
It could trivially do 60. The current core vec loop tops out at 30. In theory I think it can do 31, but it's not a given until I work it through. |
Benchmarks on ARM64 (Cortex-A53, default compilation options, GCC 9.3.0,
Looks like we shouldn't throw out the vartime matrix code just yet... |
487af7b
to
6afd499
Compare
ACK 6afd499 @robot-dreams Perhaps you're interested in reviewing this too? @peterdettman Given that your later (and much more significant) improvement builds on top of this one (at least conceptually, using initially-shifted u,v,q,r variables) and doesn't work for 32 bit yet, I'd vote to get this change merged as-is, and do the rest in a follow-up. WDYT? |
@sipa Yeah, we may as well merge this, since the other one is still under experimentation and will in any case require significant write-up and VERIFY checks. |
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.
Thanks for the tag @sipa ! You're right, I'm definitely interested in this change 😄
I took an initial look at the new writeup and it looks correct so far, but I still need to sleep on it and then review the new C implementation carefully.
doc/safegcd_implementation.md
Outdated
"""Compute zeta and transition matrix t after N divsteps (multiplied by 2^N).""" | ||
u, v, q, r = 1, 0, 0, 1 # start with identity matrix | ||
def divsteps_n_matrix(theta, f, g): | ||
"""Compute delta and transition matrix t after N divsteps (multiplied by 2^N).""" |
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.
Nit: theta, since that's what's returned?
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.
ACK 6afd499
I checked the writeup updates, made sure the updated Python code produced the same transition matrices as before (using various small parameters), and then compared the Python vs. C implementations line by line.
Am I understanding correctly that removing 3 subtractions from the inner loop gives such a dramatic speedup?
@sipa gave numbers from a different branch of mine that is more radical. This PR probably only gives a few percent, and maybe nothing if the processor could have executed them in parallel anyway. Edit: "in parallel" meaning using otherwise idle ALUs/registers, although it's also possible to have f/u/v, g/q/r, x/y/z be vectorized, in which case there might only even be the one operation saved. |
169e61c
to
9d25987
Compare
@sipa I'm currently assuming that you will get to the nits that @robot-dreams had above about safegcd_implementation.md, but I'll sort them out next week if not. |
See my updated branch https://github.com/sipa/secp256k1/commits/pr1031 . I've edited the "Update safegcd writeup to reflect the code" commit to address @robot-dreams's comments. |
b89ec94
to
a41fbcd
Compare
Thanks, @sipa. Squashed one spelling fix into my last commit. |
- Add explanation for 59 divsteps vs 2^62 scaling
a41fbcd
to
7e2acda
Compare
Rebased on top of merged #1000: https://github.com/sipa/secp256k1/commits/pr1031 |
I've taken the liberty to open a rebased PR of this #1197. |
Closing in favor of #1197 |
Changes to _divsteps_59 (_30) that give maybe 4% speed improvement to const-time modinv on 64 bit. I see a larger gain on 32 bit but measured on 64 bit so might not be real.
Start the result matrix scaled by 2^62 (resp. 2^30) and shift q, r down instead of u, v up at each step (should make life easier for vectorization). Since we're always shifting away the LSB of g, q, r, we can avoid doing a full negation for x, y, z (after a few tweaks). Then it makes sense to switch zeta back to delta (I confined this change to the local method for the moment).