136 lines
3.8 KiB
Rust
136 lines
3.8 KiB
Rust
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);
|
|
}
|
|
});
|
|
};
|
|
} |