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

8
.gitignore vendored
View File

@@ -11,3 +11,11 @@ Cargo.lock
# And these are just annoying # And these are just annoying
.DS_Store .DS_Store
.vscode
# Ignore testing files
**/*.o
**/*.hi
**/gen
**/.cabal-sandbox
**/cabal.sandbox.config

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 //! 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, //! the rest of the Simple-Crypto libraries. Feel free to use it other places,
//! of course, but that's its origin. //! of course, but that's its origin.
mod core; //!
mod addition;
mod basetypes;
mod comparison;
#[macro_use] #[macro_use]
mod builder; mod conversions;
mod traits; mod encoding;
mod multiplication;
mod subtraction;
use self::core::*; pub use self::basetypes::*;
use self::traits::*; pub use self::encoding::Decoder;
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);

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 { pub trait FromHex {
/// Simultaneously compute the quotient and remainder of this number and fn from_hex(s: String) -> Self;
/// 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;
}

View File

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

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);
}
}

123
tests/math/GenerateTests.hs Normal file
View File

@@ -0,0 +1,123 @@
import Control.Monad
import Data.Bits(shiftL,(.&.))
import Data.Map.Strict(Map)
import qualified Data.Map.Strict as Map
import Numeric(showHex)
import Prelude hiding (log)
import System.IO(hFlush,stdout,IOMode(..),withFile,Handle,hClose,hPutStrLn)
import System.Random(StdGen,newStdGen,random)
testTypes :: [(String, Int -> StdGen -> (Map String String, StdGen))]
testTypes = [("addition", addTest),
("modadd", modaddTest),
("subtraction", subTest),
("multiplication", mulTest),
("expandingmul", expmulTest)
]
bitSizes :: [Int]
bitSizes = [192,256,384,512,576,1024,2048,3072,4096,8192,15360]
numTests :: Int
numTests = 1000
mask :: Int -> Integer
mask bitsize = (1 `shiftL` bitsize) - 1
splitMod :: Int -> [Integer] -> [Integer]
splitMod bitsize xs = filtered ++ [m]
where
xs' = map (\x -> x .&. mask bitsize) xs
m = maximum xs'
filtered = go xs'
go (x:xs) | x == m = xs
| otherwise = x : go xs
addTest :: Int -> StdGen -> (Map String String, StdGen)
addTest bitsize gen0 = (res, gen2)
where
(a, gen1) = random gen0
(b, gen2) = random gen1
a' = a .&. mask bitsize
b' = b .&. mask bitsize
c = (a' + b') .&. mask bitsize
res = Map.fromList [("a", showHex a' ""),
("b", showHex b' ""),
("c", showHex c "")]
modaddTest :: Int -> StdGen -> (Map String String, StdGen)
modaddTest bitsize gen0 = (res, gen2)
where
(a, gen1) = random gen0
(b, gen2) = random gen1
(m, gen3) = random gen2
[a',b',m'] = splitMod bitsize [a,b,m]
c = (a' + b') `mod` m'
res = Map.fromList [("a", showHex a' ""),
("b", showHex b' ""),
("m", showHex m' ""),
("c", showHex c "")]
subTest :: Int -> StdGen -> (Map String String, StdGen)
subTest bitsize gen0 = (res, gen2)
where
(a, gen1) = random gen0
(b, gen2) = random gen1
a' = a .&. mask bitsize
b' = b .&. mask bitsize
c = (a' - b') .&. mask bitsize
res = Map.fromList [("a", showHex a' ""),
("b", showHex b' ""),
("c", showHex c "")]
mulTest :: Int -> StdGen -> (Map String String, StdGen)
mulTest bitsize gen0 = (res, gen2)
where
(a, gen1) = random gen0
(b, gen2) = random gen1
a' = a .&. mask bitsize
b' = b .&. mask bitsize
c = (a' * b') .&. mask bitsize
res = Map.fromList [("a", showHex a' ""),
("b", showHex b' ""),
("c", showHex c "")]
expmulTest :: Int -> StdGen -> (Map String String, StdGen)
expmulTest bitsize gen0 = (res, gen2)
where
(a, gen1) = random gen0
(b, gen2) = random gen1
a' = a .&. mask bitsize
b' = b .&. mask bitsize
c = (a' * b')
res = Map.fromList [("a", showHex a' ""),
("b", showHex b' ""),
("c", showHex c "")]
log :: String -> IO ()
log str =
do putStr str
hFlush stdout
generateData :: Handle -> (StdGen -> (Map String String, StdGen)) ->
StdGen -> () ->
IO StdGen
generateData hndl generator gen () =
do let (res, gen') = generator gen
forM_ (Map.toList res) $ \ (key,val) ->
do hPutStrLn hndl (key ++ ": " ++ val)
log "."
return gen'
main :: IO ()
main =
forM_ testTypes $ \ (testName, testFun) ->
forM_ bitSizes $ \ bitsize ->
do log ("Generating " ++ show bitsize ++ "-bit " ++ testName ++ " tests")
withFile (testName ++ "U" ++ show bitsize ++ ".test") WriteMode $ \ hndl ->
do gen <- newStdGen
foldM_ (generateData hndl (testFun bitsize))
gen
(replicate numTests ())
hClose hndl
log " done\n"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3000
tests/math/additionU192.test Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3000
tests/math/additionU256.test Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3000
tests/math/additionU384.test Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3000
tests/math/additionU512.test Normal file

File diff suppressed because it is too large Load Diff

3000
tests/math/additionU576.test Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4000
tests/math/modaddU1024.test Normal file

File diff suppressed because it is too large Load Diff

4000
tests/math/modaddU15360.test Normal file

File diff suppressed because it is too large Load Diff

4000
tests/math/modaddU192.test Normal file

File diff suppressed because it is too large Load Diff

4000
tests/math/modaddU2048.test Normal file

File diff suppressed because it is too large Load Diff

4000
tests/math/modaddU256.test Normal file

File diff suppressed because it is too large Load Diff

4000
tests/math/modaddU3072.test Normal file

File diff suppressed because it is too large Load Diff

4000
tests/math/modaddU384.test Normal file

File diff suppressed because it is too large Load Diff

4000
tests/math/modaddU4096.test Normal file

File diff suppressed because it is too large Load Diff

4000
tests/math/modaddU512.test Normal file

File diff suppressed because it is too large Load Diff

4000
tests/math/modaddU576.test Normal file

File diff suppressed because it is too large Load Diff

4000
tests/math/modaddU8192.test Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff