From d53cdb6c97189a453f352c4b21f88d8ea978f908 Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Sun, 25 Mar 2018 20:14:25 -0700 Subject: [PATCH] And, or, and xor. --- src/cryptonum/complete_arith.rs | 50 ++++++++ src/cryptonum/mod.rs | 217 +++++++++++++++++++++++++++++++- 2 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 src/cryptonum/complete_arith.rs diff --git a/src/cryptonum/complete_arith.rs b/src/cryptonum/complete_arith.rs new file mode 100644 index 0000000..eb6b467 --- /dev/null +++ b/src/cryptonum/complete_arith.rs @@ -0,0 +1,50 @@ +macro_rules! derive_arithmetic_operators +{ + ($type: ident, $cl: ident, $fn: ident, $asncl: ident, $asnfn: ident) => { + impl $asncl for $type { + fn $asnfn(&mut self, other: $type) { + self.$asnfn(&other) + } + } + + impl $cl for $type { + type Output = $type; + + fn $fn(self, other: $type) -> $type { + let mut res = self.clone(); + res.$asnfn(&other); + res + } + } + + impl<'a> $cl<&'a $type> for $type { + type Output = $type; + + fn $fn(self, other: &$type) -> $type { + let mut res = self.clone(); + res.$asnfn(other); + res + } + } + + impl<'a> $cl<$type> for &'a $type { + type Output = $type; + + fn $fn(self, other: $type) -> $type { + let mut res = self.clone(); + res.$asnfn(&other); + res + } + } + + impl<'a,'b> $cl<&'a $type> for &'b $type { + type Output = $type; + + fn $fn(self, other: &$type) -> $type { + let mut res = self.clone(); + res.$asnfn(other); + res + } + } + } +} diff --git a/src/cryptonum/mod.rs b/src/cryptonum/mod.rs index c7bf5b0..758eae8 100644 --- a/src/cryptonum/mod.rs +++ b/src/cryptonum/mod.rs @@ -1,7 +1,11 @@ #[macro_use] mod conversions; +#[macro_use] +mod complete_arith; use num::{BigUint,ToPrimitive,Zero}; +use std::fmt; +use std::fmt::Write; use std::cmp::Ordering; use std::ops::*; @@ -26,6 +30,58 @@ impl UCN { } } } + + fn expand(&mut self, rhs: &UCN) { + while self.contents.len() < rhs.contents.len() { + self.contents.push(0); + } + } +} + +impl fmt::UpperHex for UCN { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(),fmt::Error> { + for x in self.contents.iter().rev() { + fmt.write_char(tochar_upper(x >> 60))?; + fmt.write_char(tochar_upper(x >> 56))?; + fmt.write_char(tochar_upper(x >> 52))?; + fmt.write_char(tochar_upper(x >> 48))?; + fmt.write_char(tochar_upper(x >> 44))?; + fmt.write_char(tochar_upper(x >> 40))?; + fmt.write_char(tochar_upper(x >> 36))?; + fmt.write_char(tochar_upper(x >> 32))?; + fmt.write_char(tochar_upper(x >> 28))?; + fmt.write_char(tochar_upper(x >> 24))?; + fmt.write_char(tochar_upper(x >> 20))?; + fmt.write_char(tochar_upper(x >> 16))?; + fmt.write_char(tochar_upper(x >> 12))?; + fmt.write_char(tochar_upper(x >> 8))?; + fmt.write_char(tochar_upper(x >> 4))?; + fmt.write_char(tochar_upper(x >> 0))?; + } + Ok(()) + } +} + +fn tochar_upper(x: u64) -> char { + match (x as u8) & (0xF as u8) { + 0x0 => '0', + 0x1 => '1', + 0x2 => '2', + 0x3 => '3', + 0x4 => '4', + 0x5 => '5', + 0x6 => '6', + 0x7 => '7', + 0x8 => '8', + 0x9 => '9', + 0xA => 'A', + 0xB => 'B', + 0xC => 'C', + 0xD => 'D', + 0xE => 'E', + 0xF => 'F', + _ => panic!("the world is broken") + } } //------------------------------------------------------------------------------ @@ -132,6 +188,81 @@ impl Not for UCN { } } +impl<'a> Not for &'a UCN { + type Output = UCN; + + fn not(self) -> UCN { + let res = self.clone(); + res.not() + } +} + +impl<'a> BitOrAssign<&'a UCN> for UCN { + fn bitor_assign(&mut self, rhs: &UCN) { + self.expand(&rhs); + { + let mut iter_me = self.contents.iter_mut(); + let mut iter_tm = rhs.contents.iter(); + + loop { + match (iter_me.next(), iter_tm.next()) { + (Some(dest), Some(val)) => + *dest |= val, + _ => + break + } + } + } + self.clean(); + } +} + +impl<'a> BitXorAssign<&'a UCN> for UCN { + fn bitxor_assign(&mut self, rhs: &UCN) { + self.expand(&rhs); + { + let mut iter_me = self.contents.iter_mut(); + let mut iter_tm = rhs.contents.iter(); + + loop { + match (iter_me.next(), iter_tm.next()) { + (Some(dest), Some(val)) => + *dest ^= val, + _ => + break + } + } + } + self.clean(); + } +} + +impl<'a> BitAndAssign<&'a UCN> for UCN { + fn bitand_assign(&mut self, rhs: &UCN) { + if self.contents.len() > rhs.contents.len() { + self.contents.resize(rhs.contents.len(), 0); + } + { + let mut iter_me = self.contents.iter_mut(); + let mut iter_tm = rhs.contents.iter(); + + loop { + match (iter_me.next(), iter_tm.next()) { + (Some(dest), Some(val)) => + *dest &= val, + _ => + break + } + } + } + self.clean(); + } +} + +derive_arithmetic_operators!(UCN, BitOr, bitor, BitOrAssign, bitor_assign); +derive_arithmetic_operators!(UCN, BitXor, bitxor, BitXorAssign, bitxor_assign); +derive_arithmetic_operators!(UCN, BitAnd, bitand, BitAndAssign, bitand_assign); + //------------------------------------------------------------------------------ // // Tests! @@ -232,7 +363,7 @@ mod test { impl Arbitrary for UCN { fn arbitrary(g: &mut G) -> UCN { - let lenopts = [4,8,16,32,48,64,112,128,240]; + let lenopts = [4,8]; //,8,16,32,48,64,112,128,240]; let mut len = *g.choose(&lenopts).unwrap(); let mut contents = Vec::with_capacity(len); @@ -260,4 +391,88 @@ mod test { x3 == x } } + + quickcheck! { + fn or_associative(a: UCN, b: UCN, c: UCN) -> bool { + ((&a | &b) | &c) == (&a | (&b | &c)) + } + fn xor_associative(a: UCN, b: UCN, c: UCN) -> bool { + ((&a ^ &b) ^ &c) == (&a ^ (&b ^ &c)) + } + fn and_associative(a: UCN, b: UCN, c: UCN) -> bool { + ((&a & &b) & &c) == (&a & (&b & &c)) + } + } + + quickcheck! { + fn or_commutative(a: UCN, b: UCN) -> bool { + (&a | &b) == (&b | &a) + } + fn xor_commutative(a: UCN, b: UCN) -> bool { + (&a ^ &b) == (&b ^ &a) + } + fn and_commutative(a: UCN, b: UCN) -> bool { + (&a & &b) == (&b & &a) + } + } + + quickcheck! { + fn or_identity(a: UCN) -> bool { + (&a | &UCN{ contents: vec![] }) == a + } + fn xor_identity(a: UCN) -> bool { + (&a ^ &UCN{ contents: vec![] }) == a + } + fn and_identity(a: UCN) -> bool { + let mut contents = Vec::new(); + contents.resize(a.contents.len(), 0xFFFFFFFFFFFFFFFF); + let effs = UCN{ contents: contents }; + (&a & &effs) == a + } + } + + quickcheck! { + fn or_annihilator(a: UCN) -> bool { + let mut contents = Vec::new(); + contents.resize(a.contents.len(), 0xFFFFFFFFFFFFFFFF); + let effs = UCN{ contents: contents }; + (&a | &effs) == effs + } + fn and_annihilator(a: UCN) -> bool { + let zero = UCN{ contents: vec![] }; + (&a & &zero) == zero + } + fn xor_inverse(a: UCN, b: UCN) -> bool { + ((&a ^ &b) ^ &b) == a + } + fn or_idempotent(a: UCN, b: UCN) -> bool { + (&a | &b) == ((&a | &b) | &b) + } + fn and_idempotent(a: UCN, b: UCN) -> bool { + (&a & &b) == ((&a & &b) & &b) + } + fn andor_absorbtion(a: UCN, b: UCN) -> bool { + (&a & (&a | &b)) == a + } + fn orand_absorbtion(a: UCN, b: UCN) -> bool { + (&a | (&a & &b)) == a + } + fn and_over_or_distribution(a: UCN, b: UCN, c: UCN) -> bool { + (&a & (&b | &c)) == ((&a & &b) | (&a & &c)) + } + fn and_over_xor_distribution(a: UCN, b: UCN, c: UCN) -> bool { + (&a & (&b ^ &c)) == ((&a & &b) ^ (&a & &c)) + } + fn or_over_and_distribution(a: UCN, b: UCN, c: UCN) -> bool { + (&a | (&b & &c)) == ((&a | &b) & (&a | &c)) + } + fn demorgans(a: UCN, b: UCN) -> bool { + let mut a2 = if a.contents.len() < b.contents.len() {a.clone()} + else {b.clone()}; + let b2 = if a.contents.len() < b.contents.len() {b.clone()} + else {a.clone()}; + expand_to_match(&mut a2, &b2); + (!(&a2 | &b2)) == (!a2 & !b2) + } + } }