Checkpoint; not sure where this code is, but I'm rethinking.

This commit is contained in:
2018-10-27 15:10:19 -07:00
parent b30fe6a75f
commit 43b73139cd
248 changed files with 801610 additions and 516822 deletions

View File

@@ -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.3"
digest = "^0.7.1"
num = "^0.1.42"
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"

View File

@@ -1,107 +1,97 @@
use cryptonum::{U192, U256, U384, U512, U576, use cryptonum::basetypes::*;
U1024, U2048, U3072, U4096, U8192, use std::ops::Add;
U15360};
use cryptonum::comparison::bignum_ge;
use cryptonum::subtraction::raw_subtraction;
use std::ops::{Add,AddAssign};
pub fn raw_addition(x: &mut [u64], y: &[u64]) -> u64 { pub trait UnsafeAdd {
assert_eq!(x.len(), y.len()); fn unsafe_add(self, other: &Self) -> Self;
let xiter = x.iter_mut();
let yiter = y.iter();
let mut carry = 0;
for (x, y) in xiter.zip(yiter) {
let bigger = (*x as u128) + (*y as u128) + carry;
carry = bigger >> 64;
*x = bigger as u64;
}
carry as u64
}
pub trait ModAdd<T=Self> {
fn modadd(&mut self, y: &Self, m: &T);
} }
macro_rules! generate_adders macro_rules! generate_adders
{ {
($name: ident) => { ($name: ident, $size: expr) => {
impl AddAssign for $name { impl UnsafeAdd for $name {
fn add_assign(&mut self, rhs: $name) { fn unsafe_add(self, other: &$name) -> $name {
raw_addition(&mut self.values, &rhs.values); let mut result = $name::zero();
} let mut carry = 0;
}
impl<'a> AddAssign<&'a $name> for $name { for i in 0..$size/64 {
fn add_assign(&mut self, rhs: &$name) { let x128 = self.values[i] as u128;
raw_addition(&mut self.values, &rhs.values); let y128 = other.values[i] as u128;
} let bigger = x128 + y128 + carry;
} carry = bigger >> 64;
impl Add for $name { result.values[i] = bigger as u64;
type Output = $name; }
fn add(self, other: $name) -> $name {
let mut result = $name{ values: self.values };
result.add_assign(other);
result result
} }
} }
impl<'a> Add<&'a $name> for $name {
type Output = $name;
fn add(self, other: &$name) -> $name { };
let mut result = $name{ values: self.values }; ($name: ident, $bigger: ident, $size: expr) => {
result.add_assign(other); generate_adders!($name, $size);
result
}
}
impl<'a,'b> Add<&'a $name> for &'b $name { impl<'a,'b> Add<&'a $name> for &'b $name {
type Output = $name; type Output = $bigger;
fn add(self, other: &$name) -> $bigger {
let mut result = $bigger::zero();
let mut carry = 0;
for i in 0..$size/64 {
let x128 = self.values[i] as u128;
let y128 = other.values[i] as u128;
let bigger = x128 + y128 + carry;
carry = bigger >> 64;
result.values[i] = bigger as u64;
}
result.values[$size/64] = carry as u64;
fn add(self, other: &$name) -> $name {
let mut result = $name{ values: self.values };
result.add_assign(other);
result result
} }
} }
impl ModAdd for $name {
fn modadd(&mut self, y: &$name, m: &$name) { impl Add<$name> for $name {
let carry = raw_addition(&mut self.values, &y.values); type Output = $bigger;
if carry > 0 {
let mut left = Vec::with_capacity(self.values.len() + 1); fn add(self, other: $name) -> $bigger {
for x in self.values.iter() { left.push(*x) } &self + &other
left.push(carry);
let mut right = Vec::with_capacity(self.values.len() + 1);
for x in m.values.iter() { right.push(*x) }
right.push(0);
raw_subtraction(&mut left, &right);
for i in 0..self.values.len() {
self.values[i] = left[i];
}
}
if bignum_ge(&self.values, &m.values) {
raw_subtraction(&mut self.values, &m.values);
}
} }
} }
} }
} }
generate_adders!(U192); generate_adders!(U192, U256, 192);
generate_adders!(U256); generate_adders!(U256, U320, 256);
generate_adders!(U384); generate_adders!(U384, U448, 384);
generate_adders!(U512); generate_adders!(U512, U576, 512);
generate_adders!(U576); generate_adders!(U576, U640, 576);
generate_adders!(U1024); generate_adders!(U1024, U1088, 1024);
generate_adders!(U2048); generate_adders!(U2048, U2112, 2048);
generate_adders!(U3072); generate_adders!(U3072, U3136, 3072);
generate_adders!(U4096); generate_adders!(U4096, U4160, 4096);
generate_adders!(U8192); generate_adders!(U7680, U7744, 7680);
generate_adders!(U15360); generate_adders!(U8192, U8256, 8192);
generate_adders!(U15360, U15424, 15360);
generate_adders!(U320, 320);
generate_adders!(U448, 448);
generate_adders!(U768, 768);
generate_adders!(U832, 832);
generate_adders!(U1088, 1088);
generate_adders!(U1216, 1216);
generate_adders!(U2112, 2112);
generate_adders!(U3136, 3136);
generate_adders!(U4160, 4160);
generate_adders!(U6144, 6144);
generate_adders!(U6208, 6208);
generate_adders!(U8256, 8256);
generate_adders!(U15424, 15424);
generate_adders!(U16384, 16384);
generate_adders!(U16448, 16448);
generate_adders!(U30720, 30720);
generate_adders!(U30784, 30784);
macro_rules! generate_tests { macro_rules! generate_tests {
( $( $name:ident ),* ) => { ( $( ($name:ident, $bigger: ident) ),* ) => {
#[cfg(test)] #[cfg(test)]
mod normal { mod normal {
use cryptonum::Decoder; use cryptonum::Decoder;
@@ -118,44 +108,11 @@ macro_rules! generate_tests {
let (neg0, abytes) = case.get("a").unwrap(); let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap(); let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, cbytes) = case.get("c").unwrap(); let (neg2, cbytes) = case.get("c").unwrap();
assert!(!neg0 && !neg1 && !neg2); assert!(!neg0 && !neg1 && !neg2);
let mut a = $name::from_bytes(abytes); let a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes); let b = $name::from_bytes(bbytes);
let c = $name::from_bytes(cbytes); let c = $bigger::from_bytes(cbytes);
assert_eq!(&a + &b, c); assert_eq!(&a + &b, c);
a += b;
assert_eq!(a, c);
});
}
)*
}
#[cfg(test)]
mod modular {
use cryptonum::encoding::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/modadd{}.test",
stringify!($name));
run_test(fname.to_string(), 4, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, cbytes) = case.get("c").unwrap();
let (neg3, mbytes) = case.get("m").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3);
let mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let m = $name::from_bytes(mbytes);
let c = $name::from_bytes(cbytes);
a.modadd(&b, &m);
assert_eq!(a, c);
}); });
} }
)* )*
@@ -163,4 +120,14 @@ macro_rules! generate_tests {
} }
} }
generate_tests!(U192, U256, U384, U512, U576, U1024, U2048, U3072, U4096, U8192, U15360); generate_tests!((U192, U256),
(U256, U320),
(U384, U448),
(U512, U576),
(U576, U640),
(U1024, U1088),
(U2048, U2112),
(U3072, U3136),
(U4096, U4160),
(U8192, U8256),
(U15360, U15424));

View File

@@ -1,107 +1,40 @@
use cryptonum::{U192, U256, U384, U512, U576, use cryptonum::addition::UnsafeAdd;
U1024, U2048, U3072, U4096, U8192, use cryptonum::basetypes::*;
U15360}; use std::cmp::min;
use cryptonum::addition::{ModAdd,raw_addition};
use cryptonum::comparison::{bignum_cmp,bignum_ge};
use cryptonum::division::divmod;
use cryptonum::exponentiation::ModExp;
use cryptonum::multiplication::{ModMul,raw_multiplication};
use cryptonum::squaring::{ModSquare,raw_square};
use cryptonum::subtraction::raw_subtraction;
use std::cmp::{Ordering,min};
use std::fmt;
macro_rules! generate_barrett_implementations { macro_rules! generate_barretts {
($bname: ident, $name: ident, $size: expr) => { ($bname:ident,$name:ident,$big:ident,$bg2:ident,$dbl:ident,$size:expr) =>
{
#[derive(Debug,PartialEq)]
pub struct $bname { pub struct $bname {
pub(crate) k: usize, pub(crate) k: usize,
pub(crate) m: [u64; $size/32], pub(crate) m: $big,
pub(crate) mu: [u64; $size/32] pub(crate) mu: $big
}
impl fmt::Debug for $bname {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, stringify!($bname))?;
write!(f, "{{ ")?;
for x in self.mu.iter() {
write!(f, "{:X} ", *x)?;
}
write!(f, "}} ")
}
}
impl PartialEq for $bname {
fn eq(&self, rhs: &$bname) -> bool {
for (left, right) in rhs.mu.iter().zip(rhs.mu.iter()) {
if *left != *right {
return false;
}
}
true
}
} }
impl $bname { impl $bname {
pub fn new(m: &$name) -> $bname { pub fn new(m: &$name) -> $bname {
let mut b = [0; ($size/32) + 1]; // Step #1: Figure out k
let mut widerm = [0; ($size/32) + 1]; let mut k = 0;
let mut quot = [0; ($size/32) + 1]; for i in 0..$size/64 {
let mut remndr = [0; ($size/32) + 1]; if m.values[i] != 0 {
let mut result = $bname{ k: 0, k = i;
m: [0; $size/32], }
mu: [0; $size/32] };
for (idx, val) in m.values.iter().enumerate() {
let x = *val;
widerm[idx] = x;
result.m[idx] = x;
if x != 0 { result.k = idx; }
} }
result.k += 1; k += 1;
b[result.k*2] = 1; // Step #2: Compute b
divmod(&b, &widerm, &mut quot, &mut remndr); let mut b = $bg2::zero();
for (idx, val) in result.mu.iter_mut().enumerate() { *val = quot[idx]; } b.values[2*k] = 1;
result // Step #3: Divide b by m.
let bigm = $bg2::from(m);
let (quot, _) = b.divmod(&bigm);
let resm = $big::from(m);
let mu = $big::from(&quot);
// Done!
$bname{ k: k, m: resm, mu: mu }
} }
pub fn reduce(&self, x: &mut $name) { pub fn ok_for_reduce(&self, x: &$dbl) -> bool {
assert!(self.reduce_ok(&x));
// 1. q1←⌊x/bk1⌋, q2←q1 · μ, q3←⌊q2/bk+1⌋.
let mut q1 = [0; $size/32];
shiftr(&x.values, self.k - 1, &mut q1);
let mut q2 = [0; $size/16];
raw_multiplication(&q1, &self.mu, &mut q2);
let mut q3 = [0; $size/16];
shiftr(&q2, self.k + 1,&mut q3);
// 2. r1←x mod bk+1, r2←q3 · m mod bk+1, r←r1 r2.
let mut r = [0; $size/16];
let copylen = min(self.k+1, x.values.len());
for i in 0..copylen { r[i] = x.values[i]; }
let mut r2big = [0; $size/8];
let mut mwider = [0; $size/16];
for i in 0..$size/32 { mwider[i] = self.m[i]; }
raw_multiplication(&q3, &mwider, &mut r2big);
let mut r2 = [0; $size/16];
for i in 0..self.k+1 { r2[i] = r2big[i]; }
let went_negative = !bignum_ge(&r, &r2);
raw_subtraction(&mut r, &r2);
// 3. If r<0 then r←r+bk+1.
if went_negative {
let mut bk1 = [0; $size/32];
bk1[self.k+1] = 1;
raw_addition(&mut r, &bk1);
}
// 4. While r≥m do: r←rm.
while bignum_cmp(&r, &mwider) == Ordering::Greater {
raw_subtraction(&mut r, &mwider);
}
// Copy it over.
for (idx, val) in x.values.iter_mut().enumerate() {
*val = r[idx];
}
}
pub fn reduce_ok(&self, x: &$name) -> bool {
for i in self.k*2 .. x.values.len() { for i in self.k*2 .. x.values.len() {
if x.values[i] != 0 { if x.values[i] != 0 {
return false return false
@@ -109,168 +42,123 @@ macro_rules! generate_barrett_implementations {
} }
true true
} }
}
impl ModAdd<$bname> for $name { pub fn reduce(&self, x: &$dbl) -> $name {
fn modadd(&mut self, y: &$name, m: &$bname) { assert!(self.ok_for_reduce(x));
let carry = raw_addition(&mut self.values, &y.values); let m2: $bg2 = $bg2::from(&self.m);
let msized = &m.m[0..$size/64];
if carry > 0 {
let mut left = [0; $size/64 + 1];
(&mut left[0..$size/64]).copy_from_slice(&self.values);
left[$size/64] = carry;
let mut right = [0; $size/64 + 1];
(&mut right[0..$size/64]).copy_from_slice(msized);
raw_subtraction(&mut left, &right);
for i in 0..self.values.len() {
self.values[i] = left[i];
}
}
if bignum_ge(&self.values, msized) {
raw_subtraction(&mut self.values, msized);
}
}
}
impl ModMul<$bname> for $name {
fn modmul(&mut self, x: &$name, m: &$bname) {
let mut mulres = [0; $size/32];
raw_multiplication(&self.values, &x.values, &mut mulres);
// 1. q1←⌊x/bk1⌋, q2←q1 · μ, q3←⌊q2/bk+1⌋. // 1. q1←⌊x/bk1⌋, q2←q1 · μ, q3←⌊q2/bk+1⌋.
let mut q1 = [0; $size/32]; let q1: $big = x.shiftr(self.k - 1);
shiftr(&mulres, m.k - 1, &mut q1); let q2: $bg2 = q1.unsafe_mul(&self.mu);
let mut q2 = [0; $size/16]; let q3: $big = q2.check_shiftr(self.k + 1);
raw_multiplication(&q1, &m.mu, &mut q2);
let mut q3 = [0; $size/16];
shiftr(&q2, m.k + 1, &mut q3);
// 2. r1←x mod bk+1, r2←q3 · m mod bk+1, r←r1 r2. // 2. r1←x mod bk+1, r2←q3 · m mod bk+1, r←r1 r2.
let mut r = [0; $size/16]; let mut r: $bg2 = x.mask(self.k + 1);
let copylen = min(m.k + 1, mulres.len()); let mut r2: $bg2 = q3.unsafe_mul(&self.m);
for i in 0..copylen { r[i] = mulres[i]; } r2.mask_inplace(self.k + 1);
let mut r2big = [0; $size/8]; let went_negative = &r < &r2;
let mut mwider = [0; $size/16]; r -= &r2;
for i in 0..$size/32 { mwider[i] = m.m[i]; }
raw_multiplication(&q3, &mwider, &mut r2big);
let mut r2 = [0; $size/16];
for i in 0..m.k+1 { r2[i] = r2big[i]; }
let went_negative = !bignum_ge(&r, &r2);
raw_subtraction(&mut r, &r2);
// 3. If r<0 then r←r+bk+1. // 3. If r<0 then r←r+bk+1.
if went_negative { if went_negative {
let mut bk1 = [0; $size/32]; let mut bk1 = $bg2::zero();
bk1[m.k + 1] = 1; bk1.values[self.k+1] = 1;
raw_addition(&mut r, &bk1); r = r.unsafe_add(&bk1);
} }
// 4. While r≥m do: r←rm. // 4. While r≥m do: r←rm.
while bignum_cmp(&r, &mwider) == Ordering::Greater { while &r > &m2 {
raw_subtraction(&mut r, &mwider); r -= &m2;
}
// Copy it over.
for (idx, val) in self.values.iter_mut().enumerate() {
*val = r[idx];
} }
// Done!
$name::from(&r)
} }
} }
impl ModSquare<$bname> for $name { impl $dbl {
fn modsq(&mut self, m: &$bname) { fn shiftr(&self, x: usize) -> $big {
let mut sqres = [0; $size/32]; let mut res = $big::zero();
raw_square(&self.values, &mut sqres); for i in 0..self.values.len()-x {
// 1. q1←⌊x/bk1⌋, q2←q1 · μ, q3←⌊q2/bk+1⌋. if i >= res.values.len() {
let mut q1 = [0; $size/32]; assert_eq!(self.values[i+x], 0);
shiftr(&sqres, m.k - 1, &mut q1); } else {
let mut q2 = [0; $size/16]; res.values[i] = self.values[i+x];
raw_multiplication(&q1, &m.mu, &mut q2);
let mut q3 = [0; $size/16];
shiftr(&q2, m.k + 1, &mut q3);
// 2. r1←x mod bk+1, r2←q3 · m mod bk+1, r←r1 r2.
let mut r = [0; $size/16];
let copylen = min(m.k + 1, sqres.len());
for i in 0..copylen { r[i] = sqres[i]; }
let mut r2big = [0; $size/8];
let mut mwider = [0; $size/16];
for i in 0..$size/32 { mwider[i] = m.m[i]; }
raw_multiplication(&q3, &mwider, &mut r2big);
let mut r2 = [0; $size/16];
for i in 0..m.k+1 { r2[i] = r2big[i]; }
let went_negative = !bignum_ge(&r, &r2);
raw_subtraction(&mut r, &r2);
// 3. If r<0 then r←r+bk+1.
if went_negative {
let mut bk1 = [0; $size/32];
bk1[m.k + 1] = 1;
raw_addition(&mut r, &bk1);
}
// 4. While r≥m do: r←rm.
while bignum_cmp(&r, &mwider) == Ordering::Greater {
raw_subtraction(&mut r, &mwider);
}
// Copy it over.
for (idx, val) in self.values.iter_mut().enumerate() {
*val = r[idx];
}
}
}
impl ModExp<$bname> for $name {
fn modexp(&mut self, e: &$name, m: &$bname) {
// S <- g
let mut s = self.clone();
m.reduce(&mut s);
// A <- 1
for val in self.values.iter_mut() { *val = 0; }
self.values[0] = 1;
// We do a quick skim through and find the highest index that
// actually has a value in it.
let mut highest_digit = 0;
for (idx, val) in e.values.iter().enumerate() {
if *val != 0 {
highest_digit = idx;
} }
} }
// While e != 0 do the following: res
// If e is odd then A <- A * S }
// e <- floor(e / 2)
// If e != 0 then S <- S * S
for i in 0..highest_digit+1 {
let mut mask = 1;
while mask != 0 { fn mask(&self, len: usize) -> $bg2 {
if e.values[i] & mask != 0 { let mut res = $bg2::zero();
self.modmul(&s, m); let copylen = min(len, self.values.len());
for i in 0..copylen {
res.values[i] = self.values[i];
}
res
}
}
impl $big {
fn unsafe_mul(&self, rhs: &$big) -> $bg2 {
let mut w = $bg2::zero();
let len = rhs.values.len();
for i in 0..len {
let mut carry = 0;
for j in 0..len {
if i+j >= w.values.len() {
continue;
} }
mask <<= 1; let old = w.values[i+j] as u128;
s.modsq(m); let x128 = self.values[j] as u128;
let y128 = rhs.values[i] as u128;
let uv = old + (x128 * y128) + carry;
w.values[i+j] = uv as u64;
carry = uv >> 64;
}
if i+len < w.values.len() {
w.values[i+len] = carry as u64;
} }
} }
// Return A
w
} }
} }
};
}
fn shiftr(x: &[u64], amt: usize, dest: &mut [u64]) impl $bg2 {
{ fn check_shiftr(&self, x: usize) -> $big {
for i in amt..x.len() { let mut res = $big::zero();
dest[i-amt] = x[i];
for i in 0..self.values.len()-x {
if i >= res.values.len() {
assert_eq!(self.values[i+x], 0);
} else {
res.values[i] = self.values[i+x];
}
}
res
}
fn mask_inplace(&mut self, len: usize) {
let dellen = min(len, self.values.len());
for i in dellen..self.values.len() {
self.values[i] = 0;
}
}
}
} }
} }
generate_barretts!(BarrettU192, U192, U256, U448, U384, 192);
generate_barrett_implementations!(BarrettU192, U192, 192); generate_barretts!(BarrettU256, U256, U320, U576, U512, 256);
generate_barrett_implementations!(BarrettU256, U256, 256); generate_barretts!(BarrettU384, U384, U448, U832, U768, 384);
generate_barrett_implementations!(BarrettU384, U384, 384); generate_barretts!(BarrettU512, U512, U576, U1088, U1024, 512);
generate_barrett_implementations!(BarrettU512, U512, 512); generate_barretts!(BarrettU576, U576, U640, U1216, U1152, 576);
generate_barrett_implementations!(BarrettU576, U576, 576); generate_barretts!(BarrettU1024, U1024, U1088, U2112, U2048, 1024);
generate_barrett_implementations!(BarrettU1024, U1024, 1024); generate_barretts!(BarrettU2048, U2048, U2112, U4160, U4096, 2048);
generate_barrett_implementations!(BarrettU2048, U2048, 2048); generate_barretts!(BarrettU3072, U3072, U3136, U6208, U6144, 3072);
generate_barrett_implementations!(BarrettU3072, U3072, 3072); generate_barretts!(BarrettU4096, U4096, U4160, U8256, U8192, 4096);
generate_barrett_implementations!(BarrettU4096, U4096, 4096); generate_barretts!(BarrettU8192, U8192, U8256, U16448, U16384, 8192);
generate_barrett_implementations!(BarrettU8192, U8192, 8192); generate_barretts!(BarrettU15360, U15360, U15424, U30784, U30720, 15360);
generate_barrett_implementations!(BarrettU15360, U15360,15360);
macro_rules! generate_tests { macro_rules! generate_tests {
( $( ($bname: ident, $name:ident, $size:expr) ),* ) => { ( $( ($bname:ident,$name:ident,$big:ident,$dbl:ident,$size:expr) ),* ) => {
#[cfg(test)] #[cfg(test)]
mod generation { mod generation {
use cryptonum::encoding::{Decoder,raw_decoder}; use cryptonum::encoding::{Decoder,raw_decoder};
@@ -290,15 +178,13 @@ macro_rules! generate_tests {
assert!(!neg0 && !neg1 && !neg2); assert!(!neg0 && !neg1 && !neg2);
let m = $name::from_bytes(mbytes); let m = $name::from_bytes(mbytes);
let u = $big::from_bytes(ubytes);
let mut kbig = [0; 1]; let mut kbig = [0; 1];
raw_decoder(&kbytes, &mut kbig); raw_decoder(&kbytes, &mut kbig);
let mut u = $bname{ k: kbig[0] as usize, let k = kbig[0] as usize;
m: [0; $size/32],
mu: [0; $size/32]};
raw_decoder(&mbytes, &mut u.m);
raw_decoder(&ubytes, &mut u.mu);
let r = $bname::new(&m); let r = $bname::new(&m);
assert_eq!(u,r); assert_eq!(k,r.k);
assert_eq!(u,r.mu);
}); });
} }
)* )*
@@ -324,118 +210,16 @@ macro_rules! generate_tests {
let (neg4, rbytes) = case.get("r").unwrap(); let (neg4, rbytes) = case.get("r").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4); assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
let m = $big::from_bytes(mbytes);
let u = $big::from_bytes(ubytes);
let mut kbig = [0; 1]; let mut kbig = [0; 1];
raw_decoder(&kbytes, &mut kbig); raw_decoder(&kbytes, &mut kbig);
let mut u = $bname{ k: kbig[0] as usize, let k = kbig[0] as usize;
m: [0; $size/32], let x = $dbl::from_bytes(xbytes);
mu: [0; $size/32]};
raw_decoder(&mbytes, &mut u.m);
raw_decoder(&ubytes, &mut u.mu);
let mut x = $name::from_bytes(&xbytes);
let r = $name::from_bytes(&rbytes);
u.reduce(&mut x);
assert_eq!(x, r);
});
}
)*
}
#[cfg(test)]
mod modadd {
use cryptonum::encoding::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/modadd{}.test",
stringify!($name));
run_test(fname.to_string(), 4, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, cbytes) = case.get("c").unwrap();
let (neg3, mbytes) = case.get("m").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3);
let mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let m = $name::from_bytes(mbytes);
let mu = $bname::new(&m);
let c = $name::from_bytes(cbytes);
a.modadd(&b, &mu);
assert_eq!(a, c);
});
}
)*
}
#[cfg(test)]
mod modmul {
use cryptonum::encoding::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/modmul{}.test",
stringify!($name));
run_test(fname.to_string(), 4, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, cbytes) = case.get("c").unwrap();
let (neg3, mbytes) = case.get("m").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3);
let mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let m = $name::from_bytes(mbytes);
let mu = $bname::new(&m);
let c = $name::from_bytes(cbytes);
a.modmul(&b, &mu);
assert_eq!(a, c);
});
}
)*
}
#[cfg(test)]
mod modexp {
use cryptonum::encoding::{Decoder,raw_decoder};
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/bmodexp{}.test",
stringify!($name));
run_test(fname.to_string(), 6, |case| {
let (neg0, bbytes) = case.get("b").unwrap();
let (neg1, ebytes) = case.get("e").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, kbytes) = case.get("k").unwrap();
let (neg4, ubytes) = case.get("u").unwrap();
let (neg5, rbytes) = case.get("r").unwrap();
assert!(!neg0 && !neg1 && !neg2 &&
!neg3 && !neg4 && !neg5);
let mut b = $name::from_bytes(bbytes);
let e = $name::from_bytes(ebytes);
let mut kbig = [0; 1];
raw_decoder(&kbytes, &mut kbig);
let mut u = $bname{ k: kbig[0] as usize,
m: [0; $size/32],
mu: [0; $size/32] };
raw_decoder(&mbytes, &mut u.m);
raw_decoder(&ubytes, &mut u.mu);
let r = $name::from_bytes(rbytes); let r = $name::from_bytes(rbytes);
b.modexp(&e, &u); let bu = $bname{ k: k, m: m, mu: u };
assert_eq!(b, r); let r2 = bu.reduce(&x);
assert_eq!(r, r2);
}); });
} }
)* )*
@@ -443,14 +227,14 @@ macro_rules! generate_tests {
} }
} }
generate_tests!((BarrettU192, U192, 192), generate_tests!((BarrettU192, U192, U256, U384, 192),
(BarrettU256, U256, 256), (BarrettU256, U256, U320, U512, 256),
(BarrettU384, U384, 384), (BarrettU384, U384, U448, U768, 384),
(BarrettU512, U512, 512), (BarrettU512, U512, U576, U1024, 512),
(BarrettU576, U576, 576), (BarrettU576, U576, U640, U1152, 576),
(BarrettU1024, U1024, 1024), (BarrettU1024, U1024, U1088, U2048, 1024),
(BarrettU2048, U2048, 2048), (BarrettU2048, U2048, U2112, U4096, 2048),
(BarrettU3072, U3072, 3072), (BarrettU3072, U3072, U3136, U6144, 3072),
(BarrettU4096, U4096, 4096), (BarrettU4096, U4096, U4160, U8192, 4096),
(BarrettU8192, U8192, 8192), (BarrettU8192, U8192, U8256, U16384, 8192),
(BarrettU15360, U15360, 15360)); (BarrettU15360, U15360, U15424, U30720, 15360));

