Skip to content

Commit

Permalink
Specialize constant_time::xor to 16 bytes.
Browse files Browse the repository at this point in the history
The compiler doesn't transform the byte-wise XORs into word-wise or
SIMD XOR. Instead it generated a massive mess of instructions that
did it byte-wise. WIth this implementation, it will generate
word-wise XOR, at least.
  • Loading branch information
briansmith committed Jun 11, 2024
1 parent ee134b5 commit 60e9b43
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/aead/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ impl Key {
#[inline]
pub fn encrypt_iv_xor_block(&self, iv: Iv, input: Block, cpu_features: cpu::Features) -> Block {
let encrypted_iv = self.encrypt_block(iv.into_block_less_safe(), cpu_features);
constant_time::xor(encrypted_iv, input)
constant_time::xor_16(encrypted_iv, input)
}

#[inline]
Expand Down
2 changes: 1 addition & 1 deletion src/aead/aes_gcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ fn finish(aes_key: &aes::Key, gcm_ctx: gcm::Context, tag_iv: aes::Iv) -> Tag {
// Finalize the tag and return it.
gcm_ctx.pre_finish(|pre_tag, cpu_features| {
let encrypted_iv = aes_key.encrypt_block(tag_iv.into_block_less_safe(), cpu_features);
Tag(constant_time::xor(pre_tag, encrypted_iv))
Tag(constant_time::xor_16(pre_tag, encrypted_iv))
})
}

Expand Down
2 changes: 1 addition & 1 deletion src/aead/gcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ pub struct Xi(Block);
impl BitXorAssign<Block> for Xi {
#[inline]
fn bitxor_assign(&mut self, a: Block) {
self.0 = constant_time::xor(self.0, a)
self.0 = constant_time::xor_16(self.0, a)
}
}

Expand Down
19 changes: 10 additions & 9 deletions src/constant_time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ prefixed_extern! {
fn CRYPTO_memcmp(a: *const u8, b: *const u8, len: c::size_t) -> c::int;
}

pub(crate) fn xor<const N: usize>(mut a: [u8; N], b: [u8; N]) -> [u8; N] {
// `xor_assign_at_start()`, but avoiding relying on the compiler to
// optimize the slice iterators.
a.iter_mut().zip(b.iter()).for_each(|(a, b)| *a ^= *b);
a
pub(crate) fn xor_16(a: [u8; 16], b: [u8; 16]) -> [u8; 16] {
let a = u128::from_ne_bytes(a);
let b = u128::from_ne_bytes(b);
let r = a ^ b;
r.to_ne_bytes()
}

/// XORs the first N bytes of `b` into `a`, where N is
Expand All @@ -54,9 +54,7 @@ pub(crate) fn xor_assign_at_start<'a>(

#[cfg(test)]
mod tests {
use super::*;
use crate::limb::LimbMask;
use crate::{bssl, error, rand};
use crate::{bssl, constant_time::xor_assign_at_start, error, limb::LimbMask, rand};

#[test]
fn test_constant_time() -> Result<(), error::Unspecified> {
Expand Down Expand Up @@ -107,7 +105,10 @@ mod tests {
let b = (rand::generate::<[u8; 1]>(&rng)?.expose()[0] & 0x0f) != 0;

let ref_in = input;
let ref_out = if b { xor(out, ref_in) } else { out };
let mut ref_out = out;
if b {
xor_assign_at_start(&mut ref_out, &ref_in)
};

prefixed_extern! {
fn bssl_constant_time_test_conditional_memxor(dst: &mut [u8; 256], src: &[u8; 256], b: LimbMask);
Expand Down

0 comments on commit 60e9b43

Please sign in to comment.