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

@@ -1,107 +1,97 @@
use cryptonum::{U192, U256, U384, U512, U576,
U1024, U2048, U3072, U4096, U8192,
U15360};
use cryptonum::comparison::bignum_ge;
use cryptonum::subtraction::raw_subtraction;
use std::ops::{Add,AddAssign};
use cryptonum::basetypes::*;
use std::ops::Add;
pub fn raw_addition(x: &mut [u64], y: &[u64]) -> u64 {
assert_eq!(x.len(), y.len());
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);
pub trait UnsafeAdd {
fn unsafe_add(self, other: &Self) -> Self;
}
macro_rules! generate_adders
{
($name: ident) => {
impl AddAssign for $name {
fn add_assign(&mut self, rhs: $name) {
raw_addition(&mut self.values, &rhs.values);
}
}
impl<'a> AddAssign<&'a $name> for $name {
fn add_assign(&mut self, rhs: &$name) {
raw_addition(&mut self.values, &rhs.values);
}
}
impl Add for $name {
type Output = $name;
($name: ident, $size: expr) => {
impl UnsafeAdd for $name {
fn unsafe_add(self, other: &$name) -> $name {
let mut result = $name::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;
}
fn add(self, other: $name) -> $name {
let mut result = $name{ values: self.values };
result.add_assign(other);
result
}
}
impl<'a> Add<&'a $name> for $name {
type Output = $name;
fn add(self, other: &$name) -> $name {
let mut result = $name{ values: self.values };
result.add_assign(other);
result
}
}
};
($name: ident, $bigger: ident, $size: expr) => {
generate_adders!($name, $size);
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
}
}
impl ModAdd for $name {
fn modadd(&mut self, y: &$name, m: &$name) {
let carry = raw_addition(&mut self.values, &y.values);
if carry > 0 {
let mut left = Vec::with_capacity(self.values.len() + 1);
for x in self.values.iter() { left.push(*x) }
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);
}
impl Add<$name> for $name {
type Output = $bigger;
fn add(self, other: $name) -> $bigger {
&self + &other
}
}
}
}
generate_adders!(U192);
generate_adders!(U256);
generate_adders!(U384);
generate_adders!(U512);
generate_adders!(U576);
generate_adders!(U1024);
generate_adders!(U2048);
generate_adders!(U3072);
generate_adders!(U4096);
generate_adders!(U8192);
generate_adders!(U15360);
generate_adders!(U192, U256, 192);
generate_adders!(U256, U320, 256);
generate_adders!(U384, U448, 384);
generate_adders!(U512, U576, 512);
generate_adders!(U576, U640, 576);
generate_adders!(U1024, U1088, 1024);
generate_adders!(U2048, U2112, 2048);
generate_adders!(U3072, U3136, 3072);
generate_adders!(U4096, U4160, 4096);
generate_adders!(U7680, U7744, 7680);
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 {
( $( $name:ident ),* ) => {
( $( ($name:ident, $bigger: ident) ),* ) => {
#[cfg(test)]
mod normal {
use cryptonum::Decoder;
@@ -118,44 +108,11 @@ macro_rules! generate_tests {
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);
let mut a = $name::from_bytes(abytes);
let a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let c = $name::from_bytes(cbytes);
let c = $bigger::from_bytes(cbytes);
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,
U1024, U2048, U3072, U4096, U8192,
U15360};
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;
use cryptonum::addition::UnsafeAdd;
use cryptonum::basetypes::*;
use std::cmp::min;
macro_rules! generate_barrett_implementations {
($bname: ident, $name: ident, $size: expr) => {
macro_rules! generate_barretts {
($bname:ident,$name:ident,$big:ident,$bg2:ident,$dbl:ident,$size:expr) =>
{
#[derive(Debug,PartialEq)]
pub struct $bname {
pub(crate) k: usize,
pub(crate) m: [u64; $size/32],
pub(crate) mu: [u64; $size/32]
}
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
}
pub(crate) k: usize,
pub(crate) m: $big,
pub(crate) mu: $big
}
impl $bname {
pub fn new(m: &$name) -> $bname {
let mut b = [0; ($size/32) + 1];
let mut widerm = [0; ($size/32) + 1];
let mut quot = [0; ($size/32) + 1];
let mut remndr = [0; ($size/32) + 1];
let mut result = $bname{ k: 0,
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; }
// Step #1: Figure out k
let mut k = 0;
for i in 0..$size/64 {
if m.values[i] != 0 {
k = i;
}
}
result.k += 1;
b[result.k*2] = 1;
divmod(&b, &widerm, &mut quot, &mut remndr);
for (idx, val) in result.mu.iter_mut().enumerate() { *val = quot[idx]; }
result
k += 1;
// Step #2: Compute b
let mut b = $bg2::zero();
b.values[2*k] = 1;
// 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) {
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 {
pub fn ok_for_reduce(&self, x: &$dbl) -> bool {
for i in self.k*2 .. x.values.len() {
if x.values[i] != 0 {
return false
@@ -109,168 +42,123 @@ macro_rules! generate_barrett_implementations {
}
true
}
}
impl ModAdd<$bname> for $name {
fn modadd(&mut self, y: &$name, m: &$bname) {
let carry = raw_addition(&mut self.values, &y.values);
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);
pub fn reduce(&self, x: &$dbl) -> $name {
assert!(self.ok_for_reduce(x));
let m2: $bg2 = $bg2::from(&self.m);
// 1. q1←⌊x/bk1⌋, q2←q1 · μ, q3←⌊q2/bk+1⌋.
let mut q1 = [0; $size/32];
shiftr(&mulres, m.k - 1, &mut q1);
let mut q2 = [0; $size/16];
raw_multiplication(&q1, &m.mu, &mut q2);
let mut q3 = [0; $size/16];
shiftr(&q2, m.k + 1, &mut q3);
let q1: $big = x.shiftr(self.k - 1);
let q2: $bg2 = q1.unsafe_mul(&self.mu);
let q3: $big = q2.check_shiftr(self.k + 1);
// 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, mulres.len());
for i in 0..copylen { r[i] = mulres[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);
let mut r: $bg2 = x.mask(self.k + 1);
let mut r2: $bg2 = q3.unsafe_mul(&self.m);
r2.mask_inplace(self.k + 1);
let went_negative = &r < &r2;
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);
let mut bk1 = $bg2::zero();
bk1.values[self.k+1] = 1;
r = r.unsafe_add(&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];
while &r > &m2 {
r -= &m2;
}
// Done!
$name::from(&r)
}
}
impl ModSquare<$bname> for $name {
fn modsq(&mut self, m: &$bname) {
let mut sqres = [0; $size/32];
raw_square(&self.values, &mut sqres);
// 1. q1←⌊x/bk1⌋, q2←q1 · μ, q3←⌊q2/bk+1⌋.
let mut q1 = [0; $size/32];
shiftr(&sqres, m.k - 1, &mut q1);
let mut q2 = [0; $size/16];
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;
impl $dbl {
fn shiftr(&self, x: usize) -> $big {
let mut res = $big::zero();
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];
}
}
// 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;
res
}
while mask != 0 {
if e.values[i] & mask != 0 {
self.modmul(&s, m);
fn mask(&self, len: usize) -> $bg2 {
let mut res = $bg2::zero();
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;
s.modsq(m);
let old = w.values[i+j] as u128;
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])
{
for i in amt..x.len() {
dest[i-amt] = x[i];
impl $bg2 {
fn check_shiftr(&self, x: usize) -> $big {
let mut res = $big::zero();
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_barrett_implementations!(BarrettU192, U192, 192);
generate_barrett_implementations!(BarrettU256, U256, 256);
generate_barrett_implementations!(BarrettU384, U384, 384);
generate_barrett_implementations!(BarrettU512, U512, 512);
generate_barrett_implementations!(BarrettU576, U576, 576);
generate_barrett_implementations!(BarrettU1024, U1024, 1024);
generate_barrett_implementations!(BarrettU2048, U2048, 2048);
generate_barrett_implementations!(BarrettU3072, U3072, 3072);
generate_barrett_implementations!(BarrettU4096, U4096, 4096);
generate_barrett_implementations!(BarrettU8192, U8192, 8192);
generate_barrett_implementations!(BarrettU15360, U15360,15360);
generate_barretts!(BarrettU192, U192, U256, U448, U384, 192);
generate_barretts!(BarrettU256, U256, U320, U576, U512, 256);
generate_barretts!(BarrettU384, U384, U448, U832, U768, 384);
generate_barretts!(BarrettU512, U512, U576, U1088, U1024, 512);
generate_barretts!(BarrettU576, U576, U640, U1216, U1152, 576);
generate_barretts!(BarrettU1024, U1024, U1088, U2112, U2048, 1024);
generate_barretts!(BarrettU2048, U2048, U2112, U4160, U4096, 2048);
generate_barretts!(BarrettU3072, U3072, U3136, U6208, U6144, 3072);
generate_barretts!(BarrettU4096, U4096, U4160, U8256, U8192, 4096);
generate_barretts!(BarrettU8192, U8192, U8256, U16448, U16384, 8192);
generate_barretts!(BarrettU15360, U15360, U15424, U30784, U30720, 15360);
macro_rules! generate_tests {
( $( ($bname: ident, $name:ident, $size:expr) ),* ) => {
( $( ($bname:ident,$name:ident,$big:ident,$dbl:ident,$size:expr) ),* ) => {
#[cfg(test)]
mod generation {
use cryptonum::encoding::{Decoder,raw_decoder};
@@ -290,15 +178,13 @@ macro_rules! generate_tests {
assert!(!neg0 && !neg1 && !neg2);
let m = $name::from_bytes(mbytes);
let u = $big::from_bytes(ubytes);
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 k = kbig[0] as usize;
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();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
let m = $big::from_bytes(mbytes);
let u = $big::from_bytes(ubytes);
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 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 k = kbig[0] as usize;
let x = $dbl::from_bytes(xbytes);
let r = $name::from_bytes(rbytes);
b.modexp(&e, &u);
assert_eq!(b, r);
let bu = $bname{ k: k, m: m, mu: u };
let r2 = bu.reduce(&x);
assert_eq!(r, r2);
});
}
)*
@@ -443,14 +227,14 @@ macro_rules! generate_tests {
}
}
generate_tests!((BarrettU192, U192, 192),
(BarrettU256, U256, 256),
(BarrettU384, U384, 384),
(BarrettU512, U512, 512),
(BarrettU576, U576, 576),
(BarrettU1024, U1024, 1024),
(BarrettU2048, U2048, 2048),
(BarrettU3072, U3072, 3072),
(BarrettU4096, U4096, 4096),
(BarrettU8192, U8192, 8192),
(BarrettU15360, U15360, 15360));
generate_tests!((BarrettU192, U192, U256, U384, 192),
(BarrettU256, U256, U320, U512, 256),
(BarrettU384, U384, U448, U768, 384),
(BarrettU512, U512, U576, U1024, 512),
(BarrettU576, U576, U640, U1152, 576),
(BarrettU1024, U1024, U1088, U2048, 1024),
(BarrettU2048, U2048, U2112, U4096, 2048),
(BarrettU3072, U3072, U3136, U6144, 3072),
(BarrettU4096, U4096, U4160, U8192, 4096),
(BarrettU8192, U8192, U8256, U16384, 8192),
(BarrettU15360, U15360, U15424, U30720, 15360));

View File

@@ -1,6 +1,13 @@
use std::fmt;
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
{
($name: ident, $size: expr) => {
@@ -11,9 +18,7 @@ macro_rules! generate_unsigned
impl Clone for $name {
fn clone(&self) -> $name {
let mut result = $name{ values: [0; $size/64] };
for (idx,val) in self.values.iter().enumerate() {
result.values[idx] = *val;
}
result.values.copy_from_slice(&self.values);
result
}
}
@@ -31,33 +36,23 @@ macro_rules! generate_unsigned
impl fmt::UpperHex for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut wrote_something = false;
for x in self.values.iter() {
if !wrote_something && (*x == 0) {
continue;
} else {
f.write_char(tochar_upper(x >> 60))?;
f.write_char(tochar_upper(x >> 56))?;
f.write_char(tochar_upper(x >> 52))?;
f.write_char(tochar_upper(x >> 48))?;
f.write_char(tochar_upper(x >> 44))?;
f.write_char(tochar_upper(x >> 40))?;
f.write_char(tochar_upper(x >> 36))?;
f.write_char(tochar_upper(x >> 32))?;
f.write_char(tochar_upper(x >> 28))?;
f.write_char(tochar_upper(x >> 24))?;
f.write_char(tochar_upper(x >> 20))?;
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')?
for x in self.values.iter().rev() {
f.write_char(tochar_upper(x >> 60))?;
f.write_char(tochar_upper(x >> 56))?;
f.write_char(tochar_upper(x >> 52))?;
f.write_char(tochar_upper(x >> 48))?;
f.write_char(tochar_upper(x >> 44))?;
f.write_char(tochar_upper(x >> 40))?;
f.write_char(tochar_upper(x >> 36))?;
f.write_char(tochar_upper(x >> 32))?;
f.write_char(tochar_upper(x >> 28))?;
f.write_char(tochar_upper(x >> 24))?;
f.write_char(tochar_upper(x >> 20))?;
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))?;
}
Ok(())
}
@@ -65,66 +60,53 @@ macro_rules! generate_unsigned
impl fmt::LowerHex for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut wrote_something = false;
for x in self.values.iter() {
if !wrote_something && (*x == 0) {
continue;
} else {
f.write_char(tochar_lower(x >> 60))?;
f.write_char(tochar_lower(x >> 56))?;
f.write_char(tochar_lower(x >> 52))?;
f.write_char(tochar_lower(x >> 48))?;
f.write_char(tochar_lower(x >> 44))?;
f.write_char(tochar_lower(x >> 40))?;
f.write_char(tochar_lower(x >> 36))?;
f.write_char(tochar_lower(x >> 32))?;
f.write_char(tochar_lower(x >> 28))?;
f.write_char(tochar_lower(x >> 24))?;
f.write_char(tochar_lower(x >> 20))?;
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')?
for x in self.values.iter().rev() {
f.write_char(tochar_lower(x >> 60))?;
f.write_char(tochar_lower(x >> 56))?;
f.write_char(tochar_lower(x >> 52))?;
f.write_char(tochar_lower(x >> 48))?;
f.write_char(tochar_lower(x >> 44))?;
f.write_char(tochar_lower(x >> 40))?;
f.write_char(tochar_lower(x >> 36))?;
f.write_char(tochar_lower(x >> 32))?;
f.write_char(tochar_lower(x >> 28))?;
f.write_char(tochar_lower(x >> 24))?;
f.write_char(tochar_lower(x >> 20))?;
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))?;
}
Ok(())
}
}
impl $name {
pub fn new() -> $name {
impl CryptoNum for $name {
fn zero() -> $name {
$name{ values: [0; $size/64 ] }
}
pub fn is_odd(&self) -> bool {
fn is_odd(&self) -> bool {
(self.values[0] & 1) == 1
}
pub fn is_even(&self) -> bool {
fn is_even(&self) -> bool {
(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 {
match (x as u8) & (0xF as u8) {
0x0 => '0',
@@ -167,4 +149,52 @@ fn tochar_lower(x: u64) -> char {
0xF => 'f',
_ => 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,
U1024, U2048, U3072, U4096, U8192,
U15360};
use cryptonum::basetypes::*;
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
{
($name: ident) => {
($name: ident, $size: expr) => {
impl PartialEq for $name {
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 {
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 {
fn partial_cmp(&self, other: &$name) -> Option<Ordering> {
Some(bignum_cmp(&self.values, &other.values))
Some(self.cmp(other))
}
}
}
}
generate_compares!(U192);
generate_compares!(U256);
generate_compares!(U384);
generate_compares!(U512);
generate_compares!(U576);
generate_compares!(U1024);
generate_compares!(U2048);
generate_compares!(U3072);
generate_compares!(U4096);
generate_compares!(U8192);
generate_compares!(U15360);
generate_compares!(U192, 192);
generate_compares!(U256, 256);
generate_compares!(U320, 320); // this is just for expansion
generate_compares!(U384, 384);
generate_compares!(U448, 448); // this is just for expansion
generate_compares!(U512, 512);
generate_compares!(U576, 576);
generate_compares!(U640, 640); // this is just for expansion
generate_compares!(U768, 768); // this is just for expansion
generate_compares!(U832, 832); // this is just for Barrett
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,
U1024, U2048, U3072, U4096, U8192,
U15360};
use cryptonum::basetypes::*;
use cryptonum::encoding::Encoder;
use num::bigint::BigUint;
use num::{FromPrimitive,ToPrimitive};
macro_rules! generate_basetype_froms
{
@@ -13,13 +14,33 @@ macro_rules! generate_basetype_froms
impl From<u128> for $name {
fn from(x: u128) -> $name {
let mut base = $name::new();
let mut base = $name::zero();
base.values[0] = x as u64;
base.values[1] = (x >> 64) as u64;
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) => {
impl From<$basetype> for $name {
fn from(x: $basetype) -> $name {
let mut base = $name::new();
let mut base = $name::zero();
base.values[0] = x as u64;
base
}
}
impl From<$name> for $basetype {
fn from(x: $name) -> $basetype {
x.values[0] as $basetype
}
}
}
}
macro_rules! convert_from_smaller
{
($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 {
fn from(x: $smalltype) -> $name {
let mut base = $name::new();
let mut base = $name::zero();
for (idx, val) in x.values.iter().enumerate() {
base.values[idx] = *val;
}
@@ -54,9 +91,9 @@ macro_rules! convert_from_smaller
macro_rules! convert_from_larger
{
($name: ident, $bigtype: ident) => {
impl From<$bigtype> for $name {
fn from(x: $bigtype) -> $name {
let mut base = $name::new();
impl<'a> From<&'a $bigtype> for $name {
fn from(x: &$bigtype) -> $name {
let mut base = $name::zero();
for i in 0..base.values.len() {
base.values[i] = x.values[i];
}
@@ -68,85 +105,39 @@ macro_rules! convert_from_larger
macro_rules! convert_bignums
{
($bigger: ident, $smaller: ident) => {
($smaller: ident, $bigger: ident) => {
convert_from_smaller!($bigger, $smaller);
convert_from_larger!($smaller, $bigger);
}
}
generate_basetype_froms!(U192);
generate_basetype_froms!(U256);
generate_basetype_froms!(U384);
generate_basetype_froms!(U512);
generate_basetype_froms!(U576);
generate_basetype_froms!(U1024);
generate_basetype_froms!(U2048);
generate_basetype_froms!(U3072);
generate_basetype_froms!(U4096);
generate_basetype_froms!(U8192);
generate_basetype_froms!(U15360);
macro_rules! expand_bignums
{
($smaller: ident, $bigger: ident $(, $rest: ident)* ) => {
convert_bignums!($smaller, $bigger);
expand_bignums!($smaller, $($rest),*);
};
($smaller: ident, $(,)*) => {};
() => {}
}
convert_bignums!(U256, U192);
convert_bignums!(U384, U192);
convert_bignums!(U512, U192);
convert_bignums!(U576, U192);
convert_bignums!(U1024, U192);
convert_bignums!(U2048, U192);
convert_bignums!(U3072, U192);
convert_bignums!(U4096, U192);
convert_bignums!(U8192, U192);
convert_bignums!(U15360, U192);
macro_rules! exhaustive_expansion
{
() => {};
($last: ident) => {
generate_basetype_froms!($last);
};
($smallest: ident $(, $other: ident)*) => {
generate_basetype_froms!($smallest);
expand_bignums!($smallest, $($other),*);
exhaustive_expansion!($($other),*);
};
}
convert_bignums!(U384, U256);
convert_bignums!(U512, U256);
convert_bignums!(U576, U256);
convert_bignums!(U1024, U256);
convert_bignums!(U2048, U256);
convert_bignums!(U3072, U256);
convert_bignums!(U4096, U256);
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);
exhaustive_expansion!(U192, U256, U320, U384, U448, U512, U576,
U640, U768, U832, U896, U1024, U1088, U1152,
U1216, U1536, U1664, U2048, U2112, U2176, U2304,
U2432, U3072, U3136, U4096, U4224, U4160, U6144,
U6208, U7680, U7744, U8192, U8256, U8320, U12288,
U12416, U15360, U15424, U16384, U16448, U16512, U30720,
U30784, U32768, U32896, U61440, U61568);

View File

@@ -1,169 +1,172 @@
use cryptonum::comparison::{bignum_cmp,bignum_ge};
use cryptonum::multiplication::raw_multiplication;
use cryptonum::subtraction::raw_subtraction;
use std::cmp::Ordering;
use cryptonum::basetypes::*;
// This is based on algorithm 14.20 from the Handbook of Applied Cryptography,
// slightly modified.
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)
pub trait ModReduce<T=Self> {
fn reduce(&self, value: &T) -> T;
}
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;
for v in x.iter_mut() {
let new_carry = *v >> (64 - amt);
*v = (*v << amt) | carry;
carry = new_carry;
}
if carry != 0 {
x.push(carry);
assert!(carry == 0);
}
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
}
fn matching_bignum_ge(x: &[u64], y: &[u64]) -> bool
{
if x.len() == y.len() {
return bignum_ge(&x, &y);
}
if x.len() > y.len() {
let mut yprime = Vec::with_capacity(x.len());
yprime.extend_from_slice(&y);
while yprime.len() < x.len() { yprime.push(0); }
bignum_ge(&x, &yprime)
} else {
let mut xprime = Vec::with_capacity(y.len());
xprime.extend_from_slice(&x);
while xprime.len() < y.len() { xprime.push(0); }
bignum_ge(&xprime, &y)
}
}
generate_dividers!(U192, U384);
generate_dividers!(U256, U512);
generate_dividers!(U384, U768);
generate_dividers!(U448, U896);
generate_dividers!(U512, U1024);
generate_dividers!(U576, U1152);
generate_dividers!(U768, U1536);
generate_dividers!(U832, U1664);
generate_dividers!(U1024, U2048);
generate_dividers!(U1088, U2176);
generate_dividers!(U1152, U2304);
generate_dividers!(U1216, U2432);
generate_dividers!(U2048, U4096);
generate_dividers!(U2112, U4224);
generate_dividers!(U3072, U6144);
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)]
mod normal {
@@ -202,7 +214,6 @@ mod normal {
use cryptonum::Decoder;
use cryptonum::{U192,U256,U384,U512,U576,U1024,
U2048,U3072,U4096,U8192,U15360};
use super::*;
macro_rules! generate_tests {
($name: ident) => (
@@ -224,11 +235,7 @@ mod normal {
let b = $name::from_bytes(bbytes);
let q = $name::from_bytes(qbytes);
let r = $name::from_bytes(rbytes);
let mut myq = $name::new();
let mut myr = $name::new();
divmod(&a.values, &b.values, &mut myq.values, &mut myr.values);
let (myq, myr) = a.divmod(&b);
assert_eq!(q, myq);
assert_eq!(r, myr);
});
@@ -247,4 +254,4 @@ mod normal {
generate_tests!(U4096);
generate_tests!(U8192);
generate_tests!(U15360);
}
}

View File

@@ -1,11 +1,13 @@
use cryptonum::{U192, U256, U384, U512, U576,
U1024, U2048, U3072, U4096, U8192,
U15360};
use cryptonum::basetypes::*;
pub trait Decoder {
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])
{
let mut item = 0;
@@ -31,7 +33,7 @@ macro_rules! generate_decoder {
($name: ident) => {
impl Decoder for $name {
fn from_bytes(x: &[u8]) -> $name {
let mut res = $name::new();
let mut res = $name::zero();
raw_decoder(x, &mut res.values);
res
}
@@ -39,14 +41,184 @@ macro_rules! generate_decoder {
}
}
generate_decoder!(U192);
generate_decoder!(U256);
generate_decoder!(U384);
generate_decoder!(U512);
generate_decoder!(U576);
generate_decoder!(U1024);
generate_decoder!(U2048);
generate_decoder!(U3072);
generate_decoder!(U4096);
generate_decoder!(U8192);
generate_decoder!(U15360);
macro_rules! generate_encoder {
($name: ident) => {
impl Encoder for $name {
fn to_bytes(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(self.values.len() * 8);
for v in self.values.iter().rev() {
let val = *v;
res.push( (val >> 56) as u8);
res.push( (val >> 48) as u8);
res.push( (val >> 40) as u8);
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 basetypes;
mod comparison;
#[macro_use]
mod conversions;
mod division;
mod encoding;
mod exponentiation;
mod modmath;
mod multiplication;
mod shifts;
mod signed;
mod squaring;
mod subtraction;
pub use self::barrett::*;
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,
U1024, U2048, U3072, U4096, U8192,
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;
}
}
use cryptonum::basetypes::*;
use std::ops::Mul;
macro_rules! generate_multipliers
{
($name: 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
}
}
($name: ident, $bigger: ident, $size: expr) => {
impl<'a,'b> Mul<&'a $name> for &'b $name {
type Output = $name;
type Output = $bigger;
fn mul(self, rhs: &$name) -> $name {
let mut result = self.clone();
result.mul_assign(rhs);
result
}
}
fn mul(self, rhs: &$name) -> $bigger {
let mut w = $bigger::zero();
let len = $size/64;
impl ModMul for $name {
fn modmul(&mut self, x: &$name, m: &$name) {
let mut mulres = [0; $size/32];
raw_multiplication(&self.values, &x.values, &mut mulres);
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(&mulres, &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);
for i in 0..len {
let mut carry = 0;
for j in 0..len {
let old = w.values[i+j] as u128;
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;
}
w.values[i+len] = carry as u64;
}
w
}
}
}
}
generate_multipliers!(U192, 192);
generate_multipliers!(U256, 256);
generate_multipliers!(U384, 384);
generate_multipliers!(U512, 512);
generate_multipliers!(U576, 576);
generate_multipliers!(U1024, 1024);
generate_multipliers!(U2048, 2048);
generate_multipliers!(U3072, 3072);
generate_multipliers!(U4096, 4096);
generate_multipliers!(U8192, 8192);
generate_multipliers!(U15360, 15360);
generate_multipliers!(U192, U384, 192);
generate_multipliers!(U256, U512, 256);
generate_multipliers!(U384, U768, 384);
generate_multipliers!(U448, U896, 448);
generate_multipliers!(U512, U1024, 512);
generate_multipliers!(U576, U1152, 576);
generate_multipliers!(U768, U1536, 768);
generate_multipliers!(U832, U1664, 832);
generate_multipliers!(U1024, U2048, 1024);
generate_multipliers!(U1088, U2176, 1088);
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 {
( $( $name:ident ),* ) => {
( $( ($name:ident, $bigger:ident) ),* ) => {
#[cfg(test)]
mod normal {
use cryptonum::Decoder;
@@ -134,81 +77,27 @@ macro_rules! generate_tests {
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);
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);
let a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let mut c = Vec::with_capacity(a.values.len() * 2);
c.resize(a.values.len() * 2, 0);
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);
let c = $bigger::from_bytes(cbytes);
assert_eq!(&a * &b, c);
});
}
)*
}
#[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::division::divmod;
use cryptonum::basetypes::*;
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".
pub fn raw_square(x: &[u64], result: &mut [u64])
{
assert_eq!(x.len() * 2, result.len());
let t = x.len();
let mut w: Vec<u128> = Vec::with_capacity(t * 2);
w.resize(t * 2, 0);
for i in 0..t {
let x128 = x[i] as u128;
let mut uvb = (w[2*i] as u128) + (x128 * x128);
w[2*i] = uvb & 0xFFFFFFFFFFFFFFFF;
let mut c = uvb >> 64;
for j in (i+1)..t {
let xj128 = x[j] as u128;
let xi128 = x[i] as u128;
// this first product is safely 128 bits or less, because the
// input arguments are both 64 bits.
let xij128 = xj128 * xi128;
// this next bit may overflow, but will do so by exactly one bit.
let twoxij128 = xij128 << 1;
let carried_shl = (xij128 & (1 << 127)) != 0;
// this next bit may *also* overflow, but should also do so by no
// more than one bit.
let (newstuff, carried_add1) = twoxij128.overflowing_add(c);
// ditto ...
let (uvb2, carried_add2) = newstuff.overflowing_add(w[i+j] as u128);
// for the value we're going to save for this digit, we only care
// about the low bits, so we can forget about the carry stuff.
w[i+j] = uvb2 & 0xFFFFFFFFFFFFFFFF;
// for c, though, we do care about the carries, above. Fortunately,
// they were both by only one bit, so we should be able to just
// 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);
for i in 0..t {
let x128 = self.values[i] as u128;
let mut uvb = (w[2*i] as u128) + (x128 * x128);
w[2*i] = uvb & 0xFFFFFFFFFFFFFFFF;
let mut c = uvb >> 64;
for j in (i+1)..t {
let xj128 = self.values[j] as u128;
let xi128 = self.values[i] as u128;
// this first product is safely 128 bits or less,
// because the input arguments are both 64 bits.
let xij128 = xj128 * xi128;
// this next bit may overflow, but will do so by exactly
// one bit.
let twoxij128 = xij128 << 1;
let carried_shl = (xij128 & (1 << 127)) != 0;
// this next bit may *also* overflow, but should also do
// so by no more than one bit.
let (new,carry1) = twoxij128.overflowing_add(c);
// ditto ...
let wij = w[i+j];
let (uvb2,carry2) = new.overflowing_add(wij as u128);
// for the value we're going to save for this digit, we
// only care about the low bits, so we can forget about
// the carry stuff.
w[i+j] = uvb2 & 0xFFFFFFFFFFFFFFFF;
// for c, though, we do care about the carries, above.
// Fortunately, they were both by only one bit, so we
// should be able to just back-fix them.
c = uvb2 >> 64;
if carried_shl { c += 1 << 64; }
if carry1 { c += 1 << 64; }
if carry2 { c += 1 << 64; }
}
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!(U256, 256);
generate_squarers!(U384, 384);
generate_squarers!(U512, 512);
generate_squarers!(U576, 576);
generate_squarers!(U1024, 1024);
generate_squarers!(U2048, 2048);
generate_squarers!(U3072, 3072);
generate_squarers!(U4096, 4096);
generate_squarers!(U8192, 8192);
generate_squarers!(U15360, 15360);
generate_squarers!(U192, U384, 192);
generate_squarers!(U256, U512, 256);
generate_squarers!(U384, U768, 384);
generate_squarers!(U512, U1024, 512);
generate_squarers!(U576, U1152, 576);
generate_squarers!(U1024, U2048, 1024);
generate_squarers!(U2048, U4096, 2048);
generate_squarers!(U3072, U6144, 3072);
generate_squarers!(U4096, U8192, 4096);
generate_squarers!(U8192, U16384, 8192);
generate_squarers!(U15360, U30720,15360);
macro_rules! generate_tests {
( $( $name:ident ),* ) => {
( $( ($name:ident, $bigger:ident) ),* ) => {
#[cfg(test)]
mod normal {
use cryptonum::Decoder;
use cryptonum::encoding::raw_decoder;
use super::*;
use testing::run_test;
@@ -108,40 +92,9 @@ macro_rules! generate_tests {
assert!(!neg0 && !neg1);
let a = $name::from_bytes(abytes);
let mut result = Vec::with_capacity(a.values.len() * 2);
result.resize(a.values.len() * 2, 0);
let mut myresult = result.clone();
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);
let r = $bigger::from_bytes(rbytes);
let myres = a.square();
assert_eq!(r, myres);
});
}
)*
@@ -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,
U1024, U2048, U3072, U4096, U8192,
U15360};
use cryptonum::addition::raw_addition;
use cryptonum::basetypes::*;
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
{
($name: ident) => {
impl SubAssign for $name {
fn sub_assign(&mut self, rhs: $name) {
raw_subtraction(&mut self.values, &rhs.values);
}
}
($name: ident, $size: expr) => {
impl<'a> SubAssign<&'a $name> for $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 {
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> 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
fn sub(mut self, rhs: $name) -> $name {
self -= rhs;
self
}
}
}
}
generate_subbers!(U192);
generate_subbers!(U256);
generate_subbers!(U384);
generate_subbers!(U512);
generate_subbers!(U576);
generate_subbers!(U1024);
generate_subbers!(U2048);
generate_subbers!(U3072);
generate_subbers!(U4096);
generate_subbers!(U8192);
generate_subbers!(U15360);
generate_subbers!(U192, 192);
generate_subbers!(U256, 256);
generate_subbers!(U320, 320); // this is just for expansion
generate_subbers!(U384, 384);
generate_subbers!(U448, 448); // this is just for expansion
generate_subbers!(U512, 512);
generate_subbers!(U576, 576);
generate_subbers!(U640, 640); // this is just for expansion
generate_subbers!(U768, 768); // this is just for expansion
generate_subbers!(U832, 832); // this is just for Barrett
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 {
( $( $name:ident ),* ) => {
@@ -94,13 +124,11 @@ macro_rules! generate_tests {
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);
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;
a -= &b;
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
//! when they should use it, and examples. For now, it mostly just fowards
//! 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)]
//#[macro_use]
//extern crate quickcheck;
/// The cryptonum module provides support for large numbers at fixed,
/// The `cryptonum` module provides support for large numbers at fixed,
/// cryptographically-relevant sizes.
pub mod cryptonum;
/// The `rsa` module provides bare-bones support for RSA signing, verification,
/// encryption, decryption, and key generation.
pub mod rsa;
#[cfg(test)]
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()
}