diff --git a/src/opflags.rs b/src/opflags.rs index 6a3f367..83d4c72 100644 --- a/src/opflags.rs +++ b/src/opflags.rs @@ -29,12 +29,20 @@ impl OpFlags { (*self & other).ct_ne(&OpFlags::EMPTY) } + fn insert(&mut self, flags: OpFlags) { + *self |= flags; + } + + fn remove(&mut self, flags: OpFlags) { + *self &= !flags; + } + pub fn set(&mut self, flags: OpFlags, cond: Choice) { - if cond.into() { - *self |= flags; - } else { - *self &= !flags; - } + const OPS: [fn(&mut OpFlags, OpFlags); 2] = [OpFlags::remove, OpFlags::insert]; + + let index = (cond.to_u8() & 1) as usize; + + OPS[index](self, flags); } #[inline(always)] diff --git a/src/strobe.rs b/src/strobe.rs index a13d9f9..052e217 100644 --- a/src/strobe.rs +++ b/src/strobe.rs @@ -7,6 +7,13 @@ use crate::{ ops, }; +/// Private integer representations for Role, to allow for better constant time compat. +mod role { + pub const SENDER: u8 = 0; + pub const RECEIVER: u8 = 1; +} + +/// Public API for passing in Role #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum Role { @@ -14,12 +21,6 @@ pub enum Role { Receiver, } -impl CtEq for Role { - fn ct_eq(&self, other: &Self) -> Choice { - (*self as u8).ct_eq(&(*other as u8)) - } -} - #[derive(Debug, Clone, Copy)] #[repr(usize)] pub enum SecurityParameter { @@ -40,7 +41,7 @@ pub struct StrobeState { /// Index into `state` start: usize, /// Represents whether we're a sender or a receiver - role: Role, + role: u8, /// The last operation performed. This is to verify that the `more` flag is only used across /// identical operations. prev_flags: OpFlags, @@ -122,7 +123,7 @@ impl StrobeState { rate, position: 0, start: 0, - role, + role: role as u8, prev_flags: OpFlags::EMPTY, }; @@ -264,11 +265,7 @@ impl StrobeState { /// sending or receiving fn begin_op(&mut self, mut flags: OpFlags) { if flags.contains(OpFlags::TRANSPORT).to_bool() { - let op_role = if flags.contains(OpFlags::INBOUND).to_bool() { - Role::Receiver - } else { - Role::Sender - }; + let op_role = role::SENDER.ct_select(&role::RECEIVER, flags.contains(OpFlags::INBOUND)); // So that the sender and receiver agree, toggle the I flag as necessary flags.set(OpFlags::INBOUND, self.role.ct_ne(&op_role)); @@ -305,7 +302,7 @@ impl StrobeState { // Flags that don't pass this assertion should normally call `absorb`, but `absorb` does not mutate, // so the implementor should have used operate_no_mutate instead // RATCHET is special-cased to never call operate directly - debug_assert!(flags != ops::KEY && bool::from(flags.contains(OpFlags::CIPHER))); + debug_assert!(flags != ops::KEY && flags.contains(OpFlags::CIPHER).to_bool()); const SPECIAL_CASES: [OpFlags; 3] = [ops::PRF, ops::SEND_MAC, ops::SEND_ENC]; const OPS: [fn(&mut StrobeState, data: &mut [u8]); 4] = [ @@ -343,7 +340,7 @@ impl StrobeState { // Flags that trigger the assertion to fail are mutating operations. // RATCHET is special cased to never call operate/operate_no_mutate directly - debug_assert!(flags == ops::KEY || !bool::from(flags.contains(OpFlags::CIPHER))); + debug_assert!(flags == ops::KEY || !flags.contains(OpFlags::CIPHER).to_bool()); const OPS: [fn(&mut StrobeState, data: &[u8]); 2] = [StrobeState::absorb, StrobeState::overwrite];