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