A second crack at fixed-sized numbers.

This commit is contained in:
2018-06-02 09:26:34 -07:00
parent f3d4b102c0
commit f088f0f9a5
68 changed files with 177087 additions and 40 deletions

165
src/cryptonum/addition.rs Normal file
View File

@@ -0,0 +1,165 @@
use cryptonum::{U192, U256, U384, U512, U576,
U1024, U2048, U3072, U4096, U8192,
U15360};
use cryptonum::comparison::bignum_ge;
use cryptonum::subtraction::raw_subtraction;
use std::ops::{Add,AddAssign};
pub fn raw_addition(x: &mut [u64], y: &[u64]) -> u64 {
assert_eq!(x.len(), y.len());
let xiter = x.iter_mut();
let yiter = y.iter();
let mut carry = 0;
for (x, y) in xiter.zip(yiter) {
let bigger = (*x as u128) + (*y as u128) + carry;
carry = bigger >> 64;
*x = bigger as u64;
}
carry as u64
}
pub trait ModAdd {
fn modadd(&mut self, y: &Self, m: &Self);
}
macro_rules! generate_adders
{
($name: ident) => {
impl AddAssign for $name {
fn add_assign(&mut self, rhs: $name) {
raw_addition(&mut self.values, &rhs.values);
}
}
impl<'a> AddAssign<&'a $name> for $name {
fn add_assign(&mut self, rhs: &$name) {
raw_addition(&mut self.values, &rhs.values);
}
}
impl Add for $name {
type Output = $name;
fn add(self, other: $name) -> $name {
let mut result = $name{ values: self.values };
result.add_assign(other);
result
}
}
impl<'a> Add<&'a $name> for $name {
type Output = $name;
fn add(self, other: &$name) -> $name {
let mut result = $name{ values: self.values };
result.add_assign(other);
result
}
}
impl<'a,'b> Add<&'a $name> for &'b $name {
type Output = $name;
fn add(self, other: &$name) -> $name {
let mut result = $name{ values: self.values };
result.add_assign(other);
result
}
}
impl ModAdd for $name {
fn modadd(&mut self, y: &$name, m: &$name) {
let carry = raw_addition(&mut self.values, &y.values);
if carry > 0 {
let mut left = Vec::with_capacity(self.values.len() + 1);
for x in self.values.iter() { left.push(*x) }
left.push(carry);
let mut right = Vec::with_capacity(self.values.len() + 1);
for x in m.values.iter() { right.push(*x) }
right.push(0);
raw_subtraction(&mut left, &right);
for i in 0..self.values.len() {
self.values[i] = left[i];
}
}
if bignum_ge(&self.values, &m.values) {
raw_subtraction(&mut self.values, &m.values);
}
}
}
}
}
generate_adders!(U192);
generate_adders!(U256);
generate_adders!(U384);
generate_adders!(U512);
generate_adders!(U576);
generate_adders!(U1024);
generate_adders!(U2048);
generate_adders!(U3072);
generate_adders!(U4096);
generate_adders!(U8192);
generate_adders!(U15360);
#[cfg(test)]
use testing::run_test;
#[cfg(test)]
use cryptonum::Decoder;
macro_rules! generate_tests {
($name: ident, $testname: ident, $modtestname: ident) => (
#[cfg(test)]
#[test]
#[allow(non_snake_case)]
fn $testname() {
let fname = format!("tests/math/addition{}.test",
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 mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let c = $name::from_bytes(cbytes);
assert_eq!(&a + &b, c);
a += b;
assert_eq!(a, c);
});
}
#[cfg(test)]
#[test]
#[allow(non_snake_case)]
fn $modtestname() {
let fname = format!("tests/math/modadd{}.test",
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, cbytes) = case.get("c").unwrap();
let (neg3, mbytes) = case.get("m").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3);
let mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let m = $name::from_bytes(mbytes);
let c = $name::from_bytes(cbytes);
a.modadd(&b, &m);
assert_eq!(a, c);
});
}
)
}
generate_tests!(U192,u192,modU192);
generate_tests!(U256,u256,modU256);
generate_tests!(U384,u384,modU384);
generate_tests!(U512,u512,modU512);
generate_tests!(U576,u576,modU576);
generate_tests!(U1024,u1024,modU1024);
generate_tests!(U2048,u2048,modU2048);
generate_tests!(U3072,u3072,modU3072);
generate_tests!(U4096,u4096,modU4096);
generate_tests!(U8192,u8192,modU8192);
generate_tests!(U15360,u15360,modU15360);

