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:
parent
b6134a6cfd
commit
ec63237e41
5 changed files with 115 additions and 84 deletions
|
@ -1,6 +1,8 @@
|
||||||
use ramp::{Int, RandomInt};
|
use ramp::{Int, RandomInt};
|
||||||
use rand::{OsRng, thread_rng};
|
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,
|
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,
|
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,
|
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
|
/// Constructs a new prime number with the size of `bit_length` bits, sourced
|
||||||
/// from an already-initialized `OsRng`.
|
/// from an already-initialized `OsRng`.
|
||||||
pub fn gen_prime(bit_length: usize, rngesus: &mut OsRng) -> Int {
|
pub fn gen_prime(bit_length: usize, rngesus: &mut OsRng) -> Result {
|
||||||
debug_assert!(bit_length >= 512);
|
if bit_length < 512 {
|
||||||
let mut candidate: Int;
|
Err(Error::BitLength(bit_length))
|
||||||
|
} else {
|
||||||
|
let mut candidate: Int;
|
||||||
|
|
||||||
// In order to remove as much bias from the system as possible, test
|
// In order to remove as much bias from the system as possible, test
|
||||||
// 500 potential candidates at a time before re-seeding the candidate
|
// 500 potential candidates at a time before re-seeding the candidate
|
||||||
// with a new random number.
|
// with a new random number.
|
||||||
loop {
|
loop {
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
let mut found_prime = true;
|
let mut found_prime = true;
|
||||||
candidate = rngesus.gen_uint(bit_length);
|
candidate = rngesus.gen_uint(bit_length);
|
||||||
|
|
||||||
// We first want to make sure that the candidate is in the appropriate
|
// 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
|
// size range before continuing. This can easily be done by setting the
|
||||||
// two most significant bits of the candidate number to 1.
|
// two most significant bits of the candidate number to 1.
|
||||||
candidate.set_bit(bit_length as u32, true);
|
candidate.set_bit(bit_length as u32, true);
|
||||||
candidate.set_bit((bit_length-1) 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
|
// 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).
|
// is odd (no sense in testing primality on an even number, after all).
|
||||||
candidate.set_bit(1, true);
|
candidate.set_bit(1, true);
|
||||||
|
|
||||||
// Now run through the actual primality check!
|
// Now run through the actual primality check!
|
||||||
while !is_prime(&candidate) {
|
while !is_prime(&candidate) {
|
||||||
candidate += 2_usize;
|
candidate += 2_usize;
|
||||||
counter += 1;
|
counter += 1;
|
||||||
|
|
||||||
if counter > 499 {
|
if counter > 499 {
|
||||||
found_prime = false;
|
found_prime = false;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found_prime {
|
||||||
|
return Ok(candidate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if found_prime {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
candidate
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the following three tests on a given `candidate` to determine
|
/// Runs the following three tests on a given `candidate` to determine
|
||||||
|
|
46
src/error.rs
Normal file
46
src/error.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,6 +54,7 @@ extern crate rand;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
mod error;
|
||||||
pub mod prime;
|
pub mod prime;
|
||||||
pub mod safe_prime;
|
pub mod safe_prime;
|
||||||
|
|
||||||
|
|
40
src/prime.rs
40
src/prime.rs
|
@ -1,9 +1,9 @@
|
||||||
//! Generates cryptographically secure prime numbers.
|
//! Generates cryptographically secure prime numbers.
|
||||||
|
|
||||||
use ramp::Int;
|
|
||||||
use rand::OsRng;
|
use rand::OsRng;
|
||||||
|
|
||||||
pub use common::gen_prime as from_rng;
|
pub use common::gen_prime as from_rng;
|
||||||
|
use error::{Error, Result};
|
||||||
|
|
||||||
/// Constructs a new prime number with a size of `bit_length` bits.
|
/// 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.
|
/// `from_rng()` function.
|
||||||
///
|
///
|
||||||
/// Note: the `bit_length` MUST be at least 512-bits.
|
/// Note: the `bit_length` MUST be at least 512-bits.
|
||||||
pub fn new(bit_length: usize) -> Int {
|
pub fn new(bit_length: usize) -> Result {
|
||||||
assert!(bit_length >= 512);
|
if bit_length < 512 {
|
||||||
let mut rngesus = match OsRng::new() {
|
Err(Error::BitLength(bit_length))
|
||||||
Ok(rng) => rng,
|
} else {
|
||||||
Err(reason) => panic!("Error initializing RNG: {}", reason),
|
let mut rngesus = try!(OsRng::new());
|
||||||
};
|
Ok(try!(from_rng(bit_length, &mut rngesus)))
|
||||||
|
}
|
||||||
from_rng(bit_length, &mut rngesus)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use ramp::Int;
|
use super::{new, from_rng};
|
||||||
use super::{fermat, miller_rabin};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fermat_pass() {
|
|
||||||
assert!(fermat(&Int::from(7919)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn test_fermat_fail() {
|
fn test_prime_bad_bit_length() {
|
||||||
assert!(fermat(&Int::from(7920)));
|
new(511);
|
||||||
}
|
|
||||||
|
|
||||||
#[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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use ramp::Int;
|
||||||
use rand::OsRng;
|
use rand::OsRng;
|
||||||
|
|
||||||
pub use common::{gen_prime, is_prime};
|
pub use common::{gen_prime, is_prime};
|
||||||
|
use error::{Error, Result};
|
||||||
|
|
||||||
/// Constructs a new `SafePrime` with a size of `bit_length` bits.
|
/// 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.
|
/// `SafePrime::from_rng()` method.
|
||||||
///
|
///
|
||||||
/// Note: the `bit_length` MUST be at least 512-bits.
|
/// Note: the `bit_length` MUST be at least 512-bits.
|
||||||
pub fn new(bit_length: usize) -> Int {
|
pub fn new(bit_length: usize) -> Result {
|
||||||
debug_assert!(bit_length >= 512);
|
if bit_length < 512 {
|
||||||
let mut rngesus = match OsRng::new() {
|
Err(Error::BitLength(bit_length))
|
||||||
Ok(rng) => rng,
|
} else {
|
||||||
Err(reason) => panic!("Error initializing RNG: {}", reason),
|
let mut rngesus = try!(OsRng::new());
|
||||||
};
|
Ok(try!(from_rng(bit_length, &mut rngesus)))
|
||||||
|
}
|
||||||
from_rng(bit_length, &mut rngesus)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new `SafePrime` with the size of `bit_length` bits, sourced
|
/// Constructs a new `SafePrime` with the size of `bit_length` bits, sourced
|
||||||
/// from an already-initialized `OsRng`.
|
/// from an already-initialized `OsRng`.
|
||||||
pub fn from_rng(bit_length: usize, mut rngesus: &mut OsRng) -> Int {
|
pub fn from_rng(bit_length: usize, mut rngesus: &mut OsRng) -> Result {
|
||||||
debug_assert!(bit_length >= 512);
|
if bit_length < 512 {
|
||||||
let mut candidate: Int;
|
Err(Error::BitLength(bit_length))
|
||||||
|
} else {
|
||||||
|
let mut candidate: Int;
|
||||||
|
|
||||||
// Circumvent uninitialized warning (technically valid but compiler
|
loop {
|
||||||
// cannot determine that `clone_from` will fill the value.
|
candidate = try!(gen_prime(bit_length, &mut rngesus));
|
||||||
let mut candidate_p: Int = Int::zero();
|
|
||||||
|
|
||||||
loop {
|
let mut candidate_p = (&candidate).clone();
|
||||||
candidate = gen_prime(bit_length, &mut rngesus);
|
candidate_p -= 1_usize;
|
||||||
|
candidate_p /= 2_usize;
|
||||||
|
|
||||||
candidate_p.clone_from(&candidate);
|
if is_prime(&candidate_p) {
|
||||||
candidate_p -= 1_usize;
|
break;
|
||||||
candidate_p /= 2_usize;
|
}
|
||||||
|
|
||||||
if is_prime(&candidate_p) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
candidate
|
Ok(candidate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue