Start experimenting with full generation of all of the numeric types.
Previously, we used a little bit of generation to drive a lot of Rust macros. This works, but it's a little confusing to read and write. In addition, we used a lot of implementations with variable timings based on their input, which isn't great for crypto. This is the start of an attempt to just generate all of the relevant Rust code directly, and to use timing-channel resistant implementations for most of the routines.
This commit is contained in:
136
old/unsigned/add.rs
Normal file
136
old/unsigned/add.rs
Normal file
@@ -0,0 +1,136 @@
|
||||
pub fn addition(dest: &mut [u64], src: &[u64])
|
||||
{
|
||||
assert_eq!(dest.len(), src.len() + 1);
|
||||
let mut carry: u128 = 0;
|
||||
|
||||
for i in 0..src.len() {
|
||||
let x128 = dest[i] as u128;
|
||||
let y128 = src[i] as u128;
|
||||
let z128 = x128 + y128 + carry;
|
||||
|
||||
dest[i] = z128 as u64;
|
||||
carry = z128 >> 64;
|
||||
}
|
||||
dest[src.len()] = carry as u64;
|
||||
}
|
||||
|
||||
pub fn unsafe_addition(dest: &mut [u64], src: &[u64], really_unsafe: bool)
|
||||
{
|
||||
assert_eq!(dest.len(), src.len());
|
||||
let mut carry: u128 = 0;
|
||||
|
||||
for i in 0..src.len() {
|
||||
let x128 = dest[i] as u128;
|
||||
let y128 = src[i] as u128;
|
||||
let z128 = x128 + y128 + carry;
|
||||
|
||||
dest[i] = z128 as u64;
|
||||
carry = z128 >> 64;
|
||||
}
|
||||
|
||||
if !really_unsafe {
|
||||
assert_eq!(carry, 0, "Unsafe overflow in AddAssign");
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! addition_impls
|
||||
{
|
||||
($base: ident, $bigger: ident) => {
|
||||
impl AddAssign<$base> for $base {
|
||||
fn add_assign(&mut self, rhs: $base) {
|
||||
unsafe_addition(&mut self.value, &rhs.value, false);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AddAssign<&'a $base> for $base {
|
||||
fn add_assign(&mut self, rhs: &$base) {
|
||||
unsafe_addition(&mut self.value, &rhs.value, false);
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<$base> for $base {
|
||||
type Output = $bigger;
|
||||
|
||||
fn add(self, rhs: $base) -> $bigger
|
||||
{
|
||||
let mut dest = $bigger::zero();
|
||||
&dest.value[0..rhs.value.len()].copy_from_slice(&self.value);
|
||||
addition(&mut dest.value, &rhs.value);
|
||||
dest
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Add<&'a $base> for $base {
|
||||
type Output = $bigger;
|
||||
|
||||
fn add(self, rhs: &$base) -> $bigger
|
||||
{
|
||||
let mut dest = $bigger::zero();
|
||||
&dest.value[0..rhs.value.len()].copy_from_slice(&self.value);
|
||||
addition(&mut dest.value, &rhs.value);
|
||||
dest
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Add<$base> for &'a $base {
|
||||
type Output = $bigger;
|
||||
|
||||
fn add(self, rhs: $base) -> $bigger
|
||||
{
|
||||
let mut dest = $bigger::zero();
|
||||
&dest.value[0..rhs.value.len()].copy_from_slice(&self.value);
|
||||
addition(&mut dest.value, &rhs.value);
|
||||
dest
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b> Add<&'a $base> for &'b $base {
|
||||
type Output = $bigger;
|
||||
|
||||
fn add(self, rhs: &$base) -> $bigger
|
||||
{
|
||||
let mut dest = $bigger::zero();
|
||||
&dest.value[0..rhs.value.len()].copy_from_slice(&self.value);
|
||||
addition(&mut dest.value, &rhs.value);
|
||||
dest
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_add_tests {
|
||||
($name: ident, $lname: ident, $plus1: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_add_tests!(body $name, $lname, $plus1);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident, $plus1: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_add_tests!(body $name, $lname, $plus1);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident, $plus1: ident) => {
|
||||
let fname = build_test_path("add", 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 c = $plus1::from_bytes(cbytes);
|
||||
assert_eq!(c, &a + &b);
|
||||
|
||||
if c.value[c.value.len()-1] == 0 {
|
||||
let mut aprime = a.clone();
|
||||
aprime += b;
|
||||
assert_eq!($name::from(c), aprime);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
173
old/unsigned/barrett.rs
Normal file
173
old/unsigned/barrett.rs
Normal file
@@ -0,0 +1,173 @@
|
||||
macro_rules! barrett_impl {
|
||||
($bar: ident, $name: ident, $name64: ident, $dbl: ident, $dbl64: ident) => {
|
||||
#[derive(Clone,PartialEq)]
|
||||
pub struct $bar {
|
||||
pub(crate) k: usize,
|
||||
pub(crate) m: $name64,
|
||||
pub(crate) mu: $name64
|
||||
}
|
||||
|
||||
impl $bar {
|
||||
/// Generate a new Barrett number from the given input. This operation
|
||||
/// is relatively slow, so you should only do it if you plan to use
|
||||
/// reduce() multiple times with the ame number.
|
||||
pub fn new(m: $name) -> $bar {
|
||||
// Step #1: Figure out k
|
||||
let mut k = 0;
|
||||
for i in 0..m.value.len() {
|
||||
if m.value[i] != 0 {
|
||||
k = i;
|
||||
}
|
||||
}
|
||||
k += 1;
|
||||
// Step #2: Compute b
|
||||
let mut b = $dbl64::zero();
|
||||
b.value[2*k] = 1;
|
||||
// Step #3: Divide b by m.
|
||||
let bigm = $dbl64::from(&m);
|
||||
let quot = b / &bigm;
|
||||
let resm = $name64::from(&m);
|
||||
let mu = $name64::from(");
|
||||
// Done!
|
||||
$bar { k: k, m: resm, mu: mu }
|
||||
}
|
||||
|
||||
/// Generate a new Barrett number from its component parts. You
|
||||
/// probably don't want to use it; it's mostly here for debugging
|
||||
/// purposes, so that tests won't have to compute this all the
|
||||
/// time.
|
||||
pub fn from_components(k: usize, m: $name64, mu: $name64) -> $bar {
|
||||
$bar { k: k, m: m, mu: mu }
|
||||
}
|
||||
|
||||
// Reduce the input by this value; in other words, perform a mod
|
||||
// operation.
|
||||
#[inline(always)]
|
||||
pub fn reduce(&self, x: &$dbl) -> $name {
|
||||
// 1. q1←⌊x/bk−1⌋, q2←q1 · μ, q3←⌊q2/bk+1⌋.
|
||||
let q1: $name64 = $name64::from(x >> ((self.k - 1) * 64));
|
||||
let q2 = q1 * &self.mu;
|
||||
let q3: $name64 = $name64::from(q2 >> ((self.k + 1) * 64));
|
||||
// 2. r1←x mod bk+1, r2←q3 · m mod bk+1, r←r1 − r2.
|
||||
let mut r: $dbl64 = $dbl64::from(x);
|
||||
r.mask(self.k + 1);
|
||||
let mut r2: $dbl64 = $dbl64::from(q3 * &self.m);
|
||||
r2.mask(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 = $dbl64::zero();
|
||||
bk1.value[self.k+1] = 1;
|
||||
// this may overflow, and we should probably be OK with it.
|
||||
r += &bk1;
|
||||
}
|
||||
// 4. While r≥m do: r←r−m.
|
||||
let m2 = $dbl64::from(&self.m);
|
||||
while &r > &m2 {
|
||||
r -= &m2;
|
||||
}
|
||||
// Done!
|
||||
$name::from(&r)
|
||||
}
|
||||
}
|
||||
|
||||
impl $name {
|
||||
/// Generate a Barrett number from this number.
|
||||
pub fn generate_barrett(&self) -> $bar {
|
||||
$bar::new(self.clone())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn new_barrett(k: usize, m: $name64, mu: $name64) -> $bar {
|
||||
$bar{ k: k, m: m, mu: mu }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $bar {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct(stringify!($name))
|
||||
.field("k", &self.k)
|
||||
.field("m", &self.m)
|
||||
.field("mu", &self.mu)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_barrett_gen_tests {
|
||||
($name: ident, $lname: ident, $bname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_barrett_gen_tests!(body $name, $lname, $bname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident, $bname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_barrett_gen_tests!(body $name, $lname, $bname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident, $bname: ident) => {
|
||||
let fname = build_test_path("barrett_gen", stringify!($name));
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (neg0, mbytes) = case.get("m").unwrap();
|
||||
let (neg1, kbytes) = case.get("k").unwrap();
|
||||
let (neg2, ubytes) = case.get("u").unwrap();
|
||||
assert!(!neg0 && !neg1 && !neg2);
|
||||
|
||||
let m = $name::from_bytes(mbytes);
|
||||
let kbig = $name::from_bytes(kbytes);
|
||||
let mu = $bname::from_bytes(ubytes);
|
||||
//
|
||||
let mbig = $bname::from(&m);
|
||||
let k = usize::from(&kbig);
|
||||
//
|
||||
let bar = m.generate_barrett();
|
||||
assert_eq!(k, bar.k);
|
||||
assert_eq!(mbig, bar.m);
|
||||
assert_eq!(mu, bar.mu);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_barrett_red_tests {
|
||||
($name: ident, $lname: ident, $bname: ident, $dbl: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_barrett_red_tests!(body $name, $lname, $bname, $dbl);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident, $bname: ident, $dbl: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_barrett_red_tests!(body $name, $lname, $bname, $dbl);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident, $bname: ident, $dbl: ident) => {
|
||||
let fname = build_test_path("barrett_reduce", stringify!($name));
|
||||
run_test(fname.to_string(), 5, |case| {
|
||||
let (neg0, mbytes) = case.get("m").unwrap();
|
||||
let (neg1, kbytes) = case.get("k").unwrap();
|
||||
let (neg2, ubytes) = case.get("u").unwrap();
|
||||
let (neg3, xbytes) = case.get("x").unwrap();
|
||||
let (neg4, rbytes) = case.get("r").unwrap();
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
|
||||
|
||||
let m = $name::from_bytes(mbytes);
|
||||
let kbig = $name::from_bytes(kbytes);
|
||||
let k = usize::from(&kbig);
|
||||
let mu = $bname::from_bytes(ubytes);
|
||||
let bar = $name::new_barrett(usize::from(k), $bname::from(m), mu);
|
||||
let x = $dbl::from_bytes(xbytes);
|
||||
let r = $name::from_bytes(rbytes);
|
||||
//
|
||||
assert_eq!(r, bar.reduce(&x));
|
||||
});
|
||||
};
|
||||
}
|
||||
161
old/unsigned/base.rs
Normal file
161
old/unsigned/base.rs
Normal file
@@ -0,0 +1,161 @@
|
||||
/// A trait definition for large numbers.
|
||||
pub trait CryptoNum {
|
||||
/// Generate a new value of the given type.
|
||||
fn zero() -> Self;
|
||||
/// Test if the number is zero.
|
||||
fn is_zero(&self) -> bool;
|
||||
/// Test if the number is even.
|
||||
fn is_even(&self) -> bool;
|
||||
/// Test if the number is odd.
|
||||
fn is_odd(&self) -> bool;
|
||||
/// The size of this number in bits.
|
||||
fn bit_length() -> usize;
|
||||
/// Mask off the high parts of the number. In particular, it
|
||||
/// zeros the bits above (len * 64).
|
||||
fn mask(&mut self, len: usize);
|
||||
/// Test if the given bit is zero, where bits are numbered in
|
||||
/// least-significant order (0 is the LSB, etc.).
|
||||
fn testbit(&self, bit: usize) -> bool;
|
||||
}
|
||||
|
||||
macro_rules! generate_base
|
||||
{
|
||||
($name: ident, $size: expr) => {
|
||||
#[derive(Clone)]
|
||||
pub struct $name {
|
||||
pub(crate) value: [u64; $size]
|
||||
}
|
||||
|
||||
impl CryptoNum for $name {
|
||||
fn zero() -> $name {
|
||||
$name{ value: [0; $size] }
|
||||
}
|
||||
|
||||
fn bit_length() -> usize {
|
||||
$size * 64
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.value.iter().all(|&x| x == 0)
|
||||
}
|
||||
|
||||
fn is_even(&self) -> bool {
|
||||
(self.value[0] & 0x1) == 0
|
||||
}
|
||||
|
||||
fn is_odd(&self) -> bool {
|
||||
(self.value[0] & 0x1) == 1
|
||||
}
|
||||
|
||||
fn mask(&mut self, len: usize) {
|
||||
let dellen = min(len, $size);
|
||||
for i in dellen..$size {
|
||||
self.value[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fn testbit(&self, bit: usize) -> bool {
|
||||
let idx = bit / 64;
|
||||
let offset = bit % 64;
|
||||
if idx >= $size {
|
||||
return false;
|
||||
}
|
||||
(self.value[idx] & (1u64 << offset)) != 0
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for $name {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> $name {
|
||||
let mut res = $name::zero();
|
||||
|
||||
for val in res.value.iter_mut() {
|
||||
*val = g.next_u64();
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(stringify!($name))?;
|
||||
f.write_str("{")?;
|
||||
f.debug_list().entries(self.value.iter()).finish()?;
|
||||
f.write_str("}")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u64; $size]> for $name {
|
||||
fn from(x: [u64; $size]) -> $name {
|
||||
$name{ value: x }
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr for $name {
|
||||
type Output = $name;
|
||||
|
||||
fn bitor(mut self, rhs: Self) -> Self {
|
||||
for (idx, val) in self.value.iter_mut().enumerate() {
|
||||
*val |= rhs.value[idx];
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl BitAnd for $name {
|
||||
type Output = $name;
|
||||
|
||||
fn bitand(mut self, rhs: Self) -> Self {
|
||||
for (idx, val) in self.value.iter_mut().enumerate() {
|
||||
*val &= rhs.value[idx];
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_base_tests
|
||||
{
|
||||
($name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_base_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_base_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident) => {
|
||||
let fname = build_test_path("base", stringify!($name));
|
||||
run_test(fname.to_string(), 8, |case| {
|
||||
let (neg0, xbytes) = case.get("x").unwrap();
|
||||
let (neg1, mbytes) = case.get("m").unwrap();
|
||||
let (neg2, zbytes) = case.get("z").unwrap();
|
||||
let (neg3, ebytes) = case.get("e").unwrap();
|
||||
let (neg4, obytes) = case.get("o").unwrap();
|
||||
let (neg5, rbytes) = case.get("r").unwrap();
|
||||
let (neg6, bbytes) = case.get("b").unwrap();
|
||||
let (neg7, tbytes) = case.get("t").unwrap();
|
||||
assert!(!neg0&&!neg1&&!neg2&&!neg3&&!neg4&&!neg5&&!neg6&&!neg7);
|
||||
let mut x = $name::from_bytes(xbytes);
|
||||
let m = $name::from_bytes(mbytes);
|
||||
let z = 1 == zbytes[0];
|
||||
let e = 1 == ebytes[0];
|
||||
let o = 1 == obytes[0];
|
||||
let r = $name::from_bytes(rbytes);
|
||||
let b = usize::from($name::from_bytes(bbytes));
|
||||
let t = 1 == tbytes[0];
|
||||
assert_eq!(x.is_zero(), z);
|
||||
assert_eq!(x.is_even(), e);
|
||||
assert_eq!(x.is_odd(), o);
|
||||
assert_eq!(x.testbit(b), t);
|
||||
x.mask(usize::from(&m));
|
||||
assert_eq!(x, r);
|
||||
});
|
||||
}
|
||||
}
|
||||
82
old/unsigned/cmp.rs
Normal file
82
old/unsigned/cmp.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
use std::cmp::*;
|
||||
|
||||
pub fn compare(a: &[u64], b: &[u64]) -> Ordering {
|
||||
assert_eq!(a.len(), b.len(), "Incompatible numbers in comparison");
|
||||
|
||||
let mut i = (a.len() - 1) as isize;
|
||||
|
||||
while i >= 0 {
|
||||
let iu = i as usize;
|
||||
match a[iu].cmp(&b[iu]) {
|
||||
Ordering::Greater => return Ordering::Greater,
|
||||
Ordering::Less => return Ordering::Less,
|
||||
Ordering::Equal => i -= 1
|
||||
}
|
||||
}
|
||||
|
||||
Ordering::Equal
|
||||
}
|
||||
|
||||
macro_rules! cmp_impls {
|
||||
($name: ident) => {
|
||||
impl PartialEq for $name {
|
||||
fn eq(&self, rhs: &$name) -> bool {
|
||||
compare(&self.value, &rhs.value) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for $name {}
|
||||
|
||||
impl PartialOrd for $name {
|
||||
fn partial_cmp(&self, rhs: &$name) -> Option<Ordering> {
|
||||
Some(compare(&self.value, &rhs.value))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for $name {
|
||||
fn cmp(&self, rhs: &$name) -> Ordering {
|
||||
compare(&self.value, &rhs.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_cmp_tests {
|
||||
($name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_cmp_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_cmp_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident) => {
|
||||
let fname = build_test_path("cmp", stringify!($name));
|
||||
run_test(fname.to_string(), 5, |case| {
|
||||
let (neg0, abytes) = case.get("a").unwrap();
|
||||
let (neg1, bbytes) = case.get("b").unwrap();
|
||||
let (neg2, ebytes) = case.get("e").unwrap();
|
||||
let (neg3, gbytes) = case.get("g").unwrap();
|
||||
let (neg4, lbytes) = case.get("l").unwrap();
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
|
||||
let a = $name::from_bytes(abytes);
|
||||
let b = $name::from_bytes(bbytes);
|
||||
let e = 1 == ebytes[0];
|
||||
let g = 1 == gbytes[0];
|
||||
let l = 1 == lbytes[0];
|
||||
|
||||
assert_eq!(e, a == b);
|
||||
assert_eq!(g, a > b);
|
||||
assert_eq!(l, a < b);
|
||||
|
||||
assert_eq!(e || g, a >= b);
|
||||
assert_eq!(e || l, a <= b);
|
||||
});
|
||||
};
|
||||
}
|
||||
90
old/unsigned/codec.rs
Normal file
90
old/unsigned/codec.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
/// Conversion from bytes into the numeric type.
|
||||
pub trait Decoder {
|
||||
fn from_bytes(x: &[u8]) -> Self;
|
||||
}
|
||||
|
||||
/// Conversion from the numeric types into a byte buffer.
|
||||
pub trait Encoder {
|
||||
fn to_bytes(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
pub(crate) fn raw_decoder(input: &[u8], output: &mut [u64])
|
||||
{
|
||||
let mut item = 0;
|
||||
let mut shift = 0;
|
||||
let mut idx = 0;
|
||||
|
||||
for v in input.iter().rev() {
|
||||
item |= (*v as u64) << shift;
|
||||
shift += 8;
|
||||
if shift == 64 {
|
||||
shift = 0;
|
||||
output[idx] = item;
|
||||
idx += 1;
|
||||
item = 0;
|
||||
}
|
||||
}
|
||||
if item != 0 {
|
||||
output[idx] = item;
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_decoder {
|
||||
($name: ident) => {
|
||||
impl Decoder for $name {
|
||||
fn from_bytes(x: &[u8]) -> $name {
|
||||
let mut res = $name::zero();
|
||||
raw_decoder(x, &mut res.value);
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_encoder {
|
||||
($name: ident) => {
|
||||
impl Encoder for $name {
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut res = Vec::with_capacity(self.value.len() * 8);
|
||||
for v in self.value.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);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_codec_tests {
|
||||
($name: ident, $lname: ident) => {
|
||||
#[cfg(test)]
|
||||
mod $lname {
|
||||
use super::super::super::*;
|
||||
|
||||
quickcheck! {
|
||||
fn decode_encode(x: $name) -> bool {
|
||||
let bytes = x.to_bytes();
|
||||
let x2 = $name::from_bytes(&bytes);
|
||||
x == x2
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
103
old/unsigned/conversion.rs
Normal file
103
old/unsigned/conversion.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
macro_rules! generate_base_conversions
|
||||
{
|
||||
($name: ident) => {
|
||||
generate_base_type_convert!($name, u8);
|
||||
generate_base_type_convert!($name, u16);
|
||||
generate_base_type_convert!($name, u32);
|
||||
generate_base_type_convert!($name, u64);
|
||||
generate_base_type_convert!($name, usize);
|
||||
|
||||
impl From<u128> for $name {
|
||||
fn from(x: u128) -> $name {
|
||||
let mut res = $name::zero();
|
||||
res.value[0] = x as u64;
|
||||
res.value[1] = (x >> 64) as u64;
|
||||
res
|
||||
}
|
||||
}
|
||||
};
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_conversion_tests
|
||||
{
|
||||
($name: ident, $lname: ident) => {
|
||||
#[cfg(test)]
|
||||
mod $lname {
|
||||
use super::super::super::*;
|
||||
use std::convert::From;
|
||||
|
||||
quickcheck! {
|
||||
fn conversion_u8( x: u8) -> bool { x == u8::from($name::from(x)) }
|
||||
fn conversion_u16( x: u16) -> bool { x == u16::from($name::from(x)) }
|
||||
fn conversion_u32( x: u32) -> bool { x == u32::from($name::from(x)) }
|
||||
fn conversion_u64( x: u64) -> bool { x == u64::from($name::from(x)) }
|
||||
fn conversion_usize(x: usize) -> bool { x == usize::from($name::from(x)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! conversion_impls
|
||||
{
|
||||
($name: ident, $other: ident) => {
|
||||
impl<'a> From<&'a $other> for $name {
|
||||
fn from(x: &$other) -> $name {
|
||||
let mut res = $name::zero();
|
||||
let len = res.value.len();
|
||||
assert!(x.value.len() > res.value.len());
|
||||
res.value.copy_from_slice(&x.value[0..len]);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a $name> for $other {
|
||||
fn from(x: &$name) -> $other {
|
||||
let mut res = $other::zero();
|
||||
let len = x.value.len();
|
||||
|
||||
assert!(x.value.len() < res.value.len());
|
||||
res.value[0..len].copy_from_slice(&x.value);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$other> for $name {
|
||||
fn from(x: $other) -> $name {
|
||||
$name::from(&x)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$name> for $other {
|
||||
fn from(x: $name) -> $other {
|
||||
$other::from(&x)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! generate_base_type_convert
|
||||
{
|
||||
($name: ident, $base: ident) => {
|
||||
impl From<$base> for $name {
|
||||
fn from(x: $base) -> $name {
|
||||
let mut res = $name::zero();
|
||||
res.value[0] = x as u64;
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$name> for $base {
|
||||
fn from(x: $name) -> $base {
|
||||
x.value[0] as $base
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a $name> for $base {
|
||||
fn from(x: &$name) -> $base {
|
||||
x.value[0] as $base
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
293
old/unsigned/div.rs
Normal file
293
old/unsigned/div.rs
Normal file
@@ -0,0 +1,293 @@
|
||||
/// Concurrent div/mod operations for a number, so that you don't
|
||||
/// have to do them separately.
|
||||
pub trait DivMod
|
||||
where Self: Sized
|
||||
{
|
||||
/// Compute the quotient and remainder of a and b.
|
||||
fn divmod(&self, rhs: &Self) -> (Self, Self);
|
||||
}
|
||||
|
||||
pub fn get_number_size(v: &[u64]) -> Option<usize>
|
||||
{
|
||||
for (idx, val) in v.iter().enumerate().rev() {
|
||||
if *val != 0 {
|
||||
return Some(idx);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
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! div_impls
|
||||
{
|
||||
($name: ident, $dbl: ident) => {
|
||||
impl DivMod for $name {
|
||||
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.value) {
|
||||
None => 0,
|
||||
Some(v) => v
|
||||
};
|
||||
let t = match get_number_size(&rhs.value) {
|
||||
None => panic!("Division by zero!"),
|
||||
Some(v) => v
|
||||
};
|
||||
assert!(t <= n);
|
||||
// now generate mutable versions we can mess with
|
||||
let mut x = $dbl::from(self);
|
||||
let mut y = $dbl::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.value[t].leading_zeros() as usize;
|
||||
if lambda_shift != 0 {
|
||||
let dupx = x.value.clone();
|
||||
let dupy = y.value.clone();
|
||||
|
||||
shiftl(&mut x.value, &dupx, lambda_shift);
|
||||
shiftl(&mut y.value, &dupy, lambda_shift);
|
||||
n = get_number_size(&x.value).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 = $dbl::zero();
|
||||
// 2. While (x >= y * b^(n-t)) do the following:
|
||||
let mut ybnt = $dbl::zero();
|
||||
for i in 0..self.value.len() {
|
||||
ybnt.value[(n-t)+i] = y.value[i];
|
||||
if (n-t)+i >= ybnt.value.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while x > ybnt {
|
||||
q.value[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.value[i] == y.value[t] {
|
||||
// ... then set q[i-t-1] = b - 1
|
||||
q.value[i-t-1] = 0xFFFFFFFFFFFFFFFF;
|
||||
} else {
|
||||
// ... otherwise set q[i-t-1] =
|
||||
// floor((x[i] * b + x[i-1]) / y[t])
|
||||
let xib = (x.value[i] as u128) << 64;
|
||||
let xi1 = safesubidx!(x.value,i,1) as u128;
|
||||
let yt = y.value[t] as u128;
|
||||
let qit1 = (xib + xi1) / yt;
|
||||
q.value[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.value,i-t,1));
|
||||
let mut ybits = U192::zero();
|
||||
ybits.value[0] = safesubidx!(y.value, t, 1);
|
||||
ybits.value[1] = y.value[t];
|
||||
let qiybs = &qit1 * &ybits;
|
||||
let mut xbits = U384::zero();
|
||||
xbits.value[0] = safesubidx!(x.value,i,2);
|
||||
xbits.value[1] = safesubidx!(x.value,i,1);
|
||||
xbits.value[2] = x.value[i];
|
||||
|
||||
if !(&qiybs > &xbits) {
|
||||
break;
|
||||
}
|
||||
|
||||
// ... do q[i-t-1] = q[i-t-1] - 1
|
||||
q.value[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.value[i-t-1] = q.value[i-t-1];
|
||||
let smallery = $name::from(&y);
|
||||
let mut subpart = &smallery * &qbit1;
|
||||
if subpart > x {
|
||||
let mut addback = $dbl::zero();
|
||||
for (idx, val) in y.value.iter().enumerate() {
|
||||
let dest = idx + (i - t - 1);
|
||||
if dest < addback.value.len() {
|
||||
addback.value[dest] = *val;
|
||||
}
|
||||
}
|
||||
q.value[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);
|
||||
let dupr = r.value.clone();
|
||||
shiftr(&mut r.value, &dupr, lambda_shift);
|
||||
// 5. Return (q,r)
|
||||
let resq = $name::from(&q);
|
||||
(resq, r)
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign for $name {
|
||||
fn div_assign(&mut self, rhs: $name) {
|
||||
self.div_assign(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DivAssign<&'a $name> for $name {
|
||||
fn div_assign(&mut self, rhs: &$name) {
|
||||
let (res, _) = self.divmod(&rhs);
|
||||
self.value.copy_from_slice(&res.value);
|
||||
}
|
||||
}
|
||||
|
||||
impl Div for $name {
|
||||
type Output = $name;
|
||||
|
||||
fn div(self, rhs: $name) -> $name {
|
||||
let (res, _) = self.divmod(&rhs);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Div<&'a $name> for $name {
|
||||
type Output = $name;
|
||||
|
||||
fn div(self, rhs: &$name) -> $name {
|
||||
let (res, _) = self.divmod(rhs);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Div<$name> for &'a $name {
|
||||
type Output = $name;
|
||||
|
||||
fn div(self, rhs: $name) -> $name {
|
||||
let (res, _) = self.divmod(&rhs);
|
||||
res
|
||||
}
|
||||
}
|
||||
impl<'a,'b> Div<&'a $name> for &'b $name {
|
||||
type Output = $name;
|
||||
|
||||
fn div(self, rhs: &$name) -> $name {
|
||||
let (res, _) = self.divmod(rhs);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl RemAssign for $name {
|
||||
fn rem_assign(&mut self, rhs: $name) {
|
||||
self.rem_assign(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RemAssign<&'a $name> for $name {
|
||||
fn rem_assign(&mut self, rhs: &$name) {
|
||||
let (_, res) = self.divmod(rhs);
|
||||
self.value.copy_from_slice(&res.value);
|
||||
}
|
||||
}
|
||||
|
||||
impl Rem for $name {
|
||||
type Output = $name;
|
||||
|
||||
fn rem(self, rhs: $name) -> $name {
|
||||
let (_, res) = self.divmod(&rhs);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Rem<&'a $name> for $name {
|
||||
type Output = $name;
|
||||
|
||||
fn rem(self, rhs: &$name) -> $name {
|
||||
let (_, res) = self.divmod(&rhs);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Rem<$name> for &'a $name {
|
||||
type Output = $name;
|
||||
|
||||
fn rem(self, rhs: $name) -> $name {
|
||||
let (_, res) = self.divmod(&rhs);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b> Rem<&'a $name> for &'b $name {
|
||||
type Output = $name;
|
||||
|
||||
fn rem(self, rhs: &$name) -> $name {
|
||||
let (_, res) = self.divmod(&rhs);
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_div_tests {
|
||||
($name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_div_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_div_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident) => {
|
||||
let fname = build_test_path("div", 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, qbytes) = case.get("q").unwrap();
|
||||
let (neg3, rbytes) = case.get("r").unwrap();
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3);
|
||||
|
||||
let a = $name::from_bytes(abytes);
|
||||
let b = $name::from_bytes(bbytes);
|
||||
let q = $name::from_bytes(qbytes);
|
||||
let r = $name::from_bytes(rbytes);
|
||||
let (myq, myr) = a.divmod(&b);
|
||||
assert_eq!(q, myq);
|
||||
assert_eq!(r, myr);
|
||||
let mut a2 = a.clone();
|
||||
a2 /= &b;
|
||||
assert_eq!(a2, q);
|
||||
let mut a3 = a.clone();
|
||||
a3 %= &b;
|
||||
assert_eq!(a3, r);
|
||||
});
|
||||
};
|
||||
}
|
||||
73
old/unsigned/formatter.rs
Normal file
73
old/unsigned/formatter.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
macro_rules! generate_formatter {
|
||||
($name: ident) => {
|
||||
impl fmt::UpperHex for $name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for x in self.value.iter().rev() {
|
||||
f.write_char(tochar(true, x >> 60))?;
|
||||
f.write_char(tochar(true, x >> 56))?;
|
||||
f.write_char(tochar(true, x >> 52))?;
|
||||
f.write_char(tochar(true, x >> 48))?;
|
||||
f.write_char(tochar(true, x >> 44))?;
|
||||
f.write_char(tochar(true, x >> 40))?;
|
||||
f.write_char(tochar(true, x >> 36))?;
|
||||
f.write_char(tochar(true, x >> 32))?;
|
||||
f.write_char(tochar(true, x >> 28))?;
|
||||
f.write_char(tochar(true, x >> 24))?;
|
||||
f.write_char(tochar(true, x >> 20))?;
|
||||
f.write_char(tochar(true, x >> 16))?;
|
||||
f.write_char(tochar(true, x >> 12))?;
|
||||
f.write_char(tochar(true, x >> 8))?;
|
||||
f.write_char(tochar(true, x >> 4))?;
|
||||
f.write_char(tochar(true, x >> 0))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::LowerHex for $name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for x in self.value.iter().rev() {
|
||||
f.write_char(tochar(false, x >> 60))?;
|
||||
f.write_char(tochar(false, x >> 56))?;
|
||||
f.write_char(tochar(false, x >> 52))?;
|
||||
f.write_char(tochar(false, x >> 48))?;
|
||||
f.write_char(tochar(false, x >> 44))?;
|
||||
f.write_char(tochar(false, x >> 40))?;
|
||||
f.write_char(tochar(false, x >> 36))?;
|
||||
f.write_char(tochar(false, x >> 32))?;
|
||||
f.write_char(tochar(false, x >> 28))?;
|
||||
f.write_char(tochar(false, x >> 24))?;
|
||||
f.write_char(tochar(false, x >> 20))?;
|
||||
f.write_char(tochar(false, x >> 16))?;
|
||||
f.write_char(tochar(false, x >> 12))?;
|
||||
f.write_char(tochar(false, x >> 8))?;
|
||||
f.write_char(tochar(false, x >> 4))?;
|
||||
f.write_char(tochar(false, x >> 0))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn tochar(upper: bool, val: u64) -> char {
|
||||
match val & 0xF {
|
||||
0x0 => '0',
|
||||
0x1 => '1',
|
||||
0x2 => '2',
|
||||
0x3 => '3',
|
||||
0x4 => '4',
|
||||
0x5 => '5',
|
||||
0x6 => '6',
|
||||
0x7 => '7',
|
||||
0x8 => '8',
|
||||
0x9 => '9',
|
||||
0xA => if upper { 'A' } else { 'a' },
|
||||
0xB => if upper { 'B' } else { 'b' },
|
||||
0xC => if upper { 'C' } else { 'c' },
|
||||
0xD => if upper { 'D' } else { 'd' },
|
||||
0xE => if upper { 'E' } else { 'e' },
|
||||
0xF => if upper { 'F' } else { 'f' },
|
||||
_ => panic!("The world is broken, rejoice, rejoice.")
|
||||
}
|
||||
}
|
||||
1670
old/unsigned/invoc.rs
Normal file
1670
old/unsigned/invoc.rs
Normal file
File diff suppressed because it is too large
Load Diff
104
old/unsigned/mod.rs
Normal file
104
old/unsigned/mod.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
//! This module includes a large number of unsigned integer types for very
|
||||
//! large integers, designed to try to match good performance with a high
|
||||
//! assurance threshold.
|
||||
//!
|
||||
//! The types provided in this module, and the functions available for each
|
||||
//! of those types, is derived from standard bit widths for RSA, DSA, and
|
||||
//! Elliptic Curve encryption schemes. If this library does not include a
|
||||
//! function you would like for another cryptographic scheme, please reach
|
||||
//! out to the authors; in many cases, the relevant code can be automatically
|
||||
//! generated.
|
||||
//!
|
||||
//! For performance reasons, we also include support for Barrett reduction,
|
||||
//! which should improve the speed of modular reduction of large numbers for
|
||||
//! those cases in which you will be frequently performing modulo operations
|
||||
//! using the same modulus.
|
||||
#[macro_use]
|
||||
mod add;
|
||||
#[macro_use]
|
||||
mod barrett;
|
||||
#[macro_use]
|
||||
mod base;
|
||||
#[macro_use]
|
||||
mod cmp;
|
||||
#[macro_use]
|
||||
mod codec;
|
||||
#[macro_use]
|
||||
mod conversion;
|
||||
#[macro_use]
|
||||
mod div;
|
||||
#[macro_use]
|
||||
mod formatter;
|
||||
#[macro_use]
|
||||
mod modexp;
|
||||
#[macro_use]
|
||||
mod modmul;
|
||||
#[macro_use]
|
||||
mod modsq;
|
||||
#[macro_use]
|
||||
mod mul;
|
||||
#[macro_use]
|
||||
mod primes;
|
||||
#[macro_use]
|
||||
mod rand;
|
||||
#[macro_use]
|
||||
mod scale;
|
||||
#[macro_use]
|
||||
mod shifts;
|
||||
#[macro_use]
|
||||
mod sqrt;
|
||||
#[macro_use]
|
||||
mod square;
|
||||
#[macro_use]
|
||||
mod sub;
|
||||
|
||||
pub use self::base::CryptoNum;
|
||||
pub use self::codec::{Encoder,Decoder};
|
||||
pub use self::div::DivMod;
|
||||
pub use self::modexp::ModExp;
|
||||
pub use self::modmul::ModMul;
|
||||
pub use self::modsq::ModSquare;
|
||||
pub use self::primes::PrimeGen;
|
||||
pub use self::square::Square;
|
||||
pub use self::sqrt::SquareRoot;
|
||||
|
||||
pub(crate) use self::add::unsafe_addition;
|
||||
pub(crate) use self::scale::scale;
|
||||
|
||||
use rand::{Rng,RngCore};
|
||||
use rand::distributions::{Distribution,Standard};
|
||||
use rand::distributions::uniform::*;
|
||||
use self::add::addition;
|
||||
use self::cmp::compare;
|
||||
use self::codec::raw_decoder;
|
||||
use self::div::get_number_size;
|
||||
use self::formatter::tochar;
|
||||
use self::mul::{multiply,multiply_small};
|
||||
use self::primes::SMALL_PRIMES;
|
||||
use self::shifts::{shiftl,shiftr};
|
||||
use self::sub::subtract;
|
||||
use std::cmp::{Ordering,min};
|
||||
use std::fmt;
|
||||
use std::fmt::Write;
|
||||
use std::ops::{Add,AddAssign};
|
||||
use std::ops::{Mul,MulAssign};
|
||||
use std::ops::{Div,DivAssign};
|
||||
use std::ops::{Rem,RemAssign};
|
||||
use std::ops::{Shl,ShlAssign,Shr,ShrAssign};
|
||||
use std::ops::{Sub,SubAssign};
|
||||
use std::ops::{BitAnd,BitOr};
|
||||
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
|
||||
macro_rules! base_impls
|
||||
{
|
||||
($name: ident, $size: expr) => {
|
||||
generate_base!($name, $size);
|
||||
generate_base_conversions!($name);
|
||||
generate_codec!($name);
|
||||
generate_formatter!($name);
|
||||
cmp_impls!($name);
|
||||
}
|
||||
}
|
||||
|
||||
include!("invoc.rs");
|
||||
116
old/unsigned/modexp.rs
Normal file
116
old/unsigned/modexp.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
/// Modular exponentiation for a value.
|
||||
pub trait ModExp<T> {
|
||||
/// Modular exponentiation using the given modulus type. If it's possible,
|
||||
/// we suggest using Barrett values, which are much faster than doing
|
||||
/// modulo with the number types.
|
||||
fn modexp(&self, e: &Self, m: &T) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! modexp_impls {
|
||||
($name: ident, $other: ident) => {
|
||||
impl ModExp<$other> for $name {
|
||||
fn modexp(&self, ine: &$name, m: &$other) -> $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.value.iter().any(|x| *x != 0) {
|
||||
// If e is odd then A <- A * S
|
||||
if e.value[0] & 1 != 0 {
|
||||
a = a.modmul(&s, m);
|
||||
}
|
||||
// e <- floor(e / 2)
|
||||
let mut carry = 0;
|
||||
e.value.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 = s.modsq(m);
|
||||
}
|
||||
// Return A
|
||||
a
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_modexp_tests {
|
||||
($name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_modexp_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_modexp_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident) => {
|
||||
let fname = build_test_path("modexp", 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);
|
||||
assert_eq!(r, b.modexp(&e, &m));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_barrett_modexp_tests {
|
||||
(ignore $name: ident, $lname: ident, $bname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_barrett_modexp_tests!(body $name, $lname, $bname);
|
||||
}
|
||||
};
|
||||
($name: ident, $lname: ident, $bname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_barrett_modexp_tests!(body $name, $lname, $bname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident, $bname: ident) => {
|
||||
let fname = build_test_path("modexp", 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 = $name::from_bytes(mbytes);
|
||||
let r = $name::from_bytes(rbytes);
|
||||
let kbig = $name::from_bytes(kbytes);
|
||||
let k = usize::from(kbig);
|
||||
let mu = $bname::from_bytes(ubytes);
|
||||
let bar = $name::new_barrett(k, $bname::from(m), mu);
|
||||
|
||||
if k == b.value.len() {
|
||||
assert_eq!(r, b.modexp(&e, &bar));
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
104
old/unsigned/modmul.rs
Normal file
104
old/unsigned/modmul.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
/// Modular multiplication of the type.
|
||||
pub trait ModMul<T> {
|
||||
/// Modular multiplication using the given modulus type. If it's possible,
|
||||
/// we suggest using Barrett values, which are much faster than doing
|
||||
/// modulo with the number types.
|
||||
fn modmul(&self, x: &Self, m: &T) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! modmul_impls {
|
||||
($name: ident, $dbl: ident, $barrett: ident) => {
|
||||
impl ModMul<$name> for $name {
|
||||
fn modmul(&self, x: &$name, m: &$name) -> $name {
|
||||
let mulres = (self as &$name) * x;
|
||||
let bigm = $dbl::from(m);
|
||||
let (_, bigres) = mulres.divmod(&bigm);
|
||||
$name::from(bigres)
|
||||
}
|
||||
}
|
||||
|
||||
impl ModMul<$barrett> for $name {
|
||||
fn modmul(&self, x: &$name, m: &$barrett) -> $name {
|
||||
let mulres = (self as &$name) * x;
|
||||
m.reduce(&mulres)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_modmul_tests {
|
||||
($name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_modmul_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_modmul_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident) => {
|
||||
let fname = build_test_path("modmul", 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, cbytes) = case.get("c").unwrap();
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3);
|
||||
|
||||
let a = $name::from_bytes(abytes);
|
||||
let b = $name::from_bytes(bbytes);
|
||||
let m = $name::from_bytes(mbytes);
|
||||
let c = $name::from_bytes(cbytes);
|
||||
assert_eq!(c, a.modmul(&b, &m));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_barrett_modmul_tests {
|
||||
($name: ident, $lname: ident, $bname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_barrett_modmul_tests!(body $name, $lname, $bname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident, $bname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_barrett_modmul_tests!(body $name, $lname, $bname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident, $bname: ident) => {
|
||||
let fname = build_test_path("modmul", 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, cbytes) = case.get("c").unwrap();
|
||||
let (neg4, kbytes) = case.get("k").unwrap();
|
||||
let (neg5, ubytes) = case.get("u").unwrap();
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5);
|
||||
|
||||
let a = $name::from_bytes(abytes);
|
||||
let b = $name::from_bytes(bbytes);
|
||||
let m = $name::from_bytes(mbytes);
|
||||
let c = $name::from_bytes(cbytes);
|
||||
let kbig = $name::from_bytes(kbytes);
|
||||
let k = usize::from(kbig);
|
||||
let mu = $bname::from_bytes(ubytes);
|
||||
let bar = $name::new_barrett(k, $bname::from(m), mu);
|
||||
|
||||
if k == a.value.len() {
|
||||
assert_eq!(c, a.modmul(&b, &bar));
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
};
|
||||
}
|
||||
98
old/unsigned/modsq.rs
Normal file
98
old/unsigned/modsq.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
/// Modular squaring
|
||||
pub trait ModSquare<T> {
|
||||
/// Modular squaring using the given modulus type. If it's possible,
|
||||
/// we suggest using Barrett values, which are much faster than doing
|
||||
/// modulo with the number types.
|
||||
fn modsq(&self, m: &T) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! modsq_impls {
|
||||
($name: ident, $dbl: ident, $barrett: ident) => {
|
||||
impl ModSquare<$name> for $name {
|
||||
fn modsq(&self, m: &$name) -> $name {
|
||||
let bigsquare = self.square();
|
||||
let bigm = $dbl::from(m);
|
||||
let (_, res) = bigsquare.divmod(&bigm);
|
||||
$name::from(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl ModSquare<$barrett> for $name {
|
||||
fn modsq(&self, m: &$barrett) -> $name {
|
||||
let bigsquare = self.square();
|
||||
m.reduce(&bigsquare)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_modsq_tests {
|
||||
($name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_modsq_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_modsq_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident) => {
|
||||
let fname = build_test_path("modsq", stringify!($name));
|
||||
run_test(fname.to_string(), 5, |case| {
|
||||
let (neg0, abytes) = case.get("a").unwrap();
|
||||
let (neg1, mbytes) = case.get("m").unwrap();
|
||||
let (neg2, cbytes) = case.get("c").unwrap();
|
||||
assert!(!neg0 && !neg1 && !neg2);
|
||||
|
||||
let a = $name::from_bytes(abytes);
|
||||
let m = $name::from_bytes(mbytes);
|
||||
let c = $name::from_bytes(cbytes);
|
||||
assert_eq!(c, a.modsq(&m));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_barrett_modsq_tests {
|
||||
($name: ident, $lname: ident, $bname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_barrett_modsq_tests!(body $name, $lname, $bname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident, $bname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_barrett_modsq_tests!(body $name, $lname, $bname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident, $bname: ident) => {
|
||||
let fname = build_test_path("modsq", stringify!($name));
|
||||
run_test(fname.to_string(), 5, |case| {
|
||||
let (neg0, abytes) = case.get("a").unwrap();
|
||||
let (neg1, mbytes) = case.get("m").unwrap();
|
||||
let (neg2, cbytes) = case.get("c").unwrap();
|
||||
let (neg3, kbytes) = case.get("k").unwrap();
|
||||
let (neg4, ubytes) = case.get("u").unwrap();
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
|
||||
|
||||
let a = $name::from_bytes(abytes);
|
||||
let m = $name::from_bytes(mbytes);
|
||||
let c = $name::from_bytes(cbytes);
|
||||
let kbig = $name::from_bytes(kbytes);
|
||||
let k = usize::from(kbig);
|
||||
let mu = $bname::from_bytes(ubytes);
|
||||
let bar = $name::new_barrett(k, $bname::from(m), mu);
|
||||
|
||||
if k == a.value.len() {
|
||||
assert_eq!(c, a.modsq(&bar));
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
142
old/unsigned/mul.rs
Normal file
142
old/unsigned/mul.rs
Normal file
@@ -0,0 +1,142 @@
|
||||
pub fn multiply(dest: &mut [u64], left: &[u64], right: &[u64])
|
||||
{
|
||||
let len = right.len();
|
||||
let mut i = 0;
|
||||
|
||||
assert_eq!(left.len(), len, "Uneven argument lengths in multiply");
|
||||
assert_eq!(dest.len(), len*2, "Bad destination size in multiply");
|
||||
|
||||
while i < len {
|
||||
let mut carry = 0;
|
||||
let mut j = 0;
|
||||
|
||||
while j < len {
|
||||
let old = dest[i+j] as u128;
|
||||
let l128 = left[j] as u128;
|
||||
let r128 = right[i] as u128;
|
||||
let uv = old + (l128 * r128) + carry;
|
||||
dest[i+j] = uv as u64;
|
||||
carry = uv >> 64;
|
||||
j += 1;
|
||||
}
|
||||
dest[i+len] = carry as u64;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn multiply_small(dest: &mut [u64], left: &[u64], right: &[u64])
|
||||
{
|
||||
let len = right.len();
|
||||
|
||||
assert_eq!(dest.len(), len);
|
||||
assert_eq!(left.len(), len);
|
||||
for i in 0..len { dest[i] = 0; }
|
||||
for i in 0..len {
|
||||
let mut carry = 0;
|
||||
|
||||
for j in 0..len {
|
||||
if i+j >= len {
|
||||
carry = 0;
|
||||
continue;
|
||||
}
|
||||
let old = dest[i+j] as u128;
|
||||
let l128 = left[j] as u128;
|
||||
let r128 = right[i] as u128;
|
||||
let uv = old + (l128 * r128) + carry;
|
||||
dest[i+j] = uv as u64;
|
||||
carry = uv >> 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! multiply_impls {
|
||||
($name: ident, $dbl: ident) => {
|
||||
impl Mul<$name> for $name {
|
||||
type Output = $dbl;
|
||||
|
||||
fn mul(self, rhs: $name) -> $dbl {
|
||||
let mut res = $dbl::zero();
|
||||
multiply(&mut res.value, &self.value, &rhs.value);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Mul<$name> for &'a $name {
|
||||
type Output = $dbl;
|
||||
|
||||
fn mul(self, rhs: $name) -> $dbl {
|
||||
let mut res = $dbl::zero();
|
||||
multiply(&mut res.value, &self.value, &rhs.value);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Mul<&'a $name> for $name {
|
||||
type Output = $dbl;
|
||||
|
||||
fn mul(self, rhs: &$name) -> $dbl {
|
||||
let mut res = $dbl::zero();
|
||||
multiply(&mut res.value, &self.value, &rhs.value);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b> Mul<&'a $name> for &'b $name {
|
||||
type Output = $dbl;
|
||||
|
||||
fn mul(self, rhs: &$name) -> $dbl {
|
||||
let mut res = $dbl::zero();
|
||||
multiply(&mut res.value, &self.value, &rhs.value);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign for $name {
|
||||
fn mul_assign(&mut self, rhs: $name) {
|
||||
let copy = self.value.clone();
|
||||
multiply_small(&mut self.value, ©, &rhs.value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MulAssign<&'a $name> for $name {
|
||||
fn mul_assign(&mut self, rhs: &$name) {
|
||||
let copy = self.value.clone();
|
||||
multiply_small(&mut self.value, ©, &rhs.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_mul_tests
|
||||
{
|
||||
($name: ident, $lname: ident, $dbl: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_mul_tests!(body $name, $lname, $dbl);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident, $dbl: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_mul_tests!(body $name, $lname, $dbl);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident, $dbl: ident) => {
|
||||
let fname = build_test_path("mul", 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 mut a = $name::from_bytes(abytes);
|
||||
let b = $name::from_bytes(bbytes);
|
||||
let c = $dbl::from_bytes(cbytes);
|
||||
assert_eq!(c, &a * &b, "standard multiplication");
|
||||
a *= b;
|
||||
assert_eq!($name::from(c), a);
|
||||
});
|
||||
};
|
||||
}
|
||||
145
old/unsigned/primes.rs
Normal file
145
old/unsigned/primes.rs
Normal file
@@ -0,0 +1,145 @@
|
||||
use rand::RngCore;
|
||||
|
||||
/// Functions related to the generation of random numbers and primes.
|
||||
pub trait PrimeGen: Sized + PartialOrd {
|
||||
/// Generate a random prime number, using the given RNG and running
|
||||
/// the primality check for the given number of iterations. This is
|
||||
/// equivalent to calling `random_primef` with the identity function
|
||||
/// as the modifier.
|
||||
fn random_prime<R: RngCore>(rng: &mut R, iters: usize) -> Self {
|
||||
Self::random_primef(rng, iters, |x| Some(x))
|
||||
}
|
||||
/// Generate a random prime number, using a modification function
|
||||
/// and running the primality check for the given number of iterations.
|
||||
/// The modifier function is run after the routine generates a random
|
||||
/// number, but before the primality check, and can be used to force
|
||||
/// the return value to have certain properties: the low bit set, the
|
||||
/// high bit set, and/or the number is above a certain value.
|
||||
fn random_primef<F,R>(rng: &mut R, iters: usize, prep: F) -> Self
|
||||
where F: Fn(Self) -> Option<Self>, R: RngCore;
|
||||
/// Determine if the given number is probably prime. This should be
|
||||
/// an implementation of Miller-Rabin, with some quick sanity checks,
|
||||
/// over the given number of iterations.
|
||||
fn probably_prime<R: RngCore>(&self, rng: &mut R, iters: usize) -> bool;
|
||||
}
|
||||
|
||||
pub static SMALL_PRIMES: [u64; 310] = [
|
||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
|
||||
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
|
||||
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
|
||||
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
|
||||
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
|
||||
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
|
||||
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
|
||||
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
|
||||
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
|
||||
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
|
||||
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
|
||||
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
|
||||
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
|
||||
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
|
||||
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
|
||||
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
|
||||
947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013,
|
||||
1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069,
|
||||
1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
|
||||
1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
|
||||
1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
|
||||
1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373,
|
||||
1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
|
||||
1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
|
||||
1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583,
|
||||
1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657,
|
||||
1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
|
||||
1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
|
||||
1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,
|
||||
1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987,
|
||||
1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053];
|
||||
|
||||
macro_rules! prime_gen_impls {
|
||||
($name: ident) => {
|
||||
impl PrimeGen for $name {
|
||||
fn random_primef<F,R>(rng: &mut R, iters: usize, modifier: F) -> Self
|
||||
where
|
||||
F: Fn($name) -> Option<$name>,
|
||||
R: RngCore
|
||||
{
|
||||
loop {
|
||||
let base = rng.gen();
|
||||
|
||||
if let Some(candidate) = modifier(base) {
|
||||
let good = candidate.probably_prime(rng, iters);
|
||||
|
||||
if good {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn probably_prime<R: RngCore>(&self, rng: &mut R, iters: usize) -> bool
|
||||
{
|
||||
for tester in SMALL_PRIMES.iter() {
|
||||
if self.is_multiple_of(*tester) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.miller_rabin(rng, iters)
|
||||
}
|
||||
}
|
||||
|
||||
impl $name {
|
||||
fn miller_rabin<R: RngCore>(&self, rng: &mut R, iters: usize) -> bool
|
||||
{
|
||||
let one = $name::from(1u64);
|
||||
let two = $name::from(2u64);
|
||||
let nm1 = self - $name::from(1u64);
|
||||
// Quoth Wikipedia:
|
||||
// write n - 1 as 2^r*d with d odd by factoring powers of 2 from n - 1
|
||||
let mut d = nm1.clone();
|
||||
let mut r = 0;
|
||||
while d.is_even() {
|
||||
d >>= 1;
|
||||
r += 1;
|
||||
assert!(r < $name::bit_length());
|
||||
}
|
||||
// WitnessLoop: repeat k times
|
||||
'WitnessLoop: for _k in 0..iters {
|
||||
// pick a random integer a in the range [2, n - 2]
|
||||
let a = rng.gen_range(&two, &nm1);
|
||||
// x <- a^d mod n
|
||||
let mut x = a.modexp(&d, self);
|
||||
// if x = 1 or x = n - 1 then
|
||||
if (&x == &one) || (&x == &nm1) {
|
||||
// continue WitnessLoop
|
||||
continue 'WitnessLoop;
|
||||
}
|
||||
// repeat r - 1 times:
|
||||
for _i in 0..r {
|
||||
// x <- x^2 mod n
|
||||
x = x.modexp(&two, self);
|
||||
// if x = 1 then
|
||||
if &x == &one {
|
||||
// return composite
|
||||
return false;
|
||||
}
|
||||
// if x = n - 1 then
|
||||
if &x == &nm1 {
|
||||
// continue WitnessLoop
|
||||
continue 'WitnessLoop;
|
||||
}
|
||||
}
|
||||
// return composite
|
||||
return false;
|
||||
}
|
||||
// return probably prime
|
||||
true
|
||||
}
|
||||
|
||||
fn is_multiple_of(&self, x: u64) -> bool
|
||||
{
|
||||
(self % $name::from(x)).is_zero()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
72
old/unsigned/rand.rs
Normal file
72
old/unsigned/rand.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
macro_rules! random_impls {
|
||||
($name: ident, $uniform: ident) => {
|
||||
impl Distribution<$name> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $name
|
||||
{
|
||||
let mut res = $name::zero();
|
||||
|
||||
for x in res.value.iter_mut() {
|
||||
*x = rng.next_u64();
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
pub struct $uniform {
|
||||
low: $name,
|
||||
high: $name,
|
||||
inclusive: bool
|
||||
}
|
||||
|
||||
impl UniformSampler for $uniform {
|
||||
type X = $name;
|
||||
|
||||
fn new<B1,B2>(low: B1, high: B2) -> Self
|
||||
where B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized
|
||||
{
|
||||
$uniform {
|
||||
low: low.borrow().clone(),
|
||||
high: high.borrow().clone(),
|
||||
inclusive: false
|
||||
}
|
||||
}
|
||||
|
||||
fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
|
||||
where B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized
|
||||
{
|
||||
$uniform {
|
||||
low: low.borrow().clone(),
|
||||
high: high.borrow().clone(),
|
||||
inclusive: true
|
||||
}
|
||||
}
|
||||
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
|
||||
loop {
|
||||
let candidate = rng.gen();
|
||||
|
||||
if candidate < self.low {
|
||||
continue;
|
||||
}
|
||||
|
||||
if candidate > self.high {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !self.inclusive && (candidate == self.high) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SampleUniform for $name {
|
||||
type Sampler = $uniform;
|
||||
}
|
||||
};
|
||||
}
|
||||
93
old/unsigned/scale.rs
Normal file
93
old/unsigned/scale.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
pub fn scale(dest: &mut [u64], bignum: &[u64], factor: u64)
|
||||
{
|
||||
let len = bignum.len();
|
||||
let factor128 = factor as u128;
|
||||
let mut carry = 0;
|
||||
|
||||
assert_eq!(dest.len(), len+1, "Bad destination size in scale");
|
||||
for i in 0..len {
|
||||
let digit128 = bignum[i] as u128;
|
||||
let res128 = carry + (digit128 * factor128);
|
||||
dest[i] = res128 as u64;
|
||||
carry = res128 >> 64;
|
||||
}
|
||||
dest[len] = carry as u64;
|
||||
}
|
||||
|
||||
macro_rules! scale_impls
|
||||
{
|
||||
($base: ident, $big: ident) => {
|
||||
scale_impls!($base, $big, u8);
|
||||
scale_impls!($base, $big, u16);
|
||||
scale_impls!($base, $big, u32);
|
||||
scale_impls!($base, $big, u64);
|
||||
scale_impls!($base, $big, usize);
|
||||
};
|
||||
($base: ident, $big: ident, $prim: ident) => {
|
||||
impl Mul<$prim> for $base {
|
||||
type Output = $big;
|
||||
|
||||
fn mul(self, factor: $prim) -> $big {
|
||||
&self * factor
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Mul<$prim> for &'a $base {
|
||||
type Output = $big;
|
||||
|
||||
fn mul(self, factor: $prim) -> $big {
|
||||
let mut res = $big::zero();
|
||||
scale(&mut res.value, &self.value, factor as u64);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<$base> for $prim {
|
||||
type Output = $big;
|
||||
|
||||
fn mul(self, rhs: $base) -> $big {
|
||||
rhs.mul(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Mul<&'a $base> for $prim {
|
||||
type Output = $big;
|
||||
|
||||
fn mul(self, rhs: &$base) -> $big {
|
||||
rhs.mul(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_scale_tests
|
||||
{
|
||||
($name: ident, $lname: ident, $big: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_scale_tests!(body $name, $lname, $big);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident, $big: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_scale_tests!(body $name, $lname, $big);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident, $big: ident) => {
|
||||
let fname = build_test_path("scale", 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 c = $big::from_bytes(cbytes);
|
||||
assert_eq!(c, &a * b.value[0]);
|
||||
});
|
||||
};
|
||||
}
|
||||
152
old/unsigned/shifts.rs
Normal file
152
old/unsigned/shifts.rs
Normal file
@@ -0,0 +1,152 @@
|
||||
pub(crate) fn shiftl(res: &mut [u64], copy: &[u64], amt: usize) {
|
||||
let digits = amt / 64;
|
||||
let bits = amt % 64;
|
||||
|
||||
let mut carry = 0;
|
||||
let shift = 64 - bits;
|
||||
|
||||
for i in 0..res.len() {
|
||||
let base = if i >= digits { copy[i-digits] } else { 0 };
|
||||
let new_carry = if shift == 64 { 0 } else { base >> shift };
|
||||
res[i] = (base << bits) | carry;
|
||||
carry = new_carry;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn shiftr(res: &mut [u64], copy: &[u64], amt: usize) {
|
||||
let digits = amt / 64;
|
||||
let bits = amt % 64;
|
||||
|
||||
let mut carry = 0;
|
||||
let mask = !(0xFFFFFFFFFFFFFFFF << bits);
|
||||
let shift = (64 - bits) as u32;
|
||||
|
||||
for (idx, val) in res.iter_mut().enumerate().rev() {
|
||||
let target = idx + digits;
|
||||
let base = if target >= copy.len() { 0 } else { copy[target] };
|
||||
let (new_carry, _) = (base & mask).overflowing_shl(shift);
|
||||
*val = (base >> bits) | carry;
|
||||
carry = new_carry;
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! shift_impls
|
||||
{
|
||||
($name: ident, $size: expr) => {
|
||||
impl ShlAssign<usize> for $name {
|
||||
fn shl_assign(&mut self, amt: usize) {
|
||||
let copy = self.value.clone();
|
||||
shiftl(&mut self.value, ©, amt);
|
||||
}
|
||||
}
|
||||
|
||||
impl Shl<usize> for $name {
|
||||
type Output = $name;
|
||||
|
||||
fn shl(mut self, amt: usize) -> $name {
|
||||
let copy = self.value.clone();
|
||||
shiftl(&mut self.value, ©, amt);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Shl<usize> for &'a $name {
|
||||
type Output = $name;
|
||||
|
||||
fn shl(self, amt: usize) -> $name {
|
||||
let mut res = $name{ value: self.value.clone() };
|
||||
shiftl(&mut res.value, &self.value, amt);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl ShrAssign<usize> for $name {
|
||||
fn shr_assign(&mut self, amt: usize) {
|
||||
let copy = self.value.clone();
|
||||
shiftr(&mut self.value, ©, amt);
|
||||
}
|
||||
}
|
||||
|
||||
impl Shr<usize> for $name {
|
||||
type Output = $name;
|
||||
|
||||
fn shr(mut self, amt: usize) -> $name {
|
||||
let copy = self.value.clone();
|
||||
shiftr(&mut self.value, ©, amt);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Shr<usize> for &'a $name {
|
||||
type Output = $name;
|
||||
|
||||
fn shr(self, amt: usize) -> $name {
|
||||
let mut res = $name{ value: self.value.clone() };
|
||||
shiftr(&mut res.value, &self.value, amt);
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_shiftl_tests {
|
||||
($name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_shiftl_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_shiftl_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident) => {
|
||||
let fname = build_test_path("shiftl", stringify!($name));
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (neg0, abytes) = case.get("a").unwrap();
|
||||
let (neg1, lbytes) = case.get("l").unwrap();
|
||||
let (neg2, rbytes) = case.get("r").unwrap();
|
||||
assert!(!neg0 && !neg1 && !neg2);
|
||||
|
||||
let a = $name::from_bytes(abytes);
|
||||
let l = $name::from_bytes(lbytes);
|
||||
let r = $name::from_bytes(rbytes);
|
||||
assert_eq!(r, a << usize::from(l));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_shiftr_tests {
|
||||
($name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_shiftr_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_shiftr_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident) => {
|
||||
let fname = build_test_path("shiftr", stringify!($name));
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (neg0, abytes) = case.get("a").unwrap();
|
||||
let (neg1, lbytes) = case.get("l").unwrap();
|
||||
let (neg2, rbytes) = case.get("r").unwrap();
|
||||
assert!(!neg0 && !neg1 && !neg2);
|
||||
|
||||
let a = $name::from_bytes(abytes);
|
||||
let l = $name::from_bytes(lbytes);
|
||||
let r = $name::from_bytes(rbytes);
|
||||
assert_eq!(r, a >> usize::from(l));
|
||||
});
|
||||
};
|
||||
}
|
||||
66
old/unsigned/sqrt.rs
Normal file
66
old/unsigned/sqrt.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
pub trait SquareRoot {
|
||||
/// Compute the integer square root of the given value. The integer square
|
||||
/// root is the value Z such that the real root R satisfies Z <= R < Z+1.
|
||||
fn sqrt(&self) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! sqrt_impls
|
||||
{
|
||||
($name: ident) => {
|
||||
impl SquareRoot for $name {
|
||||
fn sqrt(&self) -> Self {
|
||||
let mut num = self.clone();
|
||||
let mut res = $name::zero();
|
||||
let mut bit = $name::from(1u64) << ($name::bit_length() - 2);
|
||||
|
||||
while bit > num {
|
||||
bit >>= 2;
|
||||
}
|
||||
|
||||
while !bit.is_zero() {
|
||||
let mut resbit = res.clone();
|
||||
|
||||
resbit += &bit;
|
||||
if num >= resbit {
|
||||
num -= resbit;
|
||||
res += &bit << 1;
|
||||
}
|
||||
|
||||
res >>= 1;
|
||||
bit >>= 2;
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_sqrt_tests {
|
||||
($name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_sqrt_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_sqrt_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident) => {
|
||||
let fname = build_test_path("sqrt", stringify!($name));
|
||||
run_test(fname.to_string(), 2, |case| {
|
||||
let (neg0, abytes) = case.get("a").unwrap();
|
||||
let (neg1, rbytes) = case.get("r").unwrap();
|
||||
assert!(!neg0 && !neg1);
|
||||
|
||||
let a = $name::from_bytes(abytes);
|
||||
let r = $name::from_bytes(rbytes);
|
||||
assert_eq!(r, a.sqrt());
|
||||
});
|
||||
};
|
||||
}
|
||||
83
old/unsigned/square.rs
Normal file
83
old/unsigned/square.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
/// Squaring of large numbers.
|
||||
pub trait Square<Output> {
|
||||
fn square(&self) -> Output;
|
||||
}
|
||||
|
||||
macro_rules! square_impls {
|
||||
($name: ident, $bigger: ident, $size: expr) => {
|
||||
impl Square<$bigger> for $name {
|
||||
fn square(&self) -> $bigger {
|
||||
let mut w = [0; $size/32];
|
||||
let t = $size / 64;
|
||||
|
||||
for i in 0..t {
|
||||
let x128 = self.value[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.value[j] as u128;
|
||||
let xi128 = self.value[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.value[i] = w[i] as u64; }
|
||||
res
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_square_tests {
|
||||
($name: ident, $lname: ident, $dbl: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_square_tests!(body $name, $lname, $dbl);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident, $dbl: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_square_tests!(body $name, $lname, $dbl);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident, $dbl: ident) => {
|
||||
let fname = build_test_path("square", stringify!($name));
|
||||
run_test(fname.to_string(), 2, |case| {
|
||||
let (neg0, abytes) = case.get("a").unwrap();
|
||||
let (neg1, rbytes) = case.get("r").unwrap();
|
||||
assert!(!neg0 && !neg1);
|
||||
|
||||
let a = $name::from_bytes(abytes);
|
||||
let r = $dbl::from_bytes(rbytes);
|
||||
assert_eq!(r, a.square());
|
||||
});
|
||||
};
|
||||
}
|
||||
107
old/unsigned/sub.rs
Normal file
107
old/unsigned/sub.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use unsigned::add::unsafe_addition;
|
||||
|
||||
pub fn subtract(res: &mut [u64], spare: &mut [u64], other: &mut [u64])
|
||||
{
|
||||
for i in 0..res.len() {
|
||||
other[i] = !other[i];
|
||||
}
|
||||
spare[0] = 1;
|
||||
unsafe_addition(other, &spare, true);
|
||||
unsafe_addition(res, &other, true);
|
||||
}
|
||||
|
||||
macro_rules! subtraction_impls
|
||||
{
|
||||
($name: ident, $size: expr) => {
|
||||
impl SubAssign for $name {
|
||||
fn sub_assign(&mut self, rhs: $name) {
|
||||
let mut temp = [0; $size];
|
||||
subtract(&mut self.value, &mut temp, &mut rhs.value.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SubAssign<&'a $name> for $name {
|
||||
fn sub_assign(&mut self, rhs: &$name) {
|
||||
let mut temp = [0; $size];
|
||||
subtract(&mut self.value, &mut temp, &mut rhs.value.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for $name {
|
||||
type Output = $name;
|
||||
|
||||
fn sub(self, rhs: $name) -> $name {
|
||||
let mut res = self.clone();
|
||||
let mut temp = [0; $size];
|
||||
subtract(&mut res.value, &mut temp, &mut rhs.value.clone());
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Sub<$name> for &'a $name {
|
||||
type Output = $name;
|
||||
|
||||
fn sub(self, rhs: $name) -> $name {
|
||||
let mut res = self.clone();
|
||||
let mut temp = [0; $size];
|
||||
subtract(&mut res.value, &mut temp, &mut rhs.value.clone());
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Sub<&'a $name> for $name {
|
||||
type Output = $name;
|
||||
|
||||
fn sub(self, rhs: &$name) -> $name {
|
||||
let mut res = self.clone();
|
||||
let mut temp = [0; $size];
|
||||
subtract(&mut res.value, &mut temp, &mut rhs.value.clone());
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b> Sub<&'a $name> for &'b $name {
|
||||
type Output = $name;
|
||||
|
||||
fn sub(self, rhs: &$name) -> $name {
|
||||
let mut res = self.clone();
|
||||
let mut temp = [0; $size];
|
||||
subtract(&mut res.value, &mut temp, &mut rhs.value.clone());
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_sub_tests {
|
||||
($name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_sub_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_sub_tests!(body $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $name: ident, $lname: ident) => {
|
||||
let fname = build_test_path("sub", 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 mut a = $name::from_bytes(abytes);
|
||||
let b = $name::from_bytes(bbytes);
|
||||
let c = $name::from_bytes(cbytes);
|
||||
assert_eq!(c, &a - &b);
|
||||
a -= b;
|
||||
assert_eq!(c, a);
|
||||
});
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user