170
src/cryptonum/basetypes.rs Normal file
View File

@@ -0,0 +1,170 @@
use std::fmt;
use std::fmt::Write;
macro_rules! generate_unsigned
{
($name: ident, $size: expr) => {
pub struct $name {
pub(crate) values: [u64; $size/64]
}
impl Clone for $name {
fn clone(&self) -> $name {
let mut result = $name{ values: [0; $size/64] };
for (idx,val) in self.values.iter().enumerate() {
result.values[idx] = *val;
}
result
}
}
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, stringify!($name))?;
write!(f, "{{ ")?;
for x in self.values.iter() {
write!(f, "{:X} ", *x)?;
}
write!(f, "}} ")
}
}
impl fmt::UpperHex for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut wrote_something = false;
for x in self.values.iter() {
if !wrote_something && (*x == 0) {
continue;
} else {
f.write_char(tochar_upper(x >> 60))?;
f.write_char(tochar_upper(x >> 56))?;
f.write_char(tochar_upper(x >> 52))?;
f.write_char(tochar_upper(x >> 48))?;
f.write_char(tochar_upper(x >> 44))?;
f.write_char(tochar_upper(x >> 40))?;
f.write_char(tochar_upper(x >> 36))?;
f.write_char(tochar_upper(x >> 32))?;
f.write_char(tochar_upper(x >> 28))?;
f.write_char(tochar_upper(x >> 24))?;
f.write_char(tochar_upper(x >> 20))?;
f.write_char(tochar_upper(x >> 16))?;
f.write_char(tochar_upper(x >> 12))?;
f.write_char(tochar_upper(x >> 8))?;
f.write_char(tochar_upper(x >> 4))?;
f.write_char(tochar_upper(x >> 0))?;
wrote_something = true;
}
}
if !wrote_something {
f.write_char('0')?
}
Ok(())
}
}
impl fmt::LowerHex for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut wrote_something = false;
for x in self.values.iter() {
if !wrote_something && (*x == 0) {
continue;
} else {
f.write_char(tochar_lower(x >> 60))?;
f.write_char(tochar_lower(x >> 56))?;
f.write_char(tochar_lower(x >> 52))?;
f.write_char(tochar_lower(x >> 48))?;
f.write_char(tochar_lower(x >> 44))?;
f.write_char(tochar_lower(x >> 40))?;
f.write_char(tochar_lower(x >> 36))?;
f.write_char(tochar_lower(x >> 32))?;
f.write_char(tochar_lower(x >> 28))?;
f.write_char(tochar_lower(x >> 24))?;
f.write_char(tochar_lower(x >> 20))?;
f.write_char(tochar_lower(x >> 16))?;
f.write_char(tochar_lower(x >> 12))?;
f.write_char(tochar_lower(x >> 8))?;
f.write_char(tochar_lower(x >> 4))?;
f.write_char(tochar_lower(x >> 0))?;
wrote_something = true;
}
}
if !wrote_something {
f.write_char('0')?
}
Ok(())
}
}
impl $name {
pub fn new() -> $name {
$name{ values: [0; $size/64 ] }
}
pub fn is_odd(&self) -> bool {
(self.values[0] & 1) == 1
}
pub fn is_even(&self) -> bool {
(self.values[0] & 1) == 0
}
}
}
}
generate_unsigned!(U192, 192);
generate_unsigned!(U256, 256);
generate_unsigned!(U384, 384);
generate_unsigned!(U512, 512);
generate_unsigned!(U576, 576);
generate_unsigned!(U1024, 1024);
generate_unsigned!(U2048, 2048);
generate_unsigned!(U3072, 3072);
generate_unsigned!(U4096, 4096);
generate_unsigned!(U8192, 8192);
generate_unsigned!(U15360, 15360);
fn tochar_upper(x: u64) -> char {
match (x as u8) & (0xF as u8) {
0x0 => '0',
0x1 => '1',
0x2 => '2',
0x3 => '3',
0x4 => '4',
0x5 => '5',
0x6 => '6',
0x7 => '7',
0x8 => '8',
0x9 => '9',
0xA => 'A',
0xB => 'B',
0xC => 'C',
0xD => 'D',
0xE => 'E',
0xF => 'F',
_ => panic!("the world is broken")
}
}
fn tochar_lower(x: u64) -> char {
match (x as u8) & (0xF as u8) {
0x0 => '0',
0x1 => '1',
0x2 => '2',
0x3 => '3',
0x4 => '4',
0x5 => '5',
0x6 => '6',
0x7 => '7',
0x8 => '8',
0x9 => '9',
0xA => 'a',
0xB => 'b',
0xC => 'c',
0xD => 'd',
0xE => 'e',
0xF => 'f',
_ => panic!("the world is broken")
}
}

