Compare commits
7 Commits
better_rsa
...
explicit_s
| Author | SHA1 | Date | |
|---|---|---|---|
| 6418c323ad | |||
| c14fa90c4a | |||
| 52103991d7 | |||
| 49b2c92d87 | |||
| 02aa03ca5c | |||
| 9594a40d32 | |||
| 10a46a7e81 |
@@ -9,7 +9,13 @@ license-file = "LICENSE"
|
|||||||
repository = "https://github.com/acw/simple_crypto"
|
repository = "https://github.com/acw/simple_crypto"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
byteorder = "^1.2.1"
|
||||||
|
digest = "^0.7.1"
|
||||||
|
num = "^0.1.39"
|
||||||
rand = "^0.3"
|
rand = "^0.3"
|
||||||
|
sha-1 = "^0.7.0"
|
||||||
|
sha2 = "^0.7.0"
|
||||||
|
simple_asn1 = "^0.1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
quickcheck = "^0.4.1"
|
quickcheck = "^0.4.1"
|
||||||
|
|||||||
70
src/cryptonum/arithmetic_traits.rs
Normal file
70
src/cryptonum/arithmetic_traits.rs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
macro_rules! define_arithmetic {
|
||||||
|
($type: ident, $asncl: ident, $asnfn: ident,
|
||||||
|
$cl: ident, $clfn: ident,
|
||||||
|
$self: ident, $o: ident, $body: block) =>
|
||||||
|
{
|
||||||
|
build_assign_operator!($type, $asncl, $asnfn, $self, $o, $body);
|
||||||
|
derive_arithmetic_operators!($type, $cl, $clfn, $asncl, $asnfn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! build_assign_operator {
|
||||||
|
($type: ident, $asncl: ident, $asnfn: ident, $self: ident,
|
||||||
|
$o: ident, $body: block) =>
|
||||||
|
{
|
||||||
|
impl<'a> $asncl<&'a $type> for $type {
|
||||||
|
fn $asnfn(&mut $self, $o: &$type) $body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! derive_arithmetic_operators
|
||||||
|
{
|
||||||
|
($type: ident, $cl: ident, $fn: ident, $asncl: ident, $asnfn: ident) => {
|
||||||
|
impl $asncl for $type {
|
||||||
|
fn $asnfn(&mut self, other: $type) {
|
||||||
|
self.$asnfn(&other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $cl for $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn $fn(self, other: $type) -> $type {
|
||||||
|
let mut res = self.clone();
|
||||||
|
res.$asnfn(&other);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> $cl<&'a $type> for $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn $fn(self, other: &$type) -> $type {
|
||||||
|
let mut res = self.clone();
|
||||||
|
res.$asnfn(other);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> $cl<$type> for &'a $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn $fn(self, other: $type) -> $type {
|
||||||
|
let mut res = self.clone();
|
||||||
|
res.$asnfn(&other);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a,'b> $cl<&'a $type> for &'b $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn $fn(self, other: &$type) -> $type {
|
||||||
|
let mut res = self.clone();
|
||||||
|
res.$asnfn(other);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
112
src/cryptonum/barrett.rs
Normal file
112
src/cryptonum/barrett.rs
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
macro_rules! derive_barrett
|
||||||
|
{
|
||||||
|
($type: ident, $barrett: ident, $count: expr) => {
|
||||||
|
impl CryptoNumFastMod for $type {
|
||||||
|
type BarrettMu = $barrett;
|
||||||
|
|
||||||
|
fn barrett_mu(&self) -> Option<$barrett> {
|
||||||
|
// Step #0: Don't divide by 0.
|
||||||
|
if self.is_zero() {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
// Step #1: Compute k.
|
||||||
|
let mut k = $count;
|
||||||
|
while self.contents[k - 1] == 0 { k -= 1 };
|
||||||
|
// Step #2: The algorithm below only works if x has at most 2k
|
||||||
|
// digits, so if k*2 < count, abort this whole process.
|
||||||
|
if (k * 2) < $count {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
// Step #2: Compute floor(b^2k / m), where m is this value.
|
||||||
|
let mut widebody_b2k = [0; ($count * 2) + 1];
|
||||||
|
let mut widebody_self = [0; ($count * 2) + 1];
|
||||||
|
let mut quotient = [0; ($count * 2) + 1];
|
||||||
|
let mut remainder = [0; ($count * 2) + 1];
|
||||||
|
widebody_b2k[$count * 2] = 1;
|
||||||
|
for i in 0..k {
|
||||||
|
widebody_self[i] = self.contents[i];
|
||||||
|
}
|
||||||
|
generic_div(&widebody_b2k, &widebody_self,
|
||||||
|
&mut quotient, &mut remainder);
|
||||||
|
let mut result = [0; $count + 1];
|
||||||
|
for (idx, val) in quotient.iter().enumerate() {
|
||||||
|
if idx < ($count + 1) {
|
||||||
|
result[idx] = *val;
|
||||||
|
} else {
|
||||||
|
if quotient[idx] != 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some($barrett{k: k, progenitor: self.clone(), contents: result})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fastmod(&self, mu: &$barrett) -> $type {
|
||||||
|
// This algorithm is from our friends at the Handbook of
|
||||||
|
// Applied Cryptography, Chapter 14, Algorithm 14.42.
|
||||||
|
// Step #0:
|
||||||
|
// Expand x so that it has the same size as the Barrett
|
||||||
|
// value.
|
||||||
|
let mut x = [0; $count + 1];
|
||||||
|
for i in 0..$count {
|
||||||
|
x[i] = self.contents[i];
|
||||||
|
}
|
||||||
|
// Step #1:
|
||||||
|
// q1 <- floor(x / b^(k-1))
|
||||||
|
let mut q1 = x.clone();
|
||||||
|
generic_shr(&mut q1, &x, 64 * (mu.k - 1));
|
||||||
|
// q2 <- q1 * mu
|
||||||
|
let q2 = expanding_mul(&q1, &mu.contents);
|
||||||
|
// q3 <- floor(q2 / b^(k+1))
|
||||||
|
let mut q3big = q2.clone();
|
||||||
|
generic_shr(&mut q3big, &q2, 64 * (mu.k + 1));
|
||||||
|
let mut q3 = [0; $count + 1];
|
||||||
|
for (idx, val) in q3big.iter().enumerate() {
|
||||||
|
if idx <= $count {
|
||||||
|
q3[idx] = *val;
|
||||||
|
} else {
|
||||||
|
assert_eq!(*val, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Step #2:
|
||||||
|
// r1 <- x mod b^(k+1)
|
||||||
|
let mut r1 = x.clone();
|
||||||
|
for i in mu.k..($count+1) {
|
||||||
|
r1[i] = 0;
|
||||||
|
}
|
||||||
|
// r2 <- q3 * m mod b^(k+1)
|
||||||
|
let mut moddedm = [0; $count + 1];
|
||||||
|
for i in 0..mu.k {
|
||||||
|
moddedm[i] = mu.progenitor.contents[i];
|
||||||
|
}
|
||||||
|
let mut r2 = q3.clone();
|
||||||
|
generic_mul(&mut r2, &q3, &moddedm);
|
||||||
|
// r <- r1 - r2
|
||||||
|
let mut r = r1.clone();
|
||||||
|
generic_sub(&mut r, &r2);
|
||||||
|
let is_negative = !ge(&r1, &r2);
|
||||||
|
// Step #3:
|
||||||
|
// if r < 0 then r <- r + b^(k + 1)
|
||||||
|
if is_negative {
|
||||||
|
let mut bk1 = [0; $count + 1];
|
||||||
|
bk1[mu.k] = 1;
|
||||||
|
generic_add(&mut r, &bk1);
|
||||||
|
}
|
||||||
|
// Step #4:
|
||||||
|
// while r >= m do: r <- r - m.
|
||||||
|
while ge(&r, &moddedm) {
|
||||||
|
generic_sub(&mut r, &moddedm);
|
||||||
|
}
|
||||||
|
// Step #5:
|
||||||
|
// return r
|
||||||
|
let mut retval = [0; $count];
|
||||||
|
for i in 0..$count {
|
||||||
|
retval[i] = r[i];
|
||||||
|
}
|
||||||
|
assert_eq!(r[$count], 0);
|
||||||
|
$type{ contents: retval }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
77
src/cryptonum/conversions.rs
Normal file
77
src/cryptonum/conversions.rs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
macro_rules! generate_unsigned_conversions
|
||||||
|
{
|
||||||
|
($type: ident, $count: expr) => {
|
||||||
|
generate_unsigned_primtype_conversions!($type, u8, $count);
|
||||||
|
generate_unsigned_primtype_conversions!($type, u16, $count);
|
||||||
|
generate_unsigned_primtype_conversions!($type, u32, $count);
|
||||||
|
generate_unsigned_primtype_conversions!($type, u64, $count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! generate_signed_conversions
|
||||||
|
{
|
||||||
|
($type: ident, $base: ident) => {
|
||||||
|
generate_signed_primtype_conversions!($type, $base, i8, u8);
|
||||||
|
generate_signed_primtype_conversions!($type, $base, i16, u16);
|
||||||
|
generate_signed_primtype_conversions!($type, $base, i32, u32);
|
||||||
|
generate_signed_primtype_conversions!($type, $base, i64, u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! generate_unsigned_primtype_conversions
|
||||||
|
{
|
||||||
|
($type: ident, $base: ty, $count: expr) => {
|
||||||
|
generate_from!($type, $base, x, {
|
||||||
|
let mut res = $type{ contents: [0; $count] };
|
||||||
|
res.contents[0] = x as u64;
|
||||||
|
res
|
||||||
|
});
|
||||||
|
generate_into!($type, $base, self, {
|
||||||
|
self.contents[0] as $base
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! generate_signed_primtype_conversions
|
||||||
|
{
|
||||||
|
($type: ident, $untype: ident, $base: ident, $unbase: ident) => {
|
||||||
|
generate_from!($type, $unbase, x, {
|
||||||
|
$type{ negative: false, value: $untype::from(x) }
|
||||||
|
});
|
||||||
|
generate_into!($type, $unbase, self, {
|
||||||
|
self.value.contents[0] as $unbase
|
||||||
|
});
|
||||||
|
generate_from!($type, $base, x, {
|
||||||
|
let neg = x < 0;
|
||||||
|
$type{negative: neg, value: $untype::from(x.abs() as $unbase)}
|
||||||
|
});
|
||||||
|
generate_into!($type, $base, self, {
|
||||||
|
if self.negative {
|
||||||
|
let start = self.value.contents[0] as $unbase;
|
||||||
|
let mask = ($unbase::max_value() - 1) >> 1;
|
||||||
|
let res = (start & mask) as $base;
|
||||||
|
-res
|
||||||
|
} else {
|
||||||
|
self.value.contents[0] as $base
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! generate_from
|
||||||
|
{
|
||||||
|
($type: ident, $base: ty, $x: ident, $body: block) => {
|
||||||
|
impl From<$base> for $type {
|
||||||
|
fn from($x: $base) -> $type $body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! generate_into
|
||||||
|
{
|
||||||
|
($type: ident, $base: ty, $self: ident, $body: block) => {
|
||||||
|
impl Into<$base> for $type {
|
||||||
|
fn into($self) -> $base $body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
use cryptonum::signed::Signed;
|
|
||||||
use cryptonum::traits::*;
|
|
||||||
use std::ops::*;
|
|
||||||
|
|
||||||
pub fn modinv<'a,T>(e: &T, phi: &T) -> T
|
|
||||||
where
|
|
||||||
T: Clone + CryptoNumBase + Ord,
|
|
||||||
T: AddAssign + SubAssign + MulAssign + DivAssign,
|
|
||||||
T: Add<Output=T> + Sub<Output=T> + Mul<Output=T> + Div<Output=T>,
|
|
||||||
&'a T: Sub<Output=T>,
|
|
||||||
T: 'a
|
|
||||||
{
|
|
||||||
let (_, mut x, _) = extended_euclidean(e, phi);
|
|
||||||
let int_phi = Signed::<T>::new(phi.clone());
|
|
||||||
while x.is_negative() {
|
|
||||||
x += &int_phi;
|
|
||||||
}
|
|
||||||
x.abs()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn modexp<T>(b: &T, e: &T, m: &T) -> T
|
|
||||||
{
|
|
||||||
panic!("modexp")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extended_euclidean<T>(a: &T, b: &T) -> (Signed<T>, Signed<T>, Signed<T>)
|
|
||||||
where
|
|
||||||
T: Clone + CryptoNumBase + Div + Mul + Sub
|
|
||||||
{
|
|
||||||
let posinta = Signed::<T>::new(a.clone());
|
|
||||||
let posintb = Signed::<T>::new(b.clone());
|
|
||||||
let (mut d, mut x, mut y) = egcd(&posinta, &posintb);
|
|
||||||
|
|
||||||
if d.is_negative() {
|
|
||||||
d.negate();
|
|
||||||
x.negate();
|
|
||||||
y.negate();
|
|
||||||
}
|
|
||||||
|
|
||||||
(d, x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn egcd<T>(a: &Signed<T>, b: &Signed<T>) -> (Signed<T>,Signed<T>,Signed<T>)
|
|
||||||
where
|
|
||||||
T: Clone + CryptoNumBase + Div + Mul + Sub
|
|
||||||
{
|
|
||||||
let mut s = Signed::<T>::zero();
|
|
||||||
let mut old_s = Signed::<T>::from_u8(1);
|
|
||||||
let mut t = Signed::<T>::from_u8(1);
|
|
||||||
let mut old_t = Signed::<T>::zero();
|
|
||||||
let mut r = b.clone();
|
|
||||||
let mut old_r = a.clone();
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
@@ -3,16 +3,61 @@
|
|||||||
//! This module is designed to provide large, fixed-width number support for
|
//! This module is designed to provide large, fixed-width number support for
|
||||||
//! the rest of the Simple-Crypto libraries. Feel free to use it other places,
|
//! the rest of the Simple-Crypto libraries. Feel free to use it other places,
|
||||||
//! of course, but that's its origin.
|
//! of course, but that's its origin.
|
||||||
|
//!
|
||||||
|
//! Key generation is supported, using either the native `OsRng` or a random
|
||||||
|
//! number generator of your choice. Obviously, you should be careful to use
|
||||||
|
//! a cryptographically-sound random number generator sufficient for the
|
||||||
|
//! security level you're going for.
|
||||||
|
//!
|
||||||
|
//! Signing and verification are via standard PKCS1 padding, but can be
|
||||||
|
//! adjusted based on the exact hash you want. This library also supports
|
||||||
|
//! somewhat arbitrary signing mechanisms used by your weirder network
|
||||||
|
//! protocols. (I'm looking at you, Tor.)
|
||||||
|
//!
|
||||||
|
//! Encryption and decryption are via the OAEP mechanism, as described in
|
||||||
|
//! NIST documents.
|
||||||
|
//!
|
||||||
|
#[macro_use]
|
||||||
|
mod arithmetic_traits;
|
||||||
|
#[macro_use]
|
||||||
|
mod barrett;
|
||||||
|
#[macro_use]
|
||||||
|
mod conversions;
|
||||||
mod core;
|
mod core;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod builder;
|
mod modops;
|
||||||
//mod extended_math;
|
#[macro_use]
|
||||||
// mod primes;
|
mod primes;
|
||||||
|
#[macro_use]
|
||||||
mod signed;
|
mod signed;
|
||||||
mod traits;
|
#[macro_use]
|
||||||
mod unsigned;
|
mod unsigned;
|
||||||
|
mod traits;
|
||||||
|
|
||||||
|
use cryptonum::core::*;
|
||||||
|
use num::{BigUint,BigInt};
|
||||||
|
use rand::Rng;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt::{Debug,Error,Formatter};
|
||||||
|
use std::ops::*;
|
||||||
|
pub use self::traits::*;
|
||||||
|
use self::primes::SMALL_PRIMES;
|
||||||
|
|
||||||
|
construct_unsigned!(U512, BarretMu512, u512, 8);
|
||||||
|
construct_unsigned!(U1024, BarretMu1024, u1024, 16);
|
||||||
|
construct_unsigned!(U2048, BarretMu2048, u2048, 32);
|
||||||
|
construct_unsigned!(U3072, BarretMu3072, u3072, 48);
|
||||||
|
construct_unsigned!(U4096, BarretMu4096, u4096, 64);
|
||||||
|
construct_unsigned!(U7680, BarretMu7680, u7680, 120);
|
||||||
|
construct_unsigned!(U8192, BarretMu8192, u8192, 128);
|
||||||
|
construct_unsigned!(U15360, BarretMu15360, u15360, 240);
|
||||||
|
|
||||||
|
construct_signed!(I512, U512, i512);
|
||||||
|
construct_signed!(I1024, U1024, i1024);
|
||||||
|
construct_signed!(I2048, U2048, i2048);
|
||||||
|
construct_signed!(I3072, U3072, i3072);
|
||||||
|
construct_signed!(I4096, U4096, i4096);
|
||||||
|
construct_signed!(I7680, U7680, i7680);
|
||||||
|
construct_signed!(I8192, U8192, i8192);
|
||||||
|
construct_signed!(I15360, U15360, i15360);
|
||||||
|
|
||||||
// pub use self::extended_math::{modexp,modinv,extended_euclidean,egcd};
|
|
||||||
// pub use self::primes::{probably_prime};
|
|
||||||
pub use self::signed::{Signed};
|
|
||||||
pub use self::unsigned::{U512,U1024,U2048,U3072,U4096,U7680,U8192,U15360};
|
|
||||||
|
|||||||
16
src/cryptonum/modops.rs
Normal file
16
src/cryptonum/modops.rs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
macro_rules! derive_modulo_operations
|
||||||
|
{
|
||||||
|
($type: ident) => {
|
||||||
|
impl CryptoNumModOps for $type {
|
||||||
|
fn modinv(&self, _b: &Self) -> Self {
|
||||||
|
panic!("modinv");
|
||||||
|
}
|
||||||
|
fn modexp(&self, _a: &Self, _b: &Self) -> Self {
|
||||||
|
panic!("modexp");
|
||||||
|
}
|
||||||
|
fn modsq(&self, _v: &Self) -> Self {
|
||||||
|
panic!("modsq");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,4 @@
|
|||||||
use cryptonum::extended_math::modexp;
|
pub static SMALL_PRIMES: [u32; 310] = [
|
||||||
use cryptonum::traits::*;
|
|
||||||
use rand::Rng;
|
|
||||||
use std::ops::*;
|
|
||||||
|
|
||||||
static SMALL_PRIMES: [u64; 310] = [
|
|
||||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
|
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
|
||||||
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
|
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
|
||||||
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
|
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
|
||||||
@@ -36,30 +31,14 @@ static SMALL_PRIMES: [u64; 310] = [
|
|||||||
1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987,
|
1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987,
|
||||||
1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053];
|
1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053];
|
||||||
|
|
||||||
|
macro_rules! derive_prime_operations
|
||||||
pub fn probably_prime<G,T>(x: &T, g: &mut G, iters: usize) -> bool
|
|
||||||
where
|
|
||||||
G: Rng,
|
|
||||||
T: Clone + PartialOrd + Rem + Sub,
|
|
||||||
T: CryptoNumBase + CryptoNumSerialization,
|
|
||||||
{
|
{
|
||||||
for tester in SMALL_PRIMES.iter() {
|
($type: ident, $count: expr) => {
|
||||||
if (x % T::from_u64(*tester)) == T::zero() {
|
impl $type {
|
||||||
return false;
|
fn miller_rabin<G: Rng>(&self, g: &mut G, iters: usize)
|
||||||
}
|
-> bool
|
||||||
}
|
{
|
||||||
miller_rabin(g, x, iters)
|
let nm1 = self - $type::from(1 as u8);
|
||||||
}
|
|
||||||
|
|
||||||
fn miller_rabin<G,T>(g: &mut G, n: T, iters: usize) -> bool
|
|
||||||
where
|
|
||||||
G: Rng,
|
|
||||||
T: Clone + PartialEq + PartialOrd + Sub,
|
|
||||||
T: CryptoNumBase + CryptoNumSerialization,
|
|
||||||
{
|
|
||||||
let one = T::from_u8(1);
|
|
||||||
let two = T::from_u8(2);
|
|
||||||
let nm1 = n - one;
|
|
||||||
// Quoth Wikipedia:
|
// Quoth Wikipedia:
|
||||||
// write n - 1 as 2^r*d with d odd by factoring powers of 2 from n - 1
|
// write n - 1 as 2^r*d with d odd by factoring powers of 2 from n - 1
|
||||||
let mut d = nm1.clone();
|
let mut d = nm1.clone();
|
||||||
@@ -67,25 +46,25 @@ fn miller_rabin<G,T>(g: &mut G, n: T, iters: usize) -> bool
|
|||||||
while d.is_even() {
|
while d.is_even() {
|
||||||
d >>= 1;
|
d >>= 1;
|
||||||
r += 1;
|
r += 1;
|
||||||
assert!(r < n.bit_size());
|
assert!(r < ($count * 64));
|
||||||
}
|
}
|
||||||
// WitnessLoop: repeat k times
|
// WitnessLoop: repeat k times
|
||||||
'WitnessLoop: for _k in 0..iters {
|
'WitnessLoop: for _k in 0..iters {
|
||||||
// pick a random integer a in the range [2, n - 2]
|
// pick a random integer a in the range [2, n - 2]
|
||||||
let a = random_in_range(g, &two, &nm1);
|
let a = $type::random_in_range(g, &$type::from(2 as u8), &nm1);
|
||||||
// x <- a^d mod n
|
// x <- a^d mod n
|
||||||
let mut x = modexp(&a, &d, &n);
|
let mut x = a.modexp(&d, &self);
|
||||||
// if x = 1 or x = n - 1 then
|
// if x = 1 or x = n - 1 then
|
||||||
if (&x == &one) || (&x == &nm1) {
|
if (&x == &$type::from(1 as u8)) || (&x == &nm1) {
|
||||||
// continue WitnessLoop
|
// continue WitnessLoop
|
||||||
continue 'WitnessLoop;
|
continue 'WitnessLoop;
|
||||||
}
|
}
|
||||||
// repeat r - 1 times:
|
// repeat r - 1 times:
|
||||||
for _i in 0..r {
|
for _i in 0..r {
|
||||||
// x <- x^2 mod n
|
// x <- x^2 mod n
|
||||||
x = modexp(&x, &two, &n);
|
x = x.modexp(&$type::from(2 as u8), &self);
|
||||||
// if x = 1 then
|
// if x = 1 then
|
||||||
if &x == &one {
|
if &x == &$type::from(1 as u8) {
|
||||||
// return composite
|
// return composite
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -100,30 +79,41 @@ fn miller_rabin<G,T>(g: &mut G, n: T, iters: usize) -> bool
|
|||||||
}
|
}
|
||||||
// return probably prime
|
// return probably prime
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_in_range<G,T>(rng: &mut G, min: &T, max: &T) -> T
|
fn random_in_range<G: Rng>(rng: &mut G, min: &$type, max: &$type)
|
||||||
where
|
-> $type
|
||||||
G: Rng,
|
{
|
||||||
T: CryptoNumSerialization + PartialOrd
|
|
||||||
{
|
|
||||||
assert_eq!(min.byte_size(), max.byte_size());
|
|
||||||
loop {
|
loop {
|
||||||
let candidate = random_number(rng, min.byte_size());
|
let candidate = $type::random_number(rng);
|
||||||
|
|
||||||
if (&candidate >= min) && (&candidate < max) {
|
if (&candidate >= min) && (&candidate < max) {
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_number<G: Rng>(rng: &mut G) -> $type {
|
||||||
|
let mut components = [0; $count];
|
||||||
|
for i in 0..$count {
|
||||||
|
components[i] = rng.gen();
|
||||||
|
}
|
||||||
|
$type{ contents: components }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CryptoNumPrimes for $type {
|
||||||
|
fn probably_prime<G: Rng>(&self, g: &mut G, iters: usize) -> bool {
|
||||||
|
for tester in SMALL_PRIMES.iter() {
|
||||||
|
let testvalue = $type::from(*tester);
|
||||||
|
if (self % testvalue).is_zero() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.miller_rabin(g, iters)
|
||||||
|
}
|
||||||
|
fn generate_prime<G: Rng>(_g: &mut G, _iters: usize, _e: &Self, _min: &Self) -> Self {
|
||||||
|
panic!("generate_prime");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_number<G,T>(rng: &mut G, bytelen: usize) -> T
|
|
||||||
where
|
|
||||||
G: Rng,
|
|
||||||
T: CryptoNumSerialization
|
|
||||||
{
|
|
||||||
let components: Vec<u8> = rng.gen_iter().take(bytelen).collect();
|
|
||||||
T::from_bytes(&components)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,48 +1,54 @@
|
|||||||
use cryptonum::traits::*;
|
macro_rules! construct_signed {
|
||||||
use std::cmp::Ordering;
|
($type: ident, $base: ident, $modname: ident) => {
|
||||||
use std::fmt::{Debug,Error,Formatter};
|
#[derive(Clone,PartialEq,Eq)]
|
||||||
use std::ops::*;
|
pub struct $type {
|
||||||
|
negative: bool,
|
||||||
pub struct Signed<T: Sized> {
|
value: $base
|
||||||
positive: bool,
|
|
||||||
value: T
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Signed<T> {
|
|
||||||
pub fn new(v: T) -> Signed<T> {
|
|
||||||
Signed{ positive: true, value: v }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn abs(&self) -> T
|
impl Debug for $type {
|
||||||
where T: Clone
|
fn fmt(&self, f: &mut Formatter) -> Result<(),Error> {
|
||||||
{
|
if self.negative {
|
||||||
self.value.clone()
|
f.write_str("-")?;
|
||||||
|
} else {
|
||||||
|
f.write_str("+")?;
|
||||||
|
}
|
||||||
|
self.value.fmt(f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_positive(&self) -> bool
|
impl<'a> PartialEq<&'a $type> for $type {
|
||||||
where T: CryptoNumBase
|
fn eq(&self, other: &&$type) -> bool {
|
||||||
{
|
(self.negative == other.negative) &&
|
||||||
self.positive && !self.value.is_zero()
|
(self.value == other.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_negative(&self) -> bool
|
impl PartialOrd for $type {
|
||||||
where T: CryptoNumBase
|
fn partial_cmp(&self, other: &$type) -> Option<Ordering> {
|
||||||
{
|
Some(self.cmp(other))
|
||||||
!self.positive && !self.value.is_zero()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn negate(&mut self)
|
impl Ord for $type {
|
||||||
{
|
fn cmp(&self, other: &$type) -> Ordering {
|
||||||
self.positive = !self.positive;
|
match (self.negative, other.negative) {
|
||||||
|
(true, true) =>
|
||||||
|
self.value.cmp(&other.value).reverse(),
|
||||||
|
(true, false) => Ordering::Greater,
|
||||||
|
(false, true) => Ordering::Less,
|
||||||
|
(false, false) =>
|
||||||
|
self.value.cmp(&other.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: CryptoNumBase> CryptoNumBase for Signed<T> {
|
impl CryptoNumBase for $type {
|
||||||
fn zero() -> Signed<T> {
|
fn zero() -> $type {
|
||||||
Signed{ positive: true, value: T::zero() }
|
$type{ negative: false, value: $base::zero() }
|
||||||
}
|
}
|
||||||
fn max_value() -> Signed<T> {
|
fn max_value() -> $type {
|
||||||
Signed{ positive: true, value: T::max_value() }
|
$type{ negative: false, value: $base::max_value() }
|
||||||
}
|
}
|
||||||
fn is_zero(&self) -> bool {
|
fn is_zero(&self) -> bool {
|
||||||
self.value.is_zero()
|
self.value.is_zero()
|
||||||
@@ -53,379 +59,179 @@ impl<T: CryptoNumBase> CryptoNumBase for Signed<T> {
|
|||||||
fn is_even(&self) -> bool {
|
fn is_even(&self) -> bool {
|
||||||
self.value.is_even()
|
self.value.is_even()
|
||||||
}
|
}
|
||||||
fn from_u8(x: u8) -> Signed<T> {
|
|
||||||
Signed{ positive: true, value: T::from_u8(x) }
|
|
||||||
}
|
}
|
||||||
fn to_u8(&self) -> u8 {
|
|
||||||
self.value.to_u8()
|
|
||||||
}
|
|
||||||
fn from_u16(x: u16) -> Signed<T> {
|
|
||||||
Signed{ positive: true, value: T::from_u16(x) }
|
|
||||||
}
|
|
||||||
fn to_u16(&self) -> u16 {
|
|
||||||
self.value.to_u16()
|
|
||||||
}
|
|
||||||
fn from_u32(x: u32) -> Signed<T> {
|
|
||||||
Signed{ positive: true, value: T::from_u32(x) }
|
|
||||||
}
|
|
||||||
fn to_u32(&self) -> u32 {
|
|
||||||
self.value.to_u32()
|
|
||||||
}
|
|
||||||
fn from_u64(x: u64) -> Signed<T> {
|
|
||||||
Signed{ positive: true, value: T::from_u64(x) }
|
|
||||||
}
|
|
||||||
fn to_u64(&self) -> u64 {
|
|
||||||
self.value.to_u64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: CryptoNumFastMod> CryptoNumFastMod for Signed<T> {
|
impl CryptoNumFastMod for $type {
|
||||||
type BarrettMu = T::BarrettMu;
|
type BarrettMu = <$base as CryptoNumFastMod>::BarrettMu;
|
||||||
|
|
||||||
fn barrett_mu(&self) -> Option<T::BarrettMu> {
|
fn barrett_mu(&self) -> Option<Self::BarrettMu> {
|
||||||
if self.positive {
|
if self.negative {
|
||||||
self.value.barrett_mu()
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fastmod(&self, mu: &T::BarrettMu) -> Signed<T> {
|
|
||||||
Signed{ positive: self.positive, value: self.value.fastmod(&mu) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> Clone for Signed<T> {
|
|
||||||
fn clone(&self) -> Signed<T> {
|
|
||||||
Signed{ positive: self.positive, value: self.value.clone() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a,T: PartialEq> PartialEq<&'a Signed<T>> for Signed<T> {
|
|
||||||
fn eq(&self, other: &&Signed<T>) -> bool {
|
|
||||||
(self.positive == other.positive) && (self.value == other.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a,T: PartialEq> PartialEq<Signed<T>> for &'a Signed<T> {
|
|
||||||
fn eq(&self, other: &Signed<T>) -> bool {
|
|
||||||
(self.positive == other.positive) && (self.value == other.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PartialEq> PartialEq for Signed<T> {
|
|
||||||
fn eq(&self, other: &Signed<T>) -> bool {
|
|
||||||
(self.positive == other.positive) && (self.value == other.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Eq> Eq for Signed<T> {}
|
|
||||||
|
|
||||||
impl<T: Debug> Debug for Signed<T> {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
if self.positive {
|
|
||||||
f.write_str("+")?;
|
|
||||||
} else {
|
} else {
|
||||||
f.write_str("-")?;
|
self.value.barrett_mu()
|
||||||
}
|
}
|
||||||
self.value.fmt(f)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Ord> Ord for Signed<T> {
|
fn fastmod(&self, mu: &Self::BarrettMu) -> $type {
|
||||||
fn cmp(&self, other: &Signed<T>) -> Ordering {
|
let res = self.value.fastmod(mu);
|
||||||
match (self.positive, other.positive) {
|
$type{ negative: self.negative, value: res }
|
||||||
(true, true) => self.value.cmp(&other.value),
|
|
||||||
(true, false) => Ordering::Greater,
|
|
||||||
(false, true) => Ordering::Less,
|
|
||||||
(false, false) =>
|
|
||||||
self.value.cmp(&other.value).reverse()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Ord> PartialOrd for Signed<T> {
|
impl CryptoNumSigned for $type {
|
||||||
fn partial_cmp(&self, other: &Signed<T>) -> Option<Ordering>{
|
type Unsigned = $base;
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
fn new(v: $base) -> $type {
|
||||||
|
$type{ negative: false, value: v.clone() }
|
||||||
|
}
|
||||||
|
fn abs(&self) -> $base {
|
||||||
|
self.value.clone()
|
||||||
|
}
|
||||||
|
fn is_positive(&self) -> bool {
|
||||||
|
!self.negative
|
||||||
|
}
|
||||||
|
fn is_negative(&self) -> bool {
|
||||||
|
self.negative
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Clone> Neg for Signed<T> {
|
impl Neg for $type {
|
||||||
type Output = Signed<T>;
|
type Output = $type;
|
||||||
|
|
||||||
fn neg(self) -> Signed<T> {
|
fn neg(self) -> $type {
|
||||||
Signed {
|
(&self).neg()
|
||||||
positive: !self.positive,
|
|
||||||
value: self.value.clone()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a,T: Clone> Neg for &'a Signed<T> {
|
impl<'a> Neg for &'a $type {
|
||||||
type Output = Signed<T>;
|
type Output = $type;
|
||||||
|
|
||||||
fn neg(self) -> Signed<T> {
|
fn neg(self) -> $type {
|
||||||
Signed {
|
if self.value.is_zero() {
|
||||||
positive: !self.positive,
|
$type{ negative: false, value: self.value.clone() }
|
||||||
value: self.value.clone()
|
} else {
|
||||||
|
$type{ negative: !self.negative, value: self.value.clone() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
define_arithmetic!($type,AddAssign,add_assign,Add,add,self,other,{
|
||||||
|
let signs_match = self.negative == other.negative;
|
||||||
|
let ordering = self.value.cmp(&other.value);
|
||||||
|
|
||||||
impl<T> AddAssign for Signed<T>
|
match (signs_match, ordering) {
|
||||||
where
|
(true, _) =>
|
||||||
T: Clone + Ord,
|
// if the signs are the same, we maintain the sign and
|
||||||
T: AddAssign + SubAssign,
|
// just increase the magnitude
|
||||||
{
|
|
||||||
fn add_assign(&mut self, other: Signed<T>) {
|
|
||||||
match (self.positive, other.positive, self.value.cmp(&other.value)) {
|
|
||||||
// if the signs are the same, we maintain the sign and just increase
|
|
||||||
// the magnitude
|
|
||||||
(x, y, _) if x == y =>
|
|
||||||
self.value.add_assign(other.value),
|
|
||||||
// if the signs are different and the numbers are equal, we just set
|
|
||||||
// this to zero. However, we actually do the subtraction to make the
|
|
||||||
// timing roughly similar.
|
|
||||||
(_, _, Ordering::Equal) => {
|
|
||||||
self.positive = true;
|
|
||||||
self.value.sub_assign(other.value);
|
|
||||||
}
|
|
||||||
// if the signs are different and the first one is less than the
|
|
||||||
// second, then we flip the sign and subtract.
|
|
||||||
(_, _, Ordering::Less) => {
|
|
||||||
self.positive = !self.positive;
|
|
||||||
let temp = self.value.clone();
|
|
||||||
self.value = other.value.clone();
|
|
||||||
self.value.sub_assign(temp);
|
|
||||||
}
|
|
||||||
// if the signs are different and the first one is greater than the
|
|
||||||
// second, then we leave the sign and subtract.
|
|
||||||
(_, _, Ordering::Greater) => {
|
|
||||||
self.value.sub_assign(other.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a,T> AddAssign<&'a Signed<T>> for Signed<T>
|
|
||||||
where
|
|
||||||
T: Clone + Ord,
|
|
||||||
T: AddAssign + SubAssign,
|
|
||||||
T: AddAssign<&'a T> + SubAssign<&'a T>
|
|
||||||
{
|
|
||||||
fn add_assign(&mut self, other: &'a Signed<T>) {
|
|
||||||
match (self.positive, other.positive, self.value.cmp(&other.value)) {
|
|
||||||
// if the signs are the same, we maintain the sign and just increase
|
|
||||||
// the magnitude
|
|
||||||
(x, y, _) if x == y =>
|
|
||||||
self.value.add_assign(&other.value),
|
self.value.add_assign(&other.value),
|
||||||
// if the signs are different and the numbers are equal, we just set
|
(false, Ordering::Equal) => {
|
||||||
// this to zero. However, we actually do the subtraction to make the
|
// if the signs are different and the numbers are equal,
|
||||||
// timing roughly similar.
|
// we just set this to zero. However, we actually do the
|
||||||
(_, _, Ordering::Equal) => {
|
// subtraction to make the timing roughly similar.
|
||||||
self.positive = true;
|
self.negative = false;
|
||||||
self.value.sub_assign(&other.value);
|
self.value.sub_assign(&other.value)
|
||||||
}
|
}
|
||||||
// if the signs are different and the first one is less than the
|
(false, Ordering::Less) => {
|
||||||
// second, then we flip the sign and subtract.
|
// if the signs are different and the first one is less
|
||||||
(_, _, Ordering::Less) => {
|
// than the second, then we flip the sign and subtract.
|
||||||
self.positive = !self.positive;
|
self.negative = !self.negative;
|
||||||
let temp = self.value.clone();
|
let mut other_copy = other.value.clone();
|
||||||
self.value = other.value.clone();
|
other_copy.sub_assign(&self.value);
|
||||||
self.value.sub_assign(temp);
|
self.value = other_copy;
|
||||||
}
|
}
|
||||||
// if the signs are different and the first one is greater than the
|
(false, Ordering::Greater) => {
|
||||||
// second, then we leave the sign and subtract.
|
// if the signs are different and the first one is
|
||||||
(_, _, Ordering::Greater) => {
|
// greater than the second, then we leave the sign and
|
||||||
self.value.sub_assign(&other.value);
|
// subtract.
|
||||||
|
self.value.sub_assign(&other.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
math_operator!(Add,add,add_assign);
|
define_arithmetic!($type,SubAssign,sub_assign,Sub,sub,self,other,{
|
||||||
|
// this is a bit inefficient, but a heck of a lot easier.
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<T> SubAssign for Signed<T>
|
|
||||||
where
|
|
||||||
T: Clone + Ord,
|
|
||||||
T: AddAssign + SubAssign,
|
|
||||||
{
|
|
||||||
fn sub_assign(&mut self, other: Signed<T>) {
|
|
||||||
let mut other2 = other.clone();
|
let mut other2 = other.clone();
|
||||||
other2.positive = !other.positive;
|
other2.negative = !other2.negative;
|
||||||
self.add_assign(other2);
|
self.add_assign(&other2)
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a,T> SubAssign<&'a Signed<T>> for Signed<T>
|
define_arithmetic!($type,MulAssign,mul_assign,Mul,mul,self,other,{
|
||||||
where
|
self.negative = self.negative ^ other.negative;
|
||||||
T: Clone + Ord,
|
self.value.mul_assign(&other.value);
|
||||||
T: AddAssign + SubAssign,
|
});
|
||||||
T: AddAssign<&'a T> + SubAssign<&'a T>
|
|
||||||
{
|
|
||||||
fn sub_assign(&mut self, other: &'a Signed<T>) {
|
|
||||||
let mut other2 = other.clone();
|
|
||||||
other2.positive = !other.positive;
|
|
||||||
self.add_assign(other2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
math_operator!(Sub,sub,sub_assign);
|
define_arithmetic!($type,DivAssign,div_assign,Div,div,self,other,{
|
||||||
|
self.negative = self.negative ^ other.negative;
|
||||||
|
self.value.div_assign(&other.value);
|
||||||
|
});
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
define_arithmetic!($type,RemAssign,rem_assign,Rem,rem,self,other,{
|
||||||
|
self.value.rem_assign(&other.value);
|
||||||
|
});
|
||||||
|
|
||||||
impl<T> MulAssign for Signed<T>
|
generate_signed_conversions!($type, $base);
|
||||||
where
|
|
||||||
T: MulAssign
|
|
||||||
{
|
|
||||||
fn mul_assign(&mut self, other: Signed<T>) {
|
|
||||||
self.positive = !(self.positive ^ other.positive);
|
|
||||||
self.value *= other.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a,T> MulAssign<&'a Signed<T>> for Signed<T>
|
#[cfg(test)]
|
||||||
where
|
mod $modname {
|
||||||
T: MulAssign + MulAssign<&'a T>
|
|
||||||
{
|
|
||||||
fn mul_assign(&mut self, other: &'a Signed<T>) {
|
|
||||||
self.positive = !(self.positive ^ other.positive);
|
|
||||||
self.value *= &other.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
math_operator!(Mul,mul,mul_assign);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<T> DivAssign for Signed<T>
|
|
||||||
where
|
|
||||||
T: DivAssign
|
|
||||||
{
|
|
||||||
fn div_assign(&mut self, other: Signed<T>) {
|
|
||||||
self.positive = !(self.positive ^ other.positive);
|
|
||||||
self.value /= other.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a,T> DivAssign<&'a Signed<T>> for Signed<T>
|
|
||||||
where
|
|
||||||
T: DivAssign + DivAssign<&'a T>
|
|
||||||
{
|
|
||||||
fn div_assign(&mut self, other: &'a Signed<T>) {
|
|
||||||
self.positive = !(self.positive ^ other.positive);
|
|
||||||
self.value /= &other.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
math_operator!(Div,div,div_assign);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use cryptonum::unsigned::U512;
|
|
||||||
use quickcheck::{Arbitrary,Gen};
|
use quickcheck::{Arbitrary,Gen};
|
||||||
use std::cmp::{max,min};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl<T: Arbitrary + CryptoNumBase> Arbitrary for Signed<T> {
|
impl Arbitrary for $type {
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Signed<T> {
|
fn arbitrary<G: Gen>(g: &mut G) -> $type {
|
||||||
let value = T::arbitrary(g);
|
let value = $base::arbitrary(g);
|
||||||
if value.is_zero() {
|
if value.is_zero() {
|
||||||
Signed {
|
$type{ negative: false, value: value }
|
||||||
positive: true,
|
|
||||||
value: value
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Signed {
|
$type{ negative: g.gen_weighted_bool(2), value: value }
|
||||||
positive: g.gen_weighted_bool(2),
|
|
||||||
value: value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn double_negation(x: Signed<U512>) -> bool {
|
fn double_negation(x: $type) -> bool {
|
||||||
&x == (- (- &x))
|
(- (- &x)) == &x
|
||||||
}
|
}
|
||||||
|
fn add_identity(x: $type) -> bool {
|
||||||
|
(&x + $type::zero()) == &x
|
||||||
}
|
}
|
||||||
|
fn add_commutivity(x: $type, y: $type) -> bool {
|
||||||
quickcheck! {
|
|
||||||
fn add_associates(x: Signed<U512>, y: Signed<U512>, z: Signed<U512>)
|
|
||||||
-> bool
|
|
||||||
{
|
|
||||||
let mut a = x.clone();
|
|
||||||
let mut b = y.clone();
|
|
||||||
let mut c = z.clone();
|
|
||||||
|
|
||||||
// we shift these right because rollover makes for weird behavior
|
|
||||||
a.value >>= 2;
|
|
||||||
b.value >>= 2;
|
|
||||||
c.value >>= 2;
|
|
||||||
|
|
||||||
(&a + (&b + &c)) == ((&a + &b) + &c)
|
|
||||||
}
|
|
||||||
fn add_commutes(x: Signed<U512>, y: Signed<U512>) -> bool {
|
|
||||||
(&x + &y) == (&y + &x)
|
(&x + &y) == (&y + &x)
|
||||||
}
|
}
|
||||||
fn add_identity(x: Signed<U512>) -> bool {
|
fn add_associativity(a: $type, b: $type, c: $type) -> bool {
|
||||||
let zero = Signed{ positive: true, value: U512::zero() };
|
// we shift these to get away from rollover
|
||||||
(&x + &zero) == &x
|
let x = $type{ negative: a.negative, value: a.value >> 2 };
|
||||||
|
let y = $type{ negative: b.negative, value: b.value >> 2 };
|
||||||
|
let z = $type{ negative: c.negative, value: c.value >> 2 };
|
||||||
|
(&x + (&y + &z)) == ((&x + &y) + &z)
|
||||||
}
|
}
|
||||||
}
|
fn sub_is_add_negation(x: $type, y: $type) -> bool {
|
||||||
|
|
||||||
quickcheck! {
|
|
||||||
fn sub_is_add_negation(x: Signed<U512>, y: Signed<U512>) -> bool {
|
|
||||||
(&x - &y) == (&x + (- &y))
|
(&x - &y) == (&x + (- &y))
|
||||||
}
|
}
|
||||||
|
fn sub_destroys(x: $type) -> bool {
|
||||||
|
(&x - &x) == $type::zero()
|
||||||
}
|
}
|
||||||
|
fn mul_identity(x: $type) -> bool {
|
||||||
quickcheck! {
|
(&x * $type::from(1)) == &x
|
||||||
fn mul_associates(x: Signed<U512>, y: Signed<U512>, z: Signed<U512>)
|
|
||||||
-> bool
|
|
||||||
{
|
|
||||||
let mut a = x.clone();
|
|
||||||
let mut b = y.clone();
|
|
||||||
let mut c = z.clone();
|
|
||||||
|
|
||||||
// we shift these right because rollover makes for weird behavior
|
|
||||||
a.value >>= 258;
|
|
||||||
b.value >>= 258;
|
|
||||||
c.value >>= 258;
|
|
||||||
|
|
||||||
(&a * (&b * &c)) == ((&a * &b) * &c)
|
|
||||||
}
|
}
|
||||||
fn mul_commutes(x: Signed<U512>, y: Signed<U512>) -> bool {
|
fn mul_commutivity(x: $type, y: $type) -> bool {
|
||||||
(&x * &y) == (&y * &x)
|
(&x * &y) == (&y * &x)
|
||||||
}
|
}
|
||||||
fn mul_identity(x: Signed<U512>) -> bool {
|
fn mul_associativity(a: $type, b: $type, c: $type) -> bool {
|
||||||
let one = Signed{ positive: true, value: U512::from_u8(1) };
|
// we shift these to get away from rollover
|
||||||
(&x * &one) == &x
|
let s = (a.value.bit_size() / 2) - 2;
|
||||||
|
let x = $type{ negative: a.negative, value: a.value >> s };
|
||||||
|
let y = $type{ negative: b.negative, value: b.value >> s };
|
||||||
|
let z = $type{ negative: c.negative, value: c.value >> s };
|
||||||
|
(&x * (&y * &z)) == ((&x * &y) * &z)
|
||||||
|
}
|
||||||
|
#[ignore]
|
||||||
|
fn div_identity(a: $type) -> bool {
|
||||||
|
&a / $type::from(1) == a
|
||||||
|
}
|
||||||
|
fn div_self_is_one(a: $type) -> bool {
|
||||||
|
(&a / &a) == $type::from(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
|
||||||
fn add_mul_distribution(x:Signed<U512>,y:Signed<U512>,z:Signed<U512>)
|
|
||||||
-> bool
|
|
||||||
{
|
|
||||||
let mut a = x.clone();
|
|
||||||
let mut b = y.clone();
|
|
||||||
let mut c = z.clone();
|
|
||||||
|
|
||||||
// we shift these right because rollover makes for weird behavior
|
|
||||||
a.value >>= 258;
|
|
||||||
b.value >>= 258;
|
|
||||||
c.value >>= 258;
|
|
||||||
|
|
||||||
(&a * (&b + &c)) == ((&a * &b) + (&a * &c))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use rand::Rng;
|
||||||
|
|
||||||
pub trait CryptoNumBase {
|
pub trait CryptoNumBase {
|
||||||
/// Generate the zero value for this type.
|
/// Generate the zero value for this type.
|
||||||
fn zero() -> Self;
|
fn zero() -> Self;
|
||||||
@@ -9,26 +11,6 @@ pub trait CryptoNumBase {
|
|||||||
fn is_odd(&self) -> bool;
|
fn is_odd(&self) -> bool;
|
||||||
/// Test if the number is even (a.k.a., the low bit is clear)
|
/// Test if the number is even (a.k.a., the low bit is clear)
|
||||||
fn is_even(&self) -> bool;
|
fn is_even(&self) -> bool;
|
||||||
/// Translate a `u8` to this type. This must be safe.
|
|
||||||
fn from_u8(x: u8) -> Self;
|
|
||||||
/// Convert this back into a `u8`. This is the equivalent of masking off
|
|
||||||
/// the lowest 8 bits and then casting to a `u8`.
|
|
||||||
fn to_u8(&self) -> u8;
|
|
||||||
/// Translate a `u16` to this type. This must be safe.
|
|
||||||
fn from_u16(x: u16) -> Self;
|
|
||||||
/// Convert this back into a `u16`. This is the equivalent of masking off
|
|
||||||
/// the lowest 16 bits and then casting to a `u16`.
|
|
||||||
fn to_u16(&self) -> u16;
|
|
||||||
/// Translate a `u32` to this type. This must be safe.
|
|
||||||
fn from_u32(x: u32) -> Self;
|
|
||||||
/// Convert this back into a `u32`. This is the equivalent of masking off
|
|
||||||
/// the lowest 32 bits and then casting to a `u32`.
|
|
||||||
fn to_u32(&self) -> u32;
|
|
||||||
/// Translate a `u64` to this type. This must be safe.
|
|
||||||
fn from_u64(x: u64) -> Self;
|
|
||||||
/// Convert this back into a `u64`. This is the equivalent of masking off
|
|
||||||
/// the lowest 64 bits and then casting to a `u64`.
|
|
||||||
fn to_u64(&self) -> u64;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CryptoNumSerialization {
|
pub trait CryptoNumSerialization {
|
||||||
@@ -56,3 +38,42 @@ pub trait CryptoNumFastMod {
|
|||||||
/// Faster modulo through the use of the Barrett constant, above.
|
/// Faster modulo through the use of the Barrett constant, above.
|
||||||
fn fastmod(&self, &Self::BarrettMu) -> Self;
|
fn fastmod(&self, &Self::BarrettMu) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait CryptoNumSigned {
|
||||||
|
/// The unsigned type that this type is related to.
|
||||||
|
type Unsigned;
|
||||||
|
|
||||||
|
/// Generate a new signed number based on the given unsigned number.
|
||||||
|
fn new(x: Self::Unsigned) -> Self;
|
||||||
|
/// Get the absolute value of the signed number, turning it back into an
|
||||||
|
/// unsigned number.
|
||||||
|
fn abs(&self) -> Self::Unsigned;
|
||||||
|
/// Test if the number is negative.
|
||||||
|
fn is_negative(&self) -> bool;
|
||||||
|
/// Test if the number is positive.
|
||||||
|
fn is_positive(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CryptoNumModOps: Sized
|
||||||
|
{
|
||||||
|
/// Compute the modular inverse of the number.
|
||||||
|
fn modinv(&self, b: &Self) -> Self;
|
||||||
|
/// Raise the number to the power of the first value, mod the second.
|
||||||
|
fn modexp(&self, a: &Self, b: &Self) -> Self;
|
||||||
|
/// Square the number, mod the given value.
|
||||||
|
fn modsq(&self, v: &Self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CryptoNumPrimes
|
||||||
|
{
|
||||||
|
/// Determine if the given number is probably prime using a quick spot
|
||||||
|
/// check and Miller-Rabin, using the given random number generator
|
||||||
|
/// and number of iterations.
|
||||||
|
fn probably_prime<G: Rng>(&self, g: &mut G, iters: usize) -> bool;
|
||||||
|
/// Generate a prime using the given random number generator, using
|
||||||
|
/// the given number of rounds to determine if the number is probably
|
||||||
|
/// prime. The other two numbers are a number for which the generator
|
||||||
|
/// should have a GCD of 1, and the minimum value for the number.
|
||||||
|
fn generate_prime<G: Rng>(g: &mut G, iters: usize, e: &Self, min: &Self)
|
||||||
|
-> Self;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,685 @@
|
|||||||
use cryptonum::core::*;
|
macro_rules! construct_unsigned {
|
||||||
use cryptonum::traits::*;
|
($type: ident, $barrett: ident, $modname: ident, $count: expr) => {
|
||||||
use std::cmp::Ordering;
|
#[derive(Clone)]
|
||||||
use std::fmt::{Debug,Error,Formatter};
|
pub struct $type {
|
||||||
use std::ops::*;
|
contents: [u64; $count]
|
||||||
|
}
|
||||||
|
|
||||||
construct_unsigned!(U512, BarretMu512, u512, 8);
|
pub struct $barrett {
|
||||||
construct_unsigned!(U1024, BarretMu1024, u1024, 16);
|
k: usize,
|
||||||
construct_unsigned!(U2048, BarretMu2048, u2048, 32);
|
progenitor: $type,
|
||||||
construct_unsigned!(U3072, BarretMu3072, u3072, 48);
|
contents: [u64; $count + 1]
|
||||||
construct_unsigned!(U4096, BarretMu4096, u4096, 64);
|
}
|
||||||
construct_unsigned!(U7680, BarretMu7680, u7680, 120);
|
|
||||||
construct_unsigned!(U8192, BarretMu8192, u8192, 128);
|
impl PartialEq for $type {
|
||||||
construct_unsigned!(U15360, BarretMu15360, u15360, 240);
|
fn eq(&self, other: &$type) -> bool {
|
||||||
|
for i in 0..$count {
|
||||||
|
if self.contents[i] != other.contents[i] {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for $type {}
|
||||||
|
|
||||||
|
impl Debug for $type {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(),Error> {
|
||||||
|
f.write_str("CryptoNum{{ ")?;
|
||||||
|
f.debug_list().entries(self.contents.iter()).finish()?;
|
||||||
|
f.write_str(" }}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for $barrett {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(),Error> {
|
||||||
|
f.write_str("BarrettMu{{ ")?;
|
||||||
|
f.write_fmt(format_args!("k = {}, ", self.k))?;
|
||||||
|
f.write_fmt(format_args!("progen = {:?}, ",self.progenitor))?;
|
||||||
|
f.write_str("contents: ")?;
|
||||||
|
f.debug_list().entries(self.contents.iter()).finish()?;
|
||||||
|
f.write_str(" }}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_unsigned_conversions!($type, $count);
|
||||||
|
|
||||||
|
impl PartialOrd for $type {
|
||||||
|
fn partial_cmp(&self, other: &$type) -> Option<Ordering> {
|
||||||
|
Some(generic_cmp(&self.contents, &other.contents))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for $type {
|
||||||
|
fn cmp(&self, other: &$type) -> Ordering {
|
||||||
|
generic_cmp(&self.contents, &other.contents)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Not for $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn not(self) -> $type {
|
||||||
|
let mut output = self.clone();
|
||||||
|
generic_not(&mut output.contents);
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Not for &'a $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn not(self) -> $type {
|
||||||
|
let mut output = self.clone();
|
||||||
|
generic_not(&mut output.contents);
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define_arithmetic!($type,BitOrAssign,bitor_assign,BitOr,bitor,self,other,{
|
||||||
|
generic_bitor(&mut self.contents, &other.contents);
|
||||||
|
});
|
||||||
|
define_arithmetic!($type,BitAndAssign,bitand_assign,BitAnd,bitand,self,other,{
|
||||||
|
generic_bitand(&mut self.contents, &other.contents);
|
||||||
|
});
|
||||||
|
define_arithmetic!($type,BitXorAssign,bitxor_assign,BitXor,bitxor,self,other,{
|
||||||
|
generic_bitxor(&mut self.contents, &other.contents);
|
||||||
|
});
|
||||||
|
define_arithmetic!($type,AddAssign,add_assign,Add,add,self,other,{
|
||||||
|
generic_add(&mut self.contents, &other.contents);
|
||||||
|
});
|
||||||
|
define_arithmetic!($type,SubAssign,sub_assign,Sub,sub,self,other,{
|
||||||
|
generic_sub(&mut self.contents, &other.contents);
|
||||||
|
});
|
||||||
|
define_arithmetic!($type,MulAssign,mul_assign,Mul,mul,self,other,{
|
||||||
|
let copy = self.contents.clone();
|
||||||
|
generic_mul(&mut self.contents, ©, &other.contents);
|
||||||
|
});
|
||||||
|
define_arithmetic!($type,DivAssign,div_assign,Div,div,self,other,{
|
||||||
|
let mut dead = [0; $count];
|
||||||
|
let copy = self.contents.clone();
|
||||||
|
generic_div(©, &other.contents,
|
||||||
|
&mut self.contents, &mut dead);
|
||||||
|
});
|
||||||
|
define_arithmetic!($type,RemAssign,rem_assign,Rem,rem,self,other,{
|
||||||
|
let mut dead = [0; $count];
|
||||||
|
let copy = self.contents.clone();
|
||||||
|
generic_div(©, &other.contents,
|
||||||
|
&mut dead, &mut self.contents);
|
||||||
|
});
|
||||||
|
|
||||||
|
shifts!($type, usize);
|
||||||
|
shifts!($type, u64);
|
||||||
|
shifts!($type, i64);
|
||||||
|
shifts!($type, u32);
|
||||||
|
shifts!($type, i32);
|
||||||
|
shifts!($type, u16);
|
||||||
|
shifts!($type, i16);
|
||||||
|
shifts!($type, u8);
|
||||||
|
shifts!($type, i8);
|
||||||
|
|
||||||
|
impl CryptoNumBase for $type {
|
||||||
|
fn zero() -> $type {
|
||||||
|
$type { contents: [0; $count] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_value() -> $type {
|
||||||
|
$type { contents: [0xFFFFFFFFFFFFFFFF; $count] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_zero(&self) -> bool {
|
||||||
|
for x in self.contents.iter() {
|
||||||
|
if *x != 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_odd(&self) -> bool {
|
||||||
|
(self.contents[0] & 1) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_even(&self) -> bool {
|
||||||
|
(self.contents[0] & 1) == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CryptoNumSerialization for $type {
|
||||||
|
fn bit_size(&self) -> usize {
|
||||||
|
$count * 64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn byte_size(&self) -> usize {
|
||||||
|
$count * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut res = Vec::with_capacity($count * 8);
|
||||||
|
for x in self.contents.iter() {
|
||||||
|
res.push( (x >> 56) as u8 );
|
||||||
|
res.push( (x >> 48) as u8 );
|
||||||
|
res.push( (x >> 40) as u8 );
|
||||||
|
res.push( (x >> 32) as u8 );
|
||||||
|
res.push( (x >> 24) as u8 );
|
||||||
|
res.push( (x >> 16) as u8 );
|
||||||
|
res.push( (x >> 8) as u8 );
|
||||||
|
res.push( (x >> 0) as u8 );
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_bytes(x: &[u8]) -> $type {
|
||||||
|
let mut res = $type::zero();
|
||||||
|
let mut i = 0;
|
||||||
|
|
||||||
|
assert!(x.len() >= ($count * 8));
|
||||||
|
for chunk in x.chunks(8) {
|
||||||
|
assert!(chunk.len() == 8);
|
||||||
|
res.contents[i] = ((chunk[0] as u64) << 56) |
|
||||||
|
((chunk[1] as u64) << 48) |
|
||||||
|
((chunk[2] as u64) << 40) |
|
||||||
|
((chunk[3] as u64) << 32) |
|
||||||
|
((chunk[4] as u64) << 24) |
|
||||||
|
((chunk[5] as u64) << 16) |
|
||||||
|
((chunk[6] as u64) << 8) |
|
||||||
|
((chunk[7] as u64) << 0);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
assert!(i == $count);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
derive_barrett!($type, $barrett, $count);
|
||||||
|
derive_modulo_operations!($type);
|
||||||
|
derive_prime_operations!($type, $count);
|
||||||
|
|
||||||
|
impl Into<BigInt> for $type {
|
||||||
|
fn into(self) -> BigInt {
|
||||||
|
panic!("into bigint")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<BigUint> for $type {
|
||||||
|
fn into(self) -> BigUint {
|
||||||
|
panic!("into big uint")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BigInt> for $type {
|
||||||
|
fn from(_x: BigInt) -> Self {
|
||||||
|
panic!("from bigint")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BigUint> for $type {
|
||||||
|
fn from(_x: BigUint) -> Self {
|
||||||
|
panic!("from biguint")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod $modname {
|
||||||
|
use quickcheck::{Arbitrary,Gen};
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl Arbitrary for $type {
|
||||||
|
fn arbitrary<G: Gen>(g: &mut G) -> $type {
|
||||||
|
let mut res = [0; $count];
|
||||||
|
|
||||||
|
for i in 0..$count {
|
||||||
|
res[i] = g.next_u64();
|
||||||
|
}
|
||||||
|
$type{ contents: res }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_builders() {
|
||||||
|
let mut buffer = [0; $count];
|
||||||
|
assert_eq!($type{ contents: buffer }, $type::from(0 as u8));
|
||||||
|
buffer[0] = 0x7F;
|
||||||
|
assert_eq!($type{ contents: buffer }, $type::from(0x7F as u8));
|
||||||
|
buffer[0] = 0x7F7F;
|
||||||
|
assert_eq!($type{ contents: buffer }, $type::from(0x7F7F as u16));
|
||||||
|
buffer[0] = 0xCA5CADE5;
|
||||||
|
assert_eq!($type{ contents: buffer },
|
||||||
|
$type::from(0xCA5CADE5 as u32));
|
||||||
|
assert_eq!($type{ contents: buffer },
|
||||||
|
$type::from(0xCA5CADE5 as u32));
|
||||||
|
buffer[0] = 0xFFFFFFFFFFFFFFFF;
|
||||||
|
assert_eq!($type{ contents: buffer },
|
||||||
|
$type::from(0xFFFFFFFFFFFFFFFF as u64));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_max() {
|
||||||
|
let max64: u64 = $type::from(u64::max_value()).into();
|
||||||
|
assert_eq!(max64, u64::max_value());
|
||||||
|
let max64v: u64 = $type::max_value().into();
|
||||||
|
assert_eq!(max64v, u64::max_value());
|
||||||
|
assert_eq!($type::max_value() + $type::from(1 as u8), $type::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn builder_u8_upgrade_u16(x: u8) -> bool {
|
||||||
|
$type::from(x) == $type::from(x as u16)
|
||||||
|
}
|
||||||
|
fn builder_u16_upgrade_u32(x: u16) -> bool {
|
||||||
|
$type::from(x) == $type::from(x as u32)
|
||||||
|
}
|
||||||
|
fn builder_u32_upgrade_u64(x: u32) -> bool {
|
||||||
|
$type::from(x) == $type::from(x as u64)
|
||||||
|
}
|
||||||
|
fn builder_u8_roundtrips(x: u8) -> bool {
|
||||||
|
let thereback: u8 = $type::from(x).into();
|
||||||
|
x == thereback
|
||||||
|
}
|
||||||
|
fn builder_u16_roundtrips(x: u16) -> bool {
|
||||||
|
let thereback: u16 = $type::from(x).into();
|
||||||
|
x == thereback
|
||||||
|
}
|
||||||
|
fn builder_u32_roundtrips(x: u32) -> bool {
|
||||||
|
let thereback: u32 = $type::from(x).into();
|
||||||
|
x == thereback
|
||||||
|
}
|
||||||
|
fn builder_u64_roundtrips(x: u64) -> bool {
|
||||||
|
let thereback: u64 = $type::from(x).into();
|
||||||
|
x == thereback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn partial_ord64_works(x: u64, y: u64) -> bool {
|
||||||
|
let xbig = $type::from(x);
|
||||||
|
let ybig = $type::from(y);
|
||||||
|
xbig.partial_cmp(&ybig) == x.partial_cmp(&y)
|
||||||
|
}
|
||||||
|
fn ord64_works(x: u64, y: u64) -> bool {
|
||||||
|
let xbig = $type::from(x);
|
||||||
|
let ybig = $type::from(y);
|
||||||
|
xbig.cmp(&ybig) == x.cmp(&y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn and_annulment(x: $type) -> bool {
|
||||||
|
(x & $type::zero()) == $type::zero()
|
||||||
|
}
|
||||||
|
fn or_annulment(x: $type) -> bool {
|
||||||
|
(x | $type::max_value()) == $type::max_value()
|
||||||
|
}
|
||||||
|
fn and_identity(x: $type) -> bool {
|
||||||
|
(&x & $type::max_value()) == x
|
||||||
|
}
|
||||||
|
fn or_identity(x: $type) -> bool {
|
||||||
|
(&x | $type::zero()) == x
|
||||||
|
}
|
||||||
|
fn and_idempotent(x: $type) -> bool {
|
||||||
|
(&x & &x) == x
|
||||||
|
}
|
||||||
|
fn or_idempotent(x: $type) -> bool {
|
||||||
|
(&x | &x) == x
|
||||||
|
}
|
||||||
|
fn and_complement(x: $type) -> bool {
|
||||||
|
(&x & &x) == x
|
||||||
|
}
|
||||||
|
fn or_complement(x: $type) -> bool {
|
||||||
|
(&x | !&x) == $type::max_value()
|
||||||
|
}
|
||||||
|
fn and_commutative(x: $type, y: $type) -> bool {
|
||||||
|
(&x & &y) == (&y & &x)
|
||||||
|
}
|
||||||
|
fn or_commutative(x: $type, y: $type) -> bool {
|
||||||
|
(&x | &y) == (&y | &x)
|
||||||
|
}
|
||||||
|
fn double_negation(x: $type) -> bool {
|
||||||
|
!!&x == x
|
||||||
|
}
|
||||||
|
fn or_distributive(a: $type, b: $type, c: $type) -> bool {
|
||||||
|
(&a & (&b | &c)) == ((&a & &b) | (&a & &c))
|
||||||
|
}
|
||||||
|
fn and_distributive(a: $type, b: $type, c: $type) -> bool {
|
||||||
|
(&a | (&b & &c)) == ((&a | &b) & (&a | &c))
|
||||||
|
}
|
||||||
|
fn or_absorption(a: $type, b: $type) -> bool {
|
||||||
|
(&a | (&a & &b)) == a
|
||||||
|
}
|
||||||
|
fn and_absorption(a: $type, b: $type) -> bool {
|
||||||
|
(&a & (&a | &b)) == a
|
||||||
|
}
|
||||||
|
fn or_associative(a: $type, b: $type, c: $type) -> bool {
|
||||||
|
(&a | (&b | &c)) == ((&a | &b) | &c)
|
||||||
|
}
|
||||||
|
fn and_associative(a: $type, b: $type, c: $type) -> bool {
|
||||||
|
(&a & (&b & &c)) == ((&a & &b) & &c)
|
||||||
|
}
|
||||||
|
fn xor_as_defined(a: $type, b: $type) -> bool {
|
||||||
|
(&a ^ &b) == ((&a | &b) & !(&a & &b))
|
||||||
|
}
|
||||||
|
fn small_or_check(x: u64, y: u64) -> bool {
|
||||||
|
let x512 = $type::from(x);
|
||||||
|
let y512 = $type::from(y);
|
||||||
|
let z512 = x512 | y512;
|
||||||
|
let res: u64 = z512.into();
|
||||||
|
res == (x | y)
|
||||||
|
}
|
||||||
|
fn small_and_check(x: u64, y: u64) -> bool {
|
||||||
|
let x512 = $type::from(x);
|
||||||
|
let y512 = $type::from(y);
|
||||||
|
let z512 = x512 & y512;
|
||||||
|
let res: u64 = z512.into();
|
||||||
|
res == (x & y)
|
||||||
|
}
|
||||||
|
fn small_xor_check(x: u64, y: u64) -> bool {
|
||||||
|
let x512 = $type::from(x);
|
||||||
|
let y512 = $type::from(y);
|
||||||
|
let z512 = x512 ^ y512;
|
||||||
|
let res: u64 = z512.into();
|
||||||
|
res == (x ^ y)
|
||||||
|
}
|
||||||
|
fn small_neg_check(x: u64) -> bool {
|
||||||
|
let x512 = $type::from(x);
|
||||||
|
let z512 = !x512;
|
||||||
|
let res: u64 = z512.into();
|
||||||
|
res == !x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shl_tests() {
|
||||||
|
let ones = [1; $count];
|
||||||
|
assert_eq!($type{ contents: ones.clone() } << 0,
|
||||||
|
$type{ contents: ones.clone() });
|
||||||
|
let mut notones = [0; $count];
|
||||||
|
for i in 0..$count {
|
||||||
|
notones[i] = (i + 1) as u64;
|
||||||
|
}
|
||||||
|
assert_eq!($type{ contents: notones.clone() } << 0,
|
||||||
|
$type{ contents: notones.clone() });
|
||||||
|
assert_eq!($type{ contents: ones.clone() } << ($count * 64),
|
||||||
|
$type::zero());
|
||||||
|
assert_eq!($type::from(2 as u8) << 1, $type::from(4 as u8));
|
||||||
|
let mut buffer = [0; $count];
|
||||||
|
buffer[1] = 1;
|
||||||
|
assert_eq!($type::from(1 as u8) << 64,
|
||||||
|
$type{ contents: buffer.clone() });
|
||||||
|
buffer[0] = 0xFFFFFFFFFFFFFFFE;
|
||||||
|
assert_eq!($type::from(0xFFFFFFFFFFFFFFFF as u64) << 1,
|
||||||
|
$type{ contents: buffer.clone() });
|
||||||
|
buffer[0] = 0;
|
||||||
|
buffer[1] = 4;
|
||||||
|
assert_eq!($type::from(1 as u8) << 66,
|
||||||
|
$type{ contents: buffer.clone() });
|
||||||
|
assert_eq!($type::from(1 as u8) << 1, $type::from(2 as u8));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shr_tests() {
|
||||||
|
let ones = [1; $count];
|
||||||
|
assert_eq!($type{ contents: ones.clone() } >> 0,
|
||||||
|
$type{ contents: ones.clone() });
|
||||||
|
let mut notones = [0; $count];
|
||||||
|
for i in 0..$count {
|
||||||
|
notones[i] = (i + 1) as u64;
|
||||||
|
}
|
||||||
|
assert_eq!($type{ contents: ones.clone() } >> 0,
|
||||||
|
$type{ contents: ones.clone() });
|
||||||
|
assert_eq!($type{ contents: ones.clone() } >> ($count * 64),
|
||||||
|
$type::zero());
|
||||||
|
assert_eq!($type::from(2 as u8) >> 1,
|
||||||
|
$type::from(1 as u8));
|
||||||
|
let mut oneleft = [0; $count];
|
||||||
|
oneleft[1] = 1;
|
||||||
|
assert_eq!($type{ contents: oneleft.clone() } >> 1,
|
||||||
|
$type::from(0x8000000000000000 as u64));
|
||||||
|
assert_eq!($type{ contents: oneleft.clone() } >> 64,
|
||||||
|
$type::from(1 as u64));
|
||||||
|
oneleft[1] = 4;
|
||||||
|
assert_eq!($type{ contents: oneleft.clone() } >> 66,
|
||||||
|
$type::from(1 as u64));
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn shift_mask_equivr(x: $type, in_shift: usize) -> bool {
|
||||||
|
let shift = in_shift % ($count * 64);
|
||||||
|
let mask = $type::max_value() << shift;
|
||||||
|
let masked_x = &x & mask;
|
||||||
|
let shift_maskr = (x >> shift) << shift;
|
||||||
|
shift_maskr == masked_x
|
||||||
|
}
|
||||||
|
fn shift_mask_equivl(x: $type, in_shift: usize) -> bool {
|
||||||
|
let shift = in_shift % ($count * 64);
|
||||||
|
let mask = $type::max_value() >> shift;
|
||||||
|
let masked_x = &x & mask;
|
||||||
|
let shift_maskl = (x << shift) >> shift;
|
||||||
|
shift_maskl == masked_x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_tests() {
|
||||||
|
let ones = [1; $count];
|
||||||
|
let twos = [2; $count];
|
||||||
|
assert_eq!($type{ contents: ones.clone() } +
|
||||||
|
$type{ contents: ones.clone() },
|
||||||
|
$type{ contents: twos.clone() });
|
||||||
|
let mut buffer = [0; $count];
|
||||||
|
buffer[1] = 1;
|
||||||
|
assert_eq!($type::from(1 as u64) +
|
||||||
|
$type::from(0xFFFFFFFFFFFFFFFF as u64),
|
||||||
|
$type{ contents: buffer.clone() });
|
||||||
|
let mut high = [0; $count];
|
||||||
|
high[$count - 1] = 0xFFFFFFFFFFFFFFFF;
|
||||||
|
buffer[1] = 0;
|
||||||
|
buffer[$count - 1] = 1;
|
||||||
|
assert_eq!($type{ contents: buffer } + $type{ contents: high },
|
||||||
|
$type{ contents: [0; $count] });
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn add_symmetry(a: $type, b: $type) -> bool {
|
||||||
|
(&a + &b) == (&b + &a)
|
||||||
|
}
|
||||||
|
fn add_commutivity(a: $type, b: $type, c: $type) -> bool {
|
||||||
|
(&a + (&b + &c)) == ((&a + &b) + &c)
|
||||||
|
}
|
||||||
|
fn add_identity(a: $type) -> bool {
|
||||||
|
(&a + $type::zero()) == a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub_tests() {
|
||||||
|
let ones = [1; $count];
|
||||||
|
assert_eq!($type{ contents: ones.clone() } -
|
||||||
|
$type{ contents: ones.clone() },
|
||||||
|
$type::zero());
|
||||||
|
let mut buffer = [0; $count];
|
||||||
|
buffer[1] = 1;
|
||||||
|
assert_eq!($type{contents:buffer.clone()} - $type::from(1 as u8),
|
||||||
|
$type::from(0xFFFFFFFFFFFFFFFF as u64));
|
||||||
|
assert_eq!($type::zero() - $type::from(1 as u8),
|
||||||
|
$type::max_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn sub_destroys(a: $type) -> bool {
|
||||||
|
(&a - &a) == $type::zero()
|
||||||
|
}
|
||||||
|
fn sub_add_ident(a: $type, b: $type) -> bool {
|
||||||
|
((&a - &b) + &b) == a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_tests() {
|
||||||
|
assert_eq!($type::from(1 as u8) * $type::from(1 as u8),
|
||||||
|
$type::from(1 as u8));
|
||||||
|
assert_eq!($type::from(1 as u8) * $type::from(0 as u8),
|
||||||
|
$type::from(0 as u8));
|
||||||
|
assert_eq!($type::from(1 as u8) * $type::from(2 as u8),
|
||||||
|
$type::from(2 as u8));
|
||||||
|
let mut temp = $type::zero();
|
||||||
|
temp.contents[0] = 1;
|
||||||
|
temp.contents[1] = 0xFFFFFFFFFFFFFFFE;
|
||||||
|
assert_eq!($type::from(0xFFFFFFFFFFFFFFFF as u64) *
|
||||||
|
$type::from(0xFFFFFFFFFFFFFFFF as u64),
|
||||||
|
temp);
|
||||||
|
let effs = $type{ contents: [0xFFFFFFFFFFFFFFFF; $count] };
|
||||||
|
assert_eq!($type::from(1 as u8) * &effs, effs);
|
||||||
|
temp = effs.clone();
|
||||||
|
temp.contents[0] = temp.contents[0] - 1;
|
||||||
|
assert_eq!($type::from(2 as u8) * &effs, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn mul_symmetry(a: $type, b: $type) -> bool {
|
||||||
|
(&a * &b) == (&b * &a)
|
||||||
|
}
|
||||||
|
fn mul_commutivity(a: $type, b: $type, c: $type) -> bool {
|
||||||
|
(&a * (&b * &c)) == ((&a * &b) * &c)
|
||||||
|
}
|
||||||
|
fn mul_identity(a: $type) -> bool {
|
||||||
|
(&a * $type::from(1 as u8)) == a
|
||||||
|
}
|
||||||
|
fn mul_zero(a: $type) -> bool {
|
||||||
|
(&a * $type::zero()) == $type::zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn addmul_distribution(a: $type, b: $type, c: $type) -> bool {
|
||||||
|
(&a * (&b + &c)) == ((&a * &b) + (&a * &c))
|
||||||
|
}
|
||||||
|
fn submul_distribution(a: $type, b: $type, c: $type) -> bool {
|
||||||
|
(&a * (&b - &c)) == ((&a * &b) - (&a * &c))
|
||||||
|
}
|
||||||
|
fn mul2shift1_equiv(a: $type) -> bool {
|
||||||
|
(&a << 1) == (&a * $type::from(2 as u8))
|
||||||
|
}
|
||||||
|
fn mul16shift4_equiv(a: $type) -> bool {
|
||||||
|
(&a << 4) == (&a * $type::from(16 as u8))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn div_tests() {
|
||||||
|
assert_eq!($type::from(2 as u8) / $type::from(2 as u8),
|
||||||
|
$type::from(1 as u8));
|
||||||
|
assert_eq!($type::from(2 as u8) / $type::from(1 as u8),
|
||||||
|
$type::from(2 as u8));
|
||||||
|
assert_eq!($type::from(4 as u8) / $type::from(3 as u8),
|
||||||
|
$type::from(1 as u8));
|
||||||
|
assert_eq!($type::from(4 as u8) / $type::from(5 as u8),
|
||||||
|
$type::from(0 as u8));
|
||||||
|
assert_eq!($type::from(4 as u8) / $type::from(4 as u8),
|
||||||
|
$type::from(1 as u8));
|
||||||
|
let mut temp1 = $type::zero();
|
||||||
|
let mut temp2 = $type::zero();
|
||||||
|
temp1.contents[$count - 1] = 4;
|
||||||
|
temp2.contents[$count - 1] = 4;
|
||||||
|
assert_eq!(&temp1 / temp2, $type::from(1 as u8));
|
||||||
|
assert_eq!(&temp1 / $type::from(1 as u8), temp1);
|
||||||
|
temp1.contents[$count - 1] = u64::max_value();
|
||||||
|
assert_eq!(&temp1 / $type::from(1 as u8), temp1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn div0_fails() {
|
||||||
|
$type::from(0xabcd as u16) / $type::zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mod_tests() {
|
||||||
|
assert_eq!($type::from(4 as u16) % $type::from(5 as u16),
|
||||||
|
$type::from(4 as u16));
|
||||||
|
assert_eq!($type::from(5 as u16) % $type::from(4 as u16),
|
||||||
|
$type::from(1 as u16));
|
||||||
|
let fives = $type{ contents: [5; $count] };
|
||||||
|
let fours = $type{ contents: [4; $count] };
|
||||||
|
let ones = $type{ contents: [1; $count] };
|
||||||
|
assert_eq!(fives % fours, ones);
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
#[ignore]
|
||||||
|
fn div_identity(a: $type) -> bool {
|
||||||
|
&a / $type::from(1 as u16) == a
|
||||||
|
}
|
||||||
|
fn div_self_is_one(a: $type) -> bool {
|
||||||
|
if a == $type::zero() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
&a / &a == $type::from(1 as u16)
|
||||||
|
}
|
||||||
|
fn euclid_is_alive(a: $type, b: $type) -> bool {
|
||||||
|
let q = &a / &b;
|
||||||
|
let r = &a % &b;
|
||||||
|
a == ((b * q) + r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn serialization_inverts(a: $type) -> bool {
|
||||||
|
let bytes = a.to_bytes();
|
||||||
|
let b = $type::from_bytes(&bytes);
|
||||||
|
a == b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn fastmod_works(a: $type, b: $type) -> bool {
|
||||||
|
assert!(b != $type::zero());
|
||||||
|
match b.barrett_mu() {
|
||||||
|
None =>
|
||||||
|
true,
|
||||||
|
Some(barrett) => {
|
||||||
|
a.fastmod(&barrett) == (&a % &b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! shifts {
|
||||||
|
($type: ident, $shtype: ty) => {
|
||||||
|
shifts!($type, $shtype, ShlAssign, shl_assign, Shl, shl, generic_shl);
|
||||||
|
shifts!($type, $shtype, ShrAssign, shr_assign, Shr, shr, generic_shr);
|
||||||
|
};
|
||||||
|
|
||||||
|
($type: ident, $shtype: ty, $asncl: ident, $asnfn: ident,
|
||||||
|
$cl: ident, $fn: ident, $impl: ident) => {
|
||||||
|
impl $asncl<$shtype> for $type {
|
||||||
|
fn $asnfn(&mut self, amount: $shtype) {
|
||||||
|
let copy = self.contents.clone();
|
||||||
|
$impl(&mut self.contents, ©, amount as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $cl<$shtype> for $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn $fn(self, rhs: $shtype) -> $type {
|
||||||
|
let mut res = self.clone();
|
||||||
|
$impl(&mut res.contents, &self.contents, rhs as usize);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> $cl<$shtype> for &'a $type {
|
||||||
|
type Output = $type;
|
||||||
|
|
||||||
|
fn $fn(self, rhs: $shtype) -> $type {
|
||||||
|
let mut res = self.clone();
|
||||||
|
$impl(&mut res.contents, &self.contents, rhs as usize);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
10
src/lib.rs
10
src/lib.rs
@@ -11,14 +11,24 @@
|
|||||||
//! when they should use it, and examples. For now, it mostly just fowards
|
//! when they should use it, and examples. For now, it mostly just fowards
|
||||||
//! off to more detailed modules. Help requested!
|
//! off to more detailed modules. Help requested!
|
||||||
|
|
||||||
|
extern crate byteorder;
|
||||||
|
extern crate digest;
|
||||||
|
extern crate num;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate quickcheck;
|
extern crate quickcheck;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
extern crate sha1;
|
||||||
|
extern crate sha2;
|
||||||
|
extern crate simple_asn1;
|
||||||
|
|
||||||
/// The cryptonum module provides support for large numbers at fixed,
|
/// The cryptonum module provides support for large numbers at fixed,
|
||||||
/// cryptographically-relevant sizes.
|
/// cryptographically-relevant sizes.
|
||||||
pub mod cryptonum;
|
pub mod cryptonum;
|
||||||
|
/// The RSA module performs the basic operations for RSA, and should
|
||||||
|
/// be used directly only if you're fairly confident about what you're
|
||||||
|
/// doing.
|
||||||
|
pub mod rsa;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|||||||
59
src/rsa/core.rs
Normal file
59
src/rsa/core.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
use cryptonum::{CryptoNumModOps};
|
||||||
|
use num::BigUint;
|
||||||
|
use rsa::errors::RSAError;
|
||||||
|
use simple_asn1::{ASN1DecodeErr,ASN1Block};
|
||||||
|
|
||||||
|
// encoding PKCS1 stuff
|
||||||
|
pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8> {
|
||||||
|
let mut idhash = Vec::new();
|
||||||
|
idhash.extend_from_slice(ident);
|
||||||
|
idhash.extend_from_slice(hash);
|
||||||
|
let tlen = idhash.len();
|
||||||
|
assert!(keylen > (tlen + 3));
|
||||||
|
let mut padding = Vec::new();
|
||||||
|
padding.resize(keylen - tlen - 3, 0xFF);
|
||||||
|
let mut result = vec![0x00, 0x01];
|
||||||
|
result.append(&mut padding);
|
||||||
|
result.push(0x00);
|
||||||
|
result.append(&mut idhash);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
// the RSA encryption function
|
||||||
|
pub fn ep<U: CryptoNumModOps>(n: &U, e: &U, m: &U) -> U {
|
||||||
|
m.modexp(e, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the RSA decryption function
|
||||||
|
pub fn dp<U: CryptoNumModOps>(n: &U, d: &U, c: &U) -> U {
|
||||||
|
c.modexp(d, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the RSA signature generation function
|
||||||
|
pub fn sp1<U: CryptoNumModOps>(n: &U, d: &U, m: &U) -> U {
|
||||||
|
m.modexp(d, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_biguint(b: &ASN1Block) -> Result<BigUint,RSAError> {
|
||||||
|
match b {
|
||||||
|
&ASN1Block::Integer(_, _, ref v) => {
|
||||||
|
match v.to_biguint() {
|
||||||
|
Some(sn) => Ok(sn),
|
||||||
|
_ => Err(RSAError::InvalidKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(RSAError::ASN1DecodeErr(ASN1DecodeErr::EmptyBuffer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// the RSA signature verification function
|
||||||
|
pub fn vp1<U: CryptoNumModOps>(n: &U, e: &U, s: &U) -> U {
|
||||||
|
s.modexp(e, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn xor_vecs(a: &Vec<u8>, b: &Vec<u8>) -> Vec<u8> {
|
||||||
|
a.iter().zip(b.iter()).map(|(a,b)| a^b).collect()
|
||||||
|
}
|
||||||
|
|
||||||
39
src/rsa/errors.rs
Normal file
39
src/rsa/errors.rs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
use simple_asn1::{ASN1DecodeErr};
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum RSAKeyGenError {
|
||||||
|
InvalidKeySize(usize), RngFailure(io::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for RSAKeyGenError {
|
||||||
|
fn from(e: io::Error) -> RSAKeyGenError {
|
||||||
|
RSAKeyGenError::RngFailure(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum RSAError {
|
||||||
|
BadMessageSize,
|
||||||
|
KeyTooSmallForHash,
|
||||||
|
DecryptionError,
|
||||||
|
DecryptHashMismatch,
|
||||||
|
InvalidKey,
|
||||||
|
KeySizeMismatch,
|
||||||
|
RandomGenError(io::Error),
|
||||||
|
ASN1DecodeErr(ASN1DecodeErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for RSAError {
|
||||||
|
fn from(e: io::Error) -> RSAError {
|
||||||
|
RSAError::RandomGenError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ASN1DecodeErr> for RSAError {
|
||||||
|
fn from(e: ASN1DecodeErr) -> RSAError {
|
||||||
|
RSAError::ASN1DecodeErr(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
228
src/rsa/mod.rs
Normal file
228
src/rsa/mod.rs
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
//! # An implementation of RSA.
|
||||||
|
//!
|
||||||
|
//! This module is designed to provide implementations of the core routines
|
||||||
|
//! used for asymmetric cryptography using RSA. It probably provides a bit
|
||||||
|
//! more flexibility than beginners should play with, and definitely includes
|
||||||
|
//! some capabilities largely targeted at legacy systems. New users should
|
||||||
|
//! probably stick with the stuff in the root of this crate.
|
||||||
|
mod core;
|
||||||
|
mod errors;
|
||||||
|
mod oaep;
|
||||||
|
mod private;
|
||||||
|
mod public;
|
||||||
|
mod signing_hashes;
|
||||||
|
|
||||||
|
use cryptonum::*;
|
||||||
|
use rand::{OsRng,Rng};
|
||||||
|
use std::cmp::PartialOrd;
|
||||||
|
use std::ops::*;
|
||||||
|
|
||||||
|
pub use self::errors::{RSAKeyGenError,RSAError};
|
||||||
|
pub use self::oaep::{OAEPParams};
|
||||||
|
pub use self::private::RSAPrivateKey;
|
||||||
|
pub use self::public::RSAPublicKey;
|
||||||
|
pub use self::signing_hashes::{SigningHash,
|
||||||
|
SIGNING_HASH_NULL, SIGNING_HASH_SHA1,
|
||||||
|
SIGNING_HASH_SHA224, SIGNING_HASH_SHA256,
|
||||||
|
SIGNING_HASH_SHA384, SIGNING_HASH_SHA512};
|
||||||
|
|
||||||
|
/// An RSA public and private key.
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct RSAKeyPair<Size>
|
||||||
|
where
|
||||||
|
Size: CryptoNumBase + CryptoNumSerialization
|
||||||
|
{
|
||||||
|
pub private: RSAPrivateKey<Size>,
|
||||||
|
pub public: RSAPublicKey<Size>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> RSAKeyPair<T>
|
||||||
|
where
|
||||||
|
T: Clone + Sized + PartialOrd + From<u64>,
|
||||||
|
T: CryptoNumBase + CryptoNumModOps + CryptoNumPrimes + CryptoNumSerialization,
|
||||||
|
T: Sub<Output=T> + Mul<Output=T> + Shl<usize,Output=T>
|
||||||
|
{
|
||||||
|
/// Generates a fresh RSA key pair. If you actually want to protect data,
|
||||||
|
/// use a value greater than or equal to 2048. If you don't want to spend
|
||||||
|
/// all day waiting for RSA computations to finish, choose a value less
|
||||||
|
/// than or equal to 4096.
|
||||||
|
///
|
||||||
|
/// This routine will use `OsRng` for entropy. If you want to use your
|
||||||
|
/// own random number generator, use `generate_w_rng`.
|
||||||
|
pub fn generate() -> Result<RSAKeyPair<T>,RSAKeyGenError> {
|
||||||
|
let mut rng = OsRng::new()?;
|
||||||
|
RSAKeyPair::<T>::generate_w_rng(&mut rng)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a fresh RSA key pair of the given bit size. Valid bit sizes
|
||||||
|
/// are 512, 1024, 2048, 3072, 4096, 7680, 8192, and 15360. If you
|
||||||
|
/// actually want to protect data, use a value greater than or equal to
|
||||||
|
/// 2048. If you don't want to spend all day waiting for RSA computations
|
||||||
|
/// to finish, choose a value less than or equal to 4096.
|
||||||
|
///
|
||||||
|
/// If you provide your own random number generator that is not `OsRng`,
|
||||||
|
/// you should know what you're doing, and be using a cryptographically-
|
||||||
|
/// strong RNG of your own choosing. We've warned you. Use a good one.
|
||||||
|
/// So now it's on you.
|
||||||
|
pub fn generate_w_rng<G: Rng>(rng: &mut G)
|
||||||
|
-> Result<RSAKeyPair<T>,RSAKeyGenError>
|
||||||
|
{
|
||||||
|
let e = T::from(65537);
|
||||||
|
let len_bits = e.bit_size();
|
||||||
|
match generate_pq(rng, &e) {
|
||||||
|
None =>
|
||||||
|
return Err(RSAKeyGenError::InvalidKeySize(len_bits)),
|
||||||
|
Some((p, q)) => {
|
||||||
|
let n = p.clone() * q.clone();
|
||||||
|
let phi = (p - T::from(1)) * (q - T::from(1));
|
||||||
|
let d = e.modinv(&phi);
|
||||||
|
let public_key = RSAPublicKey::new(n.clone(), e);
|
||||||
|
let private_key = RSAPrivateKey::new(n, d);
|
||||||
|
return Ok(RSAKeyPair{ private: private_key, public: public_key })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_pq<'a,G,T>(rng: &mut G, e: &T) -> Option<(T,T)>
|
||||||
|
where
|
||||||
|
G: Rng,
|
||||||
|
T: Clone + PartialOrd + Shl<usize,Output=T> + Sub<Output=T> + From<u64>,
|
||||||
|
T: CryptoNumBase + CryptoNumPrimes + CryptoNumSerialization
|
||||||
|
{
|
||||||
|
let bitlen = T::zero().bit_size();
|
||||||
|
let mindiff = T::from(1) << ((bitlen/2)-101);
|
||||||
|
let minval = T::from(6074001000) << ((mindiff.bit_size()/2) - 33);
|
||||||
|
let p = T::generate_prime(rng, 7, e, &minval);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let q = T::generate_prime(rng, 7, e, &minval);
|
||||||
|
|
||||||
|
if diff(p.clone(), q.clone()) >= mindiff {
|
||||||
|
return Some((p, q));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn diff<T: PartialOrd + Sub<Output=T>>(a: T, b: T) -> T
|
||||||
|
{
|
||||||
|
if a > b {
|
||||||
|
a - b
|
||||||
|
} else {
|
||||||
|
b - a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use quickcheck::{Arbitrary,Gen};
|
||||||
|
use rsa::core::{dp,ep,sp1,vp1};
|
||||||
|
use sha2::Sha224;
|
||||||
|
use simple_asn1::{der_decode,der_encode};
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl Arbitrary for RSAKeyPair<U512> {
|
||||||
|
fn arbitrary<G: Gen>(g: &mut G) -> RSAKeyPair<U512> {
|
||||||
|
RSAKeyPair::generate_w_rng(g).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Core primitive checks
|
||||||
|
quickcheck! {
|
||||||
|
fn ep_dp_inversion(kp: RSAKeyPair<U512>, m: U512) -> bool {
|
||||||
|
let realm = &m % &kp.public.n;
|
||||||
|
let ciphertext = ep(&kp.public.n, &kp.public.e, &realm);
|
||||||
|
let mprime = dp(&kp.private.n, &kp.private.d, &ciphertext);
|
||||||
|
mprime == m
|
||||||
|
}
|
||||||
|
fn sp_vp_inversion(kp: RSAKeyPair<U512>, m: U512) -> bool {
|
||||||
|
let realm = &m % &kp.public.n;
|
||||||
|
let sig = sp1(&kp.private.n, &kp.private.d, &realm);
|
||||||
|
let mprime = vp1(&kp.public.n, &kp.public.e, &sig);
|
||||||
|
mprime == m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public key serialization
|
||||||
|
quickcheck! {
|
||||||
|
fn asn1_encoding_inverts(kp: RSAKeyPair<U512>) -> bool {
|
||||||
|
let bytes = der_encode(&kp.public).unwrap();
|
||||||
|
let pubkey: RSAPublicKey<U512> = der_decode(&bytes).unwrap();
|
||||||
|
(pubkey.n == kp.public.n) && (pubkey.e == kp.public.e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone,Debug)]
|
||||||
|
struct Message {
|
||||||
|
m: Vec<u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Arbitrary for Message {
|
||||||
|
fn arbitrary<G: Gen>(g: &mut G) -> Message {
|
||||||
|
let len = 1 + (g.gen::<u8>() % 3);
|
||||||
|
let mut storage = Vec::new();
|
||||||
|
for _ in 0..len {
|
||||||
|
storage.push(g.gen::<u8>());
|
||||||
|
}
|
||||||
|
Message{ m: storage }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone,Debug)]
|
||||||
|
struct KeyPairAndSigHash<T>
|
||||||
|
where
|
||||||
|
T: CryptoNumSerialization + CryptoNumBase
|
||||||
|
{
|
||||||
|
kp: RSAKeyPair<T>,
|
||||||
|
sh: &'static SigningHash
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Arbitrary for KeyPairAndSigHash<T>
|
||||||
|
where
|
||||||
|
T: Clone + Sized + PartialOrd + From<u64>,
|
||||||
|
T: CryptoNumBase + CryptoNumModOps,
|
||||||
|
T: CryptoNumPrimes + CryptoNumSerialization,
|
||||||
|
T: Sub<Output=T> + Mul<Output=T> + Shl<usize,Output=T>,
|
||||||
|
RSAKeyPair<T>: Arbitrary
|
||||||
|
{
|
||||||
|
fn arbitrary<G: Gen>(g: &mut G) -> KeyPairAndSigHash<T> {
|
||||||
|
let kp = RSAKeyPair::generate_w_rng(g).unwrap();
|
||||||
|
let size = kp.public.n.bit_size();
|
||||||
|
let mut hashes = vec![&SIGNING_HASH_SHA1];
|
||||||
|
|
||||||
|
if size >= 1024 {
|
||||||
|
hashes.push(&SIGNING_HASH_SHA224);
|
||||||
|
}
|
||||||
|
|
||||||
|
if size >= 2048 {
|
||||||
|
hashes.push(&SIGNING_HASH_SHA256);
|
||||||
|
}
|
||||||
|
|
||||||
|
if size >= 4096 {
|
||||||
|
hashes.push(&SIGNING_HASH_SHA384);
|
||||||
|
hashes.push(&SIGNING_HASH_SHA512);
|
||||||
|
}
|
||||||
|
|
||||||
|
let hash = g.choose(&hashes).unwrap().clone();
|
||||||
|
KeyPairAndSigHash{ kp: kp, sh: hash }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn sign_verifies(kpsh: KeyPairAndSigHash<U512>, m: Message) -> bool {
|
||||||
|
let sig = kpsh.kp.private.sign(kpsh.sh, &m.m);
|
||||||
|
kpsh.kp.public.verify(kpsh.sh, &m.m, &sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enc_dec_roundtrips(kp: RSAKeyPair<U512>, m: Message) -> bool {
|
||||||
|
let oaep = OAEPParams {
|
||||||
|
hash: Sha224::default(),
|
||||||
|
label: "test".to_string()
|
||||||
|
};
|
||||||
|
let c = kp.public.encrypt(&oaep, &m.m).unwrap();
|
||||||
|
let mp = kp.private.decrypt(&oaep, &c).unwrap();
|
||||||
|
|
||||||
|
mp == m.m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/rsa/oaep.rs
Normal file
47
src/rsa/oaep.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
use byteorder::{BigEndian,ByteOrder};
|
||||||
|
use digest::{FixedOutput,Input};
|
||||||
|
|
||||||
|
/// Parameters for OAEP encryption and decryption: a hash function to use
|
||||||
|
/// as part of the message generation function (MGF1, if you're curious),
|
||||||
|
/// and any labels you want to include as part of the encryption.
|
||||||
|
pub struct OAEPParams<H: Clone + Input + FixedOutput> {
|
||||||
|
pub hash: H,
|
||||||
|
pub label: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: Clone + Input + FixedOutput> OAEPParams<H> {
|
||||||
|
pub fn new(hash: H, label: String)
|
||||||
|
-> OAEPParams<H>
|
||||||
|
{
|
||||||
|
OAEPParams { hash: hash, label: label }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash_len(&self) -> usize {
|
||||||
|
self.hash.clone().fixed_result().as_slice().len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash(&self, input: &[u8]) -> Vec<u8> {
|
||||||
|
let mut digest = self.hash.clone();
|
||||||
|
digest.process(input);
|
||||||
|
digest.fixed_result().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mgf1(&self, input: &[u8], len: usize) -> Vec<u8> {
|
||||||
|
let mut res = Vec::with_capacity(len);
|
||||||
|
let mut counter: u32 = 0;
|
||||||
|
|
||||||
|
while res.len() < len {
|
||||||
|
let mut c: [u8; 4] = [0; 4];
|
||||||
|
BigEndian::write_u32(&mut c, counter);
|
||||||
|
let mut digest = self.hash.clone();
|
||||||
|
digest.process(input);
|
||||||
|
digest.process(&c);
|
||||||
|
let chunk = digest.fixed_result();
|
||||||
|
res.extend_from_slice(chunk.as_slice());
|
||||||
|
counter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.truncate(len);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
117
src/rsa/private.rs
Normal file
117
src/rsa/private.rs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
use cryptonum::{CryptoNumBase,CryptoNumModOps,CryptoNumSerialization};
|
||||||
|
use digest::{FixedOutput,Input};
|
||||||
|
use rsa::core::{dp,sp1,pkcs1_pad,xor_vecs};
|
||||||
|
use rsa::oaep::{OAEPParams};
|
||||||
|
use rsa::errors::{RSAError};
|
||||||
|
use rsa::signing_hashes::SigningHash;
|
||||||
|
|
||||||
|
/// A RSA private key. As with public keys, I've left the size as a
|
||||||
|
/// parameter: 2048-4096 is standard practice, 512-1024 is weak, and
|
||||||
|
/// >4096 is going to be slow.
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct RSAPrivateKey<Size>
|
||||||
|
where
|
||||||
|
Size: CryptoNumBase + CryptoNumSerialization
|
||||||
|
{
|
||||||
|
pub(crate) n: Size,
|
||||||
|
pub(crate) d: Size
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U> RSAPrivateKey<U>
|
||||||
|
where
|
||||||
|
U: CryptoNumBase + CryptoNumModOps + CryptoNumSerialization
|
||||||
|
{
|
||||||
|
/// Generate a private key, using the given `n` and `d` parameters
|
||||||
|
/// gathered from some other source. The length should be given in
|
||||||
|
/// bits.
|
||||||
|
pub fn new(n: U, d: U) -> RSAPrivateKey<U> {
|
||||||
|
RSAPrivateKey {
|
||||||
|
n: n,
|
||||||
|
d: d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a message using the given hash.
|
||||||
|
pub fn sign(&self, sighash: &SigningHash, msg: &[u8]) -> Vec<u8> {
|
||||||
|
let hash = (sighash.run)(msg);
|
||||||
|
let em = pkcs1_pad(&sighash.ident, &hash, self.d.byte_size());
|
||||||
|
let m = U::from_bytes(&em);
|
||||||
|
let s = sp1(&self.n, &self.d, &m);
|
||||||
|
let sig = s.to_bytes();
|
||||||
|
sig
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrypt a message with the given parameters.
|
||||||
|
pub fn decrypt<H: Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, msg: &[u8])
|
||||||
|
-> Result<Vec<u8>,RSAError>
|
||||||
|
{
|
||||||
|
let mut res = Vec::new();
|
||||||
|
let byte_len = self.d.byte_size();
|
||||||
|
|
||||||
|
for chunk in msg.chunks(byte_len) {
|
||||||
|
let mut dchunk = self.oaep_decrypt(oaep, chunk)?;
|
||||||
|
res.append(&mut dchunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn oaep_decrypt<H: Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, c: &[u8])
|
||||||
|
-> Result<Vec<u8>,RSAError>
|
||||||
|
{
|
||||||
|
let byte_len = self.d.byte_size();
|
||||||
|
// Step 1b
|
||||||
|
if c.len() != byte_len {
|
||||||
|
return Err(RSAError::DecryptionError);
|
||||||
|
}
|
||||||
|
// Step 1c
|
||||||
|
if byte_len < ((2 * oaep.hash_len()) + 2) {
|
||||||
|
return Err(RSAError::DecryptHashMismatch);
|
||||||
|
}
|
||||||
|
// Step 2a
|
||||||
|
let c_ip = U::from_bytes(&c);
|
||||||
|
// Step 2b
|
||||||
|
let m_ip = dp(&self.n, &self.d, &c_ip);
|
||||||
|
// Step 2c
|
||||||
|
let em = m_ip.to_bytes();
|
||||||
|
// Step 3a
|
||||||
|
let l_hash = oaep.hash(oaep.label.as_bytes());
|
||||||
|
// Step 3b
|
||||||
|
let (y, rest) = em.split_at(1);
|
||||||
|
let (masked_seed, masked_db) = rest.split_at(oaep.hash_len());
|
||||||
|
// Step 3c
|
||||||
|
let seed_mask = oaep.mgf1(masked_db, oaep.hash_len());
|
||||||
|
// Step 3d
|
||||||
|
let seed = xor_vecs(&masked_seed.to_vec(), &seed_mask);
|
||||||
|
// Step 3e
|
||||||
|
let db_mask = oaep.mgf1(&seed, byte_len - oaep.hash_len() - 1);
|
||||||
|
// Step 3f
|
||||||
|
let db = xor_vecs(&masked_db.to_vec(), &db_mask);
|
||||||
|
// Step 3g
|
||||||
|
let (l_hash2, ps_o_m) = db.split_at(oaep.hash_len());
|
||||||
|
let o_m = drop0s(ps_o_m);
|
||||||
|
let (o, m) = o_m.split_at(1);
|
||||||
|
// Checks!
|
||||||
|
if o != [1] {
|
||||||
|
return Err(RSAError::DecryptionError);
|
||||||
|
}
|
||||||
|
if l_hash != l_hash2 {
|
||||||
|
return Err(RSAError::DecryptionError);
|
||||||
|
}
|
||||||
|
if y != [0] {
|
||||||
|
return Err(RSAError::DecryptionError);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(m.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drop0s(a: &[u8]) -> &[u8] {
|
||||||
|
let mut idx = 0;
|
||||||
|
|
||||||
|
while (idx < a.len()) && (a[idx] == 0) {
|
||||||
|
idx = idx + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&a[idx..]
|
||||||
|
}
|
||||||
196
src/rsa/public.rs
Normal file
196
src/rsa/public.rs
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
use cryptonum::{CryptoNumBase,CryptoNumModOps,CryptoNumSerialization};
|
||||||
|
use digest::{FixedOutput,Input};
|
||||||
|
use num::{BigInt,BigUint};
|
||||||
|
use rand::{OsRng,Rng};
|
||||||
|
use rsa::core::{ep,vp1,pkcs1_pad,xor_vecs,decode_biguint};
|
||||||
|
use rsa::oaep::{OAEPParams};
|
||||||
|
use rsa::errors::{RSAError};
|
||||||
|
use rsa::signing_hashes::SigningHash;
|
||||||
|
use simple_asn1::{FromASN1,ToASN1,ASN1DecodeErr,ASN1EncodeErr};
|
||||||
|
use simple_asn1::{ASN1Block,ASN1Class};
|
||||||
|
|
||||||
|
/// An RSA public key with the given modulus size. I've left the size as a
|
||||||
|
/// parameter, instead of hardcoding particular values. That being said,
|
||||||
|
/// you almost certainly want one of `U2048`, `U3072`, or `U4096` if you're
|
||||||
|
/// being pretty standard; `U512` or `U1024` if you're interfacing with
|
||||||
|
/// legacy code or want to build intentionally weak systems; or `U7680`,
|
||||||
|
/// `U8192`, or `U15360` if you like things running very slowly.
|
||||||
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
|
pub struct RSAPublicKey<Size>
|
||||||
|
where
|
||||||
|
Size: CryptoNumBase + CryptoNumSerialization
|
||||||
|
{
|
||||||
|
pub(crate) n: Size,
|
||||||
|
pub(crate) e: Size
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U> RSAPublicKey<U>
|
||||||
|
where
|
||||||
|
U: CryptoNumBase + CryptoNumModOps + CryptoNumSerialization
|
||||||
|
{
|
||||||
|
/// Create a new RSA public key from the given components, which you found
|
||||||
|
/// via some other mechanism.
|
||||||
|
pub fn new(n: U, e: U) -> RSAPublicKey<U> {
|
||||||
|
RSAPublicKey{ n: n, e: e }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify the signature for a given message, using the given signing hash,
|
||||||
|
/// return true iff the signature validates.
|
||||||
|
pub fn verify(&self, sighash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
|
||||||
|
{
|
||||||
|
let hash = (sighash.run)(msg);
|
||||||
|
let s = U::from_bytes(sig);
|
||||||
|
let m = vp1(&self.n, &self.e, &s);
|
||||||
|
let em = s.to_bytes();
|
||||||
|
let em_ = pkcs1_pad(&sighash.ident, &hash, m.byte_size());
|
||||||
|
em == em_
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encrypt the given data with the public key and parameters, returning
|
||||||
|
/// the encrypted blob or an error encountered during encryption.
|
||||||
|
///
|
||||||
|
/// OAEP encoding is used for this process, which requires a random number
|
||||||
|
/// generator. This version of the function uses `OsRng`. If you want to
|
||||||
|
/// use your own RNG, use `encrypt_w_rng`.
|
||||||
|
pub fn encrypt<H:Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>,
|
||||||
|
msg: &[u8])
|
||||||
|
-> Result<Vec<u8>,RSAError>
|
||||||
|
{
|
||||||
|
let mut g = OsRng::new()?;
|
||||||
|
self.encrypt_with_rng(&mut g, oaep, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encrypt the given data with the public key and parameters, returning
|
||||||
|
/// the encrypted blob or an error encountered during encryption. This
|
||||||
|
/// version also allows you to provide your own RNG, if you really feel
|
||||||
|
/// like shooting yourself in the foot.
|
||||||
|
pub fn encrypt_with_rng<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>,
|
||||||
|
msg: &[u8])
|
||||||
|
-> Result<Vec<u8>,RSAError>
|
||||||
|
where G: Rng, H: Clone + Input + FixedOutput
|
||||||
|
{
|
||||||
|
let mylen = self.e.byte_size();
|
||||||
|
|
||||||
|
if mylen <= ((2 * oaep.hash_len()) + 2) {
|
||||||
|
return Err(RSAError::KeyTooSmallForHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut res = Vec::new();
|
||||||
|
|
||||||
|
for chunk in msg.chunks(mylen - (2 * oaep.hash_len()) - 2) {
|
||||||
|
let mut newchunk = self.oaep_encrypt(g, oaep, chunk)?;
|
||||||
|
res.append(&mut newchunk)
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn oaep_encrypt<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
|
||||||
|
-> Result<Vec<u8>,RSAError>
|
||||||
|
where
|
||||||
|
G: Rng, H:Clone + Input + FixedOutput
|
||||||
|
{
|
||||||
|
let mylen = self.e.byte_size();
|
||||||
|
|
||||||
|
// Step 1b
|
||||||
|
if msg.len() > (mylen - (2 * oaep.hash_len()) - 2) {
|
||||||
|
return Err(RSAError::BadMessageSize)
|
||||||
|
}
|
||||||
|
// Step 2a
|
||||||
|
let mut lhash = oaep.hash(oaep.label.as_bytes());
|
||||||
|
// Step 2b
|
||||||
|
let num0s = mylen - msg.len() - (2 * oaep.hash_len()) - 2;
|
||||||
|
let mut ps = Vec::new();
|
||||||
|
ps.resize(num0s, 0);
|
||||||
|
// Step 2c
|
||||||
|
let mut db = Vec::new();
|
||||||
|
db.append(&mut lhash);
|
||||||
|
db.append(&mut ps);
|
||||||
|
db.push(1);
|
||||||
|
db.extend_from_slice(msg);
|
||||||
|
// Step 2d
|
||||||
|
let seed : Vec<u8> = g.gen_iter().take(oaep.hash_len()).collect();
|
||||||
|
// Step 2e
|
||||||
|
let db_mask = oaep.mgf1(&seed, mylen - oaep.hash_len() - 1);
|
||||||
|
// Step 2f
|
||||||
|
let mut masked_db = xor_vecs(&db, &db_mask);
|
||||||
|
// Step 2g
|
||||||
|
let seed_mask = oaep.mgf1(&masked_db, oaep.hash_len());
|
||||||
|
// Step 2h
|
||||||
|
let mut masked_seed = xor_vecs(&seed, &seed_mask);
|
||||||
|
// Step 2i
|
||||||
|
let mut em = Vec::new();
|
||||||
|
em.push(0);
|
||||||
|
em.append(&mut masked_seed);
|
||||||
|
em.append(&mut masked_db);
|
||||||
|
// Step 3a
|
||||||
|
let m_i = U::from_bytes(&em);
|
||||||
|
// Step 3b
|
||||||
|
let c_i = ep(&self.n, &self.e, &m_i);
|
||||||
|
// Step 3c
|
||||||
|
let c = c_i.to_bytes();
|
||||||
|
Ok(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> FromASN1 for RSAPublicKey<T>
|
||||||
|
where
|
||||||
|
T: CryptoNumBase + CryptoNumSerialization,
|
||||||
|
T: From<BigUint>
|
||||||
|
{
|
||||||
|
type Error = RSAError;
|
||||||
|
|
||||||
|
fn from_asn1(bs: &[ASN1Block])
|
||||||
|
-> Result<(RSAPublicKey<T>,&[ASN1Block]),RSAError>
|
||||||
|
{
|
||||||
|
match bs.split_first() {
|
||||||
|
None =>
|
||||||
|
Err(RSAError::ASN1DecodeErr(ASN1DecodeErr::EmptyBuffer)),
|
||||||
|
Some((&ASN1Block::Sequence(_, _, ref items), rest))
|
||||||
|
if items.len() == 2 =>
|
||||||
|
{
|
||||||
|
let numn = decode_biguint(&items[0])?;
|
||||||
|
let nume = decode_biguint(&items[1])?;
|
||||||
|
let nsize = numn.bits();
|
||||||
|
let mut rsa_size = 512;
|
||||||
|
|
||||||
|
while rsa_size < nsize {
|
||||||
|
rsa_size = rsa_size + 256;
|
||||||
|
}
|
||||||
|
rsa_size /= 8;
|
||||||
|
|
||||||
|
if rsa_size != (T::zero()).bit_size() {
|
||||||
|
return Err(RSAError::KeySizeMismatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
let n = T::from(numn);
|
||||||
|
let e = T::from(nume);
|
||||||
|
|
||||||
|
let res = RSAPublicKey{ n: n, e: e };
|
||||||
|
|
||||||
|
Ok((res, rest))
|
||||||
|
}
|
||||||
|
Some(_) =>
|
||||||
|
Err(RSAError::InvalidKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ToASN1 for RSAPublicKey<T>
|
||||||
|
where
|
||||||
|
T: Clone + Into<BigInt>,
|
||||||
|
T: CryptoNumBase + CryptoNumSerialization
|
||||||
|
{
|
||||||
|
type Error = ASN1EncodeErr;
|
||||||
|
|
||||||
|
fn to_asn1_class(&self, c: ASN1Class)
|
||||||
|
-> Result<Vec<ASN1Block>,Self::Error>
|
||||||
|
{
|
||||||
|
let enc_n = ASN1Block::Integer(c, 0, self.n.clone().into());
|
||||||
|
let enc_e = ASN1Block::Integer(c, 0, self.e.clone().into());
|
||||||
|
let seq = ASN1Block::Sequence(c, 0, vec![enc_n, enc_e]);
|
||||||
|
Ok(vec![seq])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
119
src/rsa/signing_hashes.rs
Normal file
119
src/rsa/signing_hashes.rs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
use digest::{FixedOutput,Input};
|
||||||
|
use sha1::Sha1;
|
||||||
|
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// A hash that can be used to sign a message.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SigningHash {
|
||||||
|
/// The name of this hash (only used for display purposes)
|
||||||
|
pub name: &'static str,
|
||||||
|
/// The approved identity string for the hash.
|
||||||
|
pub ident: &'static [u8],
|
||||||
|
/// The hash
|
||||||
|
pub run: fn(&[u8]) -> Vec<u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SigningHash {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The "null" signing hash. This signing hash has no identity, and will
|
||||||
|
/// simply pass the data through unhashed. You really should know what
|
||||||
|
/// you're doing if you use this, and probably using a somewhat strange
|
||||||
|
/// signing protocol. There's no good reason to use this in new code
|
||||||
|
/// for a new protocol or system.
|
||||||
|
pub static SIGNING_HASH_NULL: SigningHash = SigningHash {
|
||||||
|
name: "NULL",
|
||||||
|
ident: &[],
|
||||||
|
run: nohash
|
||||||
|
};
|
||||||
|
|
||||||
|
fn nohash(i: &[u8]) -> Vec<u8> {
|
||||||
|
i.to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a hash based on SHA1. You shouldn't use this unless you're using
|
||||||
|
/// very small keys, and this is the only one available to you. Even then,
|
||||||
|
/// why are you using such small keys?!
|
||||||
|
pub static SIGNING_HASH_SHA1: SigningHash = SigningHash {
|
||||||
|
name: "SHA1",
|
||||||
|
ident: &[0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,
|
||||||
|
0x02,0x1a,0x05,0x00,0x04,0x14],
|
||||||
|
run: runsha1
|
||||||
|
};
|
||||||
|
|
||||||
|
fn runsha1(i: &[u8]) -> Vec<u8> {
|
||||||
|
let mut d = Sha1::default();
|
||||||
|
d.process(i);
|
||||||
|
d.fixed_result().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a hash based on SHA2-224. This is the first reasonable choice
|
||||||
|
/// we've come across, and is useful when you have smaller RSA key sizes.
|
||||||
|
/// I wouldn't recommend it, though.
|
||||||
|
pub static SIGNING_HASH_SHA224: SigningHash = SigningHash {
|
||||||
|
name: "SHA224",
|
||||||
|
ident: &[0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||||
|
0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,
|
||||||
|
0x1c],
|
||||||
|
run: runsha224
|
||||||
|
};
|
||||||
|
|
||||||
|
fn runsha224(i: &[u8]) -> Vec<u8> {
|
||||||
|
let mut d = Sha224::default();
|
||||||
|
d.process(i);
|
||||||
|
d.fixed_result().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a hash based on SHA2-256. The first one I'd recommend!
|
||||||
|
pub static SIGNING_HASH_SHA256: SigningHash = SigningHash {
|
||||||
|
name: "SHA256",
|
||||||
|
ident: &[0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||||
|
0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,
|
||||||
|
0x20],
|
||||||
|
run: runsha256
|
||||||
|
};
|
||||||
|
|
||||||
|
fn runsha256(i: &[u8]) -> Vec<u8> {
|
||||||
|
let mut d = Sha256::default();
|
||||||
|
d.process(i);
|
||||||
|
d.fixed_result().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a hash based on SHA2-384. Approximately 50% better than
|
||||||
|
/// SHA-256.
|
||||||
|
pub static SIGNING_HASH_SHA384: SigningHash = SigningHash {
|
||||||
|
name: "SHA384",
|
||||||
|
ident: &[0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||||
|
0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,
|
||||||
|
0x30],
|
||||||
|
run: runsha384
|
||||||
|
};
|
||||||
|
|
||||||
|
fn runsha384(i: &[u8]) -> Vec<u8> {
|
||||||
|
let mut d = Sha384::default();
|
||||||
|
d.process(i);
|
||||||
|
d.fixed_result().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a hash based on SHA2-512. At this point, you're getting a bit
|
||||||
|
/// silly. But if you want to through 8kbit RSA keys with a 512 bit SHA2
|
||||||
|
/// signing hash, we're totally behind you.
|
||||||
|
pub static SIGNING_HASH_SHA512: SigningHash = SigningHash {
|
||||||
|
name: "SHA512",
|
||||||
|
ident: &[0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||||
|
0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,
|
||||||
|
0x40],
|
||||||
|
run: runsha512
|
||||||
|
};
|
||||||
|
|
||||||
|
fn runsha512(i: &[u8]) -> Vec<u8> {
|
||||||
|
let mut d = Sha512::default();
|
||||||
|
d.process(i);
|
||||||
|
d.fixed_result().as_slice().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user