View File

@@ -1,6 +1,13 @@
use std::fmt; use std::fmt;
use std::fmt::Write; use std::fmt::Write;
pub trait CryptoNum {
fn zero() -> Self;
fn is_odd(&self) -> bool;
fn is_even(&self) -> bool;
fn is_zero(&self) -> bool;
}
macro_rules! generate_unsigned macro_rules! generate_unsigned
{ {
($name: ident, $size: expr) => { ($name: ident, $size: expr) => {
@@ -11,9 +18,7 @@ macro_rules! generate_unsigned
impl Clone for $name { impl Clone for $name {
fn clone(&self) -> $name { fn clone(&self) -> $name {
let mut result = $name{ values: [0; $size/64] }; let mut result = $name{ values: [0; $size/64] };
for (idx,val) in self.values.iter().enumerate() { result.values.copy_from_slice(&self.values);
result.values[idx] = *val;
}
result result
} }
} }
@@ -31,33 +36,23 @@ macro_rules! generate_unsigned
impl fmt::UpperHex for $name { impl fmt::UpperHex for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut wrote_something = false; for x in self.values.iter().rev() {
f.write_char(tochar_upper(x >> 60))?;
for x in self.values.iter() { f.write_char(tochar_upper(x >> 56))?;
if !wrote_something && (*x == 0) { f.write_char(tochar_upper(x >> 52))?;
continue; f.write_char(tochar_upper(x >> 48))?;
} else { f.write_char(tochar_upper(x >> 44))?;
f.write_char(tochar_upper(x >> 60))?; f.write_char(tochar_upper(x >> 40))?;
f.write_char(tochar_upper(x >> 56))?; f.write_char(tochar_upper(x >> 36))?;
f.write_char(tochar_upper(x >> 52))?; f.write_char(tochar_upper(x >> 32))?;
f.write_char(tochar_upper(x >> 48))?; f.write_char(tochar_upper(x >> 28))?;
f.write_char(tochar_upper(x >> 44))?; f.write_char(tochar_upper(x >> 24))?;
f.write_char(tochar_upper(x >> 40))?; f.write_char(tochar_upper(x >> 20))?;
f.write_char(tochar_upper(x >> 36))?; f.write_char(tochar_upper(x >> 16))?;
f.write_char(tochar_upper(x >> 32))?; f.write_char(tochar_upper(x >> 12))?;
f.write_char(tochar_upper(x >> 28))?; f.write_char(tochar_upper(x >> 8))?;
f.write_char(tochar_upper(x >> 24))?; f.write_char(tochar_upper(x >> 4))?;
f.write_char(tochar_upper(x >> 20))?; f.write_char(tochar_upper(x >> 0))?;
f.write_char(tochar_upper(x >> 16))?;
f.write_char(tochar_upper(x >> 12))?;
f.write_char(tochar_upper(x >> 8))?;
f.write_char(tochar_upper(x >> 4))?;
f.write_char(tochar_upper(x >> 0))?;
wrote_something = true;
}
}
if !wrote_something {
f.write_char('0')?
} }
Ok(()) Ok(())
} }
@@ -65,66 +60,53 @@ macro_rules! generate_unsigned
impl fmt::LowerHex for $name { impl fmt::LowerHex for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut wrote_something = false; for x in self.values.iter().rev() {
f.write_char(tochar_lower(x >> 60))?;
for x in self.values.iter() { f.write_char(tochar_lower(x >> 56))?;
if !wrote_something && (*x == 0) { f.write_char(tochar_lower(x >> 52))?;
continue; f.write_char(tochar_lower(x >> 48))?;
} else { f.write_char(tochar_lower(x >> 44))?;
f.write_char(tochar_lower(x >> 60))?; f.write_char(tochar_lower(x >> 40))?;
f.write_char(tochar_lower(x >> 56))?; f.write_char(tochar_lower(x >> 36))?;
f.write_char(tochar_lower(x >> 52))?; f.write_char(tochar_lower(x >> 32))?;
f.write_char(tochar_lower(x >> 48))?; f.write_char(tochar_lower(x >> 28))?;
f.write_char(tochar_lower(x >> 44))?; f.write_char(tochar_lower(x >> 24))?;
f.write_char(tochar_lower(x >> 40))?; f.write_char(tochar_lower(x >> 20))?;
f.write_char(tochar_lower(x >> 36))?; f.write_char(tochar_lower(x >> 16))?;
f.write_char(tochar_lower(x >> 32))?; f.write_char(tochar_lower(x >> 12))?;
f.write_char(tochar_lower(x >> 28))?; f.write_char(tochar_lower(x >> 8))?;
f.write_char(tochar_lower(x >> 24))?; f.write_char(tochar_lower(x >> 4))?;
f.write_char(tochar_lower(x >> 20))?; f.write_char(tochar_lower(x >> 0))?;
f.write_char(tochar_lower(x >> 16))?;
f.write_char(tochar_lower(x >> 12))?;
f.write_char(tochar_lower(x >> 8))?;
f.write_char(tochar_lower(x >> 4))?;
f.write_char(tochar_lower(x >> 0))?;
wrote_something = true;
}
}
if !wrote_something {
f.write_char('0')?
} }
Ok(()) Ok(())
} }
} }
impl $name { impl CryptoNum for $name {
pub fn new() -> $name { fn zero() -> $name {
$name{ values: [0; $size/64 ] } $name{ values: [0; $size/64 ] }
} }
pub fn is_odd(&self) -> bool { fn is_odd(&self) -> bool {
(self.values[0] & 1) == 1 (self.values[0] & 1) == 1
} }
pub fn is_even(&self) -> bool { fn is_even(&self) -> bool {
(self.values[0] & 1) == 0 (self.values[0] & 1) == 0
} }
fn is_zero(&self) -> bool {
for x in self.values.iter() {
if *x != 0 {
return false;
}
}
true
}
} }
} }
} }
generate_unsigned!(U192, 192);
generate_unsigned!(U256, 256);
generate_unsigned!(U384, 384);
generate_unsigned!(U512, 512);
generate_unsigned!(U576, 576);
generate_unsigned!(U1024, 1024);
generate_unsigned!(U2048, 2048);
generate_unsigned!(U3072, 3072);
generate_unsigned!(U4096, 4096);
generate_unsigned!(U8192, 8192);
generate_unsigned!(U15360, 15360);
fn tochar_upper(x: u64) -> char { fn tochar_upper(x: u64) -> char {
match (x as u8) & (0xF as u8) { match (x as u8) & (0xF as u8) {
0x0 => '0', 0x0 => '0',
@@ -167,4 +149,52 @@ fn tochar_lower(x: u64) -> char {
0xF => 'f', 0xF => 'f',
_ => panic!("the world is broken") _ => panic!("the world is broken")
} }
} }
generate_unsigned!(U192, 192);
generate_unsigned!(U256, 256);
generate_unsigned!(U320, 320); // this is just for expansion
generate_unsigned!(U384, 384);
generate_unsigned!(U448, 448); // this is just for expansion
generate_unsigned!(U512, 512);
generate_unsigned!(U576, 576);
generate_unsigned!(U640, 640); // this is just for expansion
generate_unsigned!(U768, 768); // this is just for expansion
generate_unsigned!(U832, 832); // this is just for Barrett
generate_unsigned!(U896, 896); // this is just for Barrett
generate_unsigned!(U1024, 1024);
generate_unsigned!(U1088, 1088); // this is just for expansion
generate_unsigned!(U1152, 1152); // this is just for expansion
generate_unsigned!(U1216, 1216); // this is just for Barrett
generate_unsigned!(U1536, 1536); // this is just for expansion
generate_unsigned!(U1664, 1664); // this is just for Barrett
generate_unsigned!(U2048, 2048);
generate_unsigned!(U2112, 2112); // this is just for expansion
generate_unsigned!(U2176, 2176); // this is just for Barrett
generate_unsigned!(U2304, 2304); // this is just for expansion
generate_unsigned!(U2432, 2432); // this is just for Barrett
generate_unsigned!(U3072, 3072);
generate_unsigned!(U3136, 3136); // this is just for expansion
generate_unsigned!(U4096, 4096);
generate_unsigned!(U4160, 4160); // this is just for expansion
generate_unsigned!(U4224, 4224); // this is just for Barrett
generate_unsigned!(U6144, 6144); // this is just for expansion
generate_unsigned!(U6208, 6208); // this is just for Barrett
generate_unsigned!(U7680, 7680); // Useful for RSA key generation
generate_unsigned!(U7744, 7744); // Addition on previous
generate_unsigned!(U8192, 8192);
generate_unsigned!(U8256, 8256); // this is just for expansion
generate_unsigned!(U8320, 8320); // this is just for Barrett
generate_unsigned!(U12288, 12288); // this is just for expansion
generate_unsigned!(U12416, 12416); // this is just for Barrett
generate_unsigned!(U15360, 15360);
generate_unsigned!(U15424, 15424); // this is just for expansion
generate_unsigned!(U16384, 16384); // this is just for expansion
generate_unsigned!(U16448, 16448); // this is just for Barrett
generate_unsigned!(U16512, 16512); // this is just for Barrett
generate_unsigned!(U30720, 30720); // this is just for expansion
generate_unsigned!(U30784, 30784); // this is just for Barrett
generate_unsigned!(U32768, 32768); // this is just for expansion
generate_unsigned!(U32896, 32896); // this is just for Barrett
generate_unsigned!(U61440, 61440); // this is just for expansion
generate_unsigned!(U61568, 61568); // this is just for Barrett

View File

@@ -1,38 +1,17 @@
use cryptonum::{U192, U256, U384, U512, U576, use cryptonum::basetypes::*;
U1024, U2048, U3072, U4096, U8192,
U15360};
use std::cmp::{Ord,Ordering}; use std::cmp::{Ord,Ordering};
pub fn bignum_cmp(x: &[u64], y: &[u64]) -> Ordering {
assert_eq!(x.len(), y.len());
let xiter = x.iter().rev();
let yiter = y.iter().rev();
for (x,y) in xiter.zip(yiter) {
match x.cmp(&y) {
Ordering::Greater => return Ordering::Greater,
Ordering::Less => return Ordering::Less,
Ordering::Equal => continue
}
}
Ordering::Equal
}
pub fn bignum_ge(x: &[u64], y: &[u64]) -> bool {
match bignum_cmp(x,y) {
Ordering::Greater => true,
Ordering::Less => false,
Ordering::Equal => true
}
}
macro_rules! generate_compares macro_rules! generate_compares
{ {
($name: ident) => { ($name: ident, $size: expr) => {
impl PartialEq for $name { impl PartialEq for $name {
fn eq(&self, other: &$name) -> bool { fn eq(&self, other: &$name) -> bool {
bignum_cmp(&self.values, &other.values) == Ordering::Equal for i in 0..($size/64) {
if self.values[i] != other.values[i] {
return false;
}
}
true
} }
} }
@@ -40,26 +19,74 @@ macro_rules! generate_compares
impl Ord for $name { impl Ord for $name {
fn cmp(&self, other: &$name) -> Ordering { fn cmp(&self, other: &$name) -> Ordering {
bignum_cmp(&self.values, &other.values) let mut i = (($size / 64) - 1) as isize;
while i >= 0 {
let iu = i as usize;
match self.values[iu].cmp(&other.values[iu]) {
Ordering::Greater => return Ordering::Greater,
Ordering::Less => return Ordering::Less,
Ordering::Equal => i -= 1
}
}
Ordering::Equal
} }
} }
impl PartialOrd for $name { impl PartialOrd for $name {
fn partial_cmp(&self, other: &$name) -> Option<Ordering> { fn partial_cmp(&self, other: &$name) -> Option<Ordering> {
Some(bignum_cmp(&self.values, &other.values)) Some(self.cmp(other))
} }
} }
} }
} }
generate_compares!(U192); generate_compares!(U192, 192);
generate_compares!(U256); generate_compares!(U256, 256);
generate_compares!(U384); generate_compares!(U320, 320); // this is just for expansion
generate_compares!(U512); generate_compares!(U384, 384);
generate_compares!(U576); generate_compares!(U448, 448); // this is just for expansion
generate_compares!(U1024); generate_compares!(U512, 512);
generate_compares!(U2048); generate_compares!(U576, 576);
generate_compares!(U3072); generate_compares!(U640, 640); // this is just for expansion
generate_compares!(U4096); generate_compares!(U768, 768); // this is just for expansion
generate_compares!(U8192); generate_compares!(U832, 832); // this is just for Barrett
generate_compares!(U15360); generate_compares!(U896, 896); // this is just for Barrett
generate_compares!(U1024, 1024);
generate_compares!(U1088, 1088); // this is just for expansion
generate_compares!(U1152, 1152); // this is just for expansion
generate_compares!(U1216, 1216); // this is just for Barrett
generate_compares!(U1536, 1536); // this is just for expansion
generate_compares!(U1664, 1664); // this is just for Barrett
generate_compares!(U2048, 2048);
generate_compares!(U2112, 2112); // this is just for expansion
generate_compares!(U2176, 2176); // this is just for Barrett
generate_compares!(U2304, 2304); // this is just for expansion
generate_compares!(U2432, 2432); // this is just for Barrett
generate_compares!(U3072, 3072);
generate_compares!(U3136, 3136); // this is just for expansion
generate_compares!(U4096, 4096);
generate_compares!(U4160, 4160); // this is just for expansion
generate_compares!(U4224, 4224); // this is just for Barrett
generate_compares!(U6144, 6144); // this is just for expansion
generate_compares!(U6208, 6208); // this is just for Barrett
generate_compares!(U7680, 7680);
generate_compares!(U7744, 7744);
generate_compares!(U8192, 8192);
generate_compares!(U8256, 8256); // this is just for expansion
generate_compares!(U8320, 8320); // this is just for Barrett
generate_compares!(U12288, 12288); // this is just for expansion
generate_compares!(U12416, 12416); // this is just for Barrett
generate_compares!(U15360, 15360);
generate_compares!(U15424, 15424); // this is just for expansion
generate_compares!(U16384, 16384); // this is just for expansion
generate_compares!(U16448, 16448); // this is just for Barrett
generate_compares!(U16512, 16512); // this is just for Barrett
generate_compares!(U30720, 30720); // this is just for expansion
generate_compares!(U30784, 30784); // this is just for Barrett
generate_compares!(U32768, 32768); // this is just for expansion
generate_compares!(U32896, 32896); // this is just for Barrett
generate_compares!(U61440, 61440); // this is just for expansion
generate_compares!(U61568, 61568); // this is just for Barrett

View File

@@ -1,6 +1,7 @@
use cryptonum::{U192, U256, U384, U512, U576, use cryptonum::basetypes::*;
U1024, U2048, U3072, U4096, U8192, use cryptonum::encoding::Encoder;
U15360}; use num::bigint::BigUint;
use num::{FromPrimitive,ToPrimitive};
macro_rules! generate_basetype_froms macro_rules! generate_basetype_froms
{ {
@@ -13,13 +14,33 @@ macro_rules! generate_basetype_froms
impl From<u128> for $name { impl From<u128> for $name {
fn from(x: u128) -> $name { fn from(x: u128) -> $name {
let mut base = $name::new(); let mut base = $name::zero();
base.values[0] = x as u64; base.values[0] = x as u64;
base.values[1] = (x >> 64) as u64; base.values[1] = (x >> 64) as u64;
base base
} }
} }
impl From<BigUint> for $name {
fn from(mut x: BigUint) -> $name {
let mut res = $name::zero();
let mask = BigUint::from_u64(0xFFFFFFFFFFFFFFFF).unwrap();
for digit in res.values.iter_mut() {
*digit = (&x & &mask).to_u64().unwrap();
x >>= 64;
}
res
}
}
impl From<$name> for BigUint {
fn from(x: $name) -> BigUint {
let bytes: Vec<u8> = x.to_bytes();
BigUint::from_bytes_be(&bytes)
}
}
} }
} }
@@ -28,20 +49,36 @@ macro_rules! generate_basetype_from
($name: ident, $basetype: ident) => { ($name: ident, $basetype: ident) => {
impl From<$basetype> for $name { impl From<$basetype> for $name {
fn from(x: $basetype) -> $name { fn from(x: $basetype) -> $name {
let mut base = $name::new(); let mut base = $name::zero();
base.values[0] = x as u64; base.values[0] = x as u64;
base base
} }
} }
impl From<$name> for $basetype {
fn from(x: $name) -> $basetype {
x.values[0] as $basetype
}
}
} }
} }
macro_rules! convert_from_smaller macro_rules! convert_from_smaller
{ {
($name: ident, $smalltype: ident) => { ($name: ident, $smalltype: ident) => {
impl<'a> From<&'a $smalltype> for $name {
fn from(x: &$smalltype) -> $name {
let mut base = $name::zero();
for (idx, val) in x.values.iter().enumerate() {
base.values[idx] = *val;
}
base
}
}
impl From<$smalltype> for $name { impl From<$smalltype> for $name {
fn from(x: $smalltype) -> $name { fn from(x: $smalltype) -> $name {
let mut base = $name::new(); let mut base = $name::zero();
for (idx, val) in x.values.iter().enumerate() { for (idx, val) in x.values.iter().enumerate() {
base.values[idx] = *val; base.values[idx] = *val;
} }
@@ -54,9 +91,9 @@ macro_rules! convert_from_smaller
macro_rules! convert_from_larger macro_rules! convert_from_larger
{ {
($name: ident, $bigtype: ident) => { ($name: ident, $bigtype: ident) => {
impl From<$bigtype> for $name { impl<'a> From<&'a $bigtype> for $name {
fn from(x: $bigtype) -> $name { fn from(x: &$bigtype) -> $name {
let mut base = $name::new(); let mut base = $name::zero();
for i in 0..base.values.len() { for i in 0..base.values.len() {
base.values[i] = x.values[i]; base.values[i] = x.values[i];
} }
@@ -68,85 +105,39 @@ macro_rules! convert_from_larger
macro_rules! convert_bignums macro_rules! convert_bignums
{ {
($bigger: ident, $smaller: ident) => { ($smaller: ident, $bigger: ident) => {
convert_from_smaller!($bigger, $smaller); convert_from_smaller!($bigger, $smaller);
convert_from_larger!($smaller, $bigger); convert_from_larger!($smaller, $bigger);
} }
} }
generate_basetype_froms!(U192); macro_rules! expand_bignums
generate_basetype_froms!(U256); {
generate_basetype_froms!(U384); ($smaller: ident, $bigger: ident $(, $rest: ident)* ) => {
generate_basetype_froms!(U512); convert_bignums!($smaller, $bigger);
generate_basetype_froms!(U576); expand_bignums!($smaller, $($rest),*);
generate_basetype_froms!(U1024); };
generate_basetype_froms!(U2048); ($smaller: ident, $(,)*) => {};
generate_basetype_froms!(U3072); () => {}
generate_basetype_froms!(U4096); }
generate_basetype_froms!(U8192);
generate_basetype_froms!(U15360);
convert_bignums!(U256, U192); macro_rules! exhaustive_expansion
convert_bignums!(U384, U192); {
convert_bignums!(U512, U192); () => {};
convert_bignums!(U576, U192); ($last: ident) => {
convert_bignums!(U1024, U192); generate_basetype_froms!($last);
convert_bignums!(U2048, U192); };
convert_bignums!(U3072, U192); ($smallest: ident $(, $other: ident)*) => {
convert_bignums!(U4096, U192); generate_basetype_froms!($smallest);
convert_bignums!(U8192, U192); expand_bignums!($smallest, $($other),*);
convert_bignums!(U15360, U192); exhaustive_expansion!($($other),*);
};
}
convert_bignums!(U384, U256); exhaustive_expansion!(U192, U256, U320, U384, U448, U512, U576,
convert_bignums!(U512, U256); U640, U768, U832, U896, U1024, U1088, U1152,
convert_bignums!(U576, U256); U1216, U1536, U1664, U2048, U2112, U2176, U2304,
convert_bignums!(U1024, U256); U2432, U3072, U3136, U4096, U4224, U4160, U6144,
convert_bignums!(U2048, U256); U6208, U7680, U7744, U8192, U8256, U8320, U12288,
convert_bignums!(U3072, U256); U12416, U15360, U15424, U16384, U16448, U16512, U30720,
convert_bignums!(U4096, U256); U30784, U32768, U32896, U61440, U61568);
convert_bignums!(U8192, U256);
convert_bignums!(U15360, U256);
convert_bignums!(U512, U384);
convert_bignums!(U576, U384);
convert_bignums!(U1024, U384);
convert_bignums!(U2048, U384);
convert_bignums!(U3072, U384);
convert_bignums!(U4096, U384);
convert_bignums!(U8192, U384);
convert_bignums!(U15360, U384);
convert_bignums!(U576, U512);
convert_bignums!(U1024, U512);
convert_bignums!(U2048, U512);
convert_bignums!(U3072, U512);
convert_bignums!(U4096, U512);
convert_bignums!(U8192, U512);
convert_bignums!(U15360, U512);
convert_bignums!(U1024, U576);
convert_bignums!(U2048, U576);
convert_bignums!(U3072, U576);
convert_bignums!(U4096, U576);
convert_bignums!(U8192, U576);
convert_bignums!(U15360, U576);
convert_bignums!(U2048, U1024);
convert_bignums!(U3072, U1024);
convert_bignums!(U4096, U1024);
convert_bignums!(U8192, U1024);
convert_bignums!(U15360, U1024);
convert_bignums!(U3072, U2048);
convert_bignums!(U4096, U2048);
convert_bignums!(U8192, U2048);
convert_bignums!(U15360, U2048);
convert_bignums!(U4096, U3072);
convert_bignums!(U8192, U3072);
convert_bignums!(U15360, U3072);
convert_bignums!(U8192, U4096);
convert_bignums!(U15360, U4096);
convert_bignums!(U15360, U8192);

View File

@@ -1,169 +1,172 @@
use cryptonum::comparison::{bignum_cmp,bignum_ge}; use cryptonum::basetypes::*;
use cryptonum::multiplication::raw_multiplication;
use cryptonum::subtraction::raw_subtraction;
use std::cmp::Ordering;
// This is based on algorithm 14.20 from the Handbook of Applied Cryptography, pub trait ModReduce<T=Self> {
// slightly modified. fn reduce(&self, value: &T) -> T;
pub fn divmod(inx: &[u64], iny: &[u64], q: &mut [u64], r: &mut [u64])
{
// let's make sure we get the basic sizes right
assert_eq!(inx.len(), iny.len());
assert!(q.len() >= (inx.len() - 1));
assert!(r.len() >= iny.len());
// compute the basic number sizes
let mut n = match get_number_size(inx) {
None => 0,
Some(v) => v
};
let mut t = match get_number_size(iny) {
None => panic!("Division by zero!"),
Some(v) => v
};
// if the divisor is larger, then the answer is pretty simple
if t > n {
for x in q.iter_mut() {
*x = 0;
}
for (idx, val) in inx.iter().enumerate() {
r[idx] = *val;
}
return
}
// OK, if we're here, then we've cleared the conditions that n >= t,
// and that y[t] != 0. However, we have not cleared the bar that
// n >= t >= 1.
let mut x = Vec::with_capacity(inx.len());
let mut y = Vec::with_capacity(iny.len());
let added_zero = t == 0;
if added_zero {
x.push(0);
y.push(0);
n += 1;
t += 1;
}
for v in inx.iter() { x.push(*v); }
for v in iny.iter() { y.push(*v); }
// OK, now we've cleared the n >= t >= 1 hurdle. Last thing: if we want
// this to perform reasonably, it's useful if the value is shifted y[t]
// such that the high bit is set.
let lambda_shift = y[t].leading_zeros() as usize;
if lambda_shift != 0 {
shiftl(&mut x, lambda_shift);
shiftl(&mut y, lambda_shift);
n = get_number_size(&x).unwrap();
}
// At this point, we can actually start the algorithm.
// 1. For j from 0 to (n-t) do: q[j] = 0;
// [NB: I take some liberties with this concept]
for v in q.iter_mut() { *v = 0; }
// 2. While (x >= y * b^(n-t)) do the following:
let mut ybnt = y.clone();
// we can shift left by just adding the right amount of digits, adding
// some on the end of x to keep the vectors the same size.
for _ in 0..n-t { ybnt.insert(0,0); x.push(0); }
while matching_bignum_ge(&x, &ybnt) {
// q[n-t] = q[n-t] + 1
q[n-t] += 1;
// x = x - y * b^(n-t)
raw_subtraction(&mut x, &ybnt);
}
// 3. For i from n down to t+1 do the following:
let mut i = n;
while i >= (t + 1) {
// 3.1. If x[i] = y[t]
if x[i] == y[t] {
// ... then set q[i-t-1] = b - 1
q[i-t-1] = 0xFFFFFFFFFFFFFFFF;
} else {
// ... otherwise set q[i-t-1] = floor((x[i] * b + x[i-1]) / y[t])
let xib = (x[i] as u128) << 64;
let xi1 = x[i-1] as u128;
let yt = y[t] as u128;
let qit1 = (xib + xi1) / yt;
q[i-t-1] = qit1 as u64;
}
// 3.2. While q[i-t-1] * (y[t]*b + y[t-1]) > (x[i] * b^2 + x[i-1] * b + x[i-2])
loop {
let qit1: [u64; 2] = [q[i-t-1], 0];
let ybits: [u64; 2] = [y[t-1], y[t]];
let mut qiybs: [u64; 4] = [0, 0, 0, 0];
raw_multiplication(&qit1, &ybits, &mut qiybs);
let xbits: [u64; 4] = [x[i-2], x[i-1], x[i], 0];
if bignum_ge(&xbits, &qiybs) {
break;
}
// ... do q[i-t-1] = q[i-t-1] - 1
q[i-t-1] -= 1;
}
// 3.3. x = x - q[i-t-1] * y * b^(i-t-1)
// this is a bit of a pain in the ass, to make sure all the sizes line
// up. we start by computing an appropriately-shifted version of y
let mut widery = y.clone();
for _ in 0..(i-t-1) { widery.insert(0,0); }
// OK, then we need to multiply in the q[i-t-1] digit
let mut qit1 = Vec::with_capacity(widery.len());
qit1.resize(widery.len(), 0);
qit1[0] = q[i-t-1];
// Multiply these together, and we have what we want to subtract
let mut subamt = Vec::with_capacity(2 * widery.len());
subamt.resize(2 * widery.len(), 0);
raw_multiplication(&widery, &qit1, &mut subamt);
// then we make a wider version of x to match this one
let mut widerx = x.clone();
while widerx.len() < subamt.len() { widerx.push(0); }
// and compare them, which is going to inline the following steps:
// 3.4. If x < 0
// then set x = x + y * b^(i-t-1) and
// q[i-t-1] = q[i-t-1] - 1
if bignum_cmp(&subamt, &widerx) == Ordering::Greater {
assert!(subamt.len() >= widery.len());
while widery.len() < subamt.len() { widery.push(0); }
raw_subtraction(&mut subamt, &widery);
q[i-t-1] -= 1;
} else {
assert!(subamt.len() >= widerx.len());
}
raw_subtraction(&mut widerx, &subamt);
for i in 0..widerx.len() {
if i < x.len() {
x[i] = widerx[i];
} else {
assert_eq!(widerx[i], 0);
}
}
i -= 1;
}
// 4. r = x ... sort of. Remember, we potentially did a bit of shifting
// around at the very beginning, which we now need to account for. On the
// bright side, we only need to account for this in the remainder.
let offset = if added_zero { 1 } else { 0 };
for (idx, rval) in r.iter_mut().enumerate() {
let baseval = x[idx + offset] >> lambda_shift;
if idx + offset + 1 < x.len() {
let mask = !(0xFFFFFFFFFFFFFFFF << lambda_shift);
let highbits = x[idx + offset + 1] & mask;
*rval = baseval | highbits;
} else {
*rval = baseval;
}
}
// 5. Return (q,r)
} }
fn shiftl(x: &mut Vec<u64>, amt: usize) macro_rules! safesubidx
{
($array: expr, $index: expr, $amt: expr) => ({
let idx = $index;
let amt = $amt;
if idx < amt {
0
} else {
$array[idx-amt]
}
})
}
macro_rules! generate_dividers
{
($name: ident, $bigger: ident) => {
impl $name {
// This is based on algorithm 14.20 from the Handbook of Applied
// Cryptography, slightly modified.
pub fn divmod(&self, rhs: &$name) -> ($name, $name) {
// if the divisor is larger, then the answer is pretty simple
if rhs > self {
return ($name::zero(), self.clone());
}
// compute the basic number sizes
let mut n = match get_number_size(&self.values) {
None => 0,
Some(v) => v
};
let t = match get_number_size(&rhs.values) {
None => panic!("Division by zero!"),
Some(v) => v
};
assert!(t <= n);
// now generate mutable versions we can mess with
let mut x = $bigger::from(self);
let mut y = $bigger::from(rhs);
// If we want this to perform reasonable, it's useful if the
// value of y[t] is shifted so that the high bit is set.
let lambda_shift = y.values[t].leading_zeros() as usize;
if lambda_shift != 0 {
shiftl(&mut x.values, lambda_shift);
shiftl(&mut y.values, lambda_shift);
n = get_number_size(&x.values).unwrap();
}
// now go!
// 1. For j from 0 to (n-t) do: q[j] = 0;
// [NB: I take some liberties with this concept]
let mut q = $bigger::zero();
// 2. While (x >= y * b^(n-t)) do the following:
let mut ybnt = $bigger::zero();
for i in 0..self.values.len() {
ybnt.values[(n-t)+i] = y.values[i];
if (n-t)+i >= ybnt.values.len() {
break;
}
}
while x > ybnt {
q.values[n - t] += 1;
x -= &ybnt;
}
// 3. For i from n down to t+1 do the following:
let mut i = n;
while i >= (t + 1) {
// 3.1. If x[i] = y[t]
if x.values[i] == y.values[t] {
// ... then set q[i-t-1] = b - 1
q.values[i-t-1] = 0xFFFFFFFFFFFFFFFF;
} else {
// ... otherwise set q[i-t-1] =
// floor((x[i] * b + x[i-1]) / y[t])
let xib = (x.values[i] as u128) << 64;
let xi1 = safesubidx!(x.values,i,1) as u128;
let yt = y.values[t] as u128;
let qit1 = (xib + xi1) / yt;
q.values[i-t-1] = qit1 as u64;
}
// 3.2. While q[i-t-1] * (y[t]*b + y[t-1]) >
// (x[i] * b^2 + x[i-1] * b + x[i-2])
loop {
// three is very close to 2.
let qit1 = U192::from(safesubidx!(q.values,i-t,1));
let mut ybits = U192::zero();
ybits.values[0] = safesubidx!(y.values, t, 1);
ybits.values[1] = y.values[t];
let qiybs = &qit1 * &ybits;
let mut xbits = U384::zero();
xbits.values[0] = safesubidx!(x.values,i,2);
xbits.values[1] = safesubidx!(x.values,i,1);
xbits.values[2] = x.values[i];
if !(&qiybs > &xbits) {
break;
}
// ... do q[i-t-1] = q[i-t-1] - 1
q.values[i-t-1] -= 1;
}
// 3.3. x = x - q[i-t-1] * y * b^(i-t-1)
// 3.4. If x < 0
// then set x = x + y * b^(i-t-1) and
// q[i-t-1] = q[i-t-1] - 1
let mut qbit1 = $name::zero();
qbit1.values[i-t-1] = q.values[i-t-1];
let smallery = $name::from(&y);
let mut subpart = &smallery * &qbit1;
if subpart > x {
let mut addback = $bigger::zero();
for (idx, val) in y.values.iter().enumerate() {
let dest = idx + (i - t - 1);
if dest < addback.values.len() {
addback.values[dest] = *val;
}
}
q.values[i-t-1] -= 1;
subpart -= &addback;
}
assert!(subpart <= x);
x -= &subpart;
i -= 1;
}
// 4. r = x ... sort of. Remember, we potentially did a bit of shifting
// around at the very beginning, which we now need to account for. On the
// bright side, we only need to account for this in the remainder.
let mut r = $name::from(&x);
shiftr(&mut r.values, lambda_shift);
// 5. Return (q,r)
let resq = $name::from(&q);
(resq, r)
}
}
impl ModReduce for $name {
fn reduce(&self, value: &$name) -> $name {
let (_, res) = self.divmod(value);
res
}
}
}
}
fn shiftl(x: &mut [u64], amt: usize)
{ {
let mut carry = 0; let mut carry = 0;
for v in x.iter_mut() { for v in x.iter_mut() {
let new_carry = *v >> (64 - amt); let new_carry = *v >> (64 - amt);
*v = (*v << amt) | carry; *v = (*v << amt) | carry;
carry = new_carry; carry = new_carry;
} }
if carry != 0 { assert!(carry == 0);
x.push(carry); }
fn shiftr(x: &mut [u64], amt: usize)
{
let mut carry = 0;
for val in x.iter_mut().rev() {
let mask = !(0xFFFFFFFFFFFFFFFF << amt);
let newcarry = *val & mask;
*val = (*val >> amt) | carry;
carry = newcarry;
} }
} }
@@ -177,24 +180,33 @@ fn get_number_size(v: &[u64]) -> Option<usize>
None None
} }
fn matching_bignum_ge(x: &[u64], y: &[u64]) -> bool generate_dividers!(U192, U384);
{ generate_dividers!(U256, U512);
if x.len() == y.len() { generate_dividers!(U384, U768);
return bignum_ge(&x, &y); generate_dividers!(U448, U896);
} generate_dividers!(U512, U1024);
generate_dividers!(U576, U1152);
if x.len() > y.len() { generate_dividers!(U768, U1536);
let mut yprime = Vec::with_capacity(x.len()); generate_dividers!(U832, U1664);
yprime.extend_from_slice(&y); generate_dividers!(U1024, U2048);
while yprime.len() < x.len() { yprime.push(0); } generate_dividers!(U1088, U2176);
bignum_ge(&x, &yprime) generate_dividers!(U1152, U2304);
} else { generate_dividers!(U1216, U2432);
let mut xprime = Vec::with_capacity(y.len()); generate_dividers!(U2048, U4096);
xprime.extend_from_slice(&x); generate_dividers!(U2112, U4224);
while xprime.len() < y.len() { xprime.push(0); } generate_dividers!(U3072, U6144);
bignum_ge(&xprime, &y) generate_dividers!(U4096, U8192);
} generate_dividers!(U4160, U8320);
} generate_dividers!(U6144, U12288);
generate_dividers!(U6208, U12416);
generate_dividers!(U7680, U15360);
generate_dividers!(U8192, U16384);
generate_dividers!(U8256, U16512);
generate_dividers!(U15360, U30720);
generate_dividers!(U16384, U32768);
generate_dividers!(U16448, U32896);
generate_dividers!(U30720, U61440);
generate_dividers!(U30784, U61568);
#[cfg(test)] #[cfg(test)]
mod normal { mod normal {
@@ -202,7 +214,6 @@ mod normal {
use cryptonum::Decoder; use cryptonum::Decoder;
use cryptonum::{U192,U256,U384,U512,U576,U1024, use cryptonum::{U192,U256,U384,U512,U576,U1024,
U2048,U3072,U4096,U8192,U15360}; U2048,U3072,U4096,U8192,U15360};
use super::*;
macro_rules! generate_tests { macro_rules! generate_tests {
($name: ident) => ( ($name: ident) => (
@@ -224,11 +235,7 @@ mod normal {
let b = $name::from_bytes(bbytes); let b = $name::from_bytes(bbytes);
let q = $name::from_bytes(qbytes); let q = $name::from_bytes(qbytes);
let r = $name::from_bytes(rbytes); let r = $name::from_bytes(rbytes);
let (myq, myr) = a.divmod(&b);
let mut myq = $name::new();
let mut myr = $name::new();
divmod(&a.values, &b.values, &mut myq.values, &mut myr.values);
assert_eq!(q, myq); assert_eq!(q, myq);
assert_eq!(r, myr); assert_eq!(r, myr);
}); });
@@ -247,4 +254,4 @@ mod normal {
generate_tests!(U4096); generate_tests!(U4096);
generate_tests!(U8192); generate_tests!(U8192);
generate_tests!(U15360); generate_tests!(U15360);
} }

View File

@@ -1,11 +1,13 @@
use cryptonum::{U192, U256, U384, U512, U576, use cryptonum::basetypes::*;
U1024, U2048, U3072, U4096, U8192,
U15360};
pub trait Decoder { pub trait Decoder {
fn from_bytes(x: &[u8]) -> Self; fn from_bytes(x: &[u8]) -> Self;
} }
pub trait Encoder {
fn to_bytes(&self) -> Vec<u8>;
}
pub(crate) fn raw_decoder(input: &[u8], output: &mut [u64]) pub(crate) fn raw_decoder(input: &[u8], output: &mut [u64])
{ {
let mut item = 0; let mut item = 0;
@@ -31,7 +33,7 @@ macro_rules! generate_decoder {
($name: ident) => { ($name: ident) => {
impl Decoder for $name { impl Decoder for $name {
fn from_bytes(x: &[u8]) -> $name { fn from_bytes(x: &[u8]) -> $name {
let mut res = $name::new(); let mut res = $name::zero();
raw_decoder(x, &mut res.values); raw_decoder(x, &mut res.values);
res res
} }
@@ -39,14 +41,184 @@ macro_rules! generate_decoder {
} }
} }
generate_decoder!(U192); macro_rules! generate_encoder {
generate_decoder!(U256); ($name: ident) => {
generate_decoder!(U384); impl Encoder for $name {
generate_decoder!(U512); fn to_bytes(&self) -> Vec<u8> {
generate_decoder!(U576); let mut res = Vec::with_capacity(self.values.len() * 8);
generate_decoder!(U1024); for v in self.values.iter().rev() {
generate_decoder!(U2048); let val = *v;
generate_decoder!(U3072); res.push( (val >> 56) as u8);
generate_decoder!(U4096); res.push( (val >> 48) as u8);
generate_decoder!(U8192); res.push( (val >> 40) as u8);
generate_decoder!(U15360); res.push( (val >> 32) as u8);
res.push( (val >> 24) as u8);
res.push( (val >> 16) as u8);
res.push( (val >> 8) as u8);
res.push( (val >> 0) as u8);
}
res
}
}
}
}
macro_rules! generate_codec
{
($name: ident) => {
generate_decoder!($name);
generate_encoder!($name);
}
}
generate_codec!(U192);
generate_codec!(U256);
generate_codec!(U320); // this is just for expansion
generate_codec!(U384);
generate_codec!(U448); // this is just for expansion
generate_codec!(U512);
generate_codec!(U576);
generate_codec!(U640); // this is just for expansion
generate_codec!(U768); // this is just for expansion
generate_codec!(U832); // this is just for expansion
generate_codec!(U896); // this is just for expansion
generate_codec!(U1024);
generate_codec!(U1088); // this is just for expansion
generate_codec!(U1152); // this is just for expansion
generate_codec!(U1216); // this is just for expansion
generate_codec!(U1536); // this is just for expansion
generate_codec!(U1664); // this is just for expansion
generate_codec!(U2048);
generate_codec!(U2112); // this is just for expansion
generate_codec!(U2176); // this is just for expansion
generate_codec!(U2304); // this is just for expansion
generate_codec!(U2432); // this is just for expansion
generate_codec!(U3072);
generate_codec!(U3136); // this is just for expansion
generate_codec!(U4224); // this is just for expansion
generate_codec!(U4096);
generate_codec!(U4160); // this is just for expansion
generate_codec!(U6144); // this is just for expansion
generate_codec!(U6208); // this is just for expansion
generate_codec!(U7680);
generate_codec!(U7744);
generate_codec!(U8192);
generate_codec!(U8256); // this is just for expansion
generate_codec!(U8320); // this is just for expansion
generate_codec!(U12288); // this is just for expansion
generate_codec!(U12416); // this is just for expansion
generate_codec!(U15360);
generate_codec!(U15424); // this is just for expansion
generate_codec!(U16384); // this is just for expansion
generate_codec!(U16448); // this is just for expansion
generate_codec!(U16512); // this is just for expansion
generate_codec!(U30720); // this is just for expansion
generate_codec!(U30784); // this is just for expansion
generate_codec!(U32768); // this is just for expansion
generate_codec!(U32896); // this is just for expansion
generate_codec!(U61440); // this is just for expansion
generate_codec!(U61568); // this is just for expansion
macro_rules! generate_tests
{
( $( ($name: ident, $num: ident, $size: expr) ),* ) => {
$(
#[cfg(test)]
mod $name {
use cryptonum::basetypes::{CryptoNum,$num};
use cryptonum::encoding::{Decoder,Encoder};
use quickcheck::{Arbitrary,Gen};
#[derive(Clone,Debug)]
struct MyBuffer {
x: Vec<u8>
}
impl Arbitrary for $num {
fn arbitrary<G: Gen>(g: &mut G) -> $num {
let mut res = $num::zero();
for v in res.values.iter_mut() {
*v = g.gen::<u64>();
}
res
}
}
impl Arbitrary for MyBuffer {
fn arbitrary<G: Gen>(g: &mut G) -> MyBuffer {
let len = $size / 8;
let mut res = Vec::with_capacity(len);
for _ in 0..len {
res.push(g.gen::<u8>());
}
MyBuffer{ x: res }
}
}
quickcheck! {
fn i2o2i(x: $num) -> bool {
let bstr = x.to_bytes();
let x2 = $num::from_bytes(&bstr);
x == x2
}
fn o2i2o(x: MyBuffer) -> bool {
let val = $num::from_bytes(&x.x);
let x2 = val.to_bytes();
x.x == x2
}
}
}
)*
}
}
generate_tests!((u192, U192, 192),
(u256, U256, 256),
(u320, U320, 320), // this is just for expansion
(u384, U384, 384),
(u448, U448, 448), // this is just for expansion
(u512, U512, 512),
(u576, U576, 576),
(u640, U640, 640), // this is just for expansion
(u768, U768, 768), // this is just for expansion
(u832, U832, 832), // this is just for Barrett
(u896, U896, 896), // this is just for Barrett
(u1024, U1024, 1024),
(u1088, U1088, 1088), // this is just for expansion
(u1152, U1152, 1152), // this is just for expansion
(u1216, U1216, 1216), // this is just for Barrett
(u1536, U1536, 1536), // this is just for expansion
(u1664, U1664, 1664), // this is just for Barrett
(u2048, U2048, 2048),
(u2112, U2112, 2112), // this is just for expansion
(u2176, U2176, 2176), // this is just for Barrett
(u2304, U2304, 2304), // this is just for expansion
(u2432, U2432, 2432), // this is just for Barrett
(u3072, U3072, 3072),
(u3136, U3136, 3136), // this is just for expansion
(u4096, U4096, 4096),
(u4160, U4160, 4160), // this is just for expansion
(u4224, U4224, 4224), // this is just for Barrett
(u6144, U6144, 6144), // this is just for expansion
(u6208, U6208, 6208), // this is just for Barrett
(u7680, U7680, 7680),
(u7744, U7744, 7744),
(u8192, U8192, 8192),
(u8256, U8256, 8256), // this is just for expansion
(u8320, U8320, 8320), // this is just for Barrett
(u12288, U12288, 12288), // this is just for expansion
(u12416, U12416, 12416), // this is just for Barrett
(u15360, U15360, 15360),
(u15424, U15424, 15424), // this is just for expansion
(u16384, U16384, 16384), // this is just for expansion
(u16448, U16448, 16448), // this is just for Barrett
(u16512, U16512, 16512), // this is just for Barrett
(u30720, U30720, 30720), // this is just for expansion
(u30784, U30784, 30784), // this is just for Barrett
(u32768, U32768, 32768), // this is just for expansion
(u32896, U32896, 32896), // this is just for Barrett
(u61440, U61440, 61440), // this is just for expansion
(u61568, U61568, 61568)); // this is just for Barrett

View File

@@ -1,133 +0,0 @@
use cryptonum::{U192, U256, U384, U512, U576,
U1024, U2048, U3072, U4096, U8192,
U15360};
use cryptonum::division::divmod;
use cryptonum::multiplication::ModMul;
use cryptonum::squaring::ModSquare;
pub trait ModExp<T=Self> {
fn modexp(&mut self, e: &Self, m: &T);
}
macro_rules! generate_exponentiators
{
($name: ident, $size: expr) => {
impl ModExp for $name {
fn modexp(&mut self, e: &$name, m: &$name) {
// S <- g
let mut s = self.clone();
let mut _dead = [0; $size/32];
divmod(&self.values, &m.values, &mut _dead, &mut s.values);
// A <- 1
for val in self.values.iter_mut() { *val = 0; }
self.values[0] = 1;
// We do a quick skim through and find the highest index that
// actually has a value in it.
let mut highest_digit = 0;
for (idx, val) in e.values.iter().enumerate() {
if *val != 0 {
highest_digit = idx;
}
}
// While e != 0 do the following:
// If e is odd then A <- A * S
// e <- floor(e / 2)
// If e != 0 then S <- S * S
for i in 0..highest_digit+1 {
let mut mask = 1;
while mask != 0 {
if e.values[i] & mask != 0 {
self.modmul(&s, m);
}
mask <<= 1;
s.modsq(m);
}
}
// Return A
}
}
}
}
generate_exponentiators!(U192,192);
generate_exponentiators!(U256,256);
generate_exponentiators!(U384,384);
generate_exponentiators!(U512,512);
generate_exponentiators!(U576,576);
generate_exponentiators!(U1024,1024);
generate_exponentiators!(U2048,2048);
generate_exponentiators!(U3072,3072);
generate_exponentiators!(U4096,4096);
generate_exponentiators!(U8192,8192);
generate_exponentiators!(U15360,15360);
macro_rules! generate_tests {
( $( $name:ident ),* ) => {
#[cfg(test)]
mod slow_modular {
use cryptonum::encoding::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
#[ignore]
fn $name() {
let fname = format!("tests/math/modexp{}.test",
stringify!($name));
run_test(fname.to_string(), 4, |case| {
let (neg0, bbytes) = case.get("b").unwrap();
let (neg1, ebytes) = case.get("e").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, rbytes) = case.get("r").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3);
let mut b = $name::from_bytes(bbytes);
let e = $name::from_bytes(ebytes);
let m = $name::from_bytes(mbytes);
let r = $name::from_bytes(rbytes);
b.modexp(&e, &m);
assert_eq!(b, r);
});
}
)*
}
#[cfg(test)]
mod varrett_modular {
use cryptonum::encoding::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
#[ignore]
fn $name() {
let fname = format!("tests/math/modexp{}.test",
stringify!($name));
run_test(fname.to_string(), 4, |case| {
let (neg0, bbytes) = case.get("b").unwrap();
let (neg1, ebytes) = case.get("e").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, rbytes) = case.get("r").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3);
let mut b = $name::from_bytes(bbytes);
let e = $name::from_bytes(ebytes);
let m = $name::from_bytes(mbytes);
let r = $name::from_bytes(rbytes);
b.modexp(&e, &m);
assert_eq!(b, r);
});
}
)*
}
}
}
generate_tests!(U192, U256, U384, U512, U576, U1024, U2048,
U3072, U4096, U8192, U15360);

View File

@@ -8,14 +8,19 @@ mod addition;
mod barrett; mod barrett;
mod basetypes; mod basetypes;
mod comparison; mod comparison;
#[macro_use]
mod conversions; mod conversions;
mod division; mod division;
mod encoding; mod encoding;
mod exponentiation; mod modmath;
mod multiplication; mod multiplication;
mod shifts;
mod signed;
mod squaring; mod squaring;
mod subtraction; mod subtraction;
pub use self::barrett::*;
pub use self::basetypes::*; pub use self::basetypes::*;
pub use self::encoding::Decoder; pub use self::encoding::{Decoder,Encoder};
pub use self::signed::Signed;
#[allow(unused)]
pub(crate) use self::modmath::{ModExp,ModInv};

543
src/cryptonum/modmath.rs Normal file
View File

@@ -0,0 +1,543 @@
use cryptonum::addition::UnsafeAdd;
use cryptonum::basetypes::*;
use cryptonum::barrett::*;
use cryptonum::signed::*;
pub trait ModAdd<T2> {
fn modadd(&mut self, y: &Self, m: &T2);
}
pub trait ModMul<T> {
fn modmul(&mut self, x: &Self, m: &T);
}
pub trait ModSquare<T> {
fn modsq(&mut self, m: &T);
}
pub trait ModExp<T> {
fn modexp(&self, e: &Self, m: &T) -> Self;
}
pub trait ModInv
where Self: Sized
{
fn modinv(&self, phi: Self) -> Option<Self>;
}
macro_rules! generate_modmath_funs
{
($name: ident, $big: ident, $dbl: ident, $bar: ident, $size: expr) => {
impl ModAdd<$big> for $name {
fn modadd(&mut self, y: &$name, m: &$big) {
let mut base = &self.clone() + y;
if &base > m {
base -= m;
if &base > m {
base -= m;
}
}
self.values.copy_from_slice(&base.values[0..$size/64]);
}
}
impl ModMul<$name> for $name {
fn modmul(&mut self, x: &$name, m: &$name) {
let mulres = (self as &$name) * &x;
let bigm = $dbl::from(m);
let (_, bigres) = mulres.divmod(&bigm);
self.values.copy_from_slice(&bigres.values[0..$size/64]);
}
}
impl ModMul<$bar> for $name {
fn modmul(&mut self, x: &$name, m: &$bar) {
let mut mulres = (self as &$name) * &x;
let bigres = m.reduce(&mut mulres);
self.values.copy_from_slice(&bigres.values[0..$size/64]);
}
}
impl ModSquare<$name> for $name {
fn modsq(&mut self, m: &$name) {
let bigsquare = self.square();
let bigm = $dbl::from(m);
let (_, res) = bigsquare.divmod(&bigm);
self.values.copy_from_slice(&res.values[0..$size/64]);
}
}
impl ModSquare<$bar> for $name {
fn modsq(&mut self, m: &$bar) {
let bigsquare = self.square();
let bigres = m.reduce(&bigsquare);
self.values.copy_from_slice(&bigres.values[0..$size/64]);
}
}
impl<T> ModExp<T> for $name
where $name: ModMul<T> + ModSquare<T>
{
#[inline]
fn modexp(&self, ine: &$name, m: &T) -> $name {
// S <- g
let mut s = self.clone();
// A <- 1
let mut a = $name::from(1u64);
// We do a quick skim through and find the highest index that
// actually has a value in it.
let mut e = ine.clone();
// While e != 0 do the following:
while e.values.iter().any(|x| *x != 0) {
// If e is odd then A <- A * S
if e.values[0] & 1 != 0 {
a.modmul(&s, m);
}
// e <- floor(e / 2)
let mut carry = 0;
e.values.iter_mut().rev().for_each(|x| {
let new_carry = *x & 1;
*x = (*x >> 1) | (carry << 63);
carry = new_carry;
});
// If e != 0 then S <- S * S
s.modsq(m);
}
// Return A
a
}
}
impl ModInv for $name {
fn modinv(&self, phi: $name)
-> Option<$name>
{
let (_, _d, v) = self.egcd(phi);
if v != Signed::new(false, $name::from(1u64)) {
return None;
}
panic!("modinv stuff")
}
}
impl $name {
fn egcd(&self, rhs: $name)
-> (Signed<$name>, Signed<$name>, Signed<$name>)
{
println!("---------------------------------------------------");
// INPUT: two positive integers x and y.
let mut x = Signed::new(false, self.clone());
let mut y = Signed::new(false, rhs);
// OUTPUT: integers a, b, and v such that ax + by = v,
// where v = gcd(x, y).
// 1. g←1.
let mut gshift = 0;
// 2. While x and y are both even, do the following: x←x/2,
// y←y/2, g←2g.
while x.is_even() && y.is_even() {
x >>= 1;
y >>= 1;
gshift += 1;
}
// 3. u←x, v←y, A←1, B←0, C←0, D←1.
let mut u: Signed<$name> = x.clone();
let mut v: Signed<$name> = y.clone();
#[allow(non_snake_case)]
let mut A: Signed<$name> = Signed::new(false, $name::from(1u64));
#[allow(non_snake_case)]
let mut B: Signed<$name> = Signed::new(false, $name::zero());
#[allow(non_snake_case)]
let mut C: Signed<$name> = Signed::new(false, $name::zero());
#[allow(non_snake_case)]
let mut D: Signed<$name> = Signed::new(false, $name::from(1u64));
loop {
println!("START");
println!("u: {}{:X}", pos_space(&u), u);
println!("v: {}{:X}", pos_space(&v), v);
println!("A: {}{:X}", pos_space(&A), A);
println!("B: {}{:X}", pos_space(&B), B);
println!("C: {}{:X}", pos_space(&C), C);
println!("D: {}{:X}", pos_space(&D), D);
// 4. While u is even do the following:
while u.is_even() {
// 4.1 u←u/2.
u >>= 1;
// 4.2 If A≡B≡0 (mod 2) then A←A/2, B←B/2; otherwise,
// A←(A + y)/2, B←(B x)/2.
if A.is_even() && B.is_even() {
A >>= 1;
B >>= 1;
} else {
let mut big_A: Signed<$big> = &A + &y;
big_A >>= 1;
A = Signed::new(big_A.negative, $name::from(&big_A.value));
B -= &x;
B >>= 1;
}
}
println!("AFTER 4");
println!("u: {}{:X}", pos_space(&u), u);
println!("v: {}{:X}", pos_space(&v), v);
println!("A: {}{:X}", pos_space(&A), A);
println!("B: {}{:X}", pos_space(&B), B);
println!("C: {}{:X}", pos_space(&C), C);
println!("D: {}{:X}", pos_space(&D), D);
// 5. While v is even do the following:
while v.is_even() {
// 5.1 v←v/2.
v >>= 1;
// 5.2 If C ≡ D ≡ 0 (mod 2) then C←C/2, D←D/2; otherwise,
// C←(C + y)/2, D←(D x)/2.
if C.is_even() && D.is_even() {
C >>= 1;
D >>= 1;
} else {
C = C.unsafe_add(&y);
C >>= 1;
D -= &x;
D >>= 1;
}
}
println!("AFTER 5");
println!("u: {}{:X}", pos_space(&u), u);
println!("v: {}{:X}", pos_space(&v), v);
println!("A: {}{:X}", pos_space(&A), A);
println!("B: {}{:X}", pos_space(&B), B);
println!("C: {}{:X}", pos_space(&C), C);
println!("D: {}{:X}", pos_space(&D), D);
// 6. If u≥v then u←uv, A←AC,B←BD;
// otherwise,v←vu, C←CA, D←DB.
if u >= v {
u -= &v;
A -= &C;
B -= &D;
} else {
v -= &u;
C -= &A;
D -= &B;
}
// 7. If u = 0, then a←C, b←D, and return(a, b, g · v);
// otherwise, go to step 4.
println!("AFTER 6");
println!("u: {}{:X}", pos_space(&u), u);
println!("v: {}{:X}", pos_space(&v), v);
println!("A': {}{:X}", pos_space(&A), A);
println!("B': {}{:X}", pos_space(&B), B);
println!("C': {}{:X}", pos_space(&C), C);
println!("D': {}{:X}", pos_space(&D), D);
if u.is_zero() {
return (C, D, v << gshift);
}
}
}
}
}
}
generate_modmath_funs!(U192, U256, U384, BarrettU192, 192);
generate_modmath_funs!(U256, U320, U512, BarrettU256, 256);
generate_modmath_funs!(U384, U448, U768, BarrettU384, 384);
generate_modmath_funs!(U512, U576, U1024, BarrettU512, 512);
generate_modmath_funs!(U1024, U1088, U2048, BarrettU1024, 1024);
generate_modmath_funs!(U2048, U2112, U4096, BarrettU2048, 2048);
generate_modmath_funs!(U3072, U3136, U6144, BarrettU3072, 3072);
generate_modmath_funs!(U4096, U4160, U8192, BarrettU4096, 4096);
generate_modmath_funs!(U8192, U8256, U16384, BarrettU8192, 8192);
generate_modmath_funs!(U15360, U15424, U30720, BarrettU15360, 15360);
macro_rules! generate_tests {
( $( ($name:ident, $barrett: ident, $bigger: ident, $dbl: ident) ),* ) => {
#[cfg(test)]
mod addition {
use cryptonum::encoding::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/modadd{}.test",
stringify!($name));
run_test(fname.to_string(), 4, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, cbytes) = case.get("c").unwrap();
let (neg3, mbytes) = case.get("m").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3);
let mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let m = $bigger::from_bytes(mbytes);
let c = $name::from_bytes(cbytes);
a.modadd(&b, &m);
assert_eq!(a, c);
});
}
)*
}
#[cfg(test)]
mod multiplication {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/modmul{}.test",
stringify!($name));
run_test(fname.to_string(), 4, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, cbytes) = case.get("c").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3);
let mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let m = $name::from_bytes(mbytes);
let c = $name::from_bytes(cbytes);
a.modmul(&b, &m);
assert_eq!(a, c);
});
}
)*
}
#[cfg(test)]
mod barrett_multiplication {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/barrett_mul{}.test",
stringify!($name));
run_test(fname.to_string(), 6, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, rbytes) = case.get("r").unwrap();
let (neg4, kbytes) = case.get("k").unwrap();
let (neg5, ubytes) = case.get("u").unwrap();
assert!(!neg0&&!neg1&&!neg2&&!neg3&&!neg4&&!neg5);
let mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let m = $bigger::from_bytes(mbytes);
let r = $name::from_bytes(rbytes);
let k = $name::from_bytes(kbytes);
let u = $bigger::from_bytes(ubytes);
let mu = $barrett{ k: k.values[0] as usize, m:m, mu:u };
a.modmul(&b, &mu);
assert_eq!(a, r);
});
}
)*
}
#[cfg(test)]
mod modsq {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/modsq{}.test",
stringify!($name));
run_test(fname.to_string(), 5, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, rbytes) = case.get("r").unwrap();
assert!(!neg0&&!neg2&&!neg3);
let mut a = $name::from_bytes(abytes);
let m = $name::from_bytes(mbytes);
let r = $name::from_bytes(rbytes);
a.modsq(&m);
assert_eq!(a, r);
});
}
)*
}
#[cfg(test)]
mod barrett_squaring {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/modsq{}.test",
stringify!($name));
run_test(fname.to_string(), 5, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, rbytes) = case.get("r").unwrap();
let (neg4, kbytes) = case.get("k").unwrap();
let (neg5, ubytes) = case.get("u").unwrap();
assert!(!neg0&&!neg2&&!neg3&&!neg4&&!neg5);
let mut a = $name::from_bytes(abytes);
let m = $bigger::from_bytes(mbytes);
let r = $name::from_bytes(rbytes);
let k = $name::from_bytes(kbytes);
let u = $bigger::from_bytes(ubytes);
let mu = $barrett{ k: k.values[0] as usize, m:m, mu:u };
a.modsq(&mu);
assert_eq!(a, r);
});
}
)*
}
#[cfg(test)]
mod modexp {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
#[ignore]
fn $name() {
let fname = format!("tests/math/modexp{}.test",
stringify!($name));
run_test(fname.to_string(), 6, |case| {
let (neg0, bbytes) = case.get("b").unwrap();
let (neg1, ebytes) = case.get("e").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, rbytes) = case.get("r").unwrap();
assert!(!neg0&&!neg1&&!neg2&&!neg3);
let b = $name::from_bytes(bbytes);
let e = $name::from_bytes(ebytes);
let m = $name::from_bytes(mbytes);
let r = $name::from_bytes(rbytes);
let me = b.modexp(&e, &m);
assert_eq!(me, r);
});
}
)*
}
#[cfg(test)]
mod barrett_exponentiation {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/modexp{}.test",
stringify!($name));
run_test(fname.to_string(), 6, |case| {
let (neg0, bbytes) = case.get("b").unwrap();
let (neg1, ebytes) = case.get("e").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, rbytes) = case.get("r").unwrap();
let (neg4, kbytes) = case.get("k").unwrap();
let (neg5, ubytes) = case.get("u").unwrap();
assert!(!neg0&&!neg1&&!neg2&&!neg3&&!neg4&&!neg5);
let b = $name::from_bytes(bbytes);
let e = $name::from_bytes(ebytes);
let m = $bigger::from_bytes(mbytes);
let r = $name::from_bytes(rbytes);
let k = $name::from_bytes(kbytes);
let u = $bigger::from_bytes(ubytes);
let mu = $barrett{ k: k.values[0] as usize, m:m, mu:u };
let me = b.modexp(&e, &mu);
assert_eq!(me, r);
});
}
)*
}
#[cfg(test)]
mod egcd {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/egcd{}.test",
stringify!($name));
run_test(fname.to_string(), 3, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let (negg, gbytes) = case.get("g").unwrap();
assert!(!nega && !negb);
let a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let ug = $dbl::from_bytes(gbytes);
let g = Signed::new(*negg, ug.clone());
let (mys, myt, myg) = a.egcd(b.clone());
let mybigg = Signed::new(g.negative, $dbl::from(&myg.value));
println!("mybigg: {}{:X}", pos_space(&mybigg), mybigg.value);
println!("g : {}{:X}", pos_space(&g), g.value);
assert_eq!(mybigg, g);
let part1: $dbl = &mys.value * &a;
let part2: $dbl = &myt.value * &b;
let mut spart1 = Signed::new(mys.negative, part1);
let spart2 = Signed::new(myt.negative, part2);
spart1 -= &spart2;
println!("spart1: {}{:X}", pos_space(&spart1), spart1);
println!("spart1: {}{:X}", pos_space(&spart2), spart2);
assert_eq!(spart1, g);
});
}
)*
}
}
}
generate_tests!((U192, BarrettU192, U256, U384),
(U256, BarrettU256, U320, U512),
(U384, BarrettU384, U448, U768),
(U512, BarrettU512, U576, U1024),
(U1024, BarrettU1024, U1088, U2048),
(U2048, BarrettU2048, U2112, U4096),
(U3072, BarrettU3072, U3136, U6144),
(U4096, BarrettU4096, U4160, U8192),
(U8192, BarrettU8192, U8256, U16384),
(U15360, BarrettU15360, U15424, U30720));
//generate_tests!((U192, I192, BarrettU192, U256),
// (U256, I256, BarrettU256, U320),
// (U384, I384, BarrettU384, U448),
// (U512, I512, BarrettU512, U576),
// (U1024, I1024, BarrettU1024, U1088),
// (U2048, I2048, BarrettU2048, U2112),
// (U3072, I3072, BarrettU3072, U3136),
// (U4096, I4096, BarrettU4096, U4160),
// (U8192, I8192, BarrettU8192, U8256),
// (U15360, I15360, BarrettU15360, U15424));
fn pos_space<T>(x: &Signed<T>) -> &'static str {
if !x.negative {
return " ";
}
""
}

