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:
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);
|
||||
});
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user