-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Correct documentation of integer_division_remainder_used #15661
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
base: master
Are you sure you want to change the base?
Conversation
r? @Alexendoo rustbot has assigned @Alexendoo. Use |
Notes for the reviewer:
|
1. Barrett Reduction isn't constant-time, so that was eliminated. 2. The "use instead" example didn't solve the timing attack, so it was eliminated as well. 3. Added some context and recommendations for the user.
@tarcieri you opened the issue that encouraged this lint to exist :3 can I ask you for feedback on this? Like... well, basically on the changes proposed:
|
While an implementation of a Barrett Reduction won't necessarily be constant-time, it's certainly possible to implement a Barrett Reduction in constant-time, which is an extremely common technique in cryptography, and such implementations run in a fixed number of CPU cycles. See Algorithm 6) Barrett Reduction modulo p from this paper: You can read about our constant-time implementation of a Barrett Reduction for the P-256 scalar field here: https://reports.zksecurity.xyz/reports/near-p256/#analysis-of-the-bound-of-barrett-reduction And generally it's covered for cryptographic applications in HAC. See section 14.3.3: https://cacr.uwaterloo.ca/hac/about/chap14.pdf
...if you're talking about CPUs from the '80s like 80286 that predate barrel shifters, sure. These days even a Cortex-M0 has a barrel shifter. Are there any targets Rust actually supports that have non-constant-time bit shift operations? FWIW, on the @RustCrypto crates we do include a caveat about non-constant-time multipliers on e.g. PPC32 targets that short circuit on zero. I am not aware of any other specific cases of CPUs that are tier 1-3 rustc targets where operations like addition, multiplication, and bitwise operations including shifts are not constant-time, though looking over the table of Rust Tier 3 targets, I guess there's a |
@tarcieri nice! I think I'll be adding a lot of those references to the lint in my next push :3 But first.. I have more questions! If you'd have me ^^
Well, you know in cryptography, so you're more aware than I am about the importance of these nuances (and how misinformation has been used in the past to lower cryptographic defenses at the implementor's level)
I don't want the constant-timeness of something be guaranteed by happenstance. The compiler and the language don't guarantee it, so it's currently a sort of implicit guarantee? But not even that... it's more happenstance than anything else. That's why I still hesitate. Maybe the lint should just say all the caveats and not recommend any particular operation 100%
The original example worked because it was replacing a division by 4 with a shift by 2. But:
Given those two things, I wonder how would a more general example look like. One for divisions other than by 2, 4, 8, etc. Or maybe one does not divide by numbers other than 2^n in current cryptography, and I shouldn't worry about it here. |
Short of implementing the algorithm in architecture-specific assembly you can't, or rather mechanisms for ensuring such optimizations won't be applied are nascent. However, the use of division is highly problematic. This lint was motivated by a real-world example, KyberSlash, where a similar vulnerability was seen across multiple implementations in many languages impacted by many compiler versions (including the @RustCrypto The specific mitigation to use is going to be highly algorithm-dependent (the Barrett reduction example comes from Kyberslash FWIW), so perhaps the clippy lint itself shouldn't be prescriptive about the solution, but rather focus on the problem. Seems you were on the same page with that here:
As for this:
Actually cryptography deals quite a bit with dividing by things which aren't powers of two: many asymmetric cryptographic algorithms are built around modular arithmetic where the modulus is something like a very large prime number. The general strategy is to replace the division by algorithms that can be expressed in terms of additions/subtractions, multiplications, and bitwise operations, without data-dependent branches, pointer calculations, or table lookups. A Barrett reduction is one example. Several others are covered in that HAC chapter I linked earlier. Another general approach is to turn division into multiplication using e.g. a(n X)GCD algorithm and/or modular inversions. |
changelog: [
integer_division_remainder_used
]: corrected documentation errors