View File

@@ -1,123 +1,66 @@
use cryptonum::{U192, U256, U384, U512, U576, use cryptonum::basetypes::*;
U1024, U2048, U3072, U4096, U8192, use std::ops::Mul;
U15360};
use cryptonum::division::divmod;
use std::ops::{Mul,MulAssign};
pub trait ModMul<T=Self> {
fn modmul(&mut self, x: &Self, m: &T);
}
// This is algorithm 14.12 from "Handbook of Applied Cryptography"
pub fn raw_multiplication(x: &[u64], y: &[u64], w: &mut [u64])
{
assert_eq!(x.len(), y.len());
assert_eq!(x.len() * 2, w.len());
// clear out the destination array, because we're going to use it as a
// temporary
for i in 0..w.len() {
w[i] = 0;
}
for i in 0..y.len() {
let mut carry = 0;
for j in 0..x.len() {
let old = w[i+j] as u128;
let x128 = x[j] as u128;
let y128 = y[i] as u128;
let uv = old + (x128 * y128) + carry;
w[i+j] = uv as u64;
carry = uv >> 64;
}
w[i+x.len()] = carry as u64;
}
}
macro_rules! generate_multipliers macro_rules! generate_multipliers
{ {
($name: ident, $size: expr) => { ($name: ident, $bigger: ident, $size: expr) => {
impl MulAssign for $name {
fn mul_assign(&mut self, rhs: $name) {
let mut result = [0; $size/32];
raw_multiplication(&self.values, &rhs.values, &mut result);
for i in 0..self.values.len() {
self.values[i] = result[i];
}
}
}
impl<'a> MulAssign<&'a $name> for $name {
fn mul_assign(&mut self, rhs: &$name) {
let mut result = [0; $size/32];
raw_multiplication(&self.values, &rhs.values, &mut result);
for i in 0..self.values.len() {
self.values[i] = result[i];
}
}
}
impl Mul for $name {
type Output = $name;
fn mul(self, rhs: $name) -> $name {
let mut result = self.clone();
result.mul_assign(rhs);
result
}
}
impl<'a> Mul<&'a $name> for $name {
type Output = $name;
fn mul(self, rhs: &$name) -> $name {
let mut result = self.clone();
result.mul_assign(rhs);
result
}
}
impl<'a,'b> Mul<&'a $name> for &'b $name { impl<'a,'b> Mul<&'a $name> for &'b $name {
type Output = $name; type Output = $bigger;
fn mul(self, rhs: &$name) -> $name { fn mul(self, rhs: &$name) -> $bigger {
let mut result = self.clone(); let mut w = $bigger::zero();
result.mul_assign(rhs); let len = $size/64;
result
}
}
impl ModMul for $name { for i in 0..len {
fn modmul(&mut self, x: &$name, m: &$name) { let mut carry = 0;
let mut mulres = [0; $size/32]; for j in 0..len {
raw_multiplication(&self.values, &x.values, &mut mulres); let old = w.values[i+j] as u128;
let mut widerm = [0; $size/32]; let x128 = self.values[j] as u128;
for (idx,val) in m.values.iter().enumerate() { widerm[idx] = *val; } let y128 = rhs.values[i] as u128;
let mut dead = [0; $size/32]; let uv = old + (x128 * y128) + carry;
let mut answer = [0; $size/32]; w.values[i+j] = uv as u64;
divmod(&mulres, &widerm, &mut dead, &mut answer); carry = uv >> 64;
for i in 0..answer.len() {
if i < self.values.len() {
self.values[i] = answer[i];
} else {
assert_eq!(answer[i], 0);
} }
w.values[i+len] = carry as u64;
} }
w
} }
} }
} }
} }
generate_multipliers!(U192, 192); generate_multipliers!(U192, U384, 192);
generate_multipliers!(U256, 256); generate_multipliers!(U256, U512, 256);
generate_multipliers!(U384, 384); generate_multipliers!(U384, U768, 384);
generate_multipliers!(U512, 512); generate_multipliers!(U448, U896, 448);
generate_multipliers!(U576, 576); generate_multipliers!(U512, U1024, 512);
generate_multipliers!(U1024, 1024); generate_multipliers!(U576, U1152, 576);
generate_multipliers!(U2048, 2048); generate_multipliers!(U768, U1536, 768);
generate_multipliers!(U3072, 3072); generate_multipliers!(U832, U1664, 832);
generate_multipliers!(U4096, 4096); generate_multipliers!(U1024, U2048, 1024);
generate_multipliers!(U8192, 8192); generate_multipliers!(U1088, U2176, 1088);
generate_multipliers!(U15360, 15360); generate_multipliers!(U1152, U2304, 1152);
generate_multipliers!(U1216, U2432, 1216);
generate_multipliers!(U1536, U3072, 1536);
generate_multipliers!(U2048, U4096, 2048);
generate_multipliers!(U2112, U4224, 2112);
generate_multipliers!(U3072, U6144, 3072);
generate_multipliers!(U4096, U8192, 4096);
generate_multipliers!(U4160, U8320, 4160);
generate_multipliers!(U6144, U12288, 6144);
generate_multipliers!(U6208, U12416, 6208);
generate_multipliers!(U7680, U15360, 7680);
generate_multipliers!(U8192, U16384, 8192);
generate_multipliers!(U8256, U16512, 8256);
generate_multipliers!(U15360, U30720, 15360);
generate_multipliers!(U16384, U32768, 16384);
generate_multipliers!(U16448, U32896, 16448);
generate_multipliers!(U30720, U61440, 30720);
generate_multipliers!(U30784, U61568, 30784);
macro_rules! generate_tests { macro_rules! generate_tests {
( $( $name:ident ),* ) => { ( $( ($name:ident, $bigger:ident) ),* ) => {
#[cfg(test)] #[cfg(test)]
mod normal { mod normal {
use cryptonum::Decoder; use cryptonum::Decoder;
@@ -134,81 +77,27 @@ macro_rules! generate_tests {
let (neg0, abytes) = case.get("a").unwrap(); let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap(); let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, cbytes) = case.get("c").unwrap(); let (neg2, cbytes) = case.get("c").unwrap();
assert!(!neg0 && !neg1 && !neg2);
let mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let c = $name::from_bytes(cbytes);
assert_eq!(&a * &b, c);
a *= b;
assert_eq!(a, c);
});
}
)*
}
#[cfg(test)]
mod expanding {
use cryptonum::encoding::{Decoder,raw_decoder};
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/expandingmul{}.test",
stringify!($name));
run_test(fname.to_string(), 3, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, cbytes) = case.get("c").unwrap();
assert!(!neg0 && !neg1 && !neg2); assert!(!neg0 && !neg1 && !neg2);
let a = $name::from_bytes(abytes); let a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes); let b = $name::from_bytes(bbytes);
let mut c = Vec::with_capacity(a.values.len() * 2); let c = $bigger::from_bytes(cbytes);
c.resize(a.values.len() * 2, 0); assert_eq!(&a * &b, c);
raw_decoder(&cbytes, &mut c);
let mut r = Vec::with_capacity(c.len());
r.resize(c.len(), 0);
raw_multiplication(&a.values, &b.values, &mut r);
assert_eq!(c, r);
}); });
} }
)* )*
} }
#[cfg(test)]
mod slow_modular {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/modmul{}.test",
stringify!($name));
run_test(fname.to_string(), 4, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, cbytes) = case.get("c").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3);
let mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let m = $name::from_bytes(mbytes);
let c = $name::from_bytes(cbytes);
a.modmul(&b, &m);
assert_eq!(a, c);
});
}
)*
}
} }
} }
generate_tests!(U192, U256, U384, U512, U576, U1024, U2048, U3072, U4096, U8192, U15360); generate_tests!((U192, U384),
(U256, U512),
(U384, U768),
(U512, U1024),
(U576, U1152),
(U1024, U2048),
(U2048, U4096),
(U3072, U6144),
(U4096, U8192),
(U8192, U16384),
(U15360, U30720));