View File

@@ -0,0 +1,65 @@
use cryptonum::{U192, U256, U384, U512, U576,
U1024, U2048, U3072, U4096, U8192,
U15360};
use std::cmp::{Ord,Ordering};
pub fn bignum_cmp(x: &[u64], y: &[u64]) -> Ordering {
assert_eq!(x.len(), y.len());
let xiter = x.iter().rev();
let yiter = y.iter().rev();
for (x,y) in xiter.zip(yiter) {
match x.cmp(&y) {
Ordering::Greater => return Ordering::Greater,
Ordering::Less => return Ordering::Less,
Ordering::Equal => continue
}
}
Ordering::Equal
}
pub fn bignum_ge(x: &[u64], y: &[u64]) -> bool {
match bignum_cmp(x,y) {
Ordering::Greater => true,
Ordering::Less => false,
Ordering::Equal => true
}
}
macro_rules! generate_compares
{
($name: ident) => {
impl PartialEq for $name {
fn eq(&self, other: &$name) -> bool {
bignum_cmp(&self.values, &other.values) == Ordering::Equal
}
}
impl Eq for $name {}
impl Ord for $name {
fn cmp(&self, other: &$name) -> Ordering {
bignum_cmp(&self.values, &other.values)
}
}
impl PartialOrd for $name {
fn partial_cmp(&self, other: &$name) -> Option<Ordering> {
Some(bignum_cmp(&self.values, &other.values))
}
}
}
}
generate_compares!(U192);
generate_compares!(U256);
generate_compares!(U384);
generate_compares!(U512);
generate_compares!(U576);
generate_compares!(U1024);
generate_compares!(U2048);
generate_compares!(U3072);
generate_compares!(U4096);
generate_compares!(U8192);
generate_compares!(U15360);

View File

