Skip to content

Enable sha1 and sha2 AArch64 extensions from asm-hashes #97

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

Merged
merged 3 commits into from
Jan 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ matrix:
- env: NAME=features-test
rust: nightly
script: ./test_features.sh
- env: NAME=test-aarch64
arch: arm64
rust: nightly
script:
- cd sha1
- cargo test --verbose --release --features asm-aarch64
- cargo bench --verbose
- cargo bench --verbose --features asm-aarch64
- cd ../sha2
- cargo test --verbose --release --features asm-aarch64
- cargo bench --verbose
- cargo bench --verbose --features asm-aarch64

install:
- cargo install cross || true
Expand Down
5 changes: 5 additions & 0 deletions sha1/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ block-buffer = "0.7"
fake-simd = "0.1"
sha1-asm = { version = "0.4", optional = true }
opaque-debug = "0.2"
libc = { version = "0.2", optional = true }

[dev-dependencies]
digest = { version = "0.8", features = ["dev"] }
Expand All @@ -28,5 +29,9 @@ default = ["std"]
std = ["digest/std"]
asm = ["sha1-asm"]

# TODO: Remove this feature once is_aarch64_feature_detected!() is stabilised.
# Only used on AArch64 Linux systems.
asm-aarch64 = ["asm", "libc"]

[badges]
travis-ci = { repository = "RustCrypto/hashes" }
9 changes: 9 additions & 0 deletions sha1/src/aarch64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// TODO: Import those from libc, see https://github.com/rust-lang/libc/pull/1638
const AT_HWCAP: u64 = 16;
const HWCAP_SHA1: u64 = 32;

#[inline(always)]
pub fn sha1_supported() -> bool {
let hwcaps: u64 = unsafe { ::libc::getauxval(AT_HWCAP) };
(hwcaps & HWCAP_SHA1) != 0
}
10 changes: 5 additions & 5 deletions sha1/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

pub const STATE_LEN: usize = 5;

#[cfg(not(feature = "asm"))]
#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))]
pub const BLOCK_LEN: usize = 16;

#[cfg(not(feature = "asm"))]
#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))]
pub const K0: u32 = 0x5A827999u32;
#[cfg(not(feature = "asm"))]
#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))]
pub const K1: u32 = 0x6ED9EBA1u32;
#[cfg(not(feature = "asm"))]
#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))]
pub const K2: u32 = 0x8F1BBCDCu32;
#[cfg(not(feature = "asm"))]
#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))]
pub const K3: u32 = 0xCA62C1D6u32;