160
src/cryptonum/shifts.rs Normal file
View File

@@ -0,0 +1,160 @@
use cryptonum::basetypes::*;
use std::ops::{Shl,ShrAssign};
macro_rules! generate_shifts
{
($num: ident, $size: expr) => {
impl ShrAssign<usize> for $num {
fn shr_assign(&mut self, amt: usize) {
let digits = amt / 64;
let bits = amt % 64;
let mut carry = 0;
let mask = !(0xFFFFFFFFFFFFFFFF << bits);
let copy = self.values.clone();
let shift = (64 - bits) as u32;
for (idx, val) in self.values.iter_mut().enumerate().rev() {
let target = idx + digits;
let base = if target >= ($size/64) { 0 } else { copy[target] };
let (new_carry, _) = (base & mask).overflowing_shl(shift);
*val = (base >> bits) | carry;
carry = new_carry;
}
}
}
impl Shl<usize> for $num {
type Output = $num;
fn shl(mut self, amt: usize) -> $num {
let digits = amt / 64;
let bits = amt % 64;
let mut carry = 0;
let copy = self.values.clone();
let shift = 64 - bits;
for (idx, val) in self.values.iter_mut().enumerate() {
let base = if idx >= digits { copy[idx - digits] } else { 0 };
let new_carry = if shift == 64 { 0 } else { base >> shift };
*val = (base << bits) | carry;
carry = new_carry;
}
self
}
}
}
}
generate_shifts!(U192, 192);
generate_shifts!(U256, 256);
generate_shifts!(U320, 320); // this is just for expansion
generate_shifts!(U384, 384);
generate_shifts!(U448, 448); // this is just for expansion
generate_shifts!(U512, 512);
generate_shifts!(U576, 576);
generate_shifts!(U640, 640); // this is just for expansion
generate_shifts!(U768, 768); // this is just for expansion
generate_shifts!(U832, 832); // this is just for Barrett
generate_shifts!(U896, 896); // this is just for Barrett
generate_shifts!(U1024, 1024);
generate_shifts!(U1088, 1088); // this is just for expansion
generate_shifts!(U1152, 1152); // this is just for expansion
generate_shifts!(U1216, 1216); // this is just for Barrett
generate_shifts!(U1536, 1536); // this is just for expansion
generate_shifts!(U1664, 1664); // this is just for Barrett
generate_shifts!(U2048, 2048);
generate_shifts!(U2112, 2112); // this is just for expansion
generate_shifts!(U2176, 2176); // this is just for Barrett
generate_shifts!(U2304, 2304); // this is just for expansion
generate_shifts!(U2432, 2432); // this is just for Barrett
generate_shifts!(U3072, 3072);
generate_shifts!(U3136, 3136); // this is just for expansion
generate_shifts!(U4096, 4096);
generate_shifts!(U4160, 4160); // this is just for expansion
generate_shifts!(U4224, 4224); // this is just for Barrett
generate_shifts!(U6144, 6144); // this is just for expansion
generate_shifts!(U6208, 6208); // this is just for Barrett
generate_shifts!(U7680, 7680); // Useful for RSA key generation
generate_shifts!(U7744, 7744); // Addition on previous
generate_shifts!(U8192, 8192);
generate_shifts!(U8256, 8256); // this is just for expansion
generate_shifts!(U8320, 8320); // this is just for Barrett
generate_shifts!(U12288, 12288); // this is just for expansion
generate_shifts!(U12416, 12416); // this is just for Barrett
generate_shifts!(U15360, 15360);
generate_shifts!(U15424, 15424); // this is just for expansion
generate_shifts!(U16384, 16384); // this is just for expansion
generate_shifts!(U16448, 16448); // this is just for Barrett
generate_shifts!(U16512, 16512); // this is just for Barrett
generate_shifts!(U30720, 30720); // this is just for expansion
generate_shifts!(U30784, 30784); // this is just for Barrett
generate_shifts!(U32768, 32768); // this is just for expansion
generate_shifts!(U32896, 32896); // this is just for Barrett
generate_shifts!(U61440, 61440); // this is just for expansion
generate_shifts!(U61568, 61568); // this is just for Barrett
macro_rules! generate_tests {
( $( $name:ident ), * ) => {
#[cfg(test)]
mod left {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/shift{}.test",
stringify!($name));
run_test(fname.to_string(), 4, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg3, lbytes) = case.get("l").unwrap();
assert!(!neg0 && !neg1 && !neg3);
let a = $name::from_bytes(abytes);
let bigb = $name::from_bytes(bbytes);
let b = usize::from(bigb);
let l = $name::from_bytes(lbytes);
let res = a << b;
assert_eq!(res, l);
});
}
)*
}
#[cfg(test)]
mod right {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/shift{}.test",
stringify!($name));
run_test(fname.to_string(), 4, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, rbytes) = case.get("r").unwrap();
assert!(!neg0 && !neg1 && !neg2);
let mut a = $name::from_bytes(abytes);
let bigb = $name::from_bytes(bbytes);
let b = usize::from(bigb);
let r = $name::from_bytes(rbytes);
a >>= b;
assert_eq!(a, r);
});
}
)*
}
}
}
generate_tests!(U192, U256, U384, U512, U576, U1024, U2048, U3072,
U4096, U8192, U15360);