@@ -0,0 +1,152 @@
use cryptonum::{U192, U256, U384, U512, U576,
U1024, U2048, U3072, U4096, U8192,
U15360};
macro_rules! generate_basetype_froms
{
($name: ident) => {
generate_basetype_from!($name, u8);
generate_basetype_from!($name, u16);
generate_basetype_from!($name, u32);
generate_basetype_from!($name, u64);
generate_basetype_from!($name, usize);
impl From<u128> for $name {
fn from(x: u128) -> $name {
let mut base = $name::new();
base.values[0] = x as u64;
base.values[1] = (x >> 64) as u64;
base
}
}
}
}
macro_rules! generate_basetype_from
{
($name: ident, $basetype: ident) => {
impl From<$basetype> for $name {
fn from(x: $basetype) -> $name {
let mut base = $name::new();
base.values[0] = x as u64;
base
}
}
}
}
macro_rules! convert_from_smaller
{
($name: ident, $smalltype: ident) => {
impl From<$smalltype> for $name {
fn from(x: $smalltype) -> $name {
let mut base = $name::new();
for (idx, val) in x.values.iter().enumerate() {
base.values[idx] = *val;
}
base
}
}
}
}
macro_rules! convert_from_larger
{
($name: ident, $bigtype: ident) => {
impl From<$bigtype> for $name {
fn from(x: $bigtype) -> $name {
let mut base = $name::new();
for i in 0..base.values.len() {
base.values[i] = x.values[i];
}
base
}
}
}
}
macro_rules! convert_bignums
{
($bigger: ident, $smaller: ident) => {
convert_from_smaller!($bigger, $smaller);
convert_from_larger!($smaller, $bigger);
}
}
generate_basetype_froms!(U192);
generate_basetype_froms!(U256);
generate_basetype_froms!(U384);
generate_basetype_froms!(U512);
generate_basetype_froms!(U576);
generate_basetype_froms!(U1024);
generate_basetype_froms!(U2048);
generate_basetype_froms!(U3072);
generate_basetype_froms!(U4096);
generate_basetype_froms!(U8192);
generate_basetype_froms!(U15360);
convert_bignums!(U256, U192);
convert_bignums!(U384, U192);
convert_bignums!(U512, U192);
convert_bignums!(U576, U192);
convert_bignums!(U1024, U192);
convert_bignums!(U2048, U192);
convert_bignums!(U3072, U192);
convert_bignums!(U4096, U192);
convert_bignums!(U8192, U192);
convert_bignums!(U15360, U192);
convert_bignums!(U384, U256);
convert_bignums!(U512, U256);
convert_bignums!(U576, U256);
convert_bignums!(U1024, U256);
convert_bignums!(U2048, U256);
convert_bignums!(U3072, U256);
convert_bignums!(U4096, U256);
convert_bignums!(U8192, U256);
convert_bignums!(U15360, U256);
convert_bignums!(U512, U384);
convert_bignums!(U576, U384);
convert_bignums!(U1024, U384);
convert_bignums!(U2048, U384);
convert_bignums!(U3072, U384);
convert_bignums!(U4096, U384);
convert_bignums!(U8192, U384);
convert_bignums!(U15360, U384);
convert_bignums!(U576, U512);
convert_bignums!(U1024, U512);
convert_bignums!(U2048, U512);
convert_bignums!(U3072, U512);
convert_bignums!(U4096, U512);
convert_bignums!(U8192, U512);
convert_bignums!(U15360, U512);
convert_bignums!(U1024, U576);
convert_bignums!(U2048, U576);
convert_bignums!(U3072, U576);
convert_bignums!(U4096, U576);
convert_bignums!(U8192, U576);
convert_bignums!(U15360, U576);
convert_bignums!(U2048, U1024);
convert_bignums!(U3072, U1024);
convert_bignums!(U4096, U1024);
convert_bignums!(U8192, U1024);
convert_bignums!(U15360, U1024);
convert_bignums!(U3072, U2048);
convert_bignums!(U4096, U2048);
convert_bignums!(U8192, U2048);
convert_bignums!(U15360, U2048);
convert_bignums!(U4096, U3072);
convert_bignums!(U8192, U3072);
convert_bignums!(U15360, U3072);
convert_bignums!(U8192, U4096);
convert_bignums!(U15360, U4096);
convert_bignums!(U15360, U8192);

48
src/cryptonum/encoding.rs Normal file
View File

