Implemented custom Error and Result types to be returned

Like a good library ought to be, Pumpkin now returns actual Errors, rather
than panicking.
This commit is contained in:
Zach Dziura 2016-06-08 23:05:06 -04:00
parent b6134a6cfd
commit ec63237e41
5 changed files with 115 additions and 84 deletions

View file

@ -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,8 +103,10 @@ 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);
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
@ -135,11 +139,10 @@ pub fn gen_prime(bit_length: usize, rngesus: &mut OsRng) -> Int {
}
if found_prime {
break;
return Ok(candidate);
}
}
}
candidate
}
/// Runs the following three tests on a given `candidate` to determine

46
src/error.rs Normal file
View file

@ -0,0 +1,46 @@
use ramp::Int;
use std::{error, fmt, io, result};
pub type Result = result::Result<Int, Error>;
#[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<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error::OsRngInitialization(err)
}
}

View file

@ -54,6 +54,7 @@ extern crate rand;
extern crate test;
mod common;
mod error;
pub mod prime;
pub mod safe_prime;

View file

@ -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);
}
}

View file

@ -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,30 +12,27 @@ 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);
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 = gen_prime(bit_length, &mut rngesus);
candidate = try!(gen_prime(bit_length, &mut rngesus));
candidate_p.clone_from(&candidate);
let mut candidate_p = (&candidate).clone();
candidate_p -= 1_usize;
candidate_p /= 2_usize;
@ -43,5 +41,6 @@ pub fn from_rng(bit_length: usize, mut rngesus: &mut OsRng) -> Int {
}
}
candidate
Ok(candidate)
}
}