311
src/cryptonum/signed.rs Normal file
View File

@@ -0,0 +1,311 @@
use cryptonum::addition::UnsafeAdd;
use cryptonum::basetypes::*;
use cryptonum::encoding::Decoder;
use std::fmt;
use std::cmp::{Ord,Ordering};
use std::ops::{Add,Shl,ShrAssign,Sub,SubAssign};
pub struct Signed<T> {
pub(crate) negative: bool,
pub(crate) value: T
}
impl<T> Signed<T> {
pub fn new(negative: bool, value: T) -> Signed<T> {
Signed{ negative: negative, value: value }
}
}
impl<T: Clone> Clone for Signed<T> {
fn clone(&self) -> Self {
Signed{ negative: self.negative, value: self.value.clone() }
}
}
impl<T: CryptoNum> CryptoNum for Signed<T> {
fn zero() -> Signed<T> {
Signed::new(false, T::zero())
}
fn is_odd(&self) -> bool {
self.value.is_odd()
}
fn is_even(&self) -> bool {
self.value.is_even()
}
fn is_zero(&self) -> bool {
self.value.is_zero()
}
}
impl<T: Decoder> Decoder for Signed<T> {
fn from_bytes(x: &[u8]) -> Signed<T> {
let x: T = T::from_bytes(x);
Signed{ negative: false, value: x }
}
}
impl<T: fmt::Debug> fmt::Debug for Signed<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.negative {
write!(f, "NEGATIVE:")?;
} else {
write!(f, "POSITIVE:")?;
}
self.value.fmt(f)
}
}
impl<T: fmt::UpperHex> fmt::UpperHex for Signed<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.negative {
write!(f, "-")?;
}
self.value.fmt(f)
}
}
impl<T: fmt::LowerHex> fmt::LowerHex for Signed<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.negative {
write!(f, "-")?;
}
self.value.fmt(f)
}
}
impl<T: PartialEq> PartialEq for Signed<T> {
fn eq(&self, other: &Signed<T>) -> bool {
(self.negative == other.negative) && (self.value == other.value)
}
}
impl<T: Eq> Eq for Signed<T> {}
impl<T> ShrAssign<usize> for Signed<T>
where
T: ShrAssign<usize> + UnsafeAdd + CryptoNum + From<u64> + Clone + fmt::UpperHex,
T: Shl<usize,Output=T> + PartialEq
{
fn shr_assign(&mut self, rhs: usize) {
// arithmatic right shift is normal right shift, but always rounding
// to negative infinity. To implement this, we first shift right by
// rhs bits, and then shift that value back left rhs bits. If the two
// are the same, we just cleared out even bits, and there's no rounding
// to worry about. If they aren't the same, then we add one back.
let original = self.value.clone();
self.value.shr_assign(rhs);
if self.negative {
let review = self.value.clone() << rhs;
if review != original {
self.value = self.value.clone().unsafe_add(&T::from(1u64));
}
}
}
}
impl<T> UnsafeAdd for Signed<T>
where
T: UnsafeAdd + SubAssign + Sub<Output=T>,
T: PartialOrd + Ord,
T: Clone
{
fn unsafe_add(mut self, rhs: &Signed<T>) -> Signed<T> {
if self.negative == rhs.negative {
Signed{
negative: self.negative,
value: self.value.unsafe_add(&rhs.value)
}
} else {
if self.value > rhs.value {
self.value -= rhs.value.clone();
} else {
self.value = rhs.value.clone() - self.value.clone();
self.negative = rhs.negative;
}
self
}
}
}
impl<'a,'b,T,U> Add<&'a Signed<T>> for &'b Signed<T>
where
&'a T: Add<&'b T,Output=U> + Sub<&'b T,Output=T>,
T: PartialOrd + Ord,
T: Clone,
U: From<T>
{
type Output = Signed<U>;
fn add(self, rhs: &Signed<T>) -> Signed<U> {
if self.negative == rhs.negative {
Signed {
negative: self.negative,
value: &self.value + &rhs.value
}
} else {
if self.value > rhs.value {
Signed {
negative: self.negative,
value: U::from(&self.value - &rhs.value)
}
} else {
Signed {
negative: rhs.negative,
value: U::from(&rhs.value - &self.value)
}
}
}
}
}
impl<'a,T> SubAssign<&'a Signed<T>> for Signed<T>
where
T: SubAssign<T>,
T: Sub<T,Output=T>,
T: UnsafeAdd,
T: PartialOrd,
T: Clone
{
fn sub_assign(&mut self, rhs: &Signed<T>) {
if self.negative == rhs.negative {
if &self.value >= &rhs.value {
self.value -= rhs.value.clone();
} else {
self.value = rhs.value.clone() - self.value.clone();
self.negative = !self.negative;
}
} else {
self.value = rhs.value.clone().unsafe_add(&self.value);
}
}
}
impl<T: Ord + PartialOrd> PartialOrd for Signed<T> {
fn partial_cmp(&self, other: &Signed<T>) -> Option<Ordering> {
Some(self.cmp(&other))
}
}
impl<T: Ord + PartialOrd> Ord for Signed<T> {
fn cmp(&self, other: &Signed<T>) -> Ordering {
match (self.negative, other.negative) {
(false, false) => self.value.cmp(&other.value),
(true, false) => Ordering::Greater,
(false, true) => Ordering::Less,
(true, true) => self.value.cmp(&other.value).reverse()
}
}
}
impl<T> Shl<usize> for Signed<T>
where T: Shl<usize,Output=T>
{
type Output = Signed<T>;
fn shl(mut self, amt: usize) -> Signed<T> {
self.value = self.value << amt;
self
}
}
macro_rules! generate_tests {
( $( $name:ident ),* ) => {
#[cfg(test)]
mod shr {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/sigshr{}.test",
stringify!($name));
run_test(fname.to_string(), 3, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let (negx, xbytes) = case.get("x").unwrap();
assert!(!negb);
let ua = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let ux = $name::from_bytes(xbytes);
let mut a = Signed::new(*nega, ua);
let x = Signed::new(*negx, ux);
a >>= usize::from(b);
assert_eq!(a, x);
});
}
)*
}
#[cfg(test)]
mod add {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/sigadd{}.test",
stringify!($name));
run_test(fname.to_string(), 3, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let (negx, xbytes) = case.get("x").unwrap();
let ua = $name::from_bytes(abytes);
let ub = $name::from_bytes(bbytes);
let ux = $name::from_bytes(xbytes);
let a = Signed::new(*nega, ua);
let b = Signed::new(*negb, ub);
let x = Signed::new(*negx, ux);
let res = a.unsafe_add(&b);
assert_eq!(res, x);
});
}
)*
}
#[cfg(test)]
mod sub {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/sigsub{}.test",
stringify!($name));
run_test(fname.to_string(), 3, |case| {
let (nega, abytes) = case.get("a").unwrap();
let (negb, bbytes) = case.get("b").unwrap();
let (negx, xbytes) = case.get("x").unwrap();
let ua = $name::from_bytes(abytes);
let ub = $name::from_bytes(bbytes);
let ux = $name::from_bytes(xbytes);
let mut a = Signed::new(*nega, ua);
let b = Signed::new(*negb, ub);
let b2 = b.clone();
let x = Signed::new(*negx, ux);
a -= &b2;
assert_eq!(a, x);
assert_eq!(b, b2);
});
}
)*
}
}
}
generate_tests!(U192, U256, U384, U512, U1024,
U2048, U3072, U4096, U8192, U15360);

