Base implementation of signed numbers and EGCD, with tests.
This commit is contained in:
113
src/signed/add.rs
Normal file
113
src/signed/add.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
macro_rules! add_impls
|
||||
{
|
||||
($name: ident, $bigger: ident, $ubigger: ident) => {
|
||||
impl AddAssign<$name> for $name {
|
||||
fn add_assign(&mut self, rhs: $name) {
|
||||
self.add_assign(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AddAssign<&'a $name> for $name {
|
||||
fn add_assign(&mut self, rhs: &$name) {
|
||||
if self.negative == rhs.negative {
|
||||
unsafe_addition(&mut self.value.value, &rhs.value.value, true);
|
||||
} else {
|
||||
if self.value > rhs.value {
|
||||
self.value -= rhs.value.clone();
|
||||
} else {
|
||||
self.value = rhs.value.clone() - self.value.clone();
|
||||
self.negative = rhs.negative;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<$name> for $name {
|
||||
type Output = $bigger;
|
||||
|
||||
fn add(self, rhs: $name) -> $bigger
|
||||
{
|
||||
&self + &rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Add<&'a $name> for $name {
|
||||
type Output = $bigger;
|
||||
|
||||
fn add(self, rhs: &$name) -> $bigger
|
||||
{
|
||||
&self + rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Add<$name> for &'a $name {
|
||||
type Output = $bigger;
|
||||
|
||||
fn add(self, rhs: $name) -> $bigger
|
||||
{
|
||||
self + &rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b> Add<&'a $name> for &'b $name {
|
||||
type Output = $bigger;
|
||||
|
||||
fn add(self, rhs: &$name) -> $bigger
|
||||
{
|
||||
if self.negative == rhs.negative {
|
||||
$bigger{
|
||||
negative: self.negative,
|
||||
value: &self.value + &rhs.value
|
||||
}
|
||||
} else {
|
||||
if self.value > rhs.value {
|
||||
$bigger {
|
||||
negative: self.negative,
|
||||
value: $ubigger::from(&self.value - &rhs.value)
|
||||
}
|
||||
} else {
|
||||
$bigger {
|
||||
negative: rhs.negative,
|
||||
value: $ubigger::from(&rhs.value - &self.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_sigadd_tests {
|
||||
($sname: ident, $name: ident, $lname: ident, $bigger: ident, $ubigger: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_sigadd_tests!(body$sname, $name, $lname, $bigger, $ubigger);
|
||||
}
|
||||
};
|
||||
(ignore $sname: ident, $name: ident, $lname: ident, $bigger: ident, $ubigger: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_sigadd_tests!(body $sname, $name, $lname, $bigger, $ubigger);
|
||||
}
|
||||
};
|
||||
(body $sname: ident, $name: ident, $lname: ident, $bigger: ident, $ubigger: ident) => {
|
||||
let fname = format!("testdata/sigadd/{}.tests", stringify!($sname));
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
|
||||
let mut a = $sname::new(*nega, $name::from_bytes(abytes));
|
||||
let b = $sname::new(*negb, $name::from_bytes(bbytes));
|
||||
let c = $bigger::new(*negc, $ubigger::from_bytes(cbytes));
|
||||
assert_eq!(c, &a + &b, "base addition");
|
||||
|
||||
if c.value.value[c.value.value.len()-1] == 0 {
|
||||
a += b;
|
||||
assert_eq!($sname::from(c), a, "mutating addition");
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
154
src/signed/base.rs
Normal file
154
src/signed/base.rs
Normal file
@@ -0,0 +1,154 @@
|
||||
macro_rules! signed_impls {
|
||||
($sname: ident, $name: ident) => {
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct $sname {
|
||||
negative: bool,
|
||||
value: $name
|
||||
}
|
||||
|
||||
impl $sname {
|
||||
pub fn new(negative: bool, value: $name) -> $sname {
|
||||
$sname{ negative: negative, value: value }
|
||||
}
|
||||
|
||||
pub fn negate(&self) -> $sname {
|
||||
$sname{ negative: !self.negative, value: self.value.clone() }
|
||||
}
|
||||
|
||||
pub fn abs(&self) -> $sname {
|
||||
$sname{ negative: false, value: self.value.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$sname> for $name {
|
||||
fn from(x: $sname) -> $name {
|
||||
x.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a $sname> for $name {
|
||||
fn from(x: &$sname) -> $name {
|
||||
x.value.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$name> for $sname {
|
||||
fn from(x: $name) -> $sname {
|
||||
$sname{ negative: false, value: x }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a $name> for $sname {
|
||||
fn from(x: &$name) -> $sname {
|
||||
$sname{ negative: false, value: x.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoNum for $sname {
|
||||
fn zero() -> $sname {
|
||||
$sname{ negative: false, value: $name::zero() }
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.value.is_zero()
|
||||
}
|
||||
|
||||
fn is_even(&self) -> bool {
|
||||
self.value.is_even()
|
||||
}
|
||||
|
||||
fn is_odd(&self) -> bool {
|
||||
self.value.is_odd()
|
||||
}
|
||||
|
||||
fn mask(&mut self, len: usize) {
|
||||
self.value.mask(len);
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// impl Arbitrary for $sname {
|
||||
// fn arbitrary<G: Gen>(g: &mut G) -> $name {
|
||||
// let neg = g.gen::<bool>();
|
||||
// let val = g.gen::<$name>();
|
||||
// $sname{ negative: neg, value: val }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[cfg(test)]
|
||||
impl fmt::Debug for $sname {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.negative {
|
||||
f.write_str("-")?;
|
||||
}
|
||||
self.value.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::UpperHex for $sname {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.negative {
|
||||
write!(f, "-{:X}", self.value)
|
||||
} else {
|
||||
if f.sign_plus() {
|
||||
write!(f, "+{:X}", self.value)
|
||||
} else {
|
||||
write!(f, "{:X}", self.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::LowerHex for $sname {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.negative {
|
||||
write!(f, "-{:x}", self.value)
|
||||
} else {
|
||||
if f.sign_plus() {
|
||||
write!(f, "+{:x}", self.value)
|
||||
} else {
|
||||
write!(f, "{:x}", self.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generate_base_conversions!($sname, $name);
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_signed_tests
|
||||
{
|
||||
($sname: ident, $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_signed_tests!(body $sname, $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $sname: ident, $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_signed_tests!(body $sname, $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $sname: ident, $name: ident, $lname: ident) => {
|
||||
let fname = format!("testdata/signed/{}.tests", stringify!($sname));
|
||||
run_test(fname.to_string(), 4, |case| {
|
||||
let (negx, xbytes) = case.get("x").unwrap();
|
||||
let (neg0, zbytes) = case.get("z").unwrap();
|
||||
let (neg1, ebytes) = case.get("e").unwrap();
|
||||
let (neg2, obytes) = case.get("o").unwrap();
|
||||
|
||||
assert!(!neg0 && !neg1 && !neg2);
|
||||
let x = $sname::new(*negx, $name::from_bytes(xbytes));
|
||||
let z = 1 == zbytes[0];
|
||||
let e = 1 == ebytes[0];
|
||||
let o = 1 == obytes[0];
|
||||
assert_eq!(x.is_zero(), z);
|
||||
assert_eq!(x.is_even(), e);
|
||||
assert_eq!(x.is_odd(), o);
|
||||
});
|
||||
}
|
||||
}
|
||||
61
src/signed/compare.rs
Normal file
61
src/signed/compare.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
macro_rules! cmp_impls {
|
||||
($name: ident) => {
|
||||
impl PartialOrd for $name {
|
||||
fn partial_cmp(&self, rhs: &$name) -> Option<Ordering> {
|
||||
Some(self.cmp(&rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for $name {
|
||||
fn cmp(&self, rhs: &$name) -> Ordering {
|
||||
match (self.negative, rhs.negative) {
|
||||
(false, false) => self.value.cmp(&rhs.value),
|
||||
(true, false) => Ordering::Less,
|
||||
(false, true) => Ordering::Greater,
|
||||
(true, true) => self.value.cmp(&rhs.value).reverse()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_sigcmp_tests {
|
||||
($sname: ident, $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_sigcmp_tests!(body $sname, $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $sname: ident, $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_sigcmp_tests!(body $sname, $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $sname: ident, $name: ident, $lname: ident) => {
|
||||
let fname = format!("testdata/sigcmp/{}.tests", stringify!($sname));
|
||||
run_test(fname.to_string(), 5, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, 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!(!neg2 && !neg3 && !neg4);
|
||||
let a = $sname::new(*nega, $name::from_bytes(abytes));
|
||||
let b = $sname::new(*negb, $name::from_bytes(bbytes));
|
||||
let e = 1 == ebytes[0];
|
||||
let g = 1 == gbytes[0];
|
||||
let l = 1 == lbytes[0];
|
||||
|
||||
assert_eq!(e, a == b, "equals wrong");
|
||||
assert_eq!(g, a > b, "greater than wrong");
|
||||
assert_eq!(l, a < b, "less than wrong");
|
||||
|
||||
assert_eq!(e || g, a >= b, "greater / equals wrong");
|
||||
assert_eq!(e || l, a <= b, "less than / equals wrong");
|
||||
});
|
||||
};
|
||||
}
|
||||
99
src/signed/conversion.rs
Normal file
99
src/signed/conversion.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
macro_rules! generate_base_conversions
|
||||
{
|
||||
($sname: ident, $name: ident) => {
|
||||
generate_base_type_convert!($sname, $name, i8, u8);
|
||||
generate_base_type_convert!($sname, $name, i16, u16);
|
||||
generate_base_type_convert!($sname, $name, i32, u32);
|
||||
generate_base_type_convert!($sname, $name, i64, u64);
|
||||
generate_base_type_convert!($sname, $name, isize, usize);
|
||||
|
||||
impl From<i128> for $sname {
|
||||
fn from(x: i128) -> $sname {
|
||||
$sname{ negative: x < 0, value: $name::from(x.abs() as u128) }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! generate_base_type_convert
|
||||
{
|
||||
($sname: ident, $name: ident, $sbase: ident, $base: ident) => {
|
||||
impl From<$sbase> for $sname {
|
||||
fn from(x: $sbase) -> $sname {
|
||||
$sname {
|
||||
negative: x < 0,
|
||||
value: $name::from(x.abs() as $base)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$sname> for $sbase {
|
||||
fn from(x: $sname) -> $sbase {
|
||||
let signum = if x.negative { -1 } else { 1 };
|
||||
signum * ($base::from(x.value) as $sbase)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a $sname> for $sbase {
|
||||
fn from(x: &$sname) -> $sbase {
|
||||
let signum = if x.negative { -1 } else { 1 };
|
||||
signum * ($base::from(&x.value) as $sbase)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_sigconversion_tests
|
||||
{
|
||||
($sname: ident, $name: ident, $lname: ident) => {
|
||||
#[cfg(test)]
|
||||
mod $lname {
|
||||
use super::super::super::*;
|
||||
use std::convert::From;
|
||||
|
||||
quickcheck! {
|
||||
fn conversion_i8( x: i8) -> bool { x == i8::from($sname::from(x)) }
|
||||
fn conversion_i16( x: i16) -> bool { x == i16::from($sname::from(x)) }
|
||||
fn conversion_i32( x: i32) -> bool { x == i32::from($sname::from(x)) }
|
||||
fn conversion_i64( x: i64) -> bool { x == i64::from($sname::from(x)) }
|
||||
fn conversion_isize(x: isize) -> bool { x == isize::from($sname::from(x)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! conversion_impls
|
||||
{
|
||||
($sname: ident, $name: ident, $sother: ident, $other: ident) => {
|
||||
impl<'a> From<&'a $sother> for $sname {
|
||||
fn from(x: &$sother) -> $sname {
|
||||
$sname {
|
||||
negative: x.negative,
|
||||
value: $name::from(&x.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a $sname> for $sother {
|
||||
fn from(x: &$sname) -> $sother {
|
||||
$sother {
|
||||
negative: x.negative,
|
||||
value: $other::from(&x.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$sother> for $sname {
|
||||
fn from(x: $sother) -> $sname {
|
||||
$sname::from(&x)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$sname> for $sother {
|
||||
fn from(x: $sname) -> $sother {
|
||||
$sother::from(&x)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
125
src/signed/egcd.rs
Normal file
125
src/signed/egcd.rs
Normal file
@@ -0,0 +1,125 @@
|
||||
pub trait EGCD<T> {
|
||||
fn egcd(&self, rhs: &Self) -> (T, T, T);
|
||||
}
|
||||
|
||||
macro_rules! egcd_impls {
|
||||
($sname: ident, $name: ident, $ssmall: ident) => {
|
||||
impl EGCD<$sname> for $name {
|
||||
fn egcd(&self, rhs: &$name) -> ($sname, $sname, $sname) {
|
||||
// INPUT: two positive integers x and y.
|
||||
let mut x = $sname::from($ssmall::from(self));
|
||||
let mut y = $sname::from($ssmall::from(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 = x.clone();
|
||||
let mut v = y.clone();
|
||||
#[allow(non_snake_case)]
|
||||
let mut A = $sname::from(1i64);
|
||||
#[allow(non_snake_case)]
|
||||
let mut B = $sname::zero();
|
||||
#[allow(non_snake_case)]
|
||||
let mut C = $sname::zero();
|
||||
#[allow(non_snake_case)]
|
||||
let mut D = $sname::from(1i64);
|
||||
loop {
|
||||
// 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 {
|
||||
A += &y;
|
||||
A >>= 1;
|
||||
B -= &x;
|
||||
B >>= 1;
|
||||
}
|
||||
}
|
||||
// 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 += &y;
|
||||
C >>= 1;
|
||||
D -= &x;
|
||||
D >>= 1;
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
if u.is_zero() {
|
||||
return (C, D, v << gshift);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_egcd_tests {
|
||||
($sname: ident, $uname: ident, $tname: ident, $sname64: ident, $uname64: ident) => {
|
||||
#[test]
|
||||
fn $tname() {
|
||||
generate_egcd_tests!(body $sname, $uname, $tname, $sname64, $uname64);
|
||||
}
|
||||
};
|
||||
(ignore $sname: ident, $uname: ident, $tname: ident, $sname64: ident, $uname64: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $tname() {
|
||||
generate_egcd_tests!(body $sname, $uname, $tname, $sname64, $uname64);
|
||||
}
|
||||
};
|
||||
(body $sname: ident, $uname: ident, $tname: ident, $sname64: ident, $uname64: ident) => {
|
||||
let fname = format!("testdata/egcd/{}.tests", stringify!($sname));
|
||||
run_test(fname.to_string(), 5, |case| {
|
||||
let (negx, xbytes) = case.get("x").unwrap();
|
||||
let (negy, ybytes) = case.get("y").unwrap();
|
||||
let (negv, vbytes) = case.get("v").unwrap();
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
|
||||
assert!(!negx && !negy);
|
||||
let x = $uname::from_bytes(xbytes);
|
||||
let y = $uname::from_bytes(ybytes);
|
||||
let v = $sname64::new(*negv, $uname64::from_bytes(vbytes));
|
||||
let a = $sname64::new(*nega, $uname64::from_bytes(abytes));
|
||||
let b = $sname64::new(*negb, $uname64::from_bytes(bbytes));
|
||||
let (mya, myb, myv) = x.egcd(&y);
|
||||
assert_eq!(v, myv, "GCD test");
|
||||
assert_eq!(a, mya, "X factor test");
|
||||
assert_eq!(b, myb, "Y factor tst");
|
||||
});
|
||||
};
|
||||
}
|
||||
315
src/signed/invoc.rs
Normal file
315
src/signed/invoc.rs
Normal file
@@ -0,0 +1,315 @@
|
||||
signed_impls!(I192, U192);
|
||||
conversion_impls!(I192, U192, I256, U256);
|
||||
egcd_impls!(I256, U192, I192);
|
||||
modinv_impls!(I192);
|
||||
add_impls!(I256, I320, U320);
|
||||
signed_impls!(I256, U256);
|
||||
cmp_impls!(I256);
|
||||
shift_impls!(I256, U256);
|
||||
subtraction_impls!(I256, I320, U320);
|
||||
conversion_impls!(I256, U256, I320, U320);
|
||||
egcd_impls!(I320, U256, I256);
|
||||
modinv_impls!(I256);
|
||||
add_impls!(I320, I384, U384);
|
||||
signed_impls!(I320, U320);
|
||||
cmp_impls!(I320);
|
||||
shift_impls!(I320, U320);
|
||||
subtraction_impls!(I320, I384, U384);
|
||||
conversion_impls!(I320, U320, I384, U384);
|
||||
signed_impls!(I384, U384);
|
||||
conversion_impls!(I384, U384, I448, U448);
|
||||
egcd_impls!(I448, U384, I384);
|
||||
modinv_impls!(I384);
|
||||
add_impls!(I448, I512, U512);
|
||||
signed_impls!(I448, U448);
|
||||
cmp_impls!(I448);
|
||||
shift_impls!(I448, U448);
|
||||
subtraction_impls!(I448, I512, U512);
|
||||
conversion_impls!(I448, U448, I512, U512);
|
||||
signed_impls!(I512, U512);
|
||||
conversion_impls!(I512, U512, I576, U576);
|
||||
egcd_impls!(I576, U512, I512);
|
||||
modinv_impls!(I512);
|
||||
add_impls!(I576, I640, U640);
|
||||
signed_impls!(I576, U576);
|
||||
cmp_impls!(I576);
|
||||
shift_impls!(I576, U576);
|
||||
subtraction_impls!(I576, I640, U640);
|
||||
conversion_impls!(I576, U576, I640, U640);
|
||||
egcd_impls!(I640, U576, I576);
|
||||
modinv_impls!(I576);
|
||||
add_impls!(I640, I704, U704);
|
||||
signed_impls!(I640, U640);
|
||||
cmp_impls!(I640);
|
||||
shift_impls!(I640, U640);
|
||||
subtraction_impls!(I640, I704, U704);
|
||||
conversion_impls!(I640, U640, I704, U704);
|
||||
signed_impls!(I704, U704);
|
||||
signed_impls!(I1024, U1024);
|
||||
conversion_impls!(I1024, U1024, I1088, U1088);
|
||||
egcd_impls!(I1088, U1024, I1024);
|
||||
modinv_impls!(I1024);
|
||||
add_impls!(I1088, I1152, U1152);
|
||||
signed_impls!(I1088, U1088);
|
||||
cmp_impls!(I1088);
|
||||
shift_impls!(I1088, U1088);
|
||||
subtraction_impls!(I1088, I1152, U1152);
|
||||
conversion_impls!(I1088, U1088, I1152, U1152);
|
||||
signed_impls!(I1152, U1152);
|
||||
signed_impls!(I2048, U2048);
|
||||
conversion_impls!(I2048, U2048, I2112, U2112);
|
||||
egcd_impls!(I2112, U2048, I2048);
|
||||
modinv_impls!(I2048);
|
||||
add_impls!(I2112, I2176, U2176);
|
||||
signed_impls!(I2112, U2112);
|
||||
cmp_impls!(I2112);
|
||||
shift_impls!(I2112, U2112);
|
||||
subtraction_impls!(I2112, I2176, U2176);
|
||||
conversion_impls!(I2112, U2112, I2176, U2176);
|
||||
signed_impls!(I2176, U2176);
|
||||
signed_impls!(I3072, U3072);
|
||||
conversion_impls!(I3072, U3072, I3136, U3136);
|
||||
egcd_impls!(I3136, U3072, I3072);
|
||||
modinv_impls!(I3072);
|
||||
add_impls!(I3136, I3200, U3200);
|
||||
signed_impls!(I3136, U3136);
|
||||
cmp_impls!(I3136);
|
||||
shift_impls!(I3136, U3136);
|
||||
subtraction_impls!(I3136, I3200, U3200);
|
||||
conversion_impls!(I3136, U3136, I3200, U3200);
|
||||
signed_impls!(I3200, U3200);
|
||||
signed_impls!(I4096, U4096);
|
||||
conversion_impls!(I4096, U4096, I4160, U4160);
|
||||
egcd_impls!(I4160, U4096, I4096);
|
||||
modinv_impls!(I4096);
|
||||
add_impls!(I4160, I4224, U4224);
|
||||
signed_impls!(I4160, U4160);
|
||||
cmp_impls!(I4160);
|
||||
shift_impls!(I4160, U4160);
|
||||
subtraction_impls!(I4160, I4224, U4224);
|
||||
conversion_impls!(I4160, U4160, I4224, U4224);
|
||||
signed_impls!(I4224, U4224);
|
||||
signed_impls!(I7680, U7680);
|
||||
conversion_impls!(I7680, U7680, I7744, U7744);
|
||||
egcd_impls!(I7744, U7680, I7680);
|
||||
modinv_impls!(I7680);
|
||||
add_impls!(I7744, I7808, U7808);
|
||||
signed_impls!(I7744, U7744);
|
||||
cmp_impls!(I7744);
|
||||
shift_impls!(I7744, U7744);
|
||||
subtraction_impls!(I7744, I7808, U7808);
|
||||
conversion_impls!(I7744, U7744, I7808, U7808);
|
||||
signed_impls!(I7808, U7808);
|
||||
signed_impls!(I8192, U8192);
|
||||
conversion_impls!(I8192, U8192, I8256, U8256);
|
||||
egcd_impls!(I8256, U8192, I8192);
|
||||
modinv_impls!(I8192);
|
||||
add_impls!(I8256, I8320, U8320);
|
||||
signed_impls!(I8256, U8256);
|
||||
cmp_impls!(I8256);
|
||||
shift_impls!(I8256, U8256);
|
||||
subtraction_impls!(I8256, I8320, U8320);
|
||||
conversion_impls!(I8256, U8256, I8320, U8320);
|
||||
signed_impls!(I8320, U8320);
|
||||
signed_impls!(I15360, U15360);
|
||||
conversion_impls!(I15360, U15360, I15424, U15424);
|
||||
egcd_impls!(I15424, U15360, I15360);
|
||||
modinv_impls!(I15360);
|
||||
add_impls!(I15424, I15488, U15488);
|
||||
signed_impls!(I15424, U15424);
|
||||
cmp_impls!(I15424);
|
||||
shift_impls!(I15424, U15424);
|
||||
subtraction_impls!(I15424, I15488, U15488);
|
||||
conversion_impls!(I15424, U15424, I15488, U15488);
|
||||
signed_impls!(I15488, U15488);
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
mod sigadd {
|
||||
use super::super::*;
|
||||
use testing::run_test;
|
||||
|
||||
generate_sigadd_tests!(I256, U256, i256, I320, U320);
|
||||
generate_sigadd_tests!(I320, U320, i320, I384, U384);
|
||||
generate_sigadd_tests!(I448, U448, i448, I512, U512);
|
||||
generate_sigadd_tests!(I576, U576, i576, I640, U640);
|
||||
generate_sigadd_tests!(I640, U640, i640, I704, U704);
|
||||
generate_sigadd_tests!(I1088, U1088, i1088, I1152, U1152);
|
||||
generate_sigadd_tests!(I2112, U2112, i2112, I2176, U2176);
|
||||
generate_sigadd_tests!(I3136, U3136, i3136, I3200, U3200);
|
||||
generate_sigadd_tests!(I4160, U4160, i4160, I4224, U4224);
|
||||
generate_sigadd_tests!(I7744, U7744, i7744, I7808, U7808);
|
||||
generate_sigadd_tests!(I8256, U8256, i8256, I8320, U8320);
|
||||
generate_sigadd_tests!(I15424, U15424, i15424, I15488, U15488);
|
||||
}
|
||||
mod sigsub {
|
||||
use super::super::*;
|
||||
use testing::run_test;
|
||||
|
||||
generate_sigsub_tests!(I256, U256, i256, I320, U320);
|
||||
generate_sigsub_tests!(I320, U320, i320, I384, U384);
|
||||
generate_sigsub_tests!(I448, U448, i448, I512, U512);
|
||||
generate_sigsub_tests!(I576, U576, i576, I640, U640);
|
||||
generate_sigsub_tests!(I640, U640, i640, I704, U704);
|
||||
generate_sigsub_tests!(I1088, U1088, i1088, I1152, U1152);
|
||||
generate_sigsub_tests!(I2112, U2112, i2112, I2176, U2176);
|
||||
generate_sigsub_tests!(I3136, U3136, i3136, I3200, U3200);
|
||||
generate_sigsub_tests!(I4160, U4160, i4160, I4224, U4224);
|
||||
generate_sigsub_tests!(I7744, U7744, i7744, I7808, U7808);
|
||||
generate_sigsub_tests!(I8256, U8256, i8256, I8320, U8320);
|
||||
generate_sigsub_tests!(I15424, U15424, i15424, I15488, U15488);
|
||||
}
|
||||
mod signed {
|
||||
use super::super::*;
|
||||
use testing::run_test;
|
||||
|
||||
generate_signed_tests!(I192, U192, i192);
|
||||
generate_signed_tests!(I256, U256, i256);
|
||||
generate_signed_tests!(I320, U320, i320);
|
||||
generate_signed_tests!(I384, U384, i384);
|
||||
generate_signed_tests!(I448, U448, i448);
|
||||
generate_signed_tests!(I512, U512, i512);
|
||||
generate_signed_tests!(I576, U576, i576);
|
||||
generate_signed_tests!(I640, U640, i640);
|
||||
generate_signed_tests!(I704, U704, i704);
|
||||
generate_signed_tests!(I1024, U1024, i1024);
|
||||
generate_signed_tests!(I1088, U1088, i1088);
|
||||
generate_signed_tests!(I1152, U1152, i1152);
|
||||
generate_signed_tests!(I2048, U2048, i2048);
|
||||
generate_signed_tests!(I2112, U2112, i2112);
|
||||
generate_signed_tests!(I2176, U2176, i2176);
|
||||
generate_signed_tests!(I3072, U3072, i3072);
|
||||
generate_signed_tests!(I3136, U3136, i3136);
|
||||
generate_signed_tests!(I3200, U3200, i3200);
|
||||
generate_signed_tests!(I4096, U4096, i4096);
|
||||
generate_signed_tests!(I4160, U4160, i4160);
|
||||
generate_signed_tests!(I4224, U4224, i4224);
|
||||
generate_signed_tests!(I7680, U7680, i7680);
|
||||
generate_signed_tests!(I7744, U7744, i7744);
|
||||
generate_signed_tests!(I7808, U7808, i7808);
|
||||
generate_signed_tests!(I8192, U8192, i8192);
|
||||
generate_signed_tests!(I8256, U8256, i8256);
|
||||
generate_signed_tests!(I8320, U8320, i8320);
|
||||
generate_signed_tests!(I15360, U15360, i15360);
|
||||
generate_signed_tests!(I15424, U15424, i15424);
|
||||
generate_signed_tests!(I15488, U15488, i15488);
|
||||
}
|
||||
mod sigconversion {
|
||||
generate_sigconversion_tests!(I192, U192, i192);
|
||||
generate_sigconversion_tests!(I256, U256, i256);
|
||||
generate_sigconversion_tests!(I320, U320, i320);
|
||||
generate_sigconversion_tests!(I384, U384, i384);
|
||||
generate_sigconversion_tests!(I448, U448, i448);
|
||||
generate_sigconversion_tests!(I512, U512, i512);
|
||||
generate_sigconversion_tests!(I576, U576, i576);
|
||||
generate_sigconversion_tests!(I640, U640, i640);
|
||||
generate_sigconversion_tests!(I704, U704, i704);
|
||||
generate_sigconversion_tests!(I1024, U1024, i1024);
|
||||
generate_sigconversion_tests!(I1088, U1088, i1088);
|
||||
generate_sigconversion_tests!(I1152, U1152, i1152);
|
||||
generate_sigconversion_tests!(I2048, U2048, i2048);
|
||||
generate_sigconversion_tests!(I2112, U2112, i2112);
|
||||
generate_sigconversion_tests!(I2176, U2176, i2176);
|
||||
generate_sigconversion_tests!(I3072, U3072, i3072);
|
||||
generate_sigconversion_tests!(I3136, U3136, i3136);
|
||||
generate_sigconversion_tests!(I3200, U3200, i3200);
|
||||
generate_sigconversion_tests!(I4096, U4096, i4096);
|
||||
generate_sigconversion_tests!(I4160, U4160, i4160);
|
||||
generate_sigconversion_tests!(I4224, U4224, i4224);
|
||||
generate_sigconversion_tests!(I7680, U7680, i7680);
|
||||
generate_sigconversion_tests!(I7744, U7744, i7744);
|
||||
generate_sigconversion_tests!(I7808, U7808, i7808);
|
||||
generate_sigconversion_tests!(I8192, U8192, i8192);
|
||||
generate_sigconversion_tests!(I8256, U8256, i8256);
|
||||
generate_sigconversion_tests!(I8320, U8320, i8320);
|
||||
generate_sigconversion_tests!(I15360, U15360, i15360);
|
||||
generate_sigconversion_tests!(I15424, U15424, i15424);
|
||||
generate_sigconversion_tests!(I15488, U15488, i15488);
|
||||
}
|
||||
mod sigcmp {
|
||||
use super::super::*;
|
||||
use testing::run_test;
|
||||
|
||||
generate_sigcmp_tests!(I256, U256, i256);
|
||||
generate_sigcmp_tests!(I320, U320, i320);
|
||||
generate_sigcmp_tests!(I448, U448, i448);
|
||||
generate_sigcmp_tests!(I576, U576, i576);
|
||||
generate_sigcmp_tests!(I640, U640, i640);
|
||||
generate_sigcmp_tests!(I1088, U1088, i1088);
|
||||
generate_sigcmp_tests!(I2112, U2112, i2112);
|
||||
generate_sigcmp_tests!(I3136, U3136, i3136);
|
||||
generate_sigcmp_tests!(I4160, U4160, i4160);
|
||||
generate_sigcmp_tests!(I7744, U7744, i7744);
|
||||
generate_sigcmp_tests!(I8256, U8256, i8256);
|
||||
generate_sigcmp_tests!(I15424, U15424, i15424);
|
||||
}
|
||||
mod sigshiftl {
|
||||
use super::super::*;
|
||||
use testing::run_test;
|
||||
|
||||
generate_sigshiftl_tests!(I256, U256, i256);
|
||||
generate_sigshiftl_tests!(I320, U320, i320);
|
||||
generate_sigshiftl_tests!(I448, U448, i448);
|
||||
generate_sigshiftl_tests!(I576, U576, i576);
|
||||
generate_sigshiftl_tests!(I640, U640, i640);
|
||||
generate_sigshiftl_tests!(I1088, U1088, i1088);
|
||||
generate_sigshiftl_tests!(I2112, U2112, i2112);
|
||||
generate_sigshiftl_tests!(I3136, U3136, i3136);
|
||||
generate_sigshiftl_tests!(I4160, U4160, i4160);
|
||||
generate_sigshiftl_tests!(I7744, U7744, i7744);
|
||||
generate_sigshiftl_tests!(I8256, U8256, i8256);
|
||||
generate_sigshiftl_tests!(I15424, U15424, i15424);
|
||||
}
|
||||
mod sigshiftr {
|
||||
use super::super::*;
|
||||
use testing::run_test;
|
||||
|
||||
generate_sigshiftr_tests!(I256, U256, i256);
|
||||
generate_sigshiftr_tests!(I320, U320, i320);
|
||||
generate_sigshiftr_tests!(I448, U448, i448);
|
||||
generate_sigshiftr_tests!(I576, U576, i576);
|
||||
generate_sigshiftr_tests!(I640, U640, i640);
|
||||
generate_sigshiftr_tests!(I1088, U1088, i1088);
|
||||
generate_sigshiftr_tests!(I2112, U2112, i2112);
|
||||
generate_sigshiftr_tests!(I3136, U3136, i3136);
|
||||
generate_sigshiftr_tests!(I4160, U4160, i4160);
|
||||
generate_sigshiftr_tests!(I7744, U7744, i7744);
|
||||
generate_sigshiftr_tests!(I8256, U8256, i8256);
|
||||
generate_sigshiftr_tests!(I15424, U15424, i15424);
|
||||
}
|
||||
mod egcd {
|
||||
use super::super::*;
|
||||
use testing::run_test;
|
||||
|
||||
generate_egcd_tests!(I192, U192, i192, I256, U256);
|
||||
generate_egcd_tests!(I256, U256, i256, I320, U320);
|
||||
generate_egcd_tests!(I384, U384, i384, I448, U448);
|
||||
generate_egcd_tests!(I512, U512, i512, I576, U576);
|
||||
generate_egcd_tests!(I576, U576, i576, I640, U640);
|
||||
generate_egcd_tests!(ignore I1024, U1024, i1024, I1088, U1088);
|
||||
generate_egcd_tests!(ignore I2048, U2048, i2048, I2112, U2112);
|
||||
generate_egcd_tests!(ignore I3072, U3072, i3072, I3136, U3136);
|
||||
generate_egcd_tests!(ignore I4096, U4096, i4096, I4160, U4160);
|
||||
generate_egcd_tests!(ignore I7680, U7680, i7680, I7744, U7744);
|
||||
generate_egcd_tests!(ignore I8192, U8192, i8192, I8256, U8256);
|
||||
generate_egcd_tests!(ignore I15360, U15360, i15360, I15424, U15424);
|
||||
}
|
||||
mod modinv {
|
||||
use super::super::*;
|
||||
use testing::run_test;
|
||||
|
||||
generate_modinv_tests!(I192, U192, i192);
|
||||
generate_modinv_tests!(I256, U256, i256);
|
||||
generate_modinv_tests!(I384, U384, i384);
|
||||
generate_modinv_tests!(I512, U512, i512);
|
||||
generate_modinv_tests!(I576, U576, i576);
|
||||
generate_modinv_tests!(I1024, U1024, i1024);
|
||||
generate_modinv_tests!(I2048, U2048, i2048);
|
||||
generate_modinv_tests!(I3072, U3072, i3072);
|
||||
generate_modinv_tests!(I4096, U4096, i4096);
|
||||
generate_modinv_tests!(I7680, U7680, i7680);
|
||||
generate_modinv_tests!(I8192, U8192, i8192);
|
||||
generate_modinv_tests!(ignore I15360, U15360, i15360);
|
||||
}
|
||||
}
|
||||
27
src/signed/mod.rs
Normal file
27
src/signed/mod.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
#[macro_use]
|
||||
mod add;
|
||||
#[macro_use]
|
||||
mod base;
|
||||
#[macro_use]
|
||||
mod compare;
|
||||
#[macro_use]
|
||||
mod conversion;
|
||||
#[macro_use]
|
||||
mod egcd;
|
||||
#[macro_use]
|
||||
mod modinv;
|
||||
#[macro_use]
|
||||
mod shift;
|
||||
#[macro_use]
|
||||
mod subtraction;
|
||||
|
||||
use std::cmp::{Ord,Ordering,PartialOrd};
|
||||
use std::fmt;
|
||||
use std::ops::{Add,AddAssign};
|
||||
use std::ops::{Shl,ShlAssign,Shr,ShrAssign};
|
||||
use std::ops::{Sub,SubAssign};
|
||||
use unsigned::*;
|
||||
|
||||
pub use self::egcd::EGCD;
|
||||
|
||||
include!("invoc.rs");
|
||||
14
src/signed/modinv.rs
Normal file
14
src/signed/modinv.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
macro_rules! modinv_impls {
|
||||
($sname: ident) => {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_modinv_tests {
|
||||
($sname: ident, $tname: ident, $mname: ident) => {
|
||||
};
|
||||
(ignore $sname: ident, $tname: ident, $mname: ident) => {
|
||||
};
|
||||
(body $sname: ident, $tname: ident, $mname: ident) => {
|
||||
};
|
||||
}
|
||||
135
src/signed/shift.rs
Normal file
135
src/signed/shift.rs
Normal file
@@ -0,0 +1,135 @@
|
||||
|
||||
macro_rules! shift_impls
|
||||
{
|
||||
($sname: ident, $name: ident) => {
|
||||
impl ShlAssign<usize> for $sname {
|
||||
fn shl_assign(&mut self, amt: usize) {
|
||||
self.value <<= amt;
|
||||
if self.value.is_zero() {
|
||||
self.negative = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Shl<usize> for $sname {
|
||||
type Output = $sname;
|
||||
|
||||
fn shl(mut self, amt: usize) -> $sname {
|
||||
self <<= amt;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Shl<usize> for &'a $sname {
|
||||
type Output = $sname;
|
||||
|
||||
fn shl(self, amt: usize) -> $sname {
|
||||
let mut res = self.clone();
|
||||
res <<= amt;
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl ShrAssign<usize> for $sname {
|
||||
fn shr_assign(&mut self, amt: 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 >>= amt;
|
||||
if self.negative {
|
||||
let review = self.value.clone() << amt;
|
||||
if review != original {
|
||||
self.value += $name::from(1u64);
|
||||
}
|
||||
}
|
||||
if self.value.is_zero() {
|
||||
self.negative = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Shr<usize> for $sname {
|
||||
type Output = $sname;
|
||||
|
||||
fn shr(mut self, amt: usize) -> $sname {
|
||||
self >>= amt;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Shr<usize> for &'a $sname {
|
||||
type Output = $sname;
|
||||
|
||||
fn shr(self, amt: usize) -> $sname {
|
||||
let mut res = self.clone();
|
||||
res >>= amt;
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_sigshiftl_tests {
|
||||
($sname: ident, $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_sigshiftl_tests!(body $sname, $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $sname: ident, $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_sigshiftl_tests!(body $sname, $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $sname: ident, $name: ident, $lname: ident) => {
|
||||
let fname = format!("testdata/sigshiftl/{}.tests", stringify!($sname));
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (neg1, lbytes) = case.get("l").unwrap();
|
||||
let (negr, rbytes) = case.get("r").unwrap();
|
||||
assert!(!neg1);
|
||||
|
||||
let a = $sname::new(*nega, $name::from_bytes(abytes));
|
||||
let l = $name::from_bytes(lbytes);
|
||||
let r = $sname::new(*negr, $name::from_bytes(rbytes));
|
||||
assert_eq!(r, a << usize::from(l));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_sigshiftr_tests {
|
||||
($sname: ident, $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_sigshiftr_tests!(body $sname, $name, $lname);
|
||||
}
|
||||
};
|
||||
(ignore $sname: ident, $name: ident, $lname: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_sigshiftr_tests!(body $sname, $name, $lname);
|
||||
}
|
||||
};
|
||||
(body $sname: ident, $name: ident, $lname: ident) => {
|
||||
let fname = format!("testdata/sigshiftr/{}.tests", stringify!($sname));
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (neg1, lbytes) = case.get("l").unwrap();
|
||||
let (negr, rbytes) = case.get("r").unwrap();
|
||||
assert!(!neg1);
|
||||
|
||||
let a = $sname::new(*nega, $name::from_bytes(abytes));
|
||||
let l = $name::from_bytes(lbytes);
|
||||
let r = $sname::new(*negr, $name::from_bytes(rbytes));
|
||||
assert_eq!(r, a >> usize::from(l));
|
||||
});
|
||||
};
|
||||
}
|
||||
113
src/signed/subtraction.rs
Normal file
113
src/signed/subtraction.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
macro_rules! subtraction_impls
|
||||
{
|
||||
($name: ident, $bigger: ident, $ubigger: ident) => {
|
||||
impl SubAssign<$name> for $name {
|
||||
fn sub_assign(&mut self, rhs: $name) {
|
||||
self.sub_assign(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SubAssign<&'a $name> for $name {
|
||||
fn sub_assign(&mut self, rhs: &$name) {
|
||||
if self.negative == rhs.negative {
|
||||
if &self.value >= &rhs.value {
|
||||
self.value -= &rhs.value;
|
||||
} else {
|
||||
self.value = rhs.value.clone() - self.value.clone();
|
||||
self.negative = !self.negative;
|
||||
}
|
||||
} else {
|
||||
unsafe_addition(&mut self.value.value, &rhs.value.value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<$name> for $name {
|
||||
type Output = $bigger;
|
||||
|
||||
fn sub(self, rhs: $name) -> $bigger
|
||||
{
|
||||
&self - &rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Sub<&'a $name> for $name {
|
||||
type Output = $bigger;
|
||||
|
||||
fn sub(self, rhs: &$name) -> $bigger
|
||||
{
|
||||
&self - rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Sub<$name> for &'a $name {
|
||||
type Output = $bigger;
|
||||
|
||||
fn sub(self, rhs: $name) -> $bigger
|
||||
{
|
||||
self - &rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b> Sub<&'a $name> for &'b $name {
|
||||
type Output = $bigger;
|
||||
|
||||
fn sub(self, rhs: &$name) -> $bigger
|
||||
{
|
||||
if self.negative == rhs.negative {
|
||||
if &self.value >= &rhs.value {
|
||||
$bigger {
|
||||
negative: self.negative,
|
||||
value: $ubigger::from(&self.value - &rhs.value)
|
||||
}
|
||||
} else {
|
||||
$bigger {
|
||||
negative: !self.negative,
|
||||
value: $ubigger::from(&rhs.value - &self.value)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$bigger {
|
||||
negative: self.negative,
|
||||
value: &self.value + &rhs.value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_sigsub_tests {
|
||||
($sname: ident, $name: ident, $lname: ident, $bigger: ident, $ubigger: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_sigsub_tests!(body$sname, $name, $lname, $bigger, $ubigger);
|
||||
}
|
||||
};
|
||||
(ignore $sname: ident, $name: ident, $lname: ident, $bigger: ident, $ubigger: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_sigsub_tests!(body $sname, $name, $lname, $bigger, $ubigger);
|
||||
}
|
||||
};
|
||||
(body $sname: ident, $name: ident, $lname: ident, $bigger: ident, $ubigger: ident) => {
|
||||
let fname = format!("testdata/sigsub/{}.tests", stringify!($sname));
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
|
||||
let mut a = $sname::new(*nega, $name::from_bytes(abytes));
|
||||
let b = $sname::new(*negb, $name::from_bytes(bbytes));
|
||||
let c = $bigger::new(*negc, $ubigger::from_bytes(cbytes));
|
||||
assert_eq!(c, &a - &b, "base subtraction");
|
||||
|
||||
if c.value.value[c.value.value.len()-1] == 0 {
|
||||
a -= b;
|
||||
assert_eq!($sname::from(c), a, "in-place subtraction");
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user