Refactor! Split the builder macros into a couple more places, and shift to From/Into instead of from_xxx and to_xxx.
This commit is contained in:
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,46 @@
|
||||
//! 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;
|
||||
#[macro_use]
|
||||
mod builder;
|
||||
mod modops;
|
||||
#[macro_use]
|
||||
mod primes;
|
||||
#[macro_use]
|
||||
mod signed;
|
||||
mod traits;
|
||||
#[macro_use]
|
||||
mod unsigned;
|
||||
mod traits;
|
||||
|
||||
pub use self::signed::{I512,I1024,I2048,I3072,I4096,I7680,I8192,I15360};
|
||||
pub use self::unsigned::{U512,U1024,U2048,U3072,U4096,U7680,U8192,U15360};
|
||||
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::*;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/cryptonum/primes.rs
Normal file
13
src/cryptonum/primes.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
macro_rules! derive_prime_operations
|
||||
{
|
||||
($type: ident) => {
|
||||
impl CryptoNumPrimes for $type {
|
||||
fn probably_prime<G: Rng>(_g: &mut G, _iters: usize) -> bool {
|
||||
panic!("probably_prime");
|
||||
}
|
||||
fn generate_prime<G: Rng>(_g: &mut G, _iters: usize, _e: &Self, _min: &Self) -> Self {
|
||||
panic!("generate_prime");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,237 @@
|
||||
use cryptonum::traits::*;
|
||||
use cryptonum::unsigned::*;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{Debug,Error,Formatter};
|
||||
use std::ops::*;
|
||||
macro_rules! construct_signed {
|
||||
($type: ident, $base: ident, $modname: ident) => {
|
||||
#[derive(Clone,PartialEq,Eq)]
|
||||
pub struct $type {
|
||||
negative: bool,
|
||||
value: $base
|
||||
}
|
||||
|
||||
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);
|
||||
impl Debug for $type {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(),Error> {
|
||||
if self.negative {
|
||||
f.write_str("-")?;
|
||||
} else {
|
||||
f.write_str("+")?;
|
||||
}
|
||||
self.value.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<&'a $type> for $type {
|
||||
fn eq(&self, other: &&$type) -> bool {
|
||||
(self.negative == other.negative) &&
|
||||
(self.value == other.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for $type {
|
||||
fn partial_cmp(&self, other: &$type) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for $type {
|
||||
fn cmp(&self, other: &$type) -> Ordering {
|
||||
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 CryptoNumBase for $type {
|
||||
fn zero() -> $type {
|
||||
$type{ negative: false, value: $base::zero() }
|
||||
}
|
||||
fn max_value() -> $type {
|
||||
$type{ negative: false, value: $base::max_value() }
|
||||
}
|
||||
fn is_zero(&self) -> bool {
|
||||
self.value.is_zero()
|
||||
}
|
||||
fn is_odd(&self) -> bool {
|
||||
self.value.is_odd()
|
||||
}
|
||||
fn is_even(&self) -> bool {
|
||||
self.value.is_even()
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoNumFastMod for $type {
|
||||
type BarrettMu = <$base as CryptoNumFastMod>::BarrettMu;
|
||||
|
||||
fn barrett_mu(&self) -> Option<Self::BarrettMu> {
|
||||
if self.negative {
|
||||
None
|
||||
} else {
|
||||
self.value.barrett_mu()
|
||||
}
|
||||
}
|
||||
|
||||
fn fastmod(&self, mu: &Self::BarrettMu) -> $type {
|
||||
let res = self.value.fastmod(mu);
|
||||
$type{ negative: self.negative, value: res }
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoNumSigned for $type {
|
||||
type Unsigned = $base;
|
||||
|
||||
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 Neg for $type {
|
||||
type Output = $type;
|
||||
|
||||
fn neg(self) -> $type {
|
||||
(&self).neg()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Neg for &'a $type {
|
||||
type Output = $type;
|
||||
|
||||
fn neg(self) -> $type {
|
||||
if self.value.is_zero() {
|
||||
$type{ negative: false, 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);
|
||||
|
||||
match (signs_match, ordering) {
|
||||
(true, _) =>
|
||||
// if the signs are the same, we maintain the sign and
|
||||
// just increase the magnitude
|
||||
self.value.add_assign(&other.value),
|
||||
(false, Ordering::Equal) => {
|
||||
// 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.
|
||||
self.negative = false;
|
||||
self.value.sub_assign(&other.value)
|
||||
}
|
||||
(false, Ordering::Less) => {
|
||||
// if the signs are different and the first one is less
|
||||
// than the second, then we flip the sign and subtract.
|
||||
self.negative = !self.negative;
|
||||
let mut other_copy = other.value.clone();
|
||||
other_copy.sub_assign(&self.value);
|
||||
self.value = other_copy;
|
||||
}
|
||||
(false, Ordering::Greater) => {
|
||||
// if the signs are different and the first one is
|
||||
// greater than the second, then we leave the sign and
|
||||
// subtract.
|
||||
self.value.sub_assign(&other.value)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
define_arithmetic!($type,SubAssign,sub_assign,Sub,sub,self,other,{
|
||||
// this is a bit inefficient, but a heck of a lot easier.
|
||||
let mut other2 = other.clone();
|
||||
other2.negative = !other2.negative;
|
||||
self.add_assign(&other2)
|
||||
});
|
||||
|
||||
define_arithmetic!($type,MulAssign,mul_assign,Mul,mul,self,other,{
|
||||
self.negative = self.negative ^ other.negative;
|
||||
self.value.mul_assign(&other.value);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
generate_signed_conversions!($type, $base);
|
||||
|
||||
#[cfg(test)]
|
||||
mod $modname {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use super::*;
|
||||
|
||||
impl Arbitrary for $type {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> $type {
|
||||
let value = $base::arbitrary(g);
|
||||
if value.is_zero() {
|
||||
$type{ negative: false, value: value }
|
||||
} else {
|
||||
$type{ negative: g.gen_weighted_bool(2), value: value }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn double_negation(x: $type) -> bool {
|
||||
(- (- &x)) == &x
|
||||
}
|
||||
fn add_identity(x: $type) -> bool {
|
||||
(&x + $type::zero()) == &x
|
||||
}
|
||||
fn add_commutivity(x: $type, y: $type) -> bool {
|
||||
(&x + &y) == (&y + &x)
|
||||
}
|
||||
fn add_associativity(a: $type, b: $type, c: $type) -> bool {
|
||||
// we shift these to get away from rollover
|
||||
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 {
|
||||
(&x - &y) == (&x + (- &y))
|
||||
}
|
||||
fn sub_destroys(x: $type) -> bool {
|
||||
(&x - &x) == $type::zero()
|
||||
}
|
||||
fn mul_identity(x: $type) -> bool {
|
||||
(&x * $type::from(1)) == &x
|
||||
}
|
||||
fn mul_commutivity(x: $type, y: $type) -> bool {
|
||||
(&x * &y) == (&y * &x)
|
||||
}
|
||||
fn mul_associativity(a: $type, b: $type, c: $type) -> bool {
|
||||
// we shift these to get away from rollover
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,26 +11,6 @@ pub trait CryptoNumBase {
|
||||
fn is_odd(&self) -> bool;
|
||||
/// Test if the number is even (a.k.a., the low bit is clear)
|
||||
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 {
|
||||
|
||||
@@ -1,16 +1,685 @@
|
||||
use cryptonum::core::*;
|
||||
use cryptonum::traits::*;
|
||||
use num::{BigUint,BigInt};
|
||||
use rand::Rng;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{Debug,Error,Formatter};
|
||||
use std::ops::*;
|
||||
macro_rules! construct_unsigned {
|
||||
($type: ident, $barrett: ident, $modname: ident, $count: expr) => {
|
||||
#[derive(Clone)]
|
||||
pub struct $type {
|
||||
contents: [u64; $count]
|
||||
}
|
||||
|
||||
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);
|
||||
pub struct $barrett {
|
||||
k: usize,
|
||||
progenitor: $type,
|
||||
contents: [u64; $count + 1]
|
||||
}
|
||||
|
||||
impl PartialEq for $type {
|
||||
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);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ pub struct RSAKeyPair<Size>
|
||||
|
||||
impl<T> RSAKeyPair<T>
|
||||
where
|
||||
T: Clone + Sized + PartialOrd,
|
||||
T: Clone + Sized + PartialOrd + From<u64>,
|
||||
T: CryptoNumBase + CryptoNumModOps + CryptoNumPrimes + CryptoNumSerialization,
|
||||
T: Sub<Output=T> + Mul<Output=T> + Shl<usize,Output=T>
|
||||
{
|
||||
@@ -67,14 +67,14 @@ impl<T> RSAKeyPair<T>
|
||||
pub fn generate_w_rng<G: Rng>(rng: &mut G)
|
||||
-> Result<RSAKeyPair<T>,RSAKeyGenError>
|
||||
{
|
||||
let e = T::from_u32(65537);
|
||||
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_u64(1)) * (q - T::from_u64(1));
|
||||
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);
|
||||
@@ -87,12 +87,12 @@ impl<T> RSAKeyPair<T>
|
||||
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>,
|
||||
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_u8(1) << ((bitlen/2)-101);
|
||||
let minval = T::from_u64(6074001000) << ((mindiff.bit_size()/2) - 33);
|
||||
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 {
|
||||
@@ -179,7 +179,7 @@ mod tests {
|
||||
|
||||
impl<T> Arbitrary for KeyPairAndSigHash<T>
|
||||
where
|
||||
T: Clone + Sized + PartialOrd,
|
||||
T: Clone + Sized + PartialOrd + From<u64>,
|
||||
T: CryptoNumBase + CryptoNumModOps,
|
||||
T: CryptoNumPrimes + CryptoNumSerialization,
|
||||
T: Sub<Output=T> + Mul<Output=T> + Shl<usize,Output=T>,
|
||||
|
||||
@@ -159,7 +159,7 @@ impl<T> FromASN1 for RSAPublicKey<T>
|
||||
}
|
||||
rsa_size /= 8;
|
||||
|
||||
if rsa_size != (T::from_u8(0)).bit_size() {
|
||||
if rsa_size != (T::zero()).bit_size() {
|
||||
return Err(RSAError::KeySizeMismatch);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user