Very frequently in cryptography, we have to do calculations on data as though the data is &[64]
or &[32]
and then return the results as &[u8]
. For example, SHA-256 is defined to operate on &[u32]
data and SHA-512 is defined to operate on &[u64]
data, but applications are always going to treat the result on &[u8]
.
I think that many uses of SIMD have similar needs, which is why the SIMD RFC defines simd_insert
and simd_extract
.
In my code, I use std::slice::from_raw_parts
for this:
pub struct Digest {
value: [u64; MAX_OUTPUT_LEN / 8],
algorithm: &'static Algorithm,
}
impl AsRef<[u8]> for Digest {
fn as_ref(&self) -> &[u8] {
unsafe {
std::slice::from_raw_parts(self.value.as_ptr() as *const u8,
self.algorithm.output_len)
}
}
}
One of my goals in my Rust crypto code is to eliminate all uses of unsafe
in it without compromising performance. Consequently, I am interested in extending Rust’s core
library (and thus std
) to expose non-unsafe
alternatives to code that currently requires the use of unsafe
.
There was a similar discussion back in July: Pre-RFC: Explicit Opt-in OIBIT for truly POD data and safe transmutes. Unfortunately, it seems like momentum on that has stopped.
One thing to note in particular is that in C/C++ such conversions are very tricky to get right because of the “strict aliasing rule”, which says that the compiler can assume that pointers to unrelated types don’t alias each other, except that char
/unsigned char
. Rust doesn’t have the same rule as C/C++; see https://doc.rust-lang.org/reference.html#behavior-considered-undefined, in particular the bit about “breaking the pointer aliasing rules.”
Thus, AFAICT, it would be 100% safe to cast &[u64]
to &[u32]
to &[u16]
to &[u8]
, and also it would be safe to cast slices of SIMD types similarly, if Rust exposed a non-unsafe
API for doing so.
Questions:
-
Does anybody disagree that Rust’s aliasing rules allow such conversions?
-
Does anybody think it would be a bad idea to add an API for doing such casts without using
unsafe
tocore
(and thusstd
)? -
Are there existing crates that could serve as the basis for an RFC to add these conversions to
core
? -
The Pref-RFC I linked to above seemed to be hoping to add a quite generic interface for such conversions. However, I think it may be better to define something simpler just for slices of
u8
,u16
,u32
,u64
, and SIMD types. Does anybody strongly disagree?
This would go a long way towards enabling safe (as in no use of unsafe
) cryptography in Rust. (Ignore the lack of side-channel-resistant operations for now. That’s a topic for another day.)