-
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
Initialize field elements when resulting in infinity #699
Initialize field elements when resulting in infinity #699
Conversation
Output of valgrind without commit 47a7b83 :
|
I don't expect this to have a measurable performance impact, so ok. But conceptually, why is this necessary? Not initializing variables in C is very much allowed by the language. |
@sipa It's not necessary, and I wanted to add a line saying that it's fine if people disagree :) (but forgot) so this shouldn't really affect things. it's just that I spent the whole day on valgrind figuring this out :) (ran a check on the field element without first checking if it's infinity and one of my tests triggered an infinity) (you can easily encounter it when writing protocols that allow infinities (unlike ECDSA/Schnorr etc.)) |
Yeah, I think it's worth doing this. I've run into this issue as well when writing unit tests (though now that I know about it it's usually a quick fix). |
The FE are meaningless when infinity is set, any code accessing them is buggy-- in the var functions they can be set to zero but elsewhere they could end up as random numbers and I don't think setting them to zero can always be costless. I suppose if it's actually costless then it would be okay if its done consistently. |
Regarding "any code accessing them is buggy", I believe the places I ran into valgrind-apparent trouble were memcpy'ing or assigning infinite group elements. This is very rarely (never?) done in the real code but in unit tests it's pretty common. |
Memcpying uninitilized data should be hunky dory, otherwise you could essentially never copy structs which may have uninitilable padding. |
I think I'd be fine with either accepting or not accepting this PR but I'm somewhat reluctant to changes of this kind. The current code is correct. And some parts of the library are heavily written with performance in mind, and this PR would break with this style in some sense. I guess there are lots of similar things that we could make "safer" but I think this is not worth the effort and it may be a step back in terms of performance. |
Ignoring versions, even the C committee itself does not really agree on whether this should be UB or not. So who knows what compilers will assume in the future?
So in this particular case, it may actually be preferable to be careful and make sure we err on side of caution... |
Given the discussion in #791, ACK. The changes here are all in exceptional branches (doubling/infinity being hit in generic addition functions, which should in non-adverserial cases only be hit with negligible probability). |
That's a great point. ACK 47a7b83 |
Summary: * Added test with additions resulting in infinity * Clear field elements when writing infinity This is a backport of secp256k1 [[bitcoin-core/secp256k1#699 | PR699]] Test Plan: ninja check-secp256k1 Reviewers: #bitcoin_abc, jasonbcox Reviewed By: #bitcoin_abc, jasonbcox Subscribers: jasonbcox Differential Revision: https://reviews.bitcoinabc.org/D7611
Summary: * Added test with additions resulting in infinity * Clear field elements when writing infinity This is a backport of secp256k1 [[bitcoin-core/secp256k1#699 | PR699]] Test Plan: ninja check-secp256k1 Reviewers: #bitcoin_abc, jasonbcox Reviewed By: #bitcoin_abc, jasonbcox Subscribers: jasonbcox Differential Revision: https://reviews.bitcoinabc.org/D7611
Currently if
secp256k1_gej_add_var
/secp256k1_gej_add_ge_var
/secp256k1_gej_add_zinv_var
receiveP + (-P)
it will setgej->infinity = 1
but doesn't call initialize the field elements.Notice that this is the only branch in the function that results in an uninitialized output.
By using
secp256k1_gej_set_infinity()
it will set the field elements to zero while also setting the infinity flag.I also added a test that fails with valgrind on current master but passes with the fix.
EDIT: This isn't a bug or something necessary, I just personally found this helpful.