From ec63237e41e60e32d9c23100f0f920b5f7a4bcb9 Mon Sep 17 00:00:00 2001 From: Zach Dziura Date: Wed, 8 Jun 2016 23:05:06 -0400 Subject: [PATCH] Implemented custom Error and Result types to be returned Like a good library ought to be, Pumpkin now returns actual Errors, rather than panicking. --- src/common.rs | 65 +++++++++++++++++++++++++---------------------- src/error.rs | 46 +++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/prime.rs | 40 ++++++++--------------------- src/safe_prime.rs | 47 +++++++++++++++++----------------- 5 files changed, 115 insertions(+), 84 deletions(-) create mode 100644 src/error.rs diff --git a/src/common.rs b/src/common.rs index 07756d8..3171063 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,6 +1,8 @@ use ramp::{Int, RandomInt}; use rand::{OsRng, thread_rng}; +use error::{Error, Result}; + static SMALL_PRIMES: [u32; 999] = [3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, @@ -101,45 +103,46 @@ static SMALL_PRIMES: [u32; 999] = [3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, /// Constructs a new prime number with the size of `bit_length` bits, sourced /// from an already-initialized `OsRng`. -pub fn gen_prime(bit_length: usize, rngesus: &mut OsRng) -> Int { - debug_assert!(bit_length >= 512); - let mut candidate: Int; +pub fn gen_prime(bit_length: usize, rngesus: &mut OsRng) -> Result { + if bit_length < 512 { + Err(Error::BitLength(bit_length)) + } else { + let mut candidate: Int; - // In order to remove as much bias from the system as possible, test - // 500 potential candidates at a time before re-seeding the candidate - // with a new random number. - loop { - let mut counter = 0; - let mut found_prime = true; - candidate = rngesus.gen_uint(bit_length); + // In order to remove as much bias from the system as possible, test + // 500 potential candidates at a time before re-seeding the candidate + // with a new random number. + loop { + let mut counter = 0; + let mut found_prime = true; + candidate = rngesus.gen_uint(bit_length); - // We first want to make sure that the candidate is in the appropriate - // size range before continuing. This can easily be done by setting the - // two most significant bits of the candidate number to 1. - candidate.set_bit(bit_length as u32, true); - candidate.set_bit((bit_length-1) as u32, true); + // We first want to make sure that the candidate is in the appropriate + // size range before continuing. This can easily be done by setting the + // two most significant bits of the candidate number to 1. + candidate.set_bit(bit_length as u32, true); + candidate.set_bit((bit_length-1) as u32, true); - // Next, flip the least significant bit to 1, to make sure the candidate - // is odd (no sense in testing primality on an even number, after all). - candidate.set_bit(1, true); + // Next, flip the least significant bit to 1, to make sure the candidate + // is odd (no sense in testing primality on an even number, after all). + candidate.set_bit(1, true); - // Now run through the actual primality check! - while !is_prime(&candidate) { - candidate += 2_usize; - counter += 1; + // Now run through the actual primality check! + while !is_prime(&candidate) { + candidate += 2_usize; + counter += 1; - if counter > 499 { - found_prime = false; - break; + if counter > 499 { + found_prime = false; + break; + } + } + + if found_prime { + return Ok(candidate); } } - - if found_prime { - break; - } } - - candidate } /// Runs the following three tests on a given `candidate` to determine diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..014c599 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,46 @@ +use ramp::Int; +use std::{error, fmt, io, result}; + +pub type Result = result::Result; + +#[derive(Debug)] +pub enum Error { + OsRngInitialization(io::Error), + BitLength(usize) +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::OsRngInitialization(ref err) => { + write!(f, + "Error initializing the random number generator: {}", + err + ) + }, + Error::BitLength(length) => { + write!(f, + "The given bit length is too small; must be at least 512: {}", + length + ) + } + } + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::OsRngInitialization(ref err) => err.description(), + Error::BitLength(_) => { + "The given bit length was less than 512" + } + } + } +} + +impl From for Error { + fn from(err: io::Error) -> Error { + Error::OsRngInitialization(err) + } +} diff --git a/src/lib.rs b/src/lib.rs index fea036e..8b59c4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,6 +54,7 @@ extern crate rand; extern crate test; mod common; +mod error; pub mod prime; pub mod safe_prime; diff --git a/src/prime.rs b/src/prime.rs index 9e009e1..b7923b3 100644 --- a/src/prime.rs +++ b/src/prime.rs @@ -1,9 +1,9 @@ //! Generates cryptographically secure prime numbers. -use ramp::Int; use rand::OsRng; pub use common::gen_prime as from_rng; +use error::{Error, Result}; /// Constructs a new prime number with a size of `bit_length` bits. /// @@ -11,40 +11,22 @@ pub use common::gen_prime as from_rng; /// `from_rng()` function. /// /// Note: the `bit_length` MUST be at least 512-bits. -pub fn new(bit_length: usize) -> Int { - assert!(bit_length >= 512); - let mut rngesus = match OsRng::new() { - Ok(rng) => rng, - Err(reason) => panic!("Error initializing RNG: {}", reason), - }; - - from_rng(bit_length, &mut rngesus) +pub fn new(bit_length: usize) -> Result { + if bit_length < 512 { + Err(Error::BitLength(bit_length)) + } else { + let mut rngesus = try!(OsRng::new()); + Ok(try!(from_rng(bit_length, &mut rngesus))) + } } #[cfg(test)] mod tests { - use ramp::Int; - use super::{fermat, miller_rabin}; - - #[test] - fn test_fermat_pass() { - assert!(fermat(&Int::from(7919))); - } + use super::{new, from_rng}; #[test] #[should_panic] - fn test_fermat_fail() { - assert!(fermat(&Int::from(7920))); - } - - #[test] - fn test_miller_rabin_pass() { - assert!(miller_rabin(&Int::from(7919), 5)); - } - - #[test] - #[should_panic] - fn test_miller_rabin_fail() { - assert!(miller_rabin(&Int::from(7920), 5)); + fn test_prime_bad_bit_length() { + new(511); } } diff --git a/src/safe_prime.rs b/src/safe_prime.rs index 10a6d34..ee9d346 100644 --- a/src/safe_prime.rs +++ b/src/safe_prime.rs @@ -4,6 +4,7 @@ use ramp::Int; use rand::OsRng; pub use common::{gen_prime, is_prime}; +use error::{Error, Result}; /// Constructs a new `SafePrime` with a size of `bit_length` bits. /// @@ -11,37 +12,35 @@ pub use common::{gen_prime, is_prime}; /// `SafePrime::from_rng()` method. /// /// Note: the `bit_length` MUST be at least 512-bits. -pub fn new(bit_length: usize) -> Int { - debug_assert!(bit_length >= 512); - let mut rngesus = match OsRng::new() { - Ok(rng) => rng, - Err(reason) => panic!("Error initializing RNG: {}", reason), - }; - - from_rng(bit_length, &mut rngesus) +pub fn new(bit_length: usize) -> Result { + if bit_length < 512 { + Err(Error::BitLength(bit_length)) + } else { + let mut rngesus = try!(OsRng::new()); + Ok(try!(from_rng(bit_length, &mut rngesus))) + } } /// Constructs a new `SafePrime` with the size of `bit_length` bits, sourced /// from an already-initialized `OsRng`. -pub fn from_rng(bit_length: usize, mut rngesus: &mut OsRng) -> Int { - debug_assert!(bit_length >= 512); - let mut candidate: Int; +pub fn from_rng(bit_length: usize, mut rngesus: &mut OsRng) -> Result { + if bit_length < 512 { + Err(Error::BitLength(bit_length)) + } else { + let mut candidate: Int; - // Circumvent uninitialized warning (technically valid but compiler - // cannot determine that `clone_from` will fill the value. - let mut candidate_p: Int = Int::zero(); + loop { + candidate = try!(gen_prime(bit_length, &mut rngesus)); - loop { - candidate = gen_prime(bit_length, &mut rngesus); + let mut candidate_p = (&candidate).clone(); + candidate_p -= 1_usize; + candidate_p /= 2_usize; - candidate_p.clone_from(&candidate); - candidate_p -= 1_usize; - candidate_p /= 2_usize; - - if is_prime(&candidate_p) { - break; + if is_prime(&candidate_p) { + break; + } } - } - candidate + Ok(candidate) + } }