From 6485605b23a0126c9cae2eb68fa2cd4cde70a874 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Fri, 3 Jan 2020 14:54:57 +0000 Subject: [PATCH 1/3] Enable sha1 AArch64 extension on Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The feature gate is specific to glibc on Linux, using getauxval() to check the CPU flags, so it’s currently not used on other systems. Patches welcome. :) Enables https://github.com/RustCrypto/asm-hashes/pull/10 --- sha1/Cargo.toml | 5 +++++ sha1/src/aarch64.rs | 9 +++++++++ sha1/src/consts.rs | 10 +++++----- sha1/src/lib.rs | 32 +++++++++++++++++++++++++++++--- 4 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 sha1/src/aarch64.rs diff --git a/sha1/Cargo.toml b/sha1/Cargo.toml index 41a941ab7..381d94463 100644 --- a/sha1/Cargo.toml +++ b/sha1/Cargo.toml @@ -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"] } @@ -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" } diff --git a/sha1/src/aarch64.rs b/sha1/src/aarch64.rs new file mode 100644 index 000000000..d3cffecd7 --- /dev/null +++ b/sha1/src/aarch64.rs @@ -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 +} diff --git a/sha1/src/consts.rs b/sha1/src/consts.rs index 7a1bb3435..628d4d6e0 100644 --- a/sha1/src/consts.rs +++ b/sha1/src/consts.rs @@ -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] = [ diff --git a/sha1/src/lib.rs b/sha1/src/lib.rs index a1a7068a0..374c234c2 100644 --- a/sha1/src/lib.rs +++ b/sha1/src/lib.rs @@ -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) { 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) { + // 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; From 33babda7de73f9a0de340bc5b2dd2b3ef0f5df0f Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 4 Jan 2020 00:22:04 +0000 Subject: [PATCH 2/3] Enable sha2 AArch64 extension on Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The feature gate is specific to glibc on Linux, using getauxval() to check the CPU flags, so it’s currently not used on other systems. Patches welcome. :) The sha2 extension only provides SHA-256 instructions, so keep using the plain Rust implementation for SHA-512 until someone adds sha512 extension assembly (I have no computer to test that with). --- sha2/Cargo.toml | 5 +++++ sha2/src/aarch64.rs | 9 +++++++++ sha2/src/lib.rs | 17 +++++++++++++++-- sha2/src/sha256.rs | 14 ++++++++++++++ sha2/src/sha512.rs | 4 ++-- 5 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 sha2/src/aarch64.rs diff --git a/sha2/Cargo.toml b/sha2/Cargo.toml index 025a495dc..b56ce37d7 100644 --- a/sha2/Cargo.toml +++ b/sha2/Cargo.toml @@ -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"] } @@ -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" } diff --git a/sha2/src/aarch64.rs b/sha2/src/aarch64.rs new file mode 100644 index 000000000..089a8f648 --- /dev/null +++ b/sha2/src/aarch64.rs @@ -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; + +#[inline(always)] +pub fn sha2_supported() -> bool { + let hwcaps: u64 = unsafe { ::libc::getauxval(AT_HWCAP) }; + (hwcaps & HWCAP_SHA2) != 0 +} diff --git a/sha2/src/lib.rs b/sha2/src/lib.rs index 9b72eb24e..2b3e93e0e 100644 --- a/sha2/src/lib.rs +++ b/sha2/src/lib.rs @@ -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; @@ -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; diff --git a/sha2/src/sha256.rs b/sha2/src/sha256.rs index 95763dbfc..9dad44489 100644 --- a/sha2/src/sha256.rs +++ b/sha2/src/sha256.rs @@ -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 diff --git a/sha2/src/sha512.rs b/sha2/src/sha512.rs index 6b39ae1ed..1a1c935ba 100644 --- a/sha2/src/sha512.rs +++ b/sha2/src/sha512.rs @@ -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; From 078c1b41a76d44ca63f70d4ccbed51420b8e00d4 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sun, 5 Jan 2020 23:58:55 +0100 Subject: [PATCH 3/3] Add an AArch64 worker to the CI --- .travis.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.travis.yml b/.travis.yml index 842be429c..d1538024e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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