Disabling overflow checks on crate's level


#1

Context

I am writing a crypto library NaCl in pure Rust. Cryptography uses overflow, and all of files in the library need integer overflow to be allowed. I currently have in my .cargo/config file the following lines:

[build]
rustflags = [ "-Z", "force-overflow-checks=off" ]

Without this configuration tests do not run, panicking on overflows

Problem

But such setting is not good, as all of my work now has a flag, turning a check off, where it may save me.

Or, when someone clones my repo and tries cargo test, panics will show. Asking to set a flag that will apply everywhere is sort of impolite :face_with_raised_eyebrow:

Question

Is there other way to allow integer overflow without changing a global configuration?
Can it be a setting in Cargo.toml? If yes, how should it look?
Can it be a setting per file with #![...]? If yes, how should it look?

Thank you in advance.


#2

Overflow checks by default are enabled only for debug builds. But either way I would strongly recommend to use explicit wrapping_* methods or Wrapping wrapper type in your code instead of the approach you had in mind.

UPD: BTW take a look at RustCrypto org, maybe you could use some of the crates from there, and/or contribute some of your work to it.


#3

@newpavlov I’ll add this to the problem

Problem (continued)

Wow. Indeed, code that uses wraps becomes less readable with wraps all over.
Readability in crypto code counts even higher than in a less critical code.


#4

If wrapping is the right-way ™, is it a zero-cost at runtime? I hope, but where is a proof?


#5

https://godbolt.org/g/MBVYjT


#6

If you don’t like explicit wrapping_* methods, then use Wrapping type. Yes, wrapping operations are zero-cost and compile down to a single assembly instruction (if we are not talking about 128 bit types), it is essentially just an explicit way to disable overflow checks and express that wrapping is indeed the desired behavior. You can always inspect assembly if you want.


#7

@emoon @newpavlov
This is convincing.

So, I should do

use std::num::Wrapping; 

How will it look for arrays on stack?

let mut a: [Wrapping<u8>; 32] = [Wrapping(0); 32];

#8

Yes, it will look like you wrote. (though do not forget that this will not carry on overflows, i.e. [Wrapping<u8>; 32] is not equivalent to 256-bit integer) You can always use playground to test your code.


#9

@newpavlov
I appreciate your concern :slight_smile:, yet don’t worry about 256-bit integers.
This is simply writing NaCl C code which was completely assembled by cryptographers. NaCl doesn’t expose a human developer to dealing with primitives. With AES and SHA primitives, I have to assemble my crypto ferrari out of parts. NaCl gives you assembled crypto ferrari. Creation of NaCl was motivated by observation that in previous decade most if not all problems came from how developers miss-assembled crypto primitives, leading to security flaws. Resulting NaCl code is everything you want, constant time, can’t be misused (modulo reuse of nonce :slight_smile: ), etc. So, I am simply bringing it to Rust.