Files
cryptonum/old/signed/base.rs
Adam Wick fa872c951a 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.
2019-07-15 17:39:06 -07:00

182 lines
5.5 KiB
Rust

macro_rules! signed_impls {
($sname: ident, $name: ident) => {
#[derive(Clone, PartialEq, Eq)]
pub struct $sname {
negative: bool,
value: $name
}
impl $sname {
/// Generate a new signed number from an unsigned number and a
/// boolean describing whether or not the new number is negative.
/// Note that if the value is zero, the value of the negative flag
/// will be ignored.
pub fn new(negative: bool, value: $name) -> $sname {
if value.is_zero() {
$sname{ negative: false, value: value }
} else {
$sname{ negative: negative, value: value }
}
}
/// Return a new number that is the negated version of this number.
pub fn negate(&self) -> $sname {
if self.value.is_zero() {
self.clone()
} else {
$sname{ negative: !self.negative, value: self.value.clone() }
}
}
/// Return the absolute value of the number.
pub fn abs(&self) -> $sname {
$sname{ negative: false, value: self.value.clone() }
}
/// Return true iff the value is negative and not zero.
pub fn is_negative(&self) -> bool {
self.negative
}
}
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 bit_length() -> usize {
$name::bit_length()
}
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);
}
fn testbit(&self, bit: usize) -> bool {
self.value.testbit(bit)
}
}
impl Arbitrary for $sname {
fn arbitrary<G>(g: &mut G) -> $sname
where G: Gen
{
let neg = bool::arbitrary(g);
let val = $name::arbitrary(g);
let neg2 = if val.is_zero() { false } else { neg };
$sname{ negative: neg2, value: val }
}
}
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 = build_test_path("signed", 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);
});
}
}