View File

@@ -1,98 +1,82 @@
use cryptonum::{U192,U256,U384,U512,U576,U1024,U2048,U3072,U4096,U8192,U15360}; use cryptonum::basetypes::*;
use cryptonum::division::divmod;
pub trait ModSquare<T=Self> macro_rules! generate_squarers
{ {
fn modsq(&mut self, m: &T); ($name: ident, $bigger: ident, $size: expr) => {
} impl $name {
pub fn square(&self) -> $bigger {
let mut w = [0; $size/32];
let t = $size / 64;
// This is algorithm 14.16 from "Handbook of Applied Cryptography". for i in 0..t {
pub fn raw_square(x: &[u64], result: &mut [u64]) let x128 = self.values[i] as u128;
{ let mut uvb = (w[2*i] as u128) + (x128 * x128);
assert_eq!(x.len() * 2, result.len()); w[2*i] = uvb & 0xFFFFFFFFFFFFFFFF;
let t = x.len(); let mut c = uvb >> 64;
let mut w: Vec<u128> = Vec::with_capacity(t * 2); for j in (i+1)..t {
w.resize(t * 2, 0); let xj128 = self.values[j] as u128;
let xi128 = self.values[i] as u128;
for i in 0..t { // this first product is safely 128 bits or less,
let x128 = x[i] as u128; // because the input arguments are both 64 bits.
let mut uvb = (w[2*i] as u128) + (x128 * x128); let xij128 = xj128 * xi128;
w[2*i] = uvb & 0xFFFFFFFFFFFFFFFF; // this next bit may overflow, but will do so by exactly
let mut c = uvb >> 64; // one bit.
for j in (i+1)..t { let twoxij128 = xij128 << 1;
let xj128 = x[j] as u128; let carried_shl = (xij128 & (1 << 127)) != 0;
let xi128 = x[i] as u128; // this next bit may *also* overflow, but should also do
// this first product is safely 128 bits or less, because the // so by no more than one bit.
// input arguments are both 64 bits. let (new,carry1) = twoxij128.overflowing_add(c);
let xij128 = xj128 * xi128; // ditto ...
// this next bit may overflow, but will do so by exactly one bit. let wij = w[i+j];
let twoxij128 = xij128 << 1; let (uvb2,carry2) = new.overflowing_add(wij as u128);
let carried_shl = (xij128 & (1 << 127)) != 0; // for the value we're going to save for this digit, we
// this next bit may *also* overflow, but should also do so by no // only care about the low bits, so we can forget about
// more than one bit. // the carry stuff.
let (newstuff, carried_add1) = twoxij128.overflowing_add(c); w[i+j] = uvb2 & 0xFFFFFFFFFFFFFFFF;
// ditto ... // for c, though, we do care about the carries, above.
let (uvb2, carried_add2) = newstuff.overflowing_add(w[i+j] as u128); // Fortunately, they were both by only one bit, so we
// for the value we're going to save for this digit, we only care // should be able to just back-fix them.
// about the low bits, so we can forget about the carry stuff. c = uvb2 >> 64;
w[i+j] = uvb2 & 0xFFFFFFFFFFFFFFFF; if carried_shl { c += 1 << 64; }
// for c, though, we do care about the carries, above. Fortunately, if carry1 { c += 1 << 64; }
// they were both by only one bit, so we should be able to just if carry2 { c += 1 << 64; }
// back-fix them.
c = uvb2 >> 64;
if carried_shl { c += 1 << 64; }
if carried_add1 { c += 1 << 64; }
if carried_add2 { c += 1 << 64; }
}
w[i+t] = c;
}
for (idx, val) in w.iter().enumerate() {
result[idx] = *val as u64;
}
}
macro_rules! generate_squarers {
($type: ident, $size: expr) => {
impl ModSquare for $type {
fn modsq(&mut self, m: &$type) {
let mut sqres = [0; $size/32];
raw_square(&self.values, &mut sqres);
let mut widerm = [0; $size/32];
for (idx,val) in m.values.iter().enumerate() { widerm[idx] = *val; }
let mut dead = [0; $size/32];
let mut answer = [0; $size/32];
divmod(&sqres, &widerm, &mut dead, &mut answer);
for i in 0..answer.len() {
if i < self.values.len() {
self.values[i] = answer[i];
} else {
assert_eq!(answer[i], 0);
} }
w[i+t] = c;
} }
let mut res = $bigger::zero();
for i in 0..w.len() { res.values[i] = w[i] as u64; }
res
} }
} }
}; //
// impl ModSquare for $name {
// fn modsq(&self, m: &$name) -> $name {
// let bigsquare = self.square();
// let bigm = $bigger::from(m);
// let bigres = bigsquare.reduce(&bigm);
// $name::from(bigres)
// }
// }
}
} }
generate_squarers!(U192, 192); generate_squarers!(U192, U384, 192);
generate_squarers!(U256, 256); generate_squarers!(U256, U512, 256);
generate_squarers!(U384, 384); generate_squarers!(U384, U768, 384);
generate_squarers!(U512, 512); generate_squarers!(U512, U1024, 512);
generate_squarers!(U576, 576); generate_squarers!(U576, U1152, 576);
generate_squarers!(U1024, 1024); generate_squarers!(U1024, U2048, 1024);
generate_squarers!(U2048, 2048); generate_squarers!(U2048, U4096, 2048);
generate_squarers!(U3072, 3072); generate_squarers!(U3072, U6144, 3072);
generate_squarers!(U4096, 4096); generate_squarers!(U4096, U8192, 4096);
generate_squarers!(U8192, 8192); generate_squarers!(U8192, U16384, 8192);
generate_squarers!(U15360, 15360); generate_squarers!(U15360, U30720,15360);
macro_rules! generate_tests { macro_rules! generate_tests {
( $( $name:ident ),* ) => { ( $( ($name:ident, $bigger:ident) ),* ) => {
#[cfg(test)] #[cfg(test)]
mod normal { mod normal {
use cryptonum::Decoder; use cryptonum::Decoder;
use cryptonum::encoding::raw_decoder;
use super::*; use super::*;
use testing::run_test; use testing::run_test;
@@ -108,40 +92,9 @@ macro_rules! generate_tests {
assert!(!neg0 && !neg1); assert!(!neg0 && !neg1);
let a = $name::from_bytes(abytes); let a = $name::from_bytes(abytes);
let mut result = Vec::with_capacity(a.values.len() * 2); let r = $bigger::from_bytes(rbytes);
result.resize(a.values.len() * 2, 0); let myres = a.square();
let mut myresult = result.clone(); assert_eq!(r, myres);
raw_decoder(rbytes, &mut result);
raw_square(&a.values, &mut myresult);
assert_eq!(result, myresult);
});
}
)*
}
#[cfg(test)]
mod slow_modular {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
$(
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("tests/math/modsq{}.test",
stringify!($name));
run_test(fname.to_string(), 3, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, mbytes) = case.get("m").unwrap();
let (neg2, rbytes) = case.get("r").unwrap();
assert!(!neg0 && !neg1 && !neg2);
let mut a = $name::from_bytes(abytes);
let m = $name::from_bytes(mbytes);
let r = $name::from_bytes(rbytes);
a.modsq(&m);
assert_eq!(a, r);
}); });
} }
)* )*
@@ -149,4 +102,14 @@ macro_rules! generate_tests {
} }
} }
generate_tests!(U192, U256, U384, U512, U576, U1024, U2048, U3072, U4096, U8192, U15360); generate_tests!((U192, U384),
(U256, U512),
(U384, U768),
(U512, U1024),
(U576, U1152),
(U1024, U2048),
(U2048, U4096),
(U3072, U6144),
(U4096, U8192),
(U8192, U16384),
(U15360, U30720));

View File

@@ -1,80 +1,110 @@
use cryptonum::{U192, U256, U384, U512, U576, use cryptonum::basetypes::*;
U1024, U2048, U3072, U4096, U8192,
U15360};
use cryptonum::addition::raw_addition;
use std::ops::{Sub,SubAssign}; use std::ops::{Sub,SubAssign};
pub fn raw_subtraction(x: &mut [u64], y: &[u64])
{
assert_eq!(x.len(), y.len());
let mut negatedy = Vec::with_capacity(y.len());
for val in y.iter() {
negatedy.push(!*val);
}
let mut one = Vec::with_capacity(y.len());
one.resize(y.len(), 0);
one[0] = 1;
raw_addition(&mut negatedy, &one);
raw_addition(x, &negatedy);
}
macro_rules! generate_subbers macro_rules! generate_subbers
{ {
($name: ident) => { ($name: ident, $size: expr) => {
impl SubAssign for $name {
fn sub_assign(&mut self, rhs: $name) {
raw_subtraction(&mut self.values, &rhs.values);
}
}
impl<'a> SubAssign<&'a $name> for $name { impl<'a> SubAssign<&'a $name> for $name {
fn sub_assign(&mut self, rhs: &$name) { fn sub_assign(&mut self, rhs: &$name) {
raw_subtraction(&mut self.values, &rhs.values); // negate the right hand size
let mut negatedy: $name = rhs.clone();
for i in 0..$size/64 {
negatedy.values[i] = !negatedy.values[i];
}
// add one
let mut bigger = 1 + (negatedy.values[0] as u128);
let mut carry = bigger >> 64;
negatedy.values[0] = bigger as u64;
for i in 1..$size/64 {
bigger = carry + (negatedy.values[i] as u128);
negatedy.values[i] = bigger as u64;
carry = bigger >> 64;
}
// then add it to ourselves
carry = 0;
for i in 0..$size/64 {
let x128 = self.values[i] as u128;
let y128 = negatedy.values[i] as u128;
bigger = x128 + y128 + carry;
carry = bigger >> 64;
self.values[i] = bigger as u64;
}
} }
} }
impl SubAssign for $name {
fn sub_assign(&mut self, rhs: $name) {
self.sub_assign(&rhs);
}
}
impl<'a,'b> Sub<&'b $name> for &'a $name {
type Output = $name;
fn sub(self, rhs: &$name) -> $name {
let mut res = self.clone();
res -= rhs;
res
}
}
impl Sub for $name { impl Sub for $name {
type Output = $name; type Output = $name;
fn sub(self, rhs: $name) -> $name { fn sub(mut self, rhs: $name) -> $name {
let mut result = $name{ values: self.values }; self -= rhs;
raw_subtraction(&mut result.values, &rhs.values); self
result
}
}
impl<'a> Sub<&'a $name> for $name {
type Output = $name;
fn sub(self, rhs: &$name) -> $name {
let mut result = $name{ values: self.values };
raw_subtraction(&mut result.values, &rhs.values);
result
}
}
impl<'a,'b> Sub<&'a $name> for &'b $name {
type Output = $name;
fn sub(self, rhs: &$name) -> $name {
let mut result = (*self).clone();
raw_subtraction(&mut result.values, &rhs.values);
result
} }
} }
} }
} }
generate_subbers!(U192); generate_subbers!(U192, 192);
generate_subbers!(U256); generate_subbers!(U256, 256);
generate_subbers!(U384); generate_subbers!(U320, 320); // this is just for expansion
generate_subbers!(U512); generate_subbers!(U384, 384);
generate_subbers!(U576); generate_subbers!(U448, 448); // this is just for expansion
generate_subbers!(U1024); generate_subbers!(U512, 512);
generate_subbers!(U2048); generate_subbers!(U576, 576);
generate_subbers!(U3072); generate_subbers!(U640, 640); // this is just for expansion
generate_subbers!(U4096); generate_subbers!(U768, 768); // this is just for expansion
generate_subbers!(U8192); generate_subbers!(U832, 832); // this is just for Barrett
generate_subbers!(U15360); generate_subbers!(U896, 896); // this is just for Barrett
generate_subbers!(U1024, 1024);
generate_subbers!(U1088, 1088); // this is just for expansion
generate_subbers!(U1152, 1152); // this is just for expansion
generate_subbers!(U1216, 1216); // this is just for Barrett
generate_subbers!(U1536, 1536); // this is just for expansion
generate_subbers!(U1664, 1664); // this is just for Barrett
generate_subbers!(U2048, 2048);
generate_subbers!(U2112, 2112); // this is just for expansion
generate_subbers!(U2176, 2176); // this is just for Barrett
generate_subbers!(U2304, 2304); // this is just for expansion
generate_subbers!(U2432, 2432); // this is just for Barrett
generate_subbers!(U3072, 3072);
generate_subbers!(U3136, 3136); // this is just for expansion
generate_subbers!(U4096, 4096);
generate_subbers!(U4160, 4160); // this is just for expansion
generate_subbers!(U4224, 4224); // this is just for Barrett
generate_subbers!(U6144, 6144); // this is just for expansion
generate_subbers!(U6208, 6208); // this is just for Barrett
generate_subbers!(U7680, 7680);
generate_subbers!(U8192, 8192);
generate_subbers!(U8256, 8256); // this is just for expansion
generate_subbers!(U8320, 8320); // this is just for Barrett
generate_subbers!(U12288, 12288); // this is just for expansion
generate_subbers!(U12416, 12416); // this is just for Barrett
generate_subbers!(U15360, 15360);
generate_subbers!(U15424, 15424); // this is just for expansion
generate_subbers!(U16384, 16384); // this is just for expansion
generate_subbers!(U16448, 16448); // this is just for Barrett
generate_subbers!(U16512, 16512); // this is just for Barrett
generate_subbers!(U30720, 30720); // this is just for expansion
generate_subbers!(U30784, 30784); // this is just for Barrett
generate_subbers!(U32768, 32768); // this is just for expansion
generate_subbers!(U32896, 32896); // this is just for Barrett
generate_subbers!(U61440, 61440); // this is just for expansion
generate_subbers!(U61568, 61568); // this is just for Barrett
macro_rules! generate_tests { macro_rules! generate_tests {
( $( $name:ident ),* ) => { ( $( $name:ident ),* ) => {
@@ -94,13 +124,11 @@ macro_rules! generate_tests {
let (neg0, abytes) = case.get("a").unwrap(); let (neg0, abytes) = case.get("a").unwrap();
let (neg1, bbytes) = case.get("b").unwrap(); let (neg1, bbytes) = case.get("b").unwrap();
let (neg2, cbytes) = case.get("c").unwrap(); let (neg2, cbytes) = case.get("c").unwrap();
assert!(!neg0 && !neg1 && !neg2); assert!(!neg0 && !neg1 && !neg2);
let mut a = $name::from_bytes(abytes); let mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes); let b = $name::from_bytes(bbytes);
let c = $name::from_bytes(cbytes); let c = $name::from_bytes(cbytes);
assert_eq!(&a - &b, c); a -= &b;
a -= b;
assert_eq!(a, c); assert_eq!(a, c);
}); });
} }
@@ -109,4 +137,6 @@ macro_rules! generate_tests {
} }
} }
generate_tests!(U192, U256, U384, U512, U576, U1024, U2048, U3072, U4096, U8192, U15360); generate_tests!(U192, U256, U384, U512, U576,
U1024, U2048, U3072, U4096, U8192,
U15360);

View File

@@ -9,14 +9,23 @@
//! that a new user should use, along with documentation regarding how and //! that a new user should use, along with documentation regarding how and
//! 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;
#[cfg(test)]
#[macro_use]
extern crate quickcheck;
extern crate num;
extern crate rand;
extern crate sha1;
extern crate sha2;
extern crate simple_asn1;
//#[cfg(test)] /// The `cryptonum` module provides support for large numbers at fixed,
//#[macro_use]
//extern crate quickcheck;
/// 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 provides bare-bones support for RSA signing, verification,
/// encryption, decryption, and key generation.
pub mod rsa;
#[cfg(test)] #[cfg(test)]
mod testing; mod testing;

48
src/rsa/core.rs Normal file
View File

