diff --git a/README.md b/README.md index ad1bc64..ca8c947 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ named feature flag. * [`bn-rs`](https://docs.rs/bn-rs/latest/bn_rs/): Implements conversion to/from the [`BN`](https://docs.rs/bn-rs/latest/bn_rs/struct.BN.html) and [`BigNumber`](https://docs.rs/bn-rs/latest/bn_rs/struct.BigNumber.html). * [`bytemuck`](https://docs.rs/bytemuck): Implements the [`Pod`](https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html) and [`Zeroable`](https://docs.rs/bytemuck/latest/bytemuck/trait.Zeroable.html) traits for [`Uint`] where the size is a multiple of 64, up to 1024. This allows `Uint` to be used where a `Pod` trait bound exists. * [`num-traits`](https://docs.rs/num-traits): Implements about forty applicable traits. -* [`subtle`](https://docs.rs/subtle): Implements [`ConditionallySelectable`](https://docs.rs/subtle/latest/subtle/trait.ConditionallySelectable.html),[`ConditionallyNegatable`](https://docs.rs/subtle/latest/subtle/trait.ConditionallyNegatable.html), [`ConstantTimeEq`](https://docs.rs/subtle/latest/subtle/trait.ConstantTimeEq.html)/[`ConstantTimeGreater`](https://docs.rs/subtle/latest/subtle/trait.ConstantTimeGreater.html)/[`ConstantTimeLess`](https://docs.rs/subtle/latest/subtle/trait.ConstantTimeLess.html). +* [`subtle`](https://docs.rs/subtle): Implements [`Uint::bit_ct`], [`ConditionallySelectable`](https://docs.rs/subtle/latest/subtle/trait.ConditionallySelectable.html),[`ConditionallyNegatable`](https://docs.rs/subtle/latest/subtle/trait.ConditionallyNegatable.html), [`ConstantTimeEq`](https://docs.rs/subtle/latest/subtle/trait.ConstantTimeEq.html)/[`ConstantTimeGreater`](https://docs.rs/subtle/latest/subtle/trait.ConstantTimeGreater.html)/[`ConstantTimeLess`](https://docs.rs/subtle/latest/subtle/trait.ConstantTimeLess.html). * [`der`](https://docs.rs/der): Implements [`Encode`](https://docs.rs/der/latest/der/trait.Encode.html)/[`Decode`](https://docs.rs/der/latest/der/trait.Decode.html) and [`TryFrom`]/[`From`] casting for [`Any`](https://docs.rs/der/latest/der/asn1/struct.Any.html), [`AnyRef`](https://docs.rs/der/latest/der/asn1/struct.AnyRef.html), [`Int`](https://docs.rs/der/latest/der/asn1/struct.Int.html), [`IntRef`](https://docs.rs/der/latest/der/asn1/struct.IntRef.html), [`Uint`](https://docs.rs/der/latest/der/asn1/struct.Uint.html), [`UintRef`](https://docs.rs/der/latest/der/asn1/struct.UintRef.html). ## Building and testing diff --git a/src/support/subtle.rs b/src/support/subtle.rs index 6c05812..acd21bf 100644 --- a/src/support/subtle.rs +++ b/src/support/subtle.rs @@ -8,6 +8,22 @@ use subtle::{ Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, }; +impl Uint { + /// Returns a [`Choice`] if the bit at index is set. + /// + /// Constant time version of [`bit`] + /// + /// # Panics + /// + /// Panics if `index >= Self::BITS`. + #[must_use] + pub fn bit_ct(&self, index: usize) -> Choice { + assert!(index < BITS); + let (limbs, bits) = (index / 64, index % 64); + (self.limbs[limbs] & (1 << bits)).ct_eq(&(1 << bits)) + } +} + impl ConditionallySelectable for Uint { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { let mut limbs = [0_u64; LIMBS]; @@ -74,6 +90,18 @@ mod tests { use proptest::proptest; use subtle::ConditionallyNegatable; + #[test] + fn test_bit() { + const_for!(BITS in SIZES { + const LIMBS: usize = nlimbs(BITS); + proptest!(|(n: Uint, i in 0..BITS)| { + let r = n.bit_ct(i); + let e = n.bit(i); + assert_eq!(bool::from(r), e); + }); + }); + } + #[test] fn test_select() { const_for!(BITS in SIZES {