Start working variable-length numbers.
This commit is contained in:
29
src/cryptonum/conversions.rs
Normal file
29
src/cryptonum/conversions.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
macro_rules! define_from
|
||||
{
|
||||
($type: ident, $base: ident) => {
|
||||
impl From<$base> for $type {
|
||||
fn from(x: $base) -> $type {
|
||||
if x == 0 {
|
||||
UCN{ contents: Vec::new() }
|
||||
} else {
|
||||
UCN{ contents: vec![x as u64] }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_into
|
||||
{
|
||||
($type: ident, $base: ident) => {
|
||||
impl Into<$base> for $type {
|
||||
fn into(self) -> $base {
|
||||
if self.contents.is_empty() {
|
||||
0
|
||||
} else {
|
||||
self.contents[0] as $base
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
165
src/cryptonum/mod.rs
Normal file
165
src/cryptonum/mod.rs
Normal file
@@ -0,0 +1,165 @@
|
||||
#[macro_use]
|
||||
mod conversions;
|
||||
|
||||
use num::{BigUint,ToPrimitive,Zero};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
/// In case you were wondering, it stands for "Unsigned Crypto Num".
|
||||
#[derive(Clone,Debug,PartialEq,Eq)]
|
||||
pub struct UCN {
|
||||
contents: Vec<u64>
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Conversions to/from crypto nums.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
define_from!(UCN, u8);
|
||||
define_from!(UCN, u16);
|
||||
define_from!(UCN, u32);
|
||||
define_from!(UCN, u64);
|
||||
define_into!(UCN, u8);
|
||||
define_into!(UCN, u16);
|
||||
define_into!(UCN, u32);
|
||||
define_into!(UCN, u64);
|
||||
|
||||
impl From<BigUint> for UCN {
|
||||
fn from(mut x: BigUint) -> UCN {
|
||||
let mut dest = Vec::new();
|
||||
let mask = BigUint::from(0xFFFFFFFFFFFFFFFF as u64);
|
||||
|
||||
while !x.is_zero() {
|
||||
match (&x & &mask).to_u64() {
|
||||
None =>
|
||||
panic!("Can't use BigUint in From<BigUint>"),
|
||||
Some(val) =>
|
||||
dest.push(val)
|
||||
}
|
||||
x >>= 64;
|
||||
}
|
||||
|
||||
UCN{ contents: dest }
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<BigUint> for UCN {
|
||||
fn into(self) -> BigUint {
|
||||
let mut result = BigUint::zero();
|
||||
|
||||
for part in self.contents.iter().rev() {
|
||||
result <<= 64;
|
||||
result += BigUint::from(*part);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Comparisons
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
impl PartialOrd for UCN {
|
||||
fn partial_cmp(&self, other: &UCN) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for UCN {
|
||||
fn cmp(&self, other: &UCN) -> Ordering {
|
||||
let mut iter_left = self.contents.iter();
|
||||
let mut iter_right = other.contents.iter();
|
||||
|
||||
loop {
|
||||
match (iter_left.next(), iter_right.next()) {
|
||||
(None, None) => return Ordering::Equal,
|
||||
(Some(_), None) => return Ordering::Greater,
|
||||
(None, Some(_)) => return Ordering::Less,
|
||||
(Some(x), Some(y)) =>
|
||||
match x.cmp(y) {
|
||||
Ordering::Equal => continue,
|
||||
result => return result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Tests!
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[allow(overflowing_literals)]
|
||||
fn test_builders() {
|
||||
assert_eq!(UCN{ contents: vec![] },
|
||||
UCN::from(0 as u8));
|
||||
assert_eq!(UCN{ contents: vec![0x7F] },
|
||||
UCN::from(0x7F as u8));
|
||||
assert_eq!(UCN{ contents: vec![0x7F7F] },
|
||||
UCN::from(0x7F7F as u16));
|
||||
assert_eq!(UCN{ contents: vec![0xCA5CADE5] },
|
||||
UCN::from(0xCA5CADE5 as u32));
|
||||
assert_eq!(UCN{ contents: vec![0xFFFFFFFFFFFFFFFF] },
|
||||
UCN::from(0xFFFFFFFFFFFFFFFF as u64));
|
||||
assert_eq!(UCN{ contents: vec![0x00000000FFFFFFFF] },
|
||||
UCN::from(0xFFFFFFFFFFFFFFFF as u32));
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn builder_u8_upgrade_u16(x: u8) -> bool {
|
||||
UCN::from(x) == UCN::from(x as u16)
|
||||
}
|
||||
fn builder_u16_upgrade_u32(x: u16) -> bool {
|
||||
UCN::from(x) == UCN::from(x as u32)
|
||||
}
|
||||
fn builder_u32_upgrade_u64(x: u32) -> bool {
|
||||
UCN::from(x) == UCN::from(x as u64)
|
||||
}
|
||||
fn builder_u8_roundtrips(x: u8) -> bool {
|
||||
let thereback: u8 = UCN::from(x).into();
|
||||
x == thereback
|
||||
}
|
||||
fn builder_u16_roundtrips(x: u16) -> bool {
|
||||
let thereback: u16 = UCN::from(x).into();
|
||||
x == thereback
|
||||
}
|
||||
fn builder_u32_roundtrips(x: u32) -> bool {
|
||||
let thereback: u32 = UCN::from(x).into();
|
||||
x == thereback
|
||||
}
|
||||
fn builder_u64_roundtrips(x: u64) -> bool {
|
||||
let thereback: u64 = UCN::from(x).into();
|
||||
x == thereback
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn u64_comparison_sane(x: u64, y: u64) -> bool {
|
||||
let ucnx = UCN::from(x);
|
||||
let ucny = UCN::from(y);
|
||||
ucnx.cmp(&ucny) == x.cmp(&y)
|
||||
}
|
||||
fn longer_is_greater(x: u64, y: u64) -> bool {
|
||||
if x == 0 {
|
||||
true
|
||||
} else {
|
||||
let ucnx = UCN{ contents: vec![x, 1] };
|
||||
let ucny = UCN::from(y);
|
||||
ucnx.cmp(&ucny) == Ordering::Greater
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user