Checkpoint; not sure where this code is, but I'm rethinking.
This commit is contained in:
@@ -9,7 +9,13 @@ license-file = "LICENSE"
|
||||
repository = "https://github.com/acw/simple_crypto"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "^1.2.3"
|
||||
digest = "^0.7.1"
|
||||
num = "^0.1.42"
|
||||
rand = "^0.3"
|
||||
sha-1 = "^0.7.0"
|
||||
sha2 = "^0.7.0"
|
||||
simple_asn1 = "^0.1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
quickcheck = "^0.4.1"
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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(");
|
||||
// Done!
|
||||
$bname{ k: k, m: resm, mu: mu }
|
||||
}
|
||||
|
||||
pub fn reduce(&self, x: &mut $name) {
|
||||
assert!(self.reduce_ok(&x));
|
||||
// 1. q1←⌊x/bk−1⌋, 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←r−m.
|
||||
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/bk−1⌋, 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←r−m.
|
||||
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/bk−1⌋, 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←r−m.
|
||||
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));
|
||||
|
||||
@@ -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',
|
||||
@@ -168,3 +150,51 @@ fn tochar_lower(x: u64) -> char {
|
||||
_ => 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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,159 +1,152 @@
|
||||
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;
|
||||
|
||||
@@ -162,8 +155,18 @@ fn shiftl(x: &mut Vec<u64>, amt: usize)
|
||||
*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);
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
@@ -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
543
src/cryptonum/modmath.rs
Normal 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←u−v, A←A−C,B←B−D;
|
||||
// otherwise,v←v−u, C←C−A, D←D−B.
|
||||
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 " ";
|
||||
}
|
||||
""
|
||||
}
|
||||
@@ -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
160
src/cryptonum/shifts.rs
Normal 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
311
src/cryptonum/signed.rs
Normal 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);
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
19
src/lib.rs
19
src/lib.rs
@@ -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
48
src/rsa/core.rs
Normal 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
27
src/rsa/errors.rs
Normal 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
92
src/rsa/mod.rs
Normal 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
48
src/rsa/oaep.rs
Normal 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
263
src/rsa/private.rs
Normal 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
404
src/rsa/public.rs
Normal 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
119
src/rsa/signing_hashes.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
use digest::{FixedOutput,Input};
|
||||
use sha1::Sha1;
|
||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||
use std::fmt;
|
||||
|
||||
/// A hash that can be used to sign a message.
|
||||
#[derive(Clone)]
|
||||
pub struct SigningHash {
|
||||
/// The name of this hash (only used for display purposes)
|
||||
pub name: &'static str,
|
||||
/// The approved identity string for the hash.
|
||||
pub ident: &'static [u8],
|
||||
/// The hash
|
||||
pub run: fn(&[u8]) -> Vec<u8>
|
||||
}
|
||||
|
||||
impl fmt::Debug for SigningHash {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
/// The "null" signing hash. This signing hash has no identity, and will
|
||||
/// simply pass the data through unhashed. You really should know what
|
||||
/// you're doing if you use this, and probably using a somewhat strange
|
||||
/// signing protocol. There's no good reason to use this in new code
|
||||
/// for a new protocol or system.
|
||||
pub static SIGNING_HASH_NULL: SigningHash = SigningHash {
|
||||
name: "NULL",
|
||||
ident: &[],
|
||||
run: nohash
|
||||
};
|
||||
|
||||
fn nohash(i: &[u8]) -> Vec<u8> {
|
||||
i.to_vec()
|
||||
}
|
||||
|
||||
/// Sign a hash based on SHA1. You shouldn't use this unless you're using
|
||||
/// very small keys, and this is the only one available to you. Even then,
|
||||
/// why are you using such small keys?!
|
||||
pub static SIGNING_HASH_SHA1: SigningHash = SigningHash {
|
||||
name: "SHA1",
|
||||
ident: &[0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,
|
||||
0x02,0x1a,0x05,0x00,0x04,0x14],
|
||||
run: runsha1
|
||||
};
|
||||
|
||||
fn runsha1(i: &[u8]) -> Vec<u8> {
|
||||
let mut d = Sha1::default();
|
||||
d.process(i);
|
||||
d.fixed_result().as_slice().to_vec()
|
||||
}
|
||||
|
||||
/// Sign a hash based on SHA2-224. This is the first reasonable choice
|
||||
/// we've come across, and is useful when you have smaller RSA key sizes.
|
||||
/// I wouldn't recommend it, though.
|
||||
pub static SIGNING_HASH_SHA224: SigningHash = SigningHash {
|
||||
name: "SHA224",
|
||||
ident: &[0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||
0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,
|
||||
0x1c],
|
||||
run: runsha224
|
||||
};
|
||||
|
||||
fn runsha224(i: &[u8]) -> Vec<u8> {
|
||||
let mut d = Sha224::default();
|
||||
d.process(i);
|
||||
d.fixed_result().as_slice().to_vec()
|
||||
}
|
||||
|
||||
/// Sign a hash based on SHA2-256. The first one I'd recommend!
|
||||
pub static SIGNING_HASH_SHA256: SigningHash = SigningHash {
|
||||
name: "SHA256",
|
||||
ident: &[0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||
0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,
|
||||
0x20],
|
||||
run: runsha256
|
||||
};
|
||||
|
||||
fn runsha256(i: &[u8]) -> Vec<u8> {
|
||||
let mut d = Sha256::default();
|
||||
d.process(i);
|
||||
d.fixed_result().as_slice().to_vec()
|
||||
}
|
||||
|
||||
/// Sign a hash based on SHA2-384. Approximately 50% better than
|
||||
/// SHA-256.
|
||||
pub static SIGNING_HASH_SHA384: SigningHash = SigningHash {
|
||||
name: "SHA384",
|
||||
ident: &[0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||
0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,
|
||||
0x30],
|
||||
run: runsha384
|
||||
};
|
||||
|
||||
fn runsha384(i: &[u8]) -> Vec<u8> {
|
||||
let mut d = Sha384::default();
|
||||
d.process(i);
|
||||
d.fixed_result().as_slice().to_vec()
|
||||
}
|
||||
|
||||
/// Sign a hash based on SHA2-512. At this point, you're getting a bit
|
||||
/// silly. But if you want to through 8kbit RSA keys with a 512 bit SHA2
|
||||
/// signing hash, we're totally behind you.
|
||||
pub static SIGNING_HASH_SHA512: SigningHash = SigningHash {
|
||||
name: "SHA512",
|
||||
ident: &[0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,
|
||||
0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,
|
||||
0x40],
|
||||
run: runsha512
|
||||
};
|
||||
|
||||
fn runsha512(i: &[u8]) -> Vec<u8> {
|
||||
let mut d = Sha512::default();
|
||||
d.process(i);
|
||||
d.fixed_result().as_slice().to_vec()
|
||||
}
|
||||
|
||||
|
||||
104
test.hs
Normal file
104
test.hs
Normal file
@@ -0,0 +1,104 @@
|
||||
import Data.Bits
|
||||
import Numeric
|
||||
|
||||
a :: Integer
|
||||
a = 0xffffffffffffffffffffffffffffffffa275ec6d0ffbb359
|
||||
|
||||
b :: Integer
|
||||
b = 0xffffffffffffffffffffffffffffffffa14e39a19260951d
|
||||
|
||||
outs :: Integer
|
||||
outs = -0x9124a315de33a9
|
||||
|
||||
outt :: Integer
|
||||
outt = 0x180b603717d35f66
|
||||
|
||||
outg :: Integer
|
||||
outg = 1
|
||||
|
||||
x :: Integer
|
||||
y :: Integer
|
||||
g :: Integer
|
||||
(x, y, g) = loop a b 1
|
||||
where loop x y g
|
||||
| even x && even y = loop (x `shiftR` 1) (y `shiftR` 1) (g `shiftL` 1)
|
||||
| otherwise = (x, y, g)
|
||||
|
||||
u0 :: Integer
|
||||
u0 = x
|
||||
|
||||
v0 :: Integer
|
||||
v0 = y
|
||||
|
||||
bigA0 :: Integer
|
||||
bigA0 = 1
|
||||
|
||||
bigB0 :: Integer
|
||||
bigB0 = 0
|
||||
|
||||
bigC0 :: Integer
|
||||
bigC0 = 0
|
||||
|
||||
bigD0 :: Integer
|
||||
bigD0 = 1
|
||||
|
||||
step4 :: (Integer, Integer, Integer, Integer, Integer, Integer) ->
|
||||
(Integer, Integer, Integer, Integer, Integer, Integer)
|
||||
step4 (u, v, bigA, bigB, bigC, bigD) = (resu, v, resA, resB, bigC, bigD)
|
||||
where
|
||||
(resu, resA, resB) = step4 u bigA bigB
|
||||
step4 inu inA inB
|
||||
| even inu = let outu = inu `div` 2
|
||||
in if even inA && even inB
|
||||
then step4 outu (inA `div` 2) (inB `div` 2)
|
||||
else step4 outu ((inA + y) `div` 2) ((inB - x) `div` 2)
|
||||
| otherwise = (inu, inA, inB)
|
||||
|
||||
step5 :: (Integer, Integer, Integer, Integer, Integer, Integer) ->
|
||||
(Integer, Integer, Integer, Integer, Integer, Integer)
|
||||
step5 (u, v, bigA, bigB, bigC, bigD) = (u, resv, bigA, bigB, resC, resD)
|
||||
where
|
||||
(resv, resC, resD) = step5 v bigC bigD
|
||||
step5 inv inC inD
|
||||
| even inv = let outv = inv `div` 2
|
||||
in if even inC && even inD
|
||||
then step5 outv (inC `div` 2) (inD `div` 2)
|
||||
else step5 outv ((inC + y) `div` 2) ((inD - x) `div` 2)
|
||||
| otherwise = (inv, inC, inD)
|
||||
|
||||
step6 :: (Integer, Integer, Integer, Integer, Integer, Integer) ->
|
||||
(Integer, Integer, Integer, Integer, Integer, Integer)
|
||||
step6 (u, v, bigA, bigB, bigC, bigD)
|
||||
| u >= v = (u - v, v, bigA - bigC, bigB - bigD, bigC, bigD)
|
||||
| otherwise = (u, v - u, bigA, bigB, bigC - bigA, bigD - bigB)
|
||||
|
||||
iteration :: (Integer, Integer, Integer, Integer, Integer, Integer) ->
|
||||
(Integer, Integer, Integer, Integer, Integer, Integer)
|
||||
iteration = step6 . step5 . step4
|
||||
|
||||
state0 :: (Integer, Integer, Integer, Integer, Integer, Integer)
|
||||
state0 = (u0, v0, bigA0, bigB0, bigC0, bigD0)
|
||||
|
||||
printIter :: (Integer, Integer, Integer, Integer, Integer, Integer) -> IO ()
|
||||
printIter (u, v, a, b, c, d) =
|
||||
do printVal "u" u
|
||||
printVal "v" v
|
||||
printVal "A" a
|
||||
printVal "B" b
|
||||
printVal "C" c
|
||||
printVal "D" d
|
||||
|
||||
printVal :: String -> Integer -> IO ()
|
||||
printVal name x =
|
||||
do putStr (name ++ ": ")
|
||||
if x < 0
|
||||
then putStr "-"
|
||||
else putStr " "
|
||||
let x' = abs x
|
||||
putStrLn (showHex x' "")
|
||||
|
||||
myImpl inState | u == 0 = outState
|
||||
| otherwise = myImpl outState
|
||||
where
|
||||
outState@(u,_,_,_,_,_) = iteration inState
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Control.Monad
|
||||
import Data.Bits(shiftL,(.&.))
|
||||
import Data.Bits(Bits,shiftL,shiftR,(.&.))
|
||||
import Data.Map.Strict(Map)
|
||||
import qualified Data.Map.Strict as Map
|
||||
import GHC.Integer.GMP.Internals(powModInteger)
|
||||
@@ -14,15 +14,20 @@ testTypes = [("addition", addTest),
|
||||
("modadd", modaddTest),
|
||||
("subtraction", subTest),
|
||||
("multiplication", mulTest),
|
||||
("expandingmul", expmulTest),
|
||||
("modmul", modmulTest),
|
||||
("squaring", squareTest),
|
||||
("modsq", modsqTest),
|
||||
("modexp", modexpTest),
|
||||
("bmodexp", bmodexpTest),
|
||||
("division", divTest),
|
||||
("shift", shiftTest),
|
||||
("sigshr", signedShiftRightTest),
|
||||
("sigadd", signedAddition),
|
||||
("sigsub", signedSubtraction),
|
||||
("barrett_gen", barrettGenTest),
|
||||
("barrett_reduce", barrettReduceTest)
|
||||
("barrett_reduce", barrettReduceTest),
|
||||
("barrett_mul", bmodmulTest),
|
||||
("egcd", egcdTest)
|
||||
]
|
||||
|
||||
bitSizes :: [Int]
|
||||
@@ -40,8 +45,9 @@ splitMod bitsize xs = filtered ++ [m]
|
||||
xs' = map (\x -> x .&. mask bitsize) xs
|
||||
m = maximum xs'
|
||||
filtered = go xs'
|
||||
go (x:xs) | x == m = xs
|
||||
| otherwise = x : go xs
|
||||
go [] = error "Didn't find case in splitMod"
|
||||
go (x:rest) | x == m = rest
|
||||
| otherwise = x : go rest
|
||||
|
||||
addTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
addTest bitsize gen0 = (res, gen2)
|
||||
@@ -50,13 +56,13 @@ addTest bitsize gen0 = (res, gen2)
|
||||
(b, gen2) = random gen1
|
||||
a' = a .&. mask bitsize
|
||||
b' = b .&. mask bitsize
|
||||
c = (a' + b') .&. mask bitsize
|
||||
c = a' + b'
|
||||
res = Map.fromList [("a", showHex a' ""),
|
||||
("b", showHex b' ""),
|
||||
("c", showHex c "")]
|
||||
|
||||
modaddTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
modaddTest bitsize gen0 = (res, gen2)
|
||||
modaddTest bitsize gen0 = (res, gen3)
|
||||
where
|
||||
(a, gen1) = random gen0
|
||||
(b, gen2) = random gen1
|
||||
@@ -82,18 +88,6 @@ subTest bitsize gen0 = (res, gen2)
|
||||
|
||||
mulTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
mulTest bitsize gen0 = (res, gen2)
|
||||
where
|
||||
(a, gen1) = random gen0
|
||||
(b, gen2) = random gen1
|
||||
a' = a .&. mask bitsize
|
||||
b' = b .&. mask bitsize
|
||||
c = (a' * b') .&. mask bitsize
|
||||
res = Map.fromList [("a", showHex a' ""),
|
||||
("b", showHex b' ""),
|
||||
("c", showHex c "")]
|
||||
|
||||
expmulTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
expmulTest bitsize gen0 = (res, gen2)
|
||||
where
|
||||
(a, gen1) = random gen0
|
||||
(b, gen2) = random gen1
|
||||
@@ -105,7 +99,7 @@ expmulTest bitsize gen0 = (res, gen2)
|
||||
("c", showHex c "")]
|
||||
|
||||
modmulTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
modmulTest bitsize gen0 = (res, gen2)
|
||||
modmulTest bitsize gen0 = (res, gen3)
|
||||
where
|
||||
(a, gen1) = random gen0
|
||||
(b, gen2) = random gen1
|
||||
@@ -127,27 +121,35 @@ squareTest bitsize gen0 = (res, gen1)
|
||||
("r", showHex r "")]
|
||||
|
||||
modsqTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
modsqTest bitsize gen0 = (res, gen1)
|
||||
modsqTest bitsize gen0 = (res, gen2)
|
||||
where
|
||||
(a, gen1) = random gen0
|
||||
(m, gen3) = random gen1
|
||||
(m, gen2) = random gen1
|
||||
[a',m'] = splitMod bitsize [a,m]
|
||||
k = computeK m'
|
||||
u = barrett m'
|
||||
r = (a' * a') `mod` m'
|
||||
res = Map.fromList [("a", showHex a' ""),
|
||||
("m", showHex m' ""),
|
||||
("k", showHex k ""),
|
||||
("u", showHex u ""),
|
||||
("r", showHex r "")]
|
||||
|
||||
modexpTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
modexpTest bitsize gen0 = (res, gen2)
|
||||
modexpTest bitsize gen0 = (res, gen3)
|
||||
where
|
||||
(b, gen1) = random gen0
|
||||
(e, gen2) = random gen1
|
||||
(m, gen3) = random gen2
|
||||
[b',e',m'] = splitMod bitsize [b,e,m]
|
||||
k = computeK m'
|
||||
u = barrett m'
|
||||
r = powModInteger b' e' m'
|
||||
res = Map.fromList [("b", showHex b' ""),
|
||||
("e", showHex e' ""),
|
||||
("m", showHex m' ""),
|
||||
("k", showHex k ""),
|
||||
("u", showHex u ""),
|
||||
("r", showHex r "")]
|
||||
|
||||
|
||||
@@ -164,13 +166,77 @@ divTest bitsize gen0 = (res, gen2)
|
||||
("q", showHex q ""),
|
||||
("r", showHex r "")]
|
||||
|
||||
shiftTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
shiftTest bitsize gen0 = (res, gen2)
|
||||
where
|
||||
(a, gen1) = random gen0
|
||||
(b, gen2) = random gen1
|
||||
a' = a .&. mask bitsize
|
||||
b' = b .&. 0xFF
|
||||
r = a' `shiftR` b'
|
||||
l = (a' `shiftL` b') .&. mask bitsize
|
||||
res = Map.fromList [("a", showHex a' ""),
|
||||
("b", showHex b' ""),
|
||||
("r", showHex r ""),
|
||||
("l", showHex l "")]
|
||||
|
||||
signedMask :: (Ord a, Num a, Bits a) => a -> a -> a
|
||||
signedMask x y | x < 0 = -(abs x .&. y)
|
||||
| otherwise = x .&. y
|
||||
|
||||
signedShiftRightTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
signedShiftRightTest bitsize gen0 = (res, gen2)
|
||||
where
|
||||
(a, gen1) = random gen0
|
||||
(b, gen2) = random gen1
|
||||
a' = signedMask a (mask bitsize)
|
||||
b' = b .&. 0xFF
|
||||
x = a' `shiftR` b'
|
||||
prefixA = if a' < 0 then "-" else ""
|
||||
prefixX = if x < 0 then "-" else ""
|
||||
res = Map.fromList [("a", prefixA ++ showHex (abs a') ""),
|
||||
("b", showHex b' ""),
|
||||
("x", prefixX ++ showHex (abs x) "")]
|
||||
|
||||
signedAddition :: Int -> StdGen -> (Map String String, StdGen)
|
||||
signedAddition bitsize gen0 = (res, gen2)
|
||||
where
|
||||
(a, gen1) = random gen0
|
||||
(b, gen2) = random gen1
|
||||
mymask = mask (bitsize - 2)
|
||||
a' = signedMask a mymask
|
||||
b' = signedMask b mymask
|
||||
x = a' + b'
|
||||
prefixA = if a' < 0 then "-" else ""
|
||||
prefixB = if b' < 0 then "-" else ""
|
||||
prefixX = if x < 0 then "-" else ""
|
||||
res = Map.fromList [("a", prefixA ++ showHex (abs a') ""),
|
||||
("b", prefixB ++ showHex (abs b') ""),
|
||||
("x", prefixX ++ showHex (abs x) "")]
|
||||
|
||||
signedSubtraction :: Int -> StdGen -> (Map String String, StdGen)
|
||||
signedSubtraction bitsize gen0 = (res, gen2)
|
||||
where
|
||||
(a, gen1) = random gen0
|
||||
(b, gen2) = random gen1
|
||||
mymask = mask (bitsize - 2)
|
||||
a' = signedMask a mymask
|
||||
b' = signedMask b mymask
|
||||
x = a' - b'
|
||||
prefixA = if a' < 0 then "-" else ""
|
||||
prefixB = if b' < 0 then "-" else ""
|
||||
prefixX = if x < 0 then "-" else ""
|
||||
res = Map.fromList [("a", prefixA ++ showHex (abs a') ""),
|
||||
("b", prefixB ++ showHex (abs b') ""),
|
||||
("x", prefixX ++ showHex (abs x) "")]
|
||||
|
||||
barrettGenTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
barrettGenTest bitsize gen0 = (res, gen1)
|
||||
where
|
||||
(m, gen1) = random gen0
|
||||
m' = m .&. mask bitsize
|
||||
k = computeK m'
|
||||
u = barrett bitsize m'
|
||||
u = barrett m'
|
||||
res = Map.fromList [("m", showHex m' ""),
|
||||
("k", showHex k ""),
|
||||
("u", showHex u "")]
|
||||
@@ -183,7 +249,7 @@ barrettReduceTest bitsize gen0 = (res, gen2)
|
||||
m' = m .&. mask bitsize
|
||||
x' = x .&. mask (min bitsize (2 * k * 64))
|
||||
k = computeK m'
|
||||
u = barrett bitsize m'
|
||||
u = barrett m'
|
||||
r = x' `mod` m'
|
||||
res = Map.fromList [("m", showHex m' ""),
|
||||
("x", showHex x' ""),
|
||||
@@ -191,15 +257,48 @@ barrettReduceTest bitsize gen0 = (res, gen2)
|
||||
("u", showHex u ""),
|
||||
("r", showHex r "")]
|
||||
|
||||
bmodmulTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
bmodmulTest bitsize gen0 = (res, gen3)
|
||||
where
|
||||
(a, gen1) = random gen0
|
||||
(b, gen2) = random gen1
|
||||
(m, gen3) = random gen2
|
||||
[a',b',m'] = splitMod bitsize [a,b,m]
|
||||
k = computeK m'
|
||||
u = barrett m'
|
||||
r = (a' * b') `mod` m'
|
||||
res = Map.fromList [("a", showHex a' ""),
|
||||
("b", showHex b' ""),
|
||||
("m", showHex m' ""),
|
||||
("k", showHex k ""),
|
||||
("u", showHex u ""),
|
||||
("r", showHex r "")]
|
||||
|
||||
egcdTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
egcdTest bitsize gen0 = (res, gen2)
|
||||
where
|
||||
(a, gen1) = random gen0
|
||||
(b, gen2) = random gen1
|
||||
a' = a .&. mask bitsize
|
||||
b' = b .&. mask bitsize
|
||||
g = gcd a b
|
||||
res = Map.fromList [("a", showSignedHex a' ""),
|
||||
("b", showSignedHex b' ""),
|
||||
("g", showSignedHex g "")]
|
||||
|
||||
showSignedHex :: (Integral a, Num a, Show a) => a -> ShowS
|
||||
showSignedHex x str | x < 0 = "-" ++ showHex (abs x) str
|
||||
| otherwise = showHex x str
|
||||
|
||||
bmodexpTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||
bmodexpTest bitsize gen0 = (res, gen2)
|
||||
bmodexpTest bitsize gen0 = (res, gen3)
|
||||
where
|
||||
(b, gen1) = random gen0
|
||||
(e, gen2) = random gen1
|
||||
(m, gen3) = random gen2
|
||||
[b',e',m'] = splitMod bitsize [b,e,m]
|
||||
k = computeK m'
|
||||
u = barrett bitsize m'
|
||||
k = computeK m'
|
||||
u = barrett m'
|
||||
r = powModInteger b' e' m'
|
||||
res = Map.fromList [("b", showHex b' ""),
|
||||
("e", showHex e' ""),
|
||||
@@ -208,18 +307,19 @@ bmodexpTest bitsize gen0 = (res, gen2)
|
||||
("u", showHex u ""),
|
||||
("r", showHex r "")]
|
||||
|
||||
base :: Integer
|
||||
base = 2 ^ (64 :: Integer)
|
||||
|
||||
barrett :: Int -> Integer -> Integer
|
||||
barrett bitsize m = (b ^ (2 * k)) `div` m
|
||||
barrett :: Integer -> Integer
|
||||
barrett m = (base ^ (2 * k)) `div` m
|
||||
where
|
||||
b = 2 ^ 64
|
||||
k = computeK m
|
||||
|
||||
computeK :: Integer -> Int
|
||||
computeK v = go 0 1
|
||||
where
|
||||
go k acc | v < acc = k + 1
|
||||
| otherwise = go (k + 1) (acc * (2 ^ 64))
|
||||
go k acc | v <= acc = k
|
||||
| otherwise = go (k + 1) (acc * base)
|
||||
|
||||
log :: String -> IO ()
|
||||
log str =
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
6000
tests/math/barrett_mulU1024.test
Normal file
6000
tests/math/barrett_mulU1024.test
Normal file
File diff suppressed because it is too large
Load Diff
6000
tests/math/barrett_mulU15360.test
Normal file
6000
tests/math/barrett_mulU15360.test
Normal file
File diff suppressed because it is too large
Load Diff
6000
tests/math/barrett_mulU192.test
Normal file
6000
tests/math/barrett_mulU192.test
Normal file
File diff suppressed because it is too large
Load Diff
6000
tests/math/barrett_mulU2048.test
Normal file
6000
tests/math/barrett_mulU2048.test
Normal file
File diff suppressed because it is too large
Load Diff
6000
tests/math/barrett_mulU256.test
Normal file
6000
tests/math/barrett_mulU256.test
Normal file
File diff suppressed because it is too large
Load Diff
6000
tests/math/barrett_mulU3072.test
Normal file
6000
tests/math/barrett_mulU3072.test
Normal file
File diff suppressed because it is too large
Load Diff
6000
tests/math/barrett_mulU384.test
Normal file
6000
tests/math/barrett_mulU384.test
Normal file
File diff suppressed because it is too large
Load Diff
6000
tests/math/barrett_mulU4096.test
Normal file
6000
tests/math/barrett_mulU4096.test
Normal file
File diff suppressed because it is too large
Load Diff
6000
tests/math/barrett_mulU512.test
Normal file
6000
tests/math/barrett_mulU512.test
Normal file
File diff suppressed because it is too large
Load Diff
6000
tests/math/barrett_mulU576.test
Normal file
6000
tests/math/barrett_mulU576.test
Normal file
File diff suppressed because it is too large
Load Diff
6000
tests/math/barrett_mulU8192.test
Normal file
6000
tests/math/barrett_mulU8192.test
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3000
tests/math/egcdU192.test
Normal file
3000
tests/math/egcdU192.test
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3000
tests/math/egcdU256.test
Normal file
3000
tests/math/egcdU256.test
Normal file
File diff suppressed because it is too large
Load Diff
3000
tests/math/egcdU3072.test
Normal file
3000
tests/math/egcdU3072.test
Normal file
File diff suppressed because it is too large
Load Diff
3000
tests/math/egcdU384.test
Normal file
3000
tests/math/egcdU384.test
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user