From b6018c0fc478a45ee39e1efa98032006d7be3d74 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 12 Jun 2025 10:27:15 -0700 Subject: [PATCH 1/3] bb: Implement `Word::is_zero`. --- src/bb/ops.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/bb/ops.rs diff --git a/src/bb/ops.rs b/src/bb/ops.rs new file mode 100644 index 0000000000..e69de29bb2 From 0898d7a3cbd14b9c885c9d85c011a1a4eb320e65 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 12 Jun 2025 11:00:43 -0700 Subject: [PATCH 2/3] bb/aarch64: Implement optimized `WordOps::is_zero`. --- src/bb/word/aarch64.rs | 18 ++++++++++++++++++ src/bb/word/mod.rs | 9 ++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/bb/word/aarch64.rs diff --git a/src/bb/word/aarch64.rs b/src/bb/word/aarch64.rs new file mode 100644 index 0000000000..e5ff3e31dc --- /dev/null +++ b/src/bb/word/aarch64.rs @@ -0,0 +1,18 @@ +use super::{super::BoolMask, Word, WordOps}; +use core::{arch::asm, mem}; + +impl WordOps for Word { + fn is_zero(self) -> BoolMask { + let r: u64; + unsafe { + asm!( + "subs {r}, {a}, #1", + "sbc {r}, {r}, {r}", // r - r - carry = 0 - carry = -carry. + a = in(reg) self, + r = lateout(reg) r, + options(nomem, nostack, pure) + ); + } + unsafe { mem::transmute::(r) } + } +} diff --git a/src/bb/word/mod.rs b/src/bb/word/mod.rs index 1cfe429085..89dea9e57d 100644 --- a/src/bb/word/mod.rs +++ b/src/bb/word/mod.rs @@ -13,6 +13,7 @@ // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use super::{BoolMask, LeakyWord}; +use cfg_if::cfg_if; /// A native word that may hold a secret. /// @@ -47,4 +48,10 @@ impl From for Word { } */ -mod fallback; +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + } else { + mod fallback; + } +} From 16c042160fe2908d4636b5d6c0aaa949ae399f1f Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 12 Jun 2025 12:24:05 -0700 Subject: [PATCH 3/3] bb: Implement `WordOps::from_u8`. --- src/bb/bytes.rs | 3 +-- src/bb/word/aarch64.rs | 14 ++++++++++++++ src/bb/word/fallback.rs | 5 +++++ src/bb/word/mod.rs | 1 + 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/bb/bytes.rs b/src/bb/bytes.rs index 73564019d0..55e05d2d2c 100644 --- a/src/bb/bytes.rs +++ b/src/bb/bytes.rs @@ -59,8 +59,7 @@ pub fn bytes_are_equal(a: &[u8], b: &[u8]) -> BoolMask { #[allow(clippy::into_iter_on_ref)] let rem = a_rem .into_iter() - .copied() - .map(Word::from) + .map(Word::from_u8) .zip(b_rem.into_iter().copied().map(Word::from)) .fold(0, |acc, (a, b)| acc | (a ^ b)); acc |= rem; diff --git a/src/bb/word/aarch64.rs b/src/bb/word/aarch64.rs index e5ff3e31dc..d0e09581bb 100644 --- a/src/bb/word/aarch64.rs +++ b/src/bb/word/aarch64.rs @@ -1,7 +1,21 @@ use super::{super::BoolMask, Word, WordOps}; +use crate::polyfill; use core::{arch::asm, mem}; impl WordOps for Word { + fn from_u8(a: &u8) -> Self { + let mut r: Self; + unsafe { + asm!( + "ldrb {r:w}, [{a_ptr}]", // zero-extended to 32-bits, then 64-bits. + a_ptr = in(reg) polyfill::ptr::from_ref(a), + r = lateout(reg) r, + options(nostack, readonly) + ); + } + r + } + fn is_zero(self) -> BoolMask { let r: u64; unsafe { diff --git a/src/bb/word/fallback.rs b/src/bb/word/fallback.rs index fb8a092257..20ce194edc 100644 --- a/src/bb/word/fallback.rs +++ b/src/bb/word/fallback.rs @@ -1,6 +1,11 @@ use super::{super::BoolMask, Word, WordOps}; impl WordOps for Word { + #[inline(always)] + fn from_u8(a: &u8) -> Self { + Self::from(*a) + } + #[inline] fn is_zero(self) -> BoolMask { use crate::limb::{Limb, LimbMask}; // XXX: Backwards dependency. diff --git a/src/bb/word/mod.rs b/src/bb/word/mod.rs index 89dea9e57d..ccbe2d2d39 100644 --- a/src/bb/word/mod.rs +++ b/src/bb/word/mod.rs @@ -29,6 +29,7 @@ use cfg_if::cfg_if; pub(crate) type Word = LeakyWord; pub(crate) trait WordOps: Copy { + fn from_u8(a: &u8) -> Self; fn is_zero(self) -> BoolMask; }