@@ -0,0 +1,48 @@
use num::bigint::BigUint;
use rsa::errors::RSAError;
use simple_asn1::{ASN1Block,ASN1DecodeErr};
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
}
pub fn drop0s(a: &[u8]) -> &[u8] {
let mut idx = 0;
while (idx < a.len()) && (a[idx] == 0) {
idx = idx + 1;
}
&a[idx..]
}
pub fn xor_vecs(a: &Vec<u8>, b: &Vec<u8>) -> Vec<u8> {
a.iter().zip(b.iter()).map(|(a,b)| a^b).collect()
}
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))
}
}

27
src/rsa/errors.rs Normal file
View File

@@ -0,0 +1,27 @@
use simple_asn1::ASN1DecodeErr;
use std::io;
#[derive(Debug)]
pub enum RSAError {
BadMessageSize,
KeyTooSmallForHash,
DecryptionError,
DecryptHashMismatch,
InvalidKey,
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)
}
}

92
src/rsa/mod.rs Normal file
View File

@@ -0,0 +1,92 @@
//! A simple RSA library.
//!
//! This library performs all the standard bits and pieces that you'd expect
//! from an RSA library, and does so using only Rust. It's a bit slow at the
//! moment, but it gets the job done.
//!
//! 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.
//!
mod core;
mod errors;
mod oaep;
mod private;
mod public;
mod signing_hashes;
pub use self::signing_hashes::{SigningHash,
SIGNING_HASH_NULL,
SIGNING_HASH_SHA1,
SIGNING_HASH_SHA224,
SIGNING_HASH_SHA256,
SIGNING_HASH_SHA384,
SIGNING_HASH_SHA512};
pub use self::oaep::OAEPParams;
pub use self::private::{RSAPrivate, RSAPrivateKey,
RSA512Private, RSA1024Private, RSA2048Private,
RSA3072Private, RSA4096Private, RSA8192Private,
RSA15360Private};
pub use self::public::{RSAPublic, RSAPublicKey,
RSA512Public, RSA1024Public, RSA2048Public,
RSA3072Public, RSA4096Public, RSA8192Public,
RSA15360Public};
use cryptonum::*;
use rand::Rng;
macro_rules! generate_rsa_pair
{
($pair: ident, $pub: ident, $priv: ident, $uint: ident, $half: ident) => {
pub struct $pair {
pub public: $pub,
pub private: $priv
}
impl $pair {
pub fn new(pu: $pub, pr: $priv) -> $pair {
$pair {
public: pu,
private: pr
}
}
pub fn generate<G: Rng>(rng: &mut G) -> $pair {
loop {
let e = $uint::from(65537u32);
let (p, q) = $pair::generate_pq(rng, &e);
let one = $half::from(1u32);
let phi = &(&p - &one) * &(&q - &one);
let n = &p * &q;
if let Some(d) = e.modinv(phi) {
let public = $pub::new(n.clone(), e);
let private = $priv::new(n, d);
return $pair::new(public, private);
}
}
}
fn generate_pq<G: Rng>(_rng: &mut G, _e: &$uint) -> ($half, $half)
{
panic!("generate_pq")
}
}
}
}
generate_rsa_pair!(RSA512KeyPair, RSA512Public, RSA512Private, U512, U256);
generate_rsa_pair!(RSA1024KeyPair, RSA1024Public, RSA1024Private, U1024, U512);
generate_rsa_pair!(RSA2048KeyPair, RSA2048Public, RSA2048Private, U2048, U1024);
generate_rsa_pair!(RSA3072KeyPair, RSA3072Public, RSA3072Private, U3072, U1536);
generate_rsa_pair!(RSA4096KeyPair, RSA4096Public, RSA4096Private, U4096, U2048);
generate_rsa_pair!(RSA8192KeyPair, RSA8192Public, RSA8192Private, U8192, U4096);
generate_rsa_pair!(RSA15360KeyPair, RSA15360Public, RSA15360Private, U15360, U7680);

48
src/rsa/oaep.rs Normal file
View File

@@ -0,0 +1,48 @@
use byteorder::{BigEndian,ByteOrder};
use digest::{FixedOutput,Input};
use std::marker::PhantomData;
/// 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: Default + Input + FixedOutput> {
pub label: String,
phantom: PhantomData<H>
}
impl<H: Default + Input + FixedOutput> OAEPParams<H> {
pub fn new(label: String)
-> OAEPParams<H>
{
OAEPParams { label: label, phantom: PhantomData }
}
pub fn hash_len(&self) -> usize {
H::default().fixed_result().as_slice().len()
}
pub fn hash(&self, input: &[u8]) -> Vec<u8> {
let mut digest = H::default();
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 = 0u32;
while res.len() < len {
let mut buffer = [0; 4];
BigEndian::write_u32(&mut buffer, counter);
let mut digest = H::default();
digest.process(input);
digest.process(&buffer);
let chunk = digest.fixed_result();
res.extend_from_slice(chunk.as_slice());
counter = counter + 1;
}
res.truncate(len);
res
}
}

263
src/rsa/private.rs Normal file
View File

@@ -0,0 +1,263 @@
use cryptonum::*;
use digest::{FixedOutput,Input};
use rsa::core::{drop0s,pkcs1_pad,xor_vecs};
use rsa::errors::RSAError;
use rsa::oaep::OAEPParams;
use rsa::signing_hashes::SigningHash;
pub trait RSAPrivateKey<N> {
/// Generate a new private key using the given modulus and private
/// exponent. You probably don't want to use this function directly
/// unless you're writing your own key generation routine or key
/// parsing library.
fn new(n: N, d: N) -> Self;
/// Sign the given message with the given private key.
fn sign(&self, signhash: &SigningHash, msg: &[u8]) -> Vec<u8>;
/// Decrypt the provided message using the given OAEP parameters. As
/// mentioned in the comment for encryption, RSA decryption is really,
/// really slow. So if your plaintext is larger than about half the
/// bit size of the key, it's almost certainly a better idea to generate
/// a fresh symmetric encryption key, encrypt only the key with RSA, and
/// then encrypt the message with that key.
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where H: Default + Input + FixedOutput;
}
pub enum RSAPrivate {
Key512(RSA512Private),
Key1024(RSA1024Private),
Key2048(RSA2048Private),
Key3072(RSA3072Private),
Key4096(RSA4096Private),
Key8192(RSA8192Private),
Key15360(RSA15360Private)
}
// fn print_vector(name: &'static str, bytes: &[u8])
// {
// print!("{}: (length {}) ", name, bytes.len());
// for x in bytes.iter() {
// print!("{:02X}", *x);
// }
// println!("");
// }
macro_rules! generate_rsa_private
{
($rsa: ident, $num: ident, $bar: ident, $size: expr) => {
pub struct $rsa {
nu: $bar,
d: $num
}
impl RSAPrivateKey<$num> for $rsa {
fn new(n: $num, d: $num) -> $rsa {
let nu = $bar::new(&n);
$rsa { nu: nu, d: d }
}
fn sign(&self, signhash: &SigningHash, msg: &[u8])
-> Vec<u8>
{
let hash = (signhash.run)(msg);
let em = pkcs1_pad(&signhash.ident, &hash, $size/8);
let m = $num::from_bytes(&em);
let s = self.sp1(&m);
let sig = s.to_bytes();
sig
}
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where H: Default + Input + FixedOutput
{
let mut res = Vec::new();
for chunk in msg.chunks($size/8) {
let mut dchunk = self.oaep_decrypt(oaep, chunk)?;
res.append(&mut dchunk);
}
Ok(res)
}
}
impl $rsa {
fn sp1(&self, m: &$num) -> $num {
m.modexp(&self.d, &self.nu)
}
fn dp(&self, c: &$num) -> $num {
c.modexp(&self.d, &self.nu)
}
fn oaep_decrypt<H>(&self, oaep: &OAEPParams<H>, c: &[u8])
-> Result<Vec<u8>,RSAError>
where
H: Default + Input + FixedOutput
{
let byte_len = $size / 8;
// 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 = $num::from_bytes(&c);
// Step 2b
let m_ip = self.dp(&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())
}
}
}
}
generate_rsa_private!(RSA512Private, U512, BarrettU512, 512);
generate_rsa_private!(RSA1024Private, U1024, BarrettU1024, 1024);
generate_rsa_private!(RSA2048Private, U2048, BarrettU2048, 2048);
generate_rsa_private!(RSA3072Private, U3072, BarrettU3072, 3072);
generate_rsa_private!(RSA4096Private, U4096, BarrettU4096, 4096);
generate_rsa_private!(RSA8192Private, U8192, BarrettU8192, 8192);
generate_rsa_private!(RSA15360Private, U15360, BarrettU15360, 15360);
macro_rules! generate_tests {
( $( ($mod: ident, $rsa: ident, $num: ident, $size: expr) ),* ) => {
$(
#[cfg(test)]
#[allow(non_snake_case)]
mod $mod {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
use rsa::signing_hashes::*;
use sha1::Sha1;
use sha2::{Sha224,Sha256,Sha384,Sha512};
#[test]
fn sign() {
let fname = format!("tests/rsa/rsa{}.test", $size);
run_test(fname.to_string(), 6, |case| {
let (neg0, dbytes) = case.get("d").unwrap();
let (neg1, nbytes) = case.get("n").unwrap();
let (neg2, hbytes) = case.get("h").unwrap();
let (neg3, mbytes) = case.get("m").unwrap();
let (neg4, sbytes) = case.get("s").unwrap();
assert!(!neg0&&!neg1&&!neg2&&!neg3&&!neg4);
let n = $num::from_bytes(nbytes);
let d = $num::from_bytes(dbytes);
let privkey = $rsa::new(n, d);
let hashnum = ((hbytes[0] as u16)<<8) + (hbytes[1] as u16);
let sighash = match hashnum {
0x160 => &SIGNING_HASH_SHA1,
0x224 => &SIGNING_HASH_SHA224,
0x256 => &SIGNING_HASH_SHA256,
0x384 => &SIGNING_HASH_SHA384,
0x512 => &SIGNING_HASH_SHA512,
_ => panic!("Bad signing hash: {}", hashnum)
};
let sig = privkey.sign(sighash, &mbytes);
assert_eq!(sig, *sbytes);
});
}
#[test]
fn decrypt() {
let fname = format!("tests/rsa/rsa{}.test", $size);
run_test(fname.to_string(), 6, |case| {
let (neg0, dbytes) = case.get("d").unwrap();
let (neg1, nbytes) = case.get("n").unwrap();
let (neg2, hbytes) = case.get("h").unwrap();
let (neg3, mbytes) = case.get("m").unwrap();
let (neg4, cbytes) = case.get("c").unwrap();
assert!(!neg0&&!neg1&&!neg2&&!neg3&&!neg4);
let n = $num::from_bytes(nbytes);
let d = $num::from_bytes(dbytes);
let privkey = $rsa::new(n, d);
let hashnum = ((hbytes[0] as u16)<<8) + (hbytes[1] as u16);
let empty = "".to_string();
match hashnum {
0x160 => {
let oaep = OAEPParams::<Sha1>::new(empty);
let plain = privkey.decrypt(&oaep, &cbytes);
assert!(plain.is_ok());
assert_eq!(*mbytes, plain.unwrap());
}
0x224 =>{
let oaep = OAEPParams::<Sha224>::new(empty);
let plain = privkey.decrypt(&oaep, &cbytes);
assert!(plain.is_ok());
assert_eq!(*mbytes, plain.unwrap());
}
0x256 => {
let oaep = OAEPParams::<Sha256>::new(empty);
let plain = privkey.decrypt(&oaep, &cbytes);
assert!(plain.is_ok());
assert_eq!(*mbytes, plain.unwrap());
}
0x384 => {
let oaep = OAEPParams::<Sha384>::new(empty);
let plain = privkey.decrypt(&oaep, &cbytes);
assert!(plain.is_ok());
assert_eq!(*mbytes, plain.unwrap());
}
0x512 => {
let oaep = OAEPParams::<Sha512>::new(empty);
let plain = privkey.decrypt(&oaep, &cbytes);
assert!(plain.is_ok());
assert_eq!(*mbytes, plain.unwrap());
}
_ => panic!("Bad signing hash: {}", hashnum)
};
});
}
}
)*
}
}
generate_tests!( (RSA512, RSA512Private, U512, 512),
(RSA1024, RSA1024Private, U1024, 1024),
(RSA2048, RSA2048Private, U2048, 2048),
(RSA3072, RSA3072Private, U3072, 3072),
(RSA4096, RSA4096Private, U4096, 4096),
(RSA8192, RSA8192Private, U8192, 8192),
(RSA15360, RSA15360Private, U15360, 15360)
);

404
src/rsa/public.rs Normal file
View File

@@ -0,0 +1,404 @@
use cryptonum::*;
use digest::{FixedOutput,Input};
use num::{BigInt,BigUint};
use rand::{OsRng,Rng};
use rsa::core::{decode_biguint,pkcs1_pad,xor_vecs};
use rsa::errors::RSAError;
use rsa::oaep::OAEPParams;
use rsa::signing_hashes::SigningHash;
use simple_asn1::{ASN1Block,ASN1DecodeErr,ASN1EncodeErr,
ASN1Class,FromASN1,ToASN1};
pub trait RSAPublicKey<N> {
/// Generate a new public key pair for the given modulus and
/// exponent. You should probably not call this directly unless
/// you're writing a key generation function or writing your own
/// public key parser.
fn new(n: N, e: N) -> Self;
/// Verify that the provided signature is valid; that the private
/// key associated with this public key sent exactly this message.
/// The hash used here must exactly match the hash used to sign
/// the message, including its ASN.1 metadata.
fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool;
/// Encrypt the message with a hash function, given the appropriate
/// label. Please note that RSA encryption is not particularly fast,
/// and decryption is very slow indeed. Thus, most crypto systems that
/// need asymmetric encryption should generate a symmetric key, encrypt
/// that key with RSA encryption, and then encrypt the actual message
/// with that symmetric key.
///
/// In this variant of the function, we use an explicit random number
/// generator, just in case you have one you really like. It better be
/// cryptographically strong, though, as some of the padding protections
/// are relying on it.
fn encrypt_rng<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where
G: Rng,
H: Default + Input + FixedOutput;
/// Encrypt the message with a hash function, given the appropriate
/// label. Please note that RSA encryption is not particularly fast,
/// and decryption is very slow indeed. Thus, most crypto systems that
/// need asymmetric encryption should generate a symmetric key, encrypt
/// that key with RSA encryption, and then encrypt the actual message
/// with that symmetric key.
///
/// This variant will just use the system RNG for its randomness.
fn encrypt<H>(&self,oaep:&OAEPParams<H>,msg:&[u8])
-> Result<Vec<u8>,RSAError>
where
H: Default + Input + FixedOutput
{
let mut g = OsRng::new()?;
self.encrypt_rng(&mut g, oaep, msg)
}
}
pub enum RSAPublic {
Key512(RSA512Public),
Key1024(RSA1024Public),
Key2048(RSA2048Public),
Key3072(RSA3072Public),
Key4096(RSA4096Public),
Key8192(RSA8192Public),
Key15360(RSA15360Public)
}
impl FromASN1 for RSAPublic {
type Error = RSAError;
fn from_asn1(bs: &[ASN1Block])
-> Result<(RSAPublic,&[ASN1Block]),RSAError>
{
match bs.split_first() {
None =>
Err(RSAError::ASN1DecodeErr(ASN1DecodeErr::EmptyBuffer)),
Some((&ASN1Block::Sequence(_, _, ref items), rest))
if items.len() == 2 =>
{
let n = decode_biguint(&items[0])?;
let e = decode_biguint(&items[1])?;
let nsize = n.bits();
let mut rsa_size = 512;
while rsa_size < nsize {
rsa_size = rsa_size + 256;
}
match rsa_size {
512 => {
let n2 = U512::from(n);
let e2 = U512::from(e);
let res = RSA512Public::new(n2, e2);
Ok((RSAPublic::Key512(res), rest))
}
1024 => {
let n2 = U1024::from(n);
let e2 = U1024::from(e);
let res = RSA1024Public::new(n2, e2);
Ok((RSAPublic::Key1024(res), rest))
}
2048 => {
let n2 = U2048::from(n);
let e2 = U2048::from(e);
let res = RSA2048Public::new(n2, e2);
Ok((RSAPublic::Key2048(res), rest))
}
3072 => {
let n2 = U3072::from(n);
let e2 = U3072::from(e);
let res = RSA3072Public::new(n2, e2);
Ok((RSAPublic::Key3072(res), rest))
}
4096 => {
let n2 = U4096::from(n);
let e2 = U4096::from(e);
let res = RSA4096Public::new(n2, e2);
Ok((RSAPublic::Key4096(res), rest))
}
8192 => {
let n2 = U8192::from(n);
let e2 = U8192::from(e);
let res = RSA8192Public::new(n2, e2);
Ok((RSAPublic::Key8192(res), rest))
}
15360 => {
let n2 = U15360::from(n);
let e2 = U15360::from(e);
let res = RSA15360Public::new(n2, e2);
Ok((RSAPublic::Key15360(res), rest))
}
_ =>
Err(RSAError::InvalidKey)
}
}
Some(_) =>
Err(RSAError::InvalidKey)
}
}
}
impl ToASN1 for RSAPublic {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,Self::Error>
{
match self {
RSAPublic::Key512(x) => x.to_asn1_class(c),
RSAPublic::Key1024(x) => x.to_asn1_class(c),
RSAPublic::Key2048(x) => x.to_asn1_class(c),
RSAPublic::Key3072(x) => x.to_asn1_class(c),
RSAPublic::Key4096(x) => x.to_asn1_class(c),
RSAPublic::Key8192(x) => x.to_asn1_class(c),
RSAPublic::Key15360(x) => x.to_asn1_class(c)
}
}
}
// fn print_vector(name: &'static str, bytes: &[u8])
// {
// print!("{}: (length {}) ", name, bytes.len());
// for x in bytes.iter() {
// print!("{:02X}", *x);
// }
// println!("");
// }
macro_rules! generate_rsa_public
{
($rsa: ident, $num: ident, $bar: ident, $var: ident, $size: expr) => {
#[derive(Debug,PartialEq)]
pub struct $rsa {
nu: $bar,
e: $num
}
impl RSAPublicKey<$num> for $rsa {
fn new(n: $num, e: $num) -> $rsa {
let nu = $bar::new(&n);
$rsa { nu: nu, e: e }
}
fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8])
-> bool
{
let hash: Vec<u8> = (signhash.run)(msg);
let s = $num::from_bytes(&sig);
let m = self.vp1(&s);
let em = m.to_bytes();
let em_ = pkcs1_pad(signhash.ident, &hash, $size/8);
em == em_
}
fn encrypt_rng<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,msg: &[u8])
-> Result<Vec<u8>,RSAError>
where
G: Rng,
H: Default + Input + FixedOutput
{
let byte_len = $size / 8;
let mut res = Vec::new();
if byte_len <= ((2 * oaep.hash_len()) + 2) {
return Err(RSAError::KeyTooSmallForHash);
}
for chunk in msg.chunks(byte_len - (2 * oaep.hash_len()) - 2) {
let mut newchunk = self.oaep_encrypt(g, oaep, chunk)?;
res.append(&mut newchunk);
}
Ok(res)
}
}
impl $rsa {
fn vp1(&self, s: &$num) -> $num {
s.modexp(&self.e, &self.nu)
}
fn ep(&self, m: &$num) -> $num {
m.modexp(&self.e, &self.nu)
}
fn oaep_encrypt<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,m: &[u8])
-> Result<Vec<u8>,RSAError>
where
G: Rng,
H: Default + Input + FixedOutput
{
let byte_len = $size / 8;
// Step 1b
if m.len() > (byte_len - (2 * oaep.hash_len()) - 2) {
return Err(RSAError::BadMessageSize)
}
// Step 2a
let mut lhash = oaep.hash(oaep.label.as_bytes());
// Step 2b
let num0s = byte_len - m.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(m);
// Step 2d
let seed : Vec<u8> = g.gen_iter().take(oaep.hash_len()).collect();
// Step 2e
let db_mask = oaep.mgf1(&seed, byte_len - 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 = $num::from_bytes(&em);
// Step 3b
let c_i = self.ep(&m_i);
// Step 3c
let c = c_i.to_bytes();
Ok(c)
}
}
impl FromASN1 for $rsa {
type Error = RSAError;
fn from_asn1(bs: &[ASN1Block])
-> Result<($rsa,&[ASN1Block]),RSAError>
{
let (core, rest) = RSAPublic::from_asn1(bs)?;
match core {
RSAPublic::$var(x) => Ok((x, rest)),
_ => Err(RSAError::InvalidKey)
}
}
}
impl ToASN1 for $rsa {
type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class)
-> Result<Vec<ASN1Block>,Self::Error>
{
let n = BigInt::from(BigUint::from(self.nu.m.clone()));
let e = BigInt::from(BigUint::from(self.e.clone()));
let enc_n = ASN1Block::Integer(c, 0, n);
let enc_e = ASN1Block::Integer(c, 0, e);
let seq = ASN1Block::Sequence(c, 0, vec![enc_n, enc_e]);
Ok(vec![seq])
}
}
}
}
generate_rsa_public!(RSA512Public, U512, BarrettU512, Key512, 512);
generate_rsa_public!(RSA1024Public, U1024, BarrettU1024, Key1024, 1024);
generate_rsa_public!(RSA2048Public, U2048, BarrettU2048, Key2048, 2048);
generate_rsa_public!(RSA3072Public, U3072, BarrettU3072, Key3072, 3072);
generate_rsa_public!(RSA4096Public, U4096, BarrettU4096, Key4096, 4096);
generate_rsa_public!(RSA8192Public, U8192, BarrettU8192, Key8192, 8192);
generate_rsa_public!(RSA15360Public, U15360, BarrettU15360, Key15360, 15360);
macro_rules! generate_tests {
( $( ($mod: ident, $rsa: ident, $num: ident, $size: expr) ),* ) => {
$(
#[cfg(test)]
#[allow(non_snake_case)]
mod $mod {
use cryptonum::Decoder;
use super::*;
use testing::run_test;
use rsa::signing_hashes::*;
#[test]
fn encode() {
let fname = format!("tests/rsa/rsa{}.test", $size);
run_test(fname.to_string(), 6, |case| {
let (neg0, nbytes) = case.get("n").unwrap();
assert!(!neg0);
let n = $num::from_bytes(nbytes);
let e = $num::from(65537u64);
let pubkey = $rsa::new(n, e);
let asn1 = pubkey.to_asn1().unwrap();
let (pubkey2, _) = $rsa::from_asn1(&asn1).unwrap();
assert_eq!(pubkey, pubkey2);
});
}
#[test]
fn verify() {
let fname = format!("tests/rsa/rsa{}.test", $size);
run_test(fname.to_string(), 6, |case| {
let (neg0, nbytes) = case.get("n").unwrap();
let (neg1, hbytes) = case.get("h").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, sbytes) = case.get("s").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3);
let n = $num::from_bytes(nbytes);
let e = $num::from(65537u64);
let pubkey = $rsa::new(n, e);
let hashnum = ((hbytes[0] as u16)<<8) + (hbytes[1] as u16);
let sighash = match hashnum {
0x160 => &SIGNING_HASH_SHA1,
0x224 => &SIGNING_HASH_SHA224,
0x256 => &SIGNING_HASH_SHA256,
0x384 => &SIGNING_HASH_SHA384,
0x512 => &SIGNING_HASH_SHA512,
_ => panic!("Bad signing hash: {}", hashnum)
};
assert!(pubkey.verify(sighash, &mbytes, &sbytes));
});
}
#[test]
fn encrypt() {
let fname = format!("tests/rsa/rsa{}.test", $size);
run_test(fname.to_string(), 6, |case| {
let (neg0, nbytes) = case.get("n").unwrap();
let (neg1, hbytes) = case.get("h").unwrap();
let (neg2, mbytes) = case.get("m").unwrap();
let (neg3, sbytes) = case.get("s").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3);
let n = $num::from_bytes(nbytes);
let e = $num::from(65537u64);
let pubkey = $rsa::new(n, e);
let hashnum = ((hbytes[0] as u16)<<8) + (hbytes[1] as u16);
let sighash = match hashnum {
0x160 => &SIGNING_HASH_SHA1,
0x224 => &SIGNING_HASH_SHA224,
0x256 => &SIGNING_HASH_SHA256,
0x384 => &SIGNING_HASH_SHA384,
0x512 => &SIGNING_HASH_SHA512,
_ => panic!("Bad signing hash: {}", hashnum)
};
assert!(pubkey.verify(sighash, &mbytes, &sbytes));
});
}
}
)*
}
}
generate_tests!( (RSA512, RSA512Public, U512, 512),
(RSA1024, RSA1024Public, U1024, 1024),
(RSA2048, RSA2048Public, U2048, 2048),
(RSA3072, RSA3072Public, U3072, 3072),
(RSA4096, RSA4096Public, U4096, 4096),
(RSA8192, RSA8192Public, U8192, 8192),
(RSA15360, RSA15360Public, U15360, 15360)
);