@@ -0,0 +1,48 @@
use cryptonum::{U192, U256, U384, U512, U576,
U1024, U2048, U3072, U4096, U8192,
U15360};
pub trait Decoder {
fn from_bytes(x: &[u8]) -> Self;
}
macro_rules! generate_decoder {
($name: ident) => {
impl Decoder for $name {
fn from_bytes(x: &[u8]) -> $name {
let mut res = $name::new();
let mut item = 0;
let mut shift = 0;
let mut idx = 0;
for v in x.iter().rev() {
item |= (*v as u64) << shift;
shift += 8;
if shift == 64 {
shift = 0;
res.values[idx] = item;
idx += 1;
item = 0;
}
}
if item != 0 {
res.values[idx] = item;
}
res
}
}
}
}
generate_decoder!(U192);
generate_decoder!(U256);
generate_decoder!(U384);
generate_decoder!(U512);
generate_decoder!(U576);
generate_decoder!(U1024);
generate_decoder!(U2048);
generate_decoder!(U3072);
generate_decoder!(U4096);
generate_decoder!(U8192);
generate_decoder!(U15360);

View File

@@ -3,22 +3,15 @@
//! This module is designed to provide large, fixed-width number support for
//! the rest of the Simple-Crypto libraries. Feel free to use it other places,
//! of course, but that's its origin.
mod core;
//!
mod addition;
mod basetypes;
mod comparison;
#[macro_use]
mod builder;
mod traits;
mod conversions;
mod encoding;
mod multiplication;
mod subtraction;
use self::core::*;
use self::traits::*;
use std::cmp::Ordering;
use std::fmt::{Debug,Error,Formatter};
use std::ops::*;
construct_unsigned!(U512, u512, 8);
construct_unsigned!(U1024, u1024, 16);
construct_unsigned!(U2048, u2048, 32);
construct_unsigned!(U3072, u3072, 48);
construct_unsigned!(U4096, u4096, 64);
construct_unsigned!(U7680, u7680, 120);
construct_unsigned!(U8192, u8192, 128);
construct_unsigned!(U15360, u15360, 240);
pub use self::basetypes::*;
pub use self::encoding::Decoder;

View File

@@ -0,0 +1,156 @@
use cryptonum::{U192, U256, U384, U512, U576,
U1024, U2048, U3072, U4096, U8192,
U15360};
use std::ops::{Mul,MulAssign};
fn raw_multiplication(x: &[u64], y: &[u64], z: &mut [u64])
{
assert_eq!(x.len(), y.len());
assert_eq!(x.len() * 2, z.len());
// clear out the destination array, because we're going to use it as a
// temporary
for i in 0..z.len() {
z[i] = 0;
}
for i in 0..y.len() { // this may legitimately be off by one
let mut carry = 0;
for j in 0..x.len() { // ditto
let old = z[i+j] as u128;
let x128 = x[j] as u128;
let y128 = y[i] as u128;
let uv = old + (x128 * y128) + carry;
z[i+j] = uv as u64;
carry = uv >> 64;
}
z[i+x.len()] = carry as u64;
}
}
macro_rules! generate_multipliers
{
($name: ident, $size: expr) => {
impl MulAssign for $name {
fn mul_assign(&mut self, rhs: $name) {
let mut result = [0; $size/32];
raw_multiplication(&self.values, &rhs.values, &mut result);
for i in 0..self.values.len() {
self.values[i] = result[i];
}
}
}
impl<'a> MulAssign<&'a $name> for $name {
fn mul_assign(&mut self, rhs: &$name) {
let mut result = [0; $size/32];
raw_multiplication(&self.values, &rhs.values, &mut result);
for i in 0..self.values.len() {
self.values[i] = result[i];
}
}
}
impl Mul for $name {
type Output = $name;
fn mul(self, rhs: $name) -> $name {
let mut result = self.clone();
result.mul_assign(rhs);
result
}
}
impl<'a> Mul<&'a $name> for $name {
type Output = $name;
fn mul(self, rhs: &$name) -> $name {
let mut result = self.clone();
result.mul_assign(rhs);
result
}
}
impl<'a,'b> Mul<&'a $name> for &'b $name {
type Output = $name;
fn mul(self, rhs: &$name) -> $name {
let mut result = self.clone();
result.mul_assign(rhs);
result
}
}
}
}
generate_multipliers!(U192, 192);
generate_multipliers!(U256, 256);
generate_multipliers!(U384, 384);
generate_multipliers!(U512, 512);
generate_multipliers!(U576, 576);
generate_multipliers!(U1024, 1024);
generate_multipliers!(U2048, 2048);
generate_multipliers!(U3072, 3072);
generate_multipliers!(U4096, 4096);
generate_multipliers!(U8192, 8192);
generate_multipliers!(U15360, 15360);
#[cfg(test)]
use cryptonum::Decoder;
#[cfg(test)]
use testing::run_test;
macro_rules! generate_tests {
($name: ident, $testname: ident) => (
#[test]
#[allow(non_snake_case)]
fn $testname() {
let fname = format!("tests/math/multiplication{}.test",
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 mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let c = $name::from_bytes(cbytes);
assert_eq!(&a * &b, c);
a *= b;
assert_eq!(a, c);
});
}
);
($name: ident, $testname: ident, $dblname: ident, $doubletest: ident) => (
generate_tests!($name, $testname);
#[test]
#[allow(non_snake_case)]
fn $doubletest() {
let fname = format!("tests/math/expandingmul{}.test",
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 = $dblname::from_bytes(cbytes);
let mut r = $dblname::new();
raw_multiplication(&a.values, &b.values, &mut r.values);
assert_eq!(c, r);
});
}
)
}
generate_tests!(U192,u192,U384,expandingU384);
generate_tests!(U256,u256,U512,expandingU512);
generate_tests!(U384,u384);
generate_tests!(U512,u512,U1024,expandingU1024);
generate_tests!(U576,u576);
generate_tests!(U1024,u1024,U2048,expandingU2048);
generate_tests!(U2048,u2048,U4096,expandingU4096);
generate_tests!(U3072,u3072);
generate_tests!(U4096,u4096,U8192,expandingU8192);
generate_tests!(U8192,u8192);
generate_tests!(U15360,u15360);

