-
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
Cleaner infinity handling in group law and ecmult_const. #791
Conversation
The second commit is an alternative to #789. |
Verified that indeed it isn't constant time on the point:
|
Can someone with access please kick travis to clear the spurious failure? |
Done. |
It seems s390x doesn't really work; I think we need to disable it again unfortunately. See #794. |
I'll rebase when 794 is merged. |
utACK 6e712dc Seems s390x is green again; let's hope it stays that way. |
Okay, then this doesn't need to be rebased. Unsurprisingly, no gross performance loss, FWIW: Before: I think that tiny difference is real but it might be compiler alignment noise. |
In the first commit, both modified functions currently have |
Yep. I didn't intend to change their infinity-handling-ness beyond making them less wrong. (for the second function too, making those handle infinities would be non-trivial) |
Yeah okay, I suspect that the fix is not that easy but I didn't bother to understand the code when I wrote the comment. But then, this seems to me like a little code smell to do Okay, so... It anyway does not make a lot to for this functions to support infinity but maybe it's a good idea to add an additional comment to the doc header that |
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.
make x/y/z always initialized for infinity.
That z implies this is for gej only?
@jonasnick What non-gej-outputting function are you thinking of? |
Rebased and added a comment that secp256k1_ecmult_odd_multiples_table's a argument cannot be infinity. |
As it seems this should be adding a strict invariant that ge/gej objects always have sane coordinates, I added checks for that in VERIFY mode: https://github.com/sipa/secp256k1/commits/202009_pr791. There was one place where this is violated ( |
Your branch needs a patch along the lines of diff --git a/src/group_impl.h b/src/group_impl.h
index 950b51d..b8ed209 100644
--- a/src/group_impl.h
+++ b/src/group_impl.h
@@ -197,6 +197,8 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
r[i].infinity = a[i].infinity;
if (!a[i].infinity) {
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
+ } else {
+ secp256k1_ge_set_infinity(&r[i]);
}
secp256k1_ge_verify(&r[i]);
} or the tests call ge_verify on incompletely initialized elements. |
Fixed. The r[i].infinity = a[i].infinity; line above can be removed now. |
If we want to initialize the coords here in the |
@real-or-random Good to point that out, the changes here not enough to guarantee that field elements in ge/gej are always initialized, and I wonder why the tests don't catch that. If we're going in the direction of actually enforcing that invariant, we should make both changes. |
Was thinking of |
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 95d8d92 diff looks good, tests pass
Let's address these nits somewhere else.
} | ||
|
||
static void secp256k1_gej_clear(secp256k1_gej *r) { | ||
r->infinity = 0; | ||
secp256k1_fe_clear(&r->x); | ||
secp256k1_fe_clear(&r->y); | ||
secp256k1_fe_clear(&r->z); | ||
secp256k1_gej_verify(r); |
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: I believe this is conceptually wrong. The purpose of the clear function is nuke the contents of the element, so those functions are not supposed to uphold any invariants. But it doesn't matter for this PR, I can clean this up in #636 .
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.
Agree.
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 got lost in rebase as well.
if (secp256k1_ge_is_infinity(a)) { | ||
secp256k1_gej_set_infinity(r); | ||
return; | ||
} |
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: Indentation
I think after this PR (and #814) we initialize group elements fully everywhere, and we could introduce VG_CHECKs for this. |
Yeah, there could be |
ACK 95d8d92 the diff looks correct and reasonable |
A rebased version of this PR, with @real-or-random's nit above addressed is here: https://github.com/sipa/secp256k1/commits/202009_pr791 |
I switched this to sipa's rebase. |
This seems to be ready for merge but needs rebase. |
Oh sorry, we should just have merged this earlier, I think we had the ACKs. :/ |
Infinity isn't currently needed here, but correctly handling it is a little more safe against future changes. Update docs for it to make it clear that it is not constant time in Q. It never was constant time in Q (and would be a little complicated to make constant time in Q). If it was later made constant time in Q infinity support would be easy to preserve, e.g. by running it on a dummy value and cmoving infinity into the output.
Also define it even when VERIFY is not set (as a no-op), to avoid conditions when calling 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.
re-ACK by verifying against rebasing myself, but a few small improvements got lost.
@@ -150,6 +150,10 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons | |||
|
|||
/* build wnaf representation for q. */ | |||
int rsize = size; | |||
if (secp256k1_ge_is_infinity(a)) { | |||
secp256k1_gej_set_infinity(r); |
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.
I believe this got lost in rebase: wrong indentation
} | ||
|
||
static void secp256k1_gej_clear(secp256k1_gej *r) { | ||
r->infinity = 0; | ||
secp256k1_fe_clear(&r->x); | ||
secp256k1_fe_clear(&r->y); | ||
secp256k1_fe_clear(&r->z); | ||
secp256k1_gej_verify(r); |
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 got lost in rebase as well.
} | ||
|
||
static void secp256k1_ge_clear(secp256k1_ge *r) { | ||
r->infinity = 0; | ||
secp256k1_fe_clear(&r->x); | ||
secp256k1_fe_clear(&r->y); | ||
secp256k1_ge_verify(r); |
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 too.
needs rebase |
Rebased as #1299. |
…up verification bbc8344 Avoid secp256k1_ge_set_gej_zinv with uninitialized z (Pieter Wuille) 0a2e0b2 Make secp256k1_{fe,ge,gej}_verify work as no-op if non-VERIFY (Pieter Wuille) f202667 Add invariant checking to group elements (Pieter Wuille) a18821d Always initialize output coordinates in secp256k1_ge_set_gej (Pieter Wuille) 3086cb9 Expose secp256k1_fe_verify to other modules (Pieter Wuille) a0e696f Make secp256k1_ecmult_const handle infinity (Gregory Maxwell) Pull request description: Rebase of #791. * Clean up infinity handling, make x/y/z always initialized for infinity. * Make secp256k1_ecmult_const handle infinity. * Infinity isn't currently needed here, but correctly handling it is a little more safe against future changes. * Update docs for it to make it clear that it is not constant time in Q. It never was constant time in Q (and would be a little complicated to make constant time in Q: needs a constant time addition function that tracks RZR). It isn't typical for ECDH to be constant time in terms of the pubkey. If it was later made constant time in Q infinity support would be easy to preserve, e.g. by running it on a dummy value and cmoving infinity into the output. * Add group verification (`secp256k1_ge_verify` and `secp256k1_gej_verify`, mimicking `secp256k1_fe_verify`). * Make the `secp256k1_{fe,ge,gej}_verify` functions also defined (as no-ops) in non-VERIFY mode. ACKs for top commit: jonasnick: ACK bbc8344 real-or-random: ACK bbc8344 Tree-SHA512: 82cb51faa2c207603aa10359a311ea618fcb5a81ba175bf15515bf84043223db6428434875854cdfce9ae95f9cfd68c74e4e415f26bd574f1791b5dec1615d19
Clean up infinity handling, make x/y/z always initialized for infinity.
Make secp256k1_ecmult_const handle infinity.
Infinity isn't currently needed here, but correctly handling it is a little more safe against future changes.
Update docs for it to make it clear that it is not constant time in Q. It never was constant time in Q (and would be a little complicated to make constant time in Q: needs a constant time addition function that tracks RZR). It isn't typical for ECDH to be constant time in terms of the pubkey.
If it was later made constant time in Q infinity support would be easy to preserve, e.g. by running it on a dummy value and cmoving infinity into the output.