119
src/rsa/signing_hashes.rs Normal file
View 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()
}

104
test.hs Normal file
View File

@@ -0,0 +1,104 @@
import Data.Bits
import Numeric
a :: Integer
a = 0xffffffffffffffffffffffffffffffffa275ec6d0ffbb359
b :: Integer
b = 0xffffffffffffffffffffffffffffffffa14e39a19260951d
outs :: Integer
outs = -0x9124a315de33a9
outt :: Integer
outt = 0x180b603717d35f66
outg :: Integer
outg = 1
x :: Integer
y :: Integer
g :: Integer
(x, y, g) = loop a b 1
where loop x y g
| even x && even y = loop (x `shiftR` 1) (y `shiftR` 1) (g `shiftL` 1)
| otherwise = (x, y, g)
u0 :: Integer
u0 = x
v0 :: Integer
v0 = y
bigA0 :: Integer
bigA0 = 1
bigB0 :: Integer
bigB0 = 0
bigC0 :: Integer
bigC0 = 0
bigD0 :: Integer
bigD0 = 1
step4 :: (Integer, Integer, Integer, Integer, Integer, Integer) ->
(Integer, Integer, Integer, Integer, Integer, Integer)
step4 (u, v, bigA, bigB, bigC, bigD) = (resu, v, resA, resB, bigC, bigD)
where
(resu, resA, resB) = step4 u bigA bigB
step4 inu inA inB
| even inu = let outu = inu `div` 2
in if even inA && even inB
then step4 outu (inA `div` 2) (inB `div` 2)
else step4 outu ((inA + y) `div` 2) ((inB - x) `div` 2)
| otherwise = (inu, inA, inB)
step5 :: (Integer, Integer, Integer, Integer, Integer, Integer) ->
(Integer, Integer, Integer, Integer, Integer, Integer)
step5 (u, v, bigA, bigB, bigC, bigD) = (u, resv, bigA, bigB, resC, resD)
where
(resv, resC, resD) = step5 v bigC bigD
step5 inv inC inD
| even inv = let outv = inv `div` 2
in if even inC && even inD
then step5 outv (inC `div` 2) (inD `div` 2)
else step5 outv ((inC + y) `div` 2) ((inD - x) `div` 2)
| otherwise = (inv, inC, inD)
step6 :: (Integer, Integer, Integer, Integer, Integer, Integer) ->
(Integer, Integer, Integer, Integer, Integer, Integer)
step6 (u, v, bigA, bigB, bigC, bigD)
| u >= v = (u - v, v, bigA - bigC, bigB - bigD, bigC, bigD)
| otherwise = (u, v - u, bigA, bigB, bigC - bigA, bigD - bigB)
iteration :: (Integer, Integer, Integer, Integer, Integer, Integer) ->
(Integer, Integer, Integer, Integer, Integer, Integer)
iteration = step6 . step5 . step4
state0 :: (Integer, Integer, Integer, Integer, Integer, Integer)
state0 = (u0, v0, bigA0, bigB0, bigC0, bigD0)
printIter :: (Integer, Integer, Integer, Integer, Integer, Integer) -> IO ()
printIter (u, v, a, b, c, d) =
do printVal "u" u
printVal "v" v
printVal "A" a
printVal "B" b
printVal "C" c
printVal "D" d
printVal :: String -> Integer -> IO ()
printVal name x =
do putStr (name ++ ": ")
if x < 0
then putStr "-"
else putStr " "
let x' = abs x
putStrLn (showHex x' "")
myImpl inState | u == 0 = outState
| otherwise = myImpl outState
where
outState@(u,_,_,_,_,_) = iteration inState

View File

@@ -1,5 +1,5 @@
import Control.Monad import Control.Monad
import Data.Bits(shiftL,(.&.)) import Data.Bits(Bits,shiftL,shiftR,(.&.))
import Data.Map.Strict(Map) import Data.Map.Strict(Map)
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import GHC.Integer.GMP.Internals(powModInteger) import GHC.Integer.GMP.Internals(powModInteger)
@@ -14,15 +14,20 @@ testTypes = [("addition", addTest),
("modadd", modaddTest), ("modadd", modaddTest),
("subtraction", subTest), ("subtraction", subTest),
("multiplication", mulTest), ("multiplication", mulTest),
("expandingmul", expmulTest),
("modmul", modmulTest), ("modmul", modmulTest),
("squaring", squareTest), ("squaring", squareTest),
("modsq", modsqTest), ("modsq", modsqTest),
("modexp", modexpTest), ("modexp", modexpTest),
("bmodexp", bmodexpTest), ("bmodexp", bmodexpTest),
("division", divTest), ("division", divTest),
("shift", shiftTest),
("sigshr", signedShiftRightTest),
("sigadd", signedAddition),
("sigsub", signedSubtraction),
("barrett_gen", barrettGenTest), ("barrett_gen", barrettGenTest),
("barrett_reduce", barrettReduceTest) ("barrett_reduce", barrettReduceTest),
("barrett_mul", bmodmulTest),
("egcd", egcdTest)
] ]
bitSizes :: [Int] bitSizes :: [Int]
@@ -40,8 +45,9 @@ splitMod bitsize xs = filtered ++ [m]
xs' = map (\x -> x .&. mask bitsize) xs xs' = map (\x -> x .&. mask bitsize) xs
m = maximum xs' m = maximum xs'
filtered = go xs' filtered = go xs'
go (x:xs) | x == m = xs go [] = error "Didn't find case in splitMod"
| otherwise = x : go xs go (x:rest) | x == m = rest
| otherwise = x : go rest
addTest :: Int -> StdGen -> (Map String String, StdGen) addTest :: Int -> StdGen -> (Map String String, StdGen)
addTest bitsize gen0 = (res, gen2) addTest bitsize gen0 = (res, gen2)
@@ -50,13 +56,13 @@ addTest bitsize gen0 = (res, gen2)
(b, gen2) = random gen1 (b, gen2) = random gen1
a' = a .&. mask bitsize a' = a .&. mask bitsize
b' = b .&. mask bitsize b' = b .&. mask bitsize
c = (a' + b') .&. mask bitsize c = a' + b'
res = Map.fromList [("a", showHex a' ""), res = Map.fromList [("a", showHex a' ""),
("b", showHex b' ""), ("b", showHex b' ""),
("c", showHex c "")] ("c", showHex c "")]
modaddTest :: Int -> StdGen -> (Map String String, StdGen) modaddTest :: Int -> StdGen -> (Map String String, StdGen)
modaddTest bitsize gen0 = (res, gen2) modaddTest bitsize gen0 = (res, gen3)
where where
(a, gen1) = random gen0 (a, gen1) = random gen0
(b, gen2) = random gen1 (b, gen2) = random gen1
@@ -82,18 +88,6 @@ subTest bitsize gen0 = (res, gen2)
mulTest :: Int -> StdGen -> (Map String String, StdGen) mulTest :: Int -> StdGen -> (Map String String, StdGen)
mulTest bitsize gen0 = (res, gen2) mulTest bitsize gen0 = (res, gen2)
where
(a, gen1) = random gen0
(b, gen2) = random gen1
a' = a .&. mask bitsize
b' = b .&. mask bitsize
c = (a' * b') .&. mask bitsize
res = Map.fromList [("a", showHex a' ""),
("b", showHex b' ""),
("c", showHex c "")]
expmulTest :: Int -> StdGen -> (Map String String, StdGen)
expmulTest bitsize gen0 = (res, gen2)
where where
(a, gen1) = random gen0 (a, gen1) = random gen0
(b, gen2) = random gen1 (b, gen2) = random gen1
@@ -105,7 +99,7 @@ expmulTest bitsize gen0 = (res, gen2)
("c", showHex c "")] ("c", showHex c "")]
modmulTest :: Int -> StdGen -> (Map String String, StdGen) modmulTest :: Int -> StdGen -> (Map String String, StdGen)
modmulTest bitsize gen0 = (res, gen2) modmulTest bitsize gen0 = (res, gen3)
where where
(a, gen1) = random gen0 (a, gen1) = random gen0
(b, gen2) = random gen1 (b, gen2) = random gen1
@@ -127,27 +121,35 @@ squareTest bitsize gen0 = (res, gen1)
("r", showHex r "")] ("r", showHex r "")]
modsqTest :: Int -> StdGen -> (Map String String, StdGen) modsqTest :: Int -> StdGen -> (Map String String, StdGen)
modsqTest bitsize gen0 = (res, gen1) modsqTest bitsize gen0 = (res, gen2)
where where
(a, gen1) = random gen0 (a, gen1) = random gen0
(m, gen3) = random gen1 (m, gen2) = random gen1
[a',m'] = splitMod bitsize [a,m] [a',m'] = splitMod bitsize [a,m]
k = computeK m'
u = barrett m'
r = (a' * a') `mod` m' r = (a' * a') `mod` m'
res = Map.fromList [("a", showHex a' ""), res = Map.fromList [("a", showHex a' ""),
("m", showHex m' ""), ("m", showHex m' ""),
("k", showHex k ""),
("u", showHex u ""),
("r", showHex r "")] ("r", showHex r "")]
modexpTest :: Int -> StdGen -> (Map String String, StdGen) modexpTest :: Int -> StdGen -> (Map String String, StdGen)
modexpTest bitsize gen0 = (res, gen2) modexpTest bitsize gen0 = (res, gen3)
where where
(b, gen1) = random gen0 (b, gen1) = random gen0
(e, gen2) = random gen1 (e, gen2) = random gen1
(m, gen3) = random gen2 (m, gen3) = random gen2
[b',e',m'] = splitMod bitsize [b,e,m] [b',e',m'] = splitMod bitsize [b,e,m]
k = computeK m'
u = barrett m'
r = powModInteger b' e' m' r = powModInteger b' e' m'
res = Map.fromList [("b", showHex b' ""), res = Map.fromList [("b", showHex b' ""),
("e", showHex e' ""), ("e", showHex e' ""),
("m", showHex m' ""), ("m", showHex m' ""),
("k", showHex k ""),
("u", showHex u ""),
("r", showHex r "")] ("r", showHex r "")]
@@ -164,13 +166,77 @@ divTest bitsize gen0 = (res, gen2)
("q", showHex q ""), ("q", showHex q ""),
("r", showHex r "")] ("r", showHex r "")]
shiftTest :: Int -> StdGen -> (Map String String, StdGen)
shiftTest bitsize gen0 = (res, gen2)
where
(a, gen1) = random gen0
(b, gen2) = random gen1
a' = a .&. mask bitsize
b' = b .&. 0xFF
r = a' `shiftR` b'
l = (a' `shiftL` b') .&. mask bitsize
res = Map.fromList [("a", showHex a' ""),
("b", showHex b' ""),
("r", showHex r ""),
("l", showHex l "")]
signedMask :: (Ord a, Num a, Bits a) => a -> a -> a
signedMask x y | x < 0 = -(abs x .&. y)
| otherwise = x .&. y
signedShiftRightTest :: Int -> StdGen -> (Map String String, StdGen)
signedShiftRightTest bitsize gen0 = (res, gen2)
where
(a, gen1) = random gen0
(b, gen2) = random gen1
a' = signedMask a (mask bitsize)
b' = b .&. 0xFF
x = a' `shiftR` b'
prefixA = if a' < 0 then "-" else ""
prefixX = if x < 0 then "-" else ""
res = Map.fromList [("a", prefixA ++ showHex (abs a') ""),
("b", showHex b' ""),
("x", prefixX ++ showHex (abs x) "")]
signedAddition :: Int -> StdGen -> (Map String String, StdGen)
signedAddition bitsize gen0 = (res, gen2)
where
(a, gen1) = random gen0
(b, gen2) = random gen1
mymask = mask (bitsize - 2)
a' = signedMask a mymask
b' = signedMask b mymask
x = a' + b'
prefixA = if a' < 0 then "-" else ""
prefixB = if b' < 0 then "-" else ""
prefixX = if x < 0 then "-" else ""
res = Map.fromList [("a", prefixA ++ showHex (abs a') ""),
("b", prefixB ++ showHex (abs b') ""),
("x", prefixX ++ showHex (abs x) "")]
signedSubtraction :: Int -> StdGen -> (Map String String, StdGen)
signedSubtraction bitsize gen0 = (res, gen2)
where
(a, gen1) = random gen0
(b, gen2) = random gen1
mymask = mask (bitsize - 2)
a' = signedMask a mymask
b' = signedMask b mymask
x = a' - b'
prefixA = if a' < 0 then "-" else ""
prefixB = if b' < 0 then "-" else ""
prefixX = if x < 0 then "-" else ""
res = Map.fromList [("a", prefixA ++ showHex (abs a') ""),
("b", prefixB ++ showHex (abs b') ""),
("x", prefixX ++ showHex (abs x) "")]
barrettGenTest :: Int -> StdGen -> (Map String String, StdGen) barrettGenTest :: Int -> StdGen -> (Map String String, StdGen)
barrettGenTest bitsize gen0 = (res, gen1) barrettGenTest bitsize gen0 = (res, gen1)
where where
(m, gen1) = random gen0 (m, gen1) = random gen0
m' = m .&. mask bitsize m' = m .&. mask bitsize
k = computeK m' k = computeK m'
u = barrett bitsize m' u = barrett m'
res = Map.fromList [("m", showHex m' ""), res = Map.fromList [("m", showHex m' ""),
("k", showHex k ""), ("k", showHex k ""),
("u", showHex u "")] ("u", showHex u "")]
@@ -183,7 +249,7 @@ barrettReduceTest bitsize gen0 = (res, gen2)
m' = m .&. mask bitsize m' = m .&. mask bitsize
x' = x .&. mask (min bitsize (2 * k * 64)) x' = x .&. mask (min bitsize (2 * k * 64))
k = computeK m' k = computeK m'
u = barrett bitsize m' u = barrett m'
r = x' `mod` m' r = x' `mod` m'
res = Map.fromList [("m", showHex m' ""), res = Map.fromList [("m", showHex m' ""),
("x", showHex x' ""), ("x", showHex x' ""),
@@ -191,15 +257,48 @@ barrettReduceTest bitsize gen0 = (res, gen2)
("u", showHex u ""), ("u", showHex u ""),
("r", showHex r "")] ("r", showHex r "")]
bmodmulTest :: Int -> StdGen -> (Map String String, StdGen)
bmodmulTest bitsize gen0 = (res, gen3)
where
(a, gen1) = random gen0
(b, gen2) = random gen1
(m, gen3) = random gen2
[a',b',m'] = splitMod bitsize [a,b,m]
k = computeK m'
u = barrett m'
r = (a' * b') `mod` m'
res = Map.fromList [("a", showHex a' ""),
("b", showHex b' ""),
("m", showHex m' ""),
("k", showHex k ""),
("u", showHex u ""),
("r", showHex r "")]
egcdTest :: Int -> StdGen -> (Map String String, StdGen)
egcdTest bitsize gen0 = (res, gen2)
where
(a, gen1) = random gen0
(b, gen2) = random gen1
a' = a .&. mask bitsize
b' = b .&. mask bitsize
g = gcd a b
res = Map.fromList [("a", showSignedHex a' ""),
("b", showSignedHex b' ""),
("g", showSignedHex g "")]
showSignedHex :: (Integral a, Num a, Show a) => a -> ShowS
showSignedHex x str | x < 0 = "-" ++ showHex (abs x) str
| otherwise = showHex x str
bmodexpTest :: Int -> StdGen -> (Map String String, StdGen) bmodexpTest :: Int -> StdGen -> (Map String String, StdGen)
bmodexpTest bitsize gen0 = (res, gen2) bmodexpTest bitsize gen0 = (res, gen3)
where where
(b, gen1) = random gen0 (b, gen1) = random gen0
(e, gen2) = random gen1 (e, gen2) = random gen1
(m, gen3) = random gen2 (m, gen3) = random gen2
[b',e',m'] = splitMod bitsize [b,e,m] [b',e',m'] = splitMod bitsize [b,e,m]
k = computeK m' k = computeK m'
u = barrett bitsize m' u = barrett m'
r = powModInteger b' e' m' r = powModInteger b' e' m'
res = Map.fromList [("b", showHex b' ""), res = Map.fromList [("b", showHex b' ""),
("e", showHex e' ""), ("e", showHex e' ""),
@@ -208,18 +307,19 @@ bmodexpTest bitsize gen0 = (res, gen2)
("u", showHex u ""), ("u", showHex u ""),
("r", showHex r "")] ("r", showHex r "")]
base :: Integer
base = 2 ^ (64 :: Integer)
barrett :: Int -> Integer -> Integer barrett :: Integer -> Integer
barrett bitsize m = (b ^ (2 * k)) `div` m barrett m = (base ^ (2 * k)) `div` m
where where
b = 2 ^ 64
k = computeK m k = computeK m
computeK :: Integer -> Int computeK :: Integer -> Int
computeK v = go 0 1 computeK v = go 0 1
where where
go k acc | v < acc = k + 1 go k acc | v <= acc = k
| otherwise = go (k + 1) (acc * (2 ^ 64)) | otherwise = go (k + 1) (acc * base)
log :: String -> IO () log :: String -> IO ()
log str = log str =

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3000
tests/math/egcdU192.test Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3000
tests/math/egcdU256.test Normal file

File diff suppressed because it is too large Load Diff

3000
tests/math/egcdU3072.test Normal file

File diff suppressed because it is too large Load Diff

3000
tests/math/egcdU384.test Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More