From 9b56d6667c5797e2d1c75f145f7a460973369554 Mon Sep 17 00:00:00 2001 From: Nicolas Kirchner Date: Wed, 2 Aug 2017 16:12:04 +0200 Subject: [PATCH] Implement assign_from_slice --- bigint/src/algorithms.rs | 14 +++++++------- bigint/src/bigint.rs | 15 +++++++++++++++ bigint/src/biguint.rs | 32 ++++++++++++++++++++++++-------- bigint/src/tests/bigint.rs | 33 +++++++++++++++++++++++++++++++++ bigint/src/tests/biguint.rs | 15 +++++++++++++++ 5 files changed, 94 insertions(+), 15 deletions(-) diff --git a/bigint/src/algorithms.rs b/bigint/src/algorithms.rs index 604fee2..3560103 100644 --- a/bigint/src/algorithms.rs +++ b/bigint/src/algorithms.rs @@ -118,7 +118,7 @@ pub fn div_rem_digit(mut a: BigUint, b: BigDigit) -> (BigUint, BigDigit) { rem = r; } - (a.normalize(), rem) + (a.normalized(), rem) } // Only for the Add impl: @@ -339,7 +339,7 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) { mac3(&mut p.data[..], x1, y1); // Not required, but the adds go faster if we drop any unneeded 0s from the end: - p = p.normalize(); + p.normalize(); add2(&mut acc[b..], &p.data[..]); add2(&mut acc[b * 2..], &p.data[..]); @@ -350,7 +350,7 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) { // p0 = x0 * y0 mac3(&mut p.data[..], x0, y0); - p = p.normalize(); + p.normalize(); add2(&mut acc[..], &p.data[..]); add2(&mut acc[b..], &p.data[..]); @@ -366,7 +366,7 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) { p.data.extend(repeat(0).take(len)); mac3(&mut p.data[..], &j0.data[..], &j1.data[..]); - p = p.normalize(); + p.normalize(); sub2(&mut acc[b..], &p.data[..]); }, @@ -383,7 +383,7 @@ pub fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint { let mut prod = BigUint { data: vec![0; len] }; mac3(&mut prod.data[..], x, y); - prod.normalize() + prod.normalized() } pub fn scalar_mul(a: &mut [BigDigit], b: BigDigit) -> BigDigit { @@ -480,14 +480,14 @@ pub fn div_rem(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) { add2(&mut q.data[j..], &q0.data[..]); sub2(&mut a.data[j..], &prod.data[..]); - a = a.normalize(); + a.normalize(); tmp = q0; } debug_assert!(a < b); - (q.normalize(), a >> shift) + (q.normalized(), a >> shift) } /// Find last set bit diff --git a/bigint/src/bigint.rs b/bigint/src/bigint.rs index 259f619..314d0e5 100644 --- a/bigint/src/bigint.rs +++ b/bigint/src/bigint.rs @@ -1395,6 +1395,21 @@ impl BigInt { BigInt::from_biguint(sign, BigUint::from_slice(slice)) } + /// Reinitializes a `BigInt`. + #[inline] + pub fn assign_from_slice(&mut self, sign: Sign, slice: &[BigDigit]) { + // Normalize: + let slice = &slice[..slice.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)]; + + if sign == NoSign || slice.len() == 0 { + self.sign = NoSign; + self.data = Zero::zero(); + } else { + self.sign = sign; + self.data.assign_from_slice(slice); + } + } + /// Creates and initializes a `BigInt`. /// /// The bytes are in big-endian byte order. diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 2c2d046..61d88cb 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -449,7 +449,7 @@ impl<'a> Sub<&'a BigUint> for BigUint { fn sub(mut self, other: &BigUint) -> BigUint { sub2(&mut self.data[..], &other.data[..]); - self.normalize() + self.normalized() } } @@ -463,7 +463,7 @@ impl<'a> Sub for &'a BigUint { } sub2rev(&self.data[..], &mut other.data[..]); - other.normalize() + other.normalized() } } @@ -477,7 +477,7 @@ impl Sub for BigUint { #[inline] fn sub(mut self, other: BigDigit) -> BigUint { sub2(&mut self.data[..], &[other]); - self.normalize() + self.normalized() } } @@ -491,7 +491,7 @@ impl Sub for BigDigit { } sub2rev(&[self], &mut other.data[..]); - other.normalize() + other.normalized() } } @@ -502,7 +502,7 @@ impl Sub for BigUint { fn sub(mut self, other: DoubleBigDigit) -> BigUint { let (hi, lo) = big_digit::from_doublebigdigit(other); sub2(&mut self.data[..], &[lo, hi]); - self.normalize() + self.normalized() } } @@ -517,7 +517,7 @@ impl Sub for DoubleBigDigit { let (hi, lo) = big_digit::from_doublebigdigit(self); sub2rev(&[lo, hi], &mut other.data[..]); - other.normalize() + other.normalized() } } @@ -1175,7 +1175,7 @@ impl BigUint { /// The digits are in little-endian base 2^32. #[inline] pub fn new(digits: Vec) -> BigUint { - BigUint { data: digits }.normalize() + BigUint { data: digits }.normalized() } /// Creates and initializes a `BigUint`. @@ -1186,6 +1186,16 @@ impl BigUint { BigUint::new(slice.to_vec()) } + /// Assign a value to a `BigUint`. + /// + /// The digits are in little-endian base 2^32. + #[inline] + pub fn assign_from_slice(&mut self, slice: &[BigDigit]) { + self.data.resize(slice.len(), 0); + self.data.copy_from_slice(slice); + self.normalize(); + } + /// Creates and initializes a `BigUint`. /// /// The bytes are in big-endian byte order. @@ -1436,10 +1446,16 @@ impl BigUint { /// Strips off trailing zero bigdigits - comparisons require the last element in the vector to /// be nonzero. #[inline] - fn normalize(mut self) -> BigUint { + fn normalize(&mut self) { while let Some(&0) = self.data.last() { self.data.pop(); } + } + + /// Returns a normalized `BigUint`. + #[inline] + fn normalized(mut self) -> BigUint { + self.normalize(); self } } diff --git a/bigint/src/tests/bigint.rs b/bigint/src/tests/bigint.rs index 9fbebb0..a3c8f6f 100644 --- a/bigint/src/tests/bigint.rs +++ b/bigint/src/tests/bigint.rs @@ -59,6 +59,39 @@ fn test_from_biguint() { check(NoSign, 1, NoSign, 0); } +#[test] +fn test_from_slice() { + fn check(inp_s: Sign, inp_n: u32, ans_s: Sign, ans_n: u32) { + let inp = BigInt::from_slice(inp_s, &[inp_n]); + let ans = BigInt { + sign: ans_s, + data: FromPrimitive::from_u32(ans_n).unwrap(), + }; + assert_eq!(inp, ans); + } + check(Plus, 1, Plus, 1); + check(Plus, 0, NoSign, 0); + check(Minus, 1, Minus, 1); + check(NoSign, 1, NoSign, 0); +} + +#[test] +fn test_assign_from_slice() { + fn check(inp_s: Sign, inp_n: u32, ans_s: Sign, ans_n: u32) { + let mut inp = BigInt::from_slice(Minus, &[2627_u32, 0_u32, 9182_u32, 42_u32]); + inp.assign_from_slice(inp_s, &[inp_n]); + let ans = BigInt { + sign: ans_s, + data: FromPrimitive::from_u32(ans_n).unwrap(), + }; + assert_eq!(inp, ans); + } + check(Plus, 1, Plus, 1); + check(Plus, 0, NoSign, 0); + check(Minus, 1, Minus, 1); + check(NoSign, 1, NoSign, 0); +} + #[test] fn test_from_bytes_be() { fn check(s: &str, result: &str) { diff --git a/bigint/src/tests/biguint.rs b/bigint/src/tests/biguint.rs index 0f3b743..c4be751 100644 --- a/bigint/src/tests/biguint.rs +++ b/bigint/src/tests/biguint.rs @@ -56,6 +56,21 @@ fn test_from_slice() { check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]); } +#[test] +fn test_assign_from_slice() { + fn check(slice: &[BigDigit], data: &[BigDigit]) { + let mut p = BigUint::from_slice(&[2627_u32, 0_u32, 9182_u32, 42_u32]); + p.assign_from_slice(slice); + assert!(p.data == data); + } + check(&[1], &[1]); + check(&[0, 0, 0], &[]); + check(&[1, 2, 0, 0], &[1, 2]); + check(&[0, 0, 1, 2], &[0, 0, 1, 2]); + check(&[0, 0, 1, 2, 0, 0], &[0, 0, 1, 2]); + check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]); +} + #[test] fn test_from_bytes_be() { fn check(s: &str, result: &str) {