View File

@@ -0,0 +1,121 @@
use cryptonum::{U192, U256, U384, U512, U576,
U1024, U2048, U3072, U4096, U8192,
U15360};
use cryptonum::addition::raw_addition;
use std::ops::{Sub,SubAssign};
pub fn raw_subtraction(x: &mut [u64], y: &[u64])
{
assert_eq!(x.len(), y.len());
let mut negatedy = Vec::with_capacity(y.len());
for val in y.iter() {
negatedy.push(!*val);
}
let mut one = Vec::with_capacity(y.len());
one.resize(y.len(), 0);
one[0] = 1;
raw_addition(&mut negatedy, &one);
raw_addition(x, &negatedy);
}
macro_rules! generate_subbers
{
($name: ident) => {
impl SubAssign for $name {
fn sub_assign(&mut self, rhs: $name) {
raw_subtraction(&mut self.values, &rhs.values);
}
}
impl<'a> SubAssign<&'a $name> for $name {
fn sub_assign(&mut self, rhs: &$name) {
raw_subtraction(&mut self.values, &rhs.values);
}
}
impl Sub for $name {
type Output = $name;
fn sub(self, rhs: $name) -> $name {
let mut result = $name{ values: self.values };
raw_subtraction(&mut result.values, &rhs.values);
result
}
}
impl<'a> Sub<&'a $name> for $name {
type Output = $name;
fn sub(self, rhs: &$name) -> $name {
let mut result = $name{ values: self.values };
raw_subtraction(&mut result.values, &rhs.values);
result
}
}
impl<'a,'b> Sub<&'a $name> for &'b $name {
type Output = $name;
fn sub(self, rhs: &$name) -> $name {
let mut result = (*self).clone();
raw_subtraction(&mut result.values, &rhs.values);
result
}
}
}
}
generate_subbers!(U192);
generate_subbers!(U256);
generate_subbers!(U384);
generate_subbers!(U512);
generate_subbers!(U576);
generate_subbers!(U1024);
generate_subbers!(U2048);
generate_subbers!(U3072);
generate_subbers!(U4096);
generate_subbers!(U8192);
generate_subbers!(U15360);
#[cfg(test)]
use testing::run_test;
#[cfg(test)]
use cryptonum::Decoder;
macro_rules! generate_tests {
($name: ident, $testname: ident) => (
#[cfg(test)]
#[test]
#[allow(non_snake_case)]
fn $testname() {
let fname = format!("tests/math/subtraction{}.test",
stringify!($name));
println!("FOO!");
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 mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes);
let c = $name::from_bytes(cbytes);
let r = &a - &b;
assert_eq!(r, c);
a -= b;
assert_eq!(a, c);
});
}
)
}
generate_tests!(U192,u192);
generate_tests!(U256,u256);
generate_tests!(U384,u384);
generate_tests!(U512,u512);
generate_tests!(U576,u576);
generate_tests!(U1024,u1024);
generate_tests!(U2048,u2048);
generate_tests!(U3072,u3072);
generate_tests!(U4096,u4096);
generate_tests!(U8192,u8192);
generate_tests!(U15360,u15360);

