use cryptonum::unsigned::{BarrettUCN,UCN,divmod}; use num::BigInt; use num::bigint::Sign; use std::fmt; use std::cmp::Ordering; use std::fmt::Write; use std::ops::*; /// In case you were wondering, it stands for "Signed Crypto Num". #[derive(Clone,Debug,PartialEq,Eq)] pub struct SCN { pub(crate) negative: bool, pub(crate) value: UCN } impl SCN { pub fn zero() -> SCN { SCN{ negative: false, value: UCN::zero() } } pub fn is_zero(&self) -> bool { self.value.is_zero() } pub fn is_negative(&self) -> bool { self.negative } pub fn from_str(x: &str) -> SCN { if x.get(0..1) == Some("-") { SCN{ negative: true, value: UCN::from_str(&x[1..]) } } else { SCN{ negative: false, value: UCN::from_str(x) } } } fn cleanup(&mut self) { if self.value.is_zero() { self.negative = false; } } pub fn egcd(self, b: SCN) -> (SCN, SCN, SCN) { let mut s = SCN::zero(); let mut old_s = SCN::from(1 as u8); let mut t = SCN::from(1 as u8); let mut old_t = SCN::zero(); let mut r = b; let mut old_r = self; while !r.is_zero() { let quotient = old_r.clone() / r.clone(); let prov_r = r.clone(); let prov_s = s.clone(); let prov_t = t.clone(); r = old_r - (r * "ient); s = old_s - (s * "ient); t = old_t - (t * "ient); old_r = prov_r; old_s = prov_s; old_t = prov_t; } (old_r, old_s, old_t) } pub fn reduce(&self, m: &BarrettUCN) -> SCN { println!("signed reduce"); SCN{ negative: false, value: self.value.reduce(m) } } pub fn divmod(&self, x: &SCN, m: &BarrettUCN) -> SCN { println!("STEP1"); let xmod = x.reduce(m); println!("STEP2"); assert!(!xmod.negative); println!("STEP3"); let i = xmod.value.modinv(&m.m); println!("STEP4"); let si = SCN::from(i); println!("STEP5"); let yi = self * si; println!("STEP6: {:X}", yi); println!(" mod {:X}", m.m); let res = yi.reduce(m); println!("STEP7"); res } } impl fmt::UpperHex for SCN { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(),fmt::Error> { if self.negative { fmt.write_char('-')?; } self.value.fmt(fmt) } } //------------------------------------------------------------------------------ // // Conversions to/from crypto nums. // //------------------------------------------------------------------------------ define_signed_from!(SCN, i8, u8); define_signed_from!(SCN, i16, u16); define_signed_from!(SCN, i32, u32); define_signed_from!(SCN, i64, u64); define_signed_into!(SCN, i8, u8); define_signed_into!(SCN, i16, u16); define_signed_into!(SCN, i32, u32); define_signed_into!(SCN, i64, u64); impl From for SCN { fn from(x: UCN) -> SCN { SCN{ negative: false, value: x } } } impl Into for SCN { fn into(self) -> UCN { self.value } } impl From for BigInt { fn from(x: SCN) -> BigInt { let sign = if x.is_negative() { Sign::Minus } else { Sign::Plus }; let numbytes = x.value.contents.len() * 8; let bytes = x.value.to_bytes(numbytes); BigInt::from_bytes_be(sign, &bytes) } } //------------------------------------------------------------------------------ // // Comparisons // //------------------------------------------------------------------------------ impl PartialOrd for SCN { fn partial_cmp(&self, other: &SCN) -> Option { Some(self.cmp(other)) } } impl Ord for SCN { fn cmp(&self, other: &SCN) -> Ordering { match (self.negative, other.negative) { (false, false) => self.value.cmp(&other.value), (false, true) => Ordering::Greater, (true, false) => Ordering::Less, (true, true) => self.value.cmp(&other.value).reverse() } } } //------------------------------------------------------------------------------ // // Shifts // //------------------------------------------------------------------------------ impl ShlAssign for SCN { fn shl_assign(&mut self, rhs: u64) { self.value <<= rhs; } } impl Shl for SCN { type Output = SCN; fn shl(self, rhs: u64) -> SCN { let mut copy = self.clone(); copy.shl_assign(rhs); copy } } derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, usize); derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u32); derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u16); derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u8); impl ShrAssign for SCN { fn shr_assign(&mut self, rhs: u64) { self.value >>= rhs; } } impl Shr for SCN { type Output = SCN; fn shr(self, rhs: u64) -> SCN { let mut copy = self.clone(); copy.shr_assign(rhs); copy } } derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, usize); derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u32); derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u16); derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u8); derive_signed_shift_operators!(SCN, usize, isize); derive_signed_shift_operators!(SCN, u64, i64); derive_signed_shift_operators!(SCN, u32, i32); derive_signed_shift_operators!(SCN, u16, i16); derive_signed_shift_operators!(SCN, u8, i8); //------------------------------------------------------------------------------ // // Arithmetic // //------------------------------------------------------------------------------ impl Neg for SCN { type Output = SCN; fn neg(self) -> SCN { if self.is_zero() { self } else { SCN{ negative: !self.negative, value: self.value } } } } impl<'a> Neg for &'a SCN { type Output = SCN; fn neg(self) -> SCN { if self.is_zero() { self.clone() } else { SCN{ negative: !self.negative, value: self.value.clone() } } } } impl<'a> AddAssign<&'a SCN> for SCN { fn add_assign(&mut self, rhs: &SCN) { if self.negative == rhs.negative { self.value.add_assign(&rhs.value); } else { if self.value >= rhs.value { self.value.sub_assign(&rhs.value); } else { self.negative = !self.negative; self.value = &rhs.value - &self.value; } } self.cleanup(); } } impl<'a> SubAssign<&'a SCN> for SCN { fn sub_assign(&mut self, rhs: &SCN) { let flipped = SCN{ negative: !rhs.negative, value: rhs.value.clone() }; self.add_assign(&flipped); self.cleanup(); } } impl<'a> MulAssign<&'a SCN> for SCN { fn mul_assign(&mut self, rhs: &SCN) { self.negative ^= rhs.negative; self.value.mul_assign(&rhs.value); self.cleanup(); } } impl<'a> DivAssign<&'a SCN> for SCN { fn div_assign(&mut self, rhs: &SCN) { self.negative ^= rhs.negative; // rounding makes me grumpy let mut remainder = Vec::new(); let copy = self.value.contents.clone(); divmod(&mut self.value.contents, &mut remainder, ©, &rhs.value.contents); if self.negative && !remainder.is_empty() { let one = UCN{ contents: vec![1] }; self.sub_assign(SCN{ negative: false, value: one}); } self.cleanup(); } } impl<'a> RemAssign<&'a SCN> for SCN { fn rem_assign(&mut self, rhs: &SCN) { let base = &self.value % &rhs.value; if self.negative == rhs.negative { self.value = base; } else { self.negative = rhs.negative; self.value = &rhs.value - &base; } self.cleanup(); } } derive_arithmetic_operators!(SCN, Add, add, AddAssign, add_assign); derive_arithmetic_operators!(SCN, Sub, sub, SubAssign, sub_assign); derive_arithmetic_operators!(SCN, Mul, mul, MulAssign, mul_assign); derive_arithmetic_operators!(SCN, Div, div, DivAssign, div_assign); derive_arithmetic_operators!(SCN, Rem, rem, RemAssign, rem_assign); //------------------------------------------------------------------------------ // // Tests! // //------------------------------------------------------------------------------ #[cfg(test)] mod test { use quickcheck::{Arbitrary,Gen}; use super::*; impl Arbitrary for SCN { fn arbitrary(g: &mut G) -> SCN { let neg = (g.next_u32() & 1) == 1; SCN{ negative: neg, value: UCN::arbitrary(g) } } } fn one() -> SCN { SCN{ negative: false, value: UCN::from(1 as u8) } } quickcheck! { fn additive_identity(x: SCN) -> bool { (&x + &SCN::zero()) == x } fn subtractive_identity(x: SCN) -> bool { (&x - &SCN::zero()) == x } fn multiplicative_identity(x: SCN) -> bool { (&x * &one()) == x } fn division_identity(x: SCN) -> bool { let result = &x / &one(); result == x } fn additive_destructor(x: SCN) -> bool { (&x + (- &x)) == SCN::zero() } fn subtractive_destructor(x: SCN) -> bool { (&x - &x) == SCN::zero() } fn multiplicative_destructor(x: SCN) -> bool { (x * SCN::zero()) == SCN::zero() } fn division_deastructor(x: SCN) -> bool { (&x / &x) == one() } fn remainder_destructor(x: SCN) -> bool { (&x % &x) == SCN::zero() } fn addition_commutes(a: SCN, b: SCN) -> bool { (&a + &b) == (&b + &a) } fn multiplication_commutes(a: SCN, b: SCN) -> bool { (&a * &b) == (&b * &a) } fn addition_associates(a: SCN, b: SCN, c: SCN) -> bool { ((&a + &b) + &c) == (&a + (&b + &c)) } fn multiplication_associates(a: SCN, b: SCN, c: SCN) -> bool { ((&a * &b) * &c) == (&a * (&b * &c)) } fn distribution_works(a: SCN, b: SCN, c: SCN) -> bool { (&a * (&b + &c)) == ((&a * &b) + (&a * &c)) } fn negation_works(a: SCN) -> bool { (- &a) == (&a * &SCN{ negative: true, value: UCN::from(1 as u8) }) } fn double_negation_works(a: SCN) -> bool { (- (- &a)) == a } fn negation_commutes(a: SCN, b: SCN) -> bool { ((- &a) * &b) == (&a * (- &b)) } fn negation_cancels(a: SCN, b: SCN) -> bool { ((- &a) * (- &b)) == (&a * &b) } fn negation_distributes(a: SCN, b: SCN) -> bool { (- (&a + &b)) == ((- &a) + (- &b)) } } quickcheck! { fn egcd_works(a: SCN, b: SCN) -> bool { let (d, x, y) = a.clone().egcd(b.clone()); ((a * x) + (b * y)) == d } } }