pub const H: [u32; STATE_LEN] = [
Expand Down
32 changes: 29 additions & 3 deletions sha1/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,50 @@
#![no_std]
#![doc(html_logo_url =
"https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]

// Give relevant error messages if the user tries to enable AArch64 asm on unsupported platforms.
#[cfg(all(feature = "asm-aarch64", target_arch = "aarch64", not(target_os = "linux")))]
compile_error!("Your OS isn’t yet supported for runtime-checking of AArch64 features.");
#[cfg(all(feature = "asm-aarch64", target_os = "linux", not(target_arch = "aarch64")))]
compile_error!("Enable the \"asm\" feature instead of \"asm-aarch64\" on non-AArch64 Linux systems.");
#[cfg(all(not(feature = "asm-aarch64"), feature = "asm", target_arch = "aarch64", target_os = "linux"))]
compile_error!("Enable the \"asm-aarch64\" feature on AArch64 if you want to use asm.");

extern crate block_buffer;
#[macro_use] extern crate opaque_debug;
#[macro_use] pub extern crate digest;
#[cfg(feature = "std")]
extern crate std;
#[cfg(not(feature = "asm"))]
#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))]
extern crate fake_simd as simd;
#[cfg(feature = "asm-aarch64")]
extern crate libc;

#[cfg(feature = "asm")]
extern crate sha1_asm;
#[cfg(feature = "asm")]
#[cfg(all(feature = "asm", not(feature = "asm-aarch64")))]
#[inline(always)]
fn compress(state: &mut [u32; 5], block: &GenericArray<u8, U64>) {
let block: &[u8; 64] = unsafe { core::mem::transmute(block) };
sha1_asm::compress(state, block);
}
#[cfg(feature = "asm-aarch64")]
mod aarch64;
#[cfg(feature = "asm-aarch64")]
#[inline(always)]
fn compress(state: &mut [u32; 5], block: &GenericArray<u8, U64>) {
// TODO: Replace this platform-specific call with is_aarch64_feature_detected!("sha1") once
// that macro is stabilised and https://github.com/rust-lang/rfcs/pull/2725 is implemented
// to let us use it on no_std.
if aarch64::sha1_supported() {
let block: &[u8; 64] = unsafe { core::mem::transmute(block) };
sha1_asm::compress(state, block);
} else {
utils::compress(state, block);
}
}

#[cfg(not(feature = "asm"))]
#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))]
mod utils;
#[cfg(not(feature = "asm"))]
use utils::compress;
Expand Down
5 changes: 5 additions & 0 deletions sha2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ block-buffer = "0.7"
fake-simd = "0.1"
opaque-debug = "0.2"
sha2-asm = { version="0.5", optional=true }
libc = { version = "0.2", optional = true }

[dev-dependencies]
digest = { version = "0.8", features = ["dev"] }
Expand All @@ -25,5 +26,9 @@ default = ["std"]
std = ["digest/std"]
asm = ["sha2-asm"]

# TODO: Remove this feature once is_aarch64_feature_detected!() is stabilised.
# Only used on AArch64 Linux systems.
asm-aarch64 = ["asm", "libc"]

[badges]
travis-ci = { repository = "RustCrypto/hashes" }
9 changes: 9 additions & 0 deletions sha2/src/aarch64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// TODO: Import those from libc, see https://github.com/rust-lang/libc/pull/1638
const AT_HWCAP: u64 = 16;
const HWCAP_SHA2: u64 = 64;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW is it possible that processor supports SHA-2 instructions, but not SHA-1 and/or AES? I thought they are part of the same crypto extension.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “crypto extension” is an ARM marketing term for a Cortex-A core bundling these three extensions, and possibly the sha512, sha3, and more in the future.

I’m not aware of any actual CPU exposing e.g. the sha2 flag but not sha1, but given they are different flags I’d rather test them properly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are using getauxval it does not matter, but during migration to intrinsics we will have to use a more coarse grained target features, which only know about the crypto extension. But I guess since LLVM does not introduce separate finer-grained features it should be fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does it work for e.g. the sha3 flag?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I don't quite get how LLVM handles features, e.g. in here they write:

Extensions can now have different meanings based on the base architecture they apply to. For example on AArch64, 'crypto' means different things for v8.{1,2,3}-a than v8.4-a. The former adds 'sha2' and 'aes', the latter adds those and 'sm4' and 'sha3' on top.

I wonder why they use crypto instead of finer-grained sha1, sha2, sha512, sha3 and aes features...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They apparently noticed they made a mistake and now have aliased crypto to sha2 + aes, see llvm-mirror/llvm@6634844#diff-5ff776706657bdcfc45aa7d7159bfeadR45

We should be able to use each feature separately nowadays.


#[inline(always)]
pub fn sha2_supported() -> bool {
let hwcaps: u64 = unsafe { ::libc::getauxval(AT_HWCAP) };
(hwcaps & HWCAP_SHA2) != 0
}
17 changes: 15 additions & 2 deletions sha2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@
#![no_std]
#![doc(html_logo_url =
"https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]

// Give relevant error messages if the user tries to enable AArch64 asm on unsupported platforms.
#[cfg(all(feature = "asm-aarch64", target_arch = "aarch64", not(target_os = "linux")))]
compile_error!("Your OS isn’t yet supported for runtime-checking of AArch64 features.");
#[cfg(all(feature = "asm-aarch64", target_os = "linux", not(target_arch = "aarch64")))]
compile_error!("Enable the \"asm\" feature instead of \"asm-aarch64\" on non-AArch64 Linux systems.");
#[cfg(all(not(feature = "asm-aarch64"), feature = "asm", target_arch = "aarch64", target_os = "linux"))]
compile_error!("Enable the \"asm-aarch64\" feature on AArch64 if you want to use asm.");

extern crate block_buffer;
extern crate fake_simd as simd;
#[macro_use] extern crate opaque_debug;
Expand All @@ -65,12 +74,16 @@ extern crate fake_simd as simd;
extern crate sha2_asm;
#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "asm-aarch64")]
extern crate libc;

mod consts;
#[cfg(not(feature = "asm"))]
#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))]
mod sha256_utils;
#[cfg(not(feature = "asm"))]
#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))]
mod sha512_utils;
#[cfg(feature = "asm-aarch64")]
mod aarch64;
mod sha256;
mod sha512;

Expand Down
14 changes: 14 additions & 0 deletions sha2/src/sha256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,24 @@ struct Engine256State {
impl Engine256State {
fn new(h: &[u32; STATE_LEN]) -> Engine256State { Engine256State { h: *h } }

#[cfg(not(feature = "asm-aarch64"))]
pub fn process_block(&mut self, block: &Block) {
let block = unsafe { &*(block.as_ptr() as *const [u8; 64]) };
compress256(&mut self.h, block);
}

#[cfg(feature = "asm-aarch64")]
pub fn process_block(&mut self, block: &Block) {
let block = unsafe { &*(block.as_ptr() as *const [u8; 64]) };
// TODO: Replace this platform-specific call with is_aarch64_feature_detected!("sha2") once
// that macro is stabilised and https://github.com/rust-lang/rfcs/pull/2725 is implemented
// to let us use it on no_std.
if ::aarch64::sha2_supported() {
compress256(&mut self.h, block);
} else {
::sha256_utils::compress256(&mut self.h, block);
}
}
}

/// A structure that keeps track of the state of the Sha-256 operation and
Expand Down
4 changes: 2 additions & 2 deletions sha2/src/sha512.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use block_buffer::byteorder::{BE, ByteOrder};

use consts::{STATE_LEN, H384, H512, H512_TRUNC_224, H512_TRUNC_256};

#[cfg(not(feature = "asm"))]
#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))]
use sha512_utils::compress512;
#[cfg(feature = "asm")]
#[cfg(all(feature = "asm", not(feature = "asm-aarch64")))]
use sha2_asm::compress512;

type BlockSize = U128;
Expand Down