Repository: RustCrypto/hashes (language: rust)

Issue:
[Feature Request] Disable SIMD with a feature
Hi!

We are developing a new research OS. Even though our OS runs on x86, it currently doesn't support SIMD instructions. It would be nice if there's a feature that allows us to disable the usage of SIMD instructions and use the software implementation instead.

https://github.com/RustCrypto/hashes/blob/bb71874240a8e9f381aa84116168795cedd33357/sha2/src/sha256.rs#L153-L157


Discussion / hints:
Greetings!

AFAIK SIMD instructions and feature detection on x86 do not need OS support. Can you please clarify what do you mean by lack of SIMD support?

Adding a feature for enforcing software implementation should not be hard and it also may be useful for reducing final binary size a bit.
It would probably make more sense to have a (potentially on-by-default) feature for SIMD that could be disabled, rather than taking away functionality with a "feature".
The main problem with such approach is that it becomes effectively impossible to disable this feature if the crate is used as an indirect dependency somewhere in a project dependency tree, since people often don't bother with `default-features = false`. So until we get some kind non-feature-based crate configurability, I think it will be better to use "disabling" features in cases like this.
Thanks for the quick response!

From [OSDev - SSE](https://wiki.osdev.org/SSE#Introduction)
> To support SSE, you will need to implement separate code paths for saving and restoring SSE state.

Since SIMD support is not critical to our paper, our implementation is still in the early stages of discussion.
Note that by default Rust compiler enables SSE2 for x86-64 builds. I thought you plan to use `sha2` in the kernel space, so since no one can interrupt execution of such code (well, of course there are literal hardware interrupts, but I think we can assume that they will not use SSE registers), saving and restoring registers should not matter. If we are talking about user-space applications, then until we implement this feature it should be enough to run your OS on CPU without SHA extension (which is relatively rare today). In this case the library simply will never take path which uses SHA instructions.
Yes, we are using `sha2` in userspace. We use custom target files to prevent the compiler from generating SSE instructions(they look something like [this](https://os.phil-opp.com/minimal-rust-kernel/#putting-it-together)).  

We are currently developing a userspace TPM driver that uses `sha2`. Rustc errors out with the message `LLVM ERROR: Do not know how to split the result of this operator!` when compiling the it. Our workaround is to fork `sha2` and hardcode it to use software implementation regardless of the target architecture.

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index e11fbbdce..c47354ffa 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -223,7 +223,7 @@ dependencies = [
 
 [[package]]
 name = "sha-1"
-version = "0.9.1"
+version = "0.9.2"
 dependencies = [
  "block-buffer",
  "cfg-if",
@@ -246,7 +246,7 @@ dependencies = [
 
 [[package]]
 name = "sha2"
-version = "0.9.1"
+version = "0.9.2"
 dependencies = [
  "block-buffer",
  "cfg-if",
diff --git a/sha1/CHANGELOG.md b/sha1/CHANGELOG.md
index 9fb07c94b..5a76f1cf6 100644
--- a/sha1/CHANGELOG.md
+++ b/sha1/CHANGELOG.md
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## 0.9.2 (2020-11-04)
+### Added
+- `force-soft` feature to enforce use of software implementation. ([#203])
+
+### Changed
+- `cfg-if` dependency updated to v1.0. ([#197])
+
+[#197]: https://github.com/RustCrypto/hashes/pull/197
+[#203]: https://github.com/RustCrypto/hashes/pull/203
+
 ## 0.9.1 (2020-06-24)
 ### Added
 - x86 hardware acceleration via SHA extension instrinsics. ([#167])
diff --git a/sha1/Cargo.toml b/sha1/Cargo.toml
index cc11543b8..1aac6d1e5 100644
--- a/sha1/Cargo.toml
+++ b/sha1/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sha-1"
-version = "0.9.1"
+version = "0.9.2"
 description = "SHA-1 hash function"
 authors = ["RustCrypto Developers"]
 license = "MIT OR Apache-2.0"
@@ -35,6 +35,8 @@ hex-literal = "0.2"
 default = ["std"]
 std = ["digest/std"]
 asm = ["sha1-asm", "libc"]
+# Force software implementation
+force-soft = []
 
 # DEPRECATED: use `asm` instead
 asm-aarch64 = ["asm"]
diff --git a/sha1/src/compress.rs b/sha1/src/compress.rs
index d00dbd1a0..af35679be 100644
--- a/sha1/src/compress.rs
+++ b/sha1/src/compress.rs
@@ -2,7 +2,10 @@ use digest::consts::U64;
 use digest::generic_array::GenericArray;
 
 cfg_if::cfg_if! {
-    if #[cfg(all(feature = "asm", target_arch = "aarch64", target_os = "linux"))] {
+    if #[cfg(feature = "force-soft")] {
+        mod soft;
+        use soft::compress as compress_inner;
+    } else if #[cfg(all(feature = "asm", target_arch = "aarch64", target_os = "linux"))] {
         mod soft;
         mod aarch64;
         use aarch64::compress as compress_inner;
diff --git a/sha2/CHANGELOG.md b/sha2/CHANGELOG.md
index 9c6d5895e..922f32d25 100644
--- a/sha2/CHANGELOG.md
+++ b/sha2/CHANGELOG.md
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## 0.9.2 (2020-11-04)
+### Added
+- `force-soft` feature to enforce use of software implementation. ([#203])
+
+### Changed
+- `cfg-if` dependency updated to v1.0. ([#197])
+
+[#197]: https://github.com/RustCrypto/hashes/pull/197
+[#203]: https://github.com/RustCrypto/hashes/pull/203
+
 ## 0.9.1 (2020-06-24)
 ### Added
 - x86 hardware acceleration of SHA-256 via SHA extension instrinsics. ([#167])
diff --git a/sha2/Cargo.toml b/sha2/Cargo.toml
index 6ed3822c8..5b63154a4 100644
--- a/sha2/Cargo.toml
+++ b/sha2/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sha2"
-version = "0.9.1"
+version = "0.9.2"
 description = """
 Pure Rust implementation of the SHA-2 hash function family
 including SHA-224, SHA-256, SHA-384, and SHA-512.
@@ -35,7 +35,10 @@ hex-literal = "0.2"
 default = ["std"]
 std = ["digest/std"]
 asm = ["sha2-asm", "libc"]
+# Expose compress function
 compress = []
+# Force software implementation
+force-soft = []
 
 # DEPRECATED: use `asm` instead
 asm-aarch64 = ["asm"]
diff --git a/sha2/src/sha256.rs b/sha2/src/sha256.rs
index 8ee97bedd..8dade9f89 100644
--- a/sha2/src/sha256.rs
+++ b/sha2/src/sha256.rs
@@ -139,7 +139,10 @@ digest::impl_write!(Sha224);
 digest::impl_write!(Sha256);
 
 cfg_if::cfg_if! {
-    if #[cfg(all(feature = "asm", target_arch = "aarch64", target_os = "linux"))] {
+    if #[cfg(feature = "force-soft")] {
+        mod soft;
+        use soft::compress;
+    } else if #[cfg(all(feature = "asm", target_arch = "aarch64", target_os = "linux"))] {
         mod soft;
         mod aarch64;
         use aarch64::compress;
diff --git a/sha2/src/sha512.rs b/sha2/src/sha512.rs
index de115d442..3280c6d21 100644
--- a/sha2/src/sha512.rs
+++ b/sha2/src/sha512.rs
@@ -228,7 +228,10 @@ digest::impl_write!(Sha512Trunc224);
 digest::impl_write!(Sha512Trunc256);
 
 cfg_if::cfg_if! {
-    if #[cfg(all(feature = "asm", any(target_arch = "x86", target_arch = "x86_64")))] {
+    if #[cfg(feature = "force-soft")] {
+        mod soft;
+        use soft::compress;
+    } else if #[cfg(all(feature = "asm", any(target_arch = "x86", target_arch = "x86_64")))] {
         // TODO: replace after sha2-asm rework
         fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) {
             for block in blocks {


Test patch: