diff --git a/cmov/src/portable.rs b/cmov/src/portable.rs index 0a6259f4..af91b27a 100644 --- a/cmov/src/portable.rs +++ b/cmov/src/portable.rs @@ -7,7 +7,14 @@ // TODO(tarcieri): more optimized implementation for small integers use crate::{Cmov, CmovEq, Condition}; -use core::{hint::black_box, mem::size_of}; +use core::hint::black_box; + +/// Bitwise non-zero: returns `1` if `x != 0`, and otherwise returns `0`. +macro_rules! bitnz { + ($value:expr, $bits:expr) => { + ($value | $value.wrapping_neg()) >> ($bits - 1) + }; +} impl Cmov for u16 { #[inline] @@ -68,13 +75,13 @@ impl CmovEq for u32 { impl Cmov for u64 { #[inline] fn cmovnz(&mut self, value: &Self, condition: Condition) { - let mask = is_non_zero(condition).wrapping_sub(1); + let mask = black_box((bitnz!(condition, u8::BITS) as u64).wrapping_sub(1)); *self = (*self & mask) | (*value & !mask); } #[inline] fn cmovz(&mut self, value: &Self, condition: Condition) { - let mask = (1 ^ is_non_zero(condition)).wrapping_sub(1); + let mask = black_box((1 ^ bitnz!(condition, u8::BITS) as u64).wrapping_sub(1)); *self = (*self & mask) | (*value & !mask); } } @@ -82,23 +89,13 @@ impl Cmov for u64 { impl CmovEq for u64 { #[inline] fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) { - output.cmovnz(&input, (self ^ rhs) as u8); + let ne = bitnz!(self ^ rhs, u64::BITS) as u8; + output.cmovnz(&input, black_box(ne)); } #[inline] fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) { - output.cmovz(&input, (self ^ rhs) as u8); + let ne = bitnz!(self ^ rhs, u64::BITS) as u8; + output.cmovnz(&input, black_box(ne ^ 1)); } } - -/// Check if the given condition value is non-zero -/// -/// # Returns -/// - `condition` is zero: `0` -/// - `condition` is non-zero: `1` -#[inline] -fn is_non_zero(condition: Condition) -> u64 { - const SHIFT_BITS: usize = size_of::() - 1; - let condition = condition as u64; - black_box(((condition | (!condition).wrapping_add(1)) >> SHIFT_BITS) & 1) -} diff --git a/cmov/tests/proptests.rs b/cmov/tests/proptests.rs index d08a52e3..b1b2f012 100644 --- a/cmov/tests/proptests.rs +++ b/cmov/tests/proptests.rs @@ -1,6 +1,3 @@ -// TODO(tarcieri): known to be broken on PPC32. See RustCrypto/utils#1298 -#![cfg(not(target_arch = "powerpc"))] - /// Write the proptests for an integer type. macro_rules! int_proptests { ( $($int:ident),+ ) => { diff --git a/cmov/tests/regression.rs b/cmov/tests/regression.rs index 90d8cc58..e9d56f48 100644 --- a/cmov/tests/regression.rs +++ b/cmov/tests/regression.rs @@ -1,8 +1,5 @@ //! Tests for previous bugs in the implementation. -// TODO(tarcieri): known to be broken on PPC32. See RustCrypto/utils#1298 -#![cfg(not(target_arch = "powerpc"))] - use cmov::CmovEq; #[test]