From c6e10bc7948252e84fa0e77e288b4150025fea73 Mon Sep 17 00:00:00 2001 From: kert Date: Sat, 16 Oct 2021 17:56:05 -0700 Subject: [PATCH 1/5] Add bitwise xor and not --- src/limb.rs | 2 + src/limb/bit_not.rs | 19 +++++++++ src/limb/bit_xor.rs | 19 +++++++++ src/uint.rs | 2 + src/uint/not.rs | 41 +++++++++++++++++++ src/uint/xor.rs | 96 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 179 insertions(+) create mode 100644 src/limb/bit_not.rs create mode 100644 src/limb/bit_xor.rs create mode 100644 src/uint/not.rs create mode 100644 src/uint/xor.rs diff --git a/src/limb.rs b/src/limb.rs index 4f37a53b..d25ed3e5 100644 --- a/src/limb.rs +++ b/src/limb.rs @@ -6,6 +6,8 @@ mod add; mod bit_and; mod bit_or; +mod bit_not; +mod bit_xor; mod cmp; mod encoding; mod from; diff --git a/src/limb/bit_not.rs b/src/limb/bit_not.rs new file mode 100644 index 00000000..19cf8262 --- /dev/null +++ b/src/limb/bit_not.rs @@ -0,0 +1,19 @@ +//! Limb bit not operations. + +use super::Limb; +use core::ops::Not; + +impl Limb { + /// Calculates `!a`. + pub const fn bitnot(self) -> Self { + Limb(!self.0) + } +} + +impl Not for Limb { + type Output = Limb; + + fn not(self) -> ::Output { + self.bitnot() + } +} diff --git a/src/limb/bit_xor.rs b/src/limb/bit_xor.rs new file mode 100644 index 00000000..a5078229 --- /dev/null +++ b/src/limb/bit_xor.rs @@ -0,0 +1,19 @@ +//! Limb bit xor operations. + +use super::Limb; +use core::ops::BitXor; + +impl Limb { + /// Calculates `a ^ b`. + pub const fn bitxor(self, rhs: Self) -> Self { + Limb(self.0 ^ rhs.0) + } +} + +impl BitXor for Limb { + type Output = Limb; + + fn bitxor(self, rhs: Self) -> Self::Output { + self.bitxor(rhs) + } +} diff --git a/src/uint.rs b/src/uint.rs index a975ac55..d2a575ba 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -18,12 +18,14 @@ mod encoding; mod from; mod mul; mod neg_mod; +mod not; mod or; mod shl; mod shr; mod sqrt; mod sub; mod sub_mod; +mod xor; #[cfg(feature = "generic-array")] mod array; diff --git a/src/uint/not.rs b/src/uint/not.rs new file mode 100644 index 00000000..6b5055bf --- /dev/null +++ b/src/uint/not.rs @@ -0,0 +1,41 @@ +//! [`UInt`] bitwise not operations. + +use super::UInt; +use crate::{Limb, Wrapping}; +use core::ops::Not; + +impl UInt { + /// Computes bitwise `!a`. + #[inline(always)] + pub const fn bitnot(&self) -> Self { + let mut limbs = [Limb::ZERO; LIMBS]; + let mut i = 0; + + while i < LIMBS { + limbs[i] = self.limbs[i].bitnot(); + i += 1; + } + + Self { limbs } + } +} + +impl Not for Wrapping> { + type Output = Self; + + fn not(self) -> ::Output { + Wrapping(self.0.bitnot()) + } +} + +#[cfg(test)] +mod tests { + use crate::U128; + + #[test] + #[test] + fn bitnot_ok() { + assert_eq!(U128::ZERO.bitnot(), U128::MAX); + assert_eq!(U128::MAX.bitnot(), U128::ZERO); + } +} diff --git a/src/uint/xor.rs b/src/uint/xor.rs new file mode 100644 index 00000000..96dbc10a --- /dev/null +++ b/src/uint/xor.rs @@ -0,0 +1,96 @@ +//! [`UInt`] bitwise xor operations. + +use super::UInt; +use crate::{Limb, Wrapping}; +use core::ops::{BitXor, BitXorAssign}; +use subtle::{Choice, CtOption}; + +impl UInt { + /// Computes bitwise `a ^ b`. + #[inline(always)] + pub const fn bitxor(&self, rhs: &Self) -> Self { + let mut limbs = [Limb::ZERO; LIMBS]; + let mut i = 0; + + while i < LIMBS { + limbs[i] = self.limbs[i].bitxor(rhs.limbs[i]); + i += 1; + } + + Self { limbs } + } + + /// Perform wrapping bitwise xor. + /// There's no way wrapping could ever happen. + /// This function exists so that all operations are accounted for in the wrapping operations + pub const fn wrapping_xor(&self, rhs: &Self) -> Self { + self.bitxor(rhs) + } + + /// Perform checked bitwise xor, returning a [`CtOption`] which `is_some` always + pub fn checked_xor(&self, rhs: &Self) -> CtOption { + let result = self.bitxor(rhs); + CtOption::new(result, Choice::from(1)) + } +} + +impl BitXor for Wrapping> { + type Output = Self; + + fn bitxor(self, rhs: Self) -> Wrapping> { + Wrapping(self.0.bitxor(&rhs.0)) + } +} + +impl BitXor<&Wrapping>> for Wrapping> { + type Output = Wrapping>; + + fn bitxor(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.bitxor(&rhs.0)) + } +} + +impl BitXor>> for &Wrapping> { + type Output = Wrapping>; + + fn bitxor(self, rhs: Wrapping>) -> Wrapping> { + Wrapping(self.0.bitxor(&rhs.0)) + } +} + +impl BitXor<&Wrapping>> for &Wrapping> { + type Output = Wrapping>; + + fn bitxor(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.bitxor(&rhs.0)) + } +} + +impl BitXorAssign for Wrapping> { + fn bitxor_assign(&mut self, other: Self) { + *self = *self ^ other; + } +} + +impl BitXorAssign<&Wrapping>> for Wrapping> { + fn bitxor_assign(&mut self, other: &Self) { + *self = *self ^ other; + } +} + +#[cfg(test)] +mod tests { + use crate::U128; + + #[test] + fn checked_xor_ok() { + let result = U128::ZERO.checked_xor(&U128::ONE); + assert_eq!(result.unwrap(), U128::ONE); + } + + #[test] + fn overlapping_xor_ok() { + let result = U128::ZERO.wrapping_xor(&U128::ONE); + assert_eq!(result, U128::ONE); + } +} From ef09db29143fa7ea74e4f19faf2c9d846b597070 Mon Sep 17 00:00:00 2001 From: kert Date: Sat, 16 Oct 2021 18:17:42 -0700 Subject: [PATCH 2/5] Fix rustfmt --- src/limb.rs | 2 +- src/uint/not.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/limb.rs b/src/limb.rs index d25ed3e5..f61f3634 100644 --- a/src/limb.rs +++ b/src/limb.rs @@ -5,8 +5,8 @@ mod add; mod bit_and; -mod bit_or; mod bit_not; +mod bit_or; mod bit_xor; mod cmp; mod encoding; diff --git a/src/uint/not.rs b/src/uint/not.rs index 6b5055bf..4a8d7836 100644 --- a/src/uint/not.rs +++ b/src/uint/not.rs @@ -32,7 +32,6 @@ impl Not for Wrapping> { mod tests { use crate::U128; - #[test] #[test] fn bitnot_ok() { assert_eq!(U128::ZERO.bitnot(), U128::MAX); From f61984be2ed1326ebace861b01c4bd3a3e813488 Mon Sep 17 00:00:00 2001 From: kert Date: Sat, 16 Oct 2021 18:21:11 -0700 Subject: [PATCH 3/5] Rename uint:bit modules --- src/uint.rs | 8 ++++---- src/uint/{and.rs => bit_and.rs} | 0 src/uint/{not.rs => bit_not.rs} | 0 src/uint/{or.rs => bit_or.rs} | 0 src/uint/{xor.rs => bit_xor.rs} | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename src/uint/{and.rs => bit_and.rs} (100%) rename src/uint/{not.rs => bit_not.rs} (100%) rename src/uint/{or.rs => bit_or.rs} (100%) rename src/uint/{xor.rs => bit_xor.rs} (100%) diff --git a/src/uint.rs b/src/uint.rs index d2a575ba..96b067fc 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -11,21 +11,21 @@ mod macros; mod add; mod add_mod; -mod and; +mod bit_and; +mod bit_not; +mod bit_or; +mod bit_xor; mod cmp; mod div; mod encoding; mod from; mod mul; mod neg_mod; -mod not; -mod or; mod shl; mod shr; mod sqrt; mod sub; mod sub_mod; -mod xor; #[cfg(feature = "generic-array")] mod array; diff --git a/src/uint/and.rs b/src/uint/bit_and.rs similarity index 100% rename from src/uint/and.rs rename to src/uint/bit_and.rs diff --git a/src/uint/not.rs b/src/uint/bit_not.rs similarity index 100% rename from src/uint/not.rs rename to src/uint/bit_not.rs diff --git a/src/uint/or.rs b/src/uint/bit_or.rs similarity index 100% rename from src/uint/or.rs rename to src/uint/bit_or.rs diff --git a/src/uint/xor.rs b/src/uint/bit_xor.rs similarity index 100% rename from src/uint/xor.rs rename to src/uint/bit_xor.rs From e40f6f0de392def7dc4386d31d22beb17676d169 Mon Sep 17 00:00:00 2001 From: kert Date: Sat, 16 Oct 2021 18:31:06 -0700 Subject: [PATCH 4/5] Proptest for xor --- tests/proptests.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/proptests.rs b/tests/proptests.rs index c423b4d0..bcf11b20 100644 --- a/tests/proptests.rs +++ b/tests/proptests.rs @@ -178,4 +178,15 @@ proptest! { } } + #[test] + fn wrapping_xor(a in uint(), b in uint()) { + let a_bi = to_biguint(&a); + let b_bi = to_biguint(&b); + if !b_bi.is_zero() { + let expected = to_uint(a_bi ^ b_bi); + let actual = a.wrapping_xor(&b); + + assert_eq!(expected, actual); + } + } } From 05120a0d3fb674296ae63e084007dbfb74a1f16c Mon Sep 17 00:00:00 2001 From: kert Date: Sat, 16 Oct 2021 18:43:49 -0700 Subject: [PATCH 5/5] Change not() to consistent naming --- src/limb/bit_not.rs | 4 ++-- src/uint/bit_not.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/limb/bit_not.rs b/src/limb/bit_not.rs index 19cf8262..26676d59 100644 --- a/src/limb/bit_not.rs +++ b/src/limb/bit_not.rs @@ -5,7 +5,7 @@ use core::ops::Not; impl Limb { /// Calculates `!a`. - pub const fn bitnot(self) -> Self { + pub const fn not(self) -> Self { Limb(!self.0) } } @@ -14,6 +14,6 @@ impl Not for Limb { type Output = Limb; fn not(self) -> ::Output { - self.bitnot() + self.not() } } diff --git a/src/uint/bit_not.rs b/src/uint/bit_not.rs index 4a8d7836..8d5dfe23 100644 --- a/src/uint/bit_not.rs +++ b/src/uint/bit_not.rs @@ -7,12 +7,12 @@ use core::ops::Not; impl UInt { /// Computes bitwise `!a`. #[inline(always)] - pub const fn bitnot(&self) -> Self { + pub const fn not(&self) -> Self { let mut limbs = [Limb::ZERO; LIMBS]; let mut i = 0; while i < LIMBS { - limbs[i] = self.limbs[i].bitnot(); + limbs[i] = self.limbs[i].not(); i += 1; } @@ -24,7 +24,7 @@ impl Not for Wrapping> { type Output = Self; fn not(self) -> ::Output { - Wrapping(self.0.bitnot()) + Wrapping(self.0.not()) } } @@ -34,7 +34,7 @@ mod tests { #[test] fn bitnot_ok() { - assert_eq!(U128::ZERO.bitnot(), U128::MAX); - assert_eq!(U128::MAX.bitnot(), U128::ZERO); + assert_eq!(U128::ZERO.not(), U128::MAX); + assert_eq!(U128::MAX.not(), U128::ZERO); } }