View File

@@ -1,12 +1,3 @@
pub trait CryptoNum {
/// Simultaneously compute the quotient and remainder of this number and
/// the given divisor.
fn divmod(&self, a: &Self, q: &mut Self, r: &mut Self);
/// Convert a number to a series of bytes, in standard order (most to
/// least significant)
fn to_bytes(&self) -> Vec<u8>;
/// Convert a series of bytes into the number. The size of the given slice
/// must be greater than or equal to the size of the number, and must be
/// a multiple of 8 bytes long. Unused bytes should be ignored.
fn from_bytes(&[u8]) -> Self;
}
pub trait FromHex {
fn from_hex(s: String) -> Self;
}

View File

@@ -1,4 +1,3 @@
#![feature(i128_type)]
//! # Simple Crypto: A quaint little crypto library for rust.
//!
//! This is the simple_crypto library. Its goal is to provide straightforward
@@ -11,19 +10,13 @@
//! when they should use it, and examples. For now, it mostly just fowards
//! off to more detailed modules. Help requested!
#[cfg(test)]
#[macro_use]
extern crate quickcheck;
//#[cfg(test)]
//#[macro_use]
//extern crate quickcheck;
/// The cryptonum module provides support for large numbers at fixed,
/// cryptographically-relevant sizes.
pub mod cryptonum;
#[cfg(test)]
mod test {
#[test]
fn testing_works() {
assert!(true);
}
}
mod testing;

62
src/testing.rs Normal file
View File

@@ -0,0 +1,62 @@
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::str::Lines;
fn next_value_set(line: &str) -> (String, bool, Vec<u8>)
{
assert!(line.is_ascii());
let mut items = line.split(": ");
let key = items.next().unwrap();
let valbits = items.next().unwrap();
let neg = valbits.contains('-');
let valbitsnoneg = valbits.trim_left_matches("-");
let mut nibble_iter = valbitsnoneg.chars().rev();
let mut val = Vec::new();
while let Some(c1) = nibble_iter.next() {
match nibble_iter.next() {
None => {
val.push( c1.to_digit(16).unwrap() as u8 );
}
Some(c2) => {
let b1 = c1.to_digit(16).unwrap() as u8;
let b2 = c2.to_digit(16).unwrap() as u8;
val.push( (b2 << 4) | b1 );
}
}
}
val.reverse();
(key.to_string(), neg, val)
}
fn next_test_case(contents: &mut Lines, lines: usize) ->
Option<HashMap<String,(bool,Vec<u8>)>>
{
let mut res = HashMap::new();
let mut count = 0;
while count < lines {
let line = contents.next()?;
let (key, neg, val) = next_value_set(line);
res.insert(key, (neg,val));
count += 1;
}
Some(res)
}
pub fn run_test<F>(fname: String, i: usize, f: F)
where F: Fn(HashMap<String,(bool,Vec<u8>)>)
{
let mut file = File::open(fname).unwrap();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
let mut iter = contents.lines();
while let Some(scase) = next_test_case(&mut iter, i) {
f(scase);
}
}