Initial commit!

This commit is contained in:
2018-09-26 14:47:30 -05:00
commit 3b68363b49
389 changed files with 1415972 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
/target
**/*.rs.bk
Cargo.lock
generate.hi
generate.o
generate

6
Cargo.toml Normal file
View File

@@ -0,0 +1,6 @@
[package]
name = "cryptonum"
version = "0.1.0"
authors = ["awick"]
[dependencies]

243
generate.hs Normal file
View File

@@ -0,0 +1,243 @@
import Control.Monad(foldM_,forM_,when)
import Data.Bits(shiftL,shiftR)
import Data.List(sort)
import qualified Data.Map.Strict as Map
import Numeric(showHex)
import Prelude hiding (log)
import System.Directory(createDirectoryIfMissing)
import System.Environment(getArgs)
import System.FilePath((</>))
import System.IO(Handle,IOMode(WriteMode),hPutStrLn,withFile,hFlush,hPutStr,stderr)
import System.Random(StdGen,newStdGen,random,split)
data Level = Base | DivMul | Barrett
deriving (Eq, Ord, Show)
bitSizes :: [Int]
bitSizes = [192,256,384,512,576,1024,2048,3072,4096,7680,8192,15360]
numberOfTests :: Int
numberOfTests = 1000
baseMap :: Map.Map Int Level
baseMap = foldr (\ s m -> Map.insert s Barrett m) Map.empty bitSizes
smartInsert :: Int -> Level -> Map.Map Int Level -> Map.Map Int Level
smartInsert size level map = Map.insertWith max size level map
generateNext :: Int -> Level -> Map.Map Int Level -> Map.Map Int Level
generateNext size Base acc = acc
generateNext size DivMul acc = smartInsert (size + 64) Base $
smartInsert (size * 2) Base $
acc
generateNext size Barrett acc = smartInsert (size + 64) Base $
smartInsert (size * 2) Base $
smartInsert ( size + 64) DivMul $
smartInsert ((size * 2) + 64) DivMul $
acc
step :: Map.Map Int Level -> Map.Map Int Level
step m = Map.foldrWithKey generateNext m m
fixpoint :: Map.Map Int Level -> Map.Map Int Level
fixpoint m | m == m' = m
| otherwise = fixpoint m'
where m' = step m
finalMap :: Map.Map Int Level
finalMap = fixpoint baseMap
conversions :: [Int] -> [(Int,Int)]
conversions [] = []
conversions (x:rest) = (map (\ y -> (x,y)) rest) ++ conversions rest
generateTestBlock :: Handle -> String -> IO ()
generateTestBlock hndl name =
do hPutStrLn hndl (" mod " ++ name ++ " {")
hPutStrLn hndl (" use super::super::*;\n")
hPutStrLn hndl (" use testing::run_test;\n")
forM_ (sort (Map.toList finalMap)) $ \ (size, kind) ->
when (kind >= Base) $
hPutStrLn hndl (" generate_" ++ name ++
"_tests!(U" ++ show size ++ ");")
hPutStrLn hndl " }"
generateInvocs :: IO ()
generateInvocs =
withFile "src/unsigned/invoc.rs" WriteMode $ \ hndl ->
do forM_ (sort (Map.toList finalMap)) $ \ item ->
case item of
(size, Base) ->
hPutStrLn hndl ("generate_number!(U" ++ show size ++ ", " ++
show (size `div` 64) ++ ");")
(size, DivMul) ->
hPutStrLn hndl ("generate_number!(U" ++ show size ++ ", " ++
show (size `div` 64) ++ ", U" ++
show (size + 64) ++ ", U" ++
show (size * 2) ++ ");")
(size, Barrett) ->
hPutStrLn hndl ("generate_number!(U" ++ show size ++ ", " ++
show (size `div` 64) ++ ", U" ++
show (size + 64) ++ ", U" ++
show (size * 2) ++ ", U" ++
show ((size * 2) + 64) ++ ", BarrettU" ++
show size ++ ");")
hPutStrLn hndl ""
forM_ (conversions (Map.keys finalMap)) $ \ (a,b) ->
hPutStrLn hndl ("conversion_impls!(U" ++ show a ++ ", " ++
"U" ++ show b ++ ");")
hPutStrLn hndl "\n#[cfg(test)]"
hPutStrLn hndl "mod tests {"
generateTestBlock hndl "base"
hPutStrLn hndl "}"
log :: String -> IO ()
log str = hPutStr stderr str >> hFlush stderr
generateTests :: Level -> String -> a -> (Int -> a -> (Map.Map String String, a)) -> IO ()
generateTests minLevel directory init runner =
forM_ (sort (Map.toList finalMap)) $ \ (size, myLevel) ->
when (myLevel >= minLevel) $
do createDirectoryIfMissing True ("testdata" </> directory)
log $ "Generating " ++ show size ++ "-bit " ++ directory ++ " tests "
let dest = "testdata" </> directory </> ("U" ++ show size ++ ".tests")
withFile dest WriteMode $ \ hndl ->
foldM_ (writer hndl size runner) init [0..numberOfTests]
log "done.\n"
where
writer :: Handle -> Int -> (Int -> a -> (Map.Map String String, a)) -> a -> Int -> IO a
writer hndl size runner input _ =
do let (output, acc) = runner size input
forM_ (Map.toList output) $ \ (key, val) ->
do hPutStrLn hndl (key ++ ": " ++ val)
log "."
return acc
type Database = (Map.Map String [Integer], StdGen)
emptyDatabase :: StdGen -> (Database, StdGen)
emptyDatabase g0 =
let (g, g') = split g0
in ((Map.empty, g), g')
generateNum :: Database -> String -> Int -> (Integer, Database)
generateNum (db, rng0) varname size =
let (x, rng1) = random rng0
x' = modulate x size
before = Map.findWithDefault [] varname db
in if length (filter (== x') before) < 10
then (x', (Map.insert varname (x':before) db, rng1))
else generateNum (db, rng1) varname size
modulate :: Integer -> Int -> Integer
modulate x size = x `mod` (2 ^ size)
showX :: (Integral a, Show a) => a -> String
showX x = showHex x ""
showB :: Bool -> String
showB False = "0"
showB True = "1"
base :: Integer
base = 2 ^ (64 :: Integer)
barrett :: Integer -> Integer
barrett m = (base ^ (2 * k)) `div` m
where
k = computeK m
computeK :: Integer -> Int
computeK v = go 0 1
where
go k acc | v <= acc = k
| otherwise = go (k + 1) (acc * base)
generateAllTheTests :: IO ()
generateAllTheTests =
do gen0 <- newStdGen
let (db1, gen1) = emptyDatabase gen0
generateTests DivMul "add" db1 $ \ size memory0 ->
let (a, memory1) = generateNum memory0 "a" size
(b, memory2) = generateNum memory1 "b" size
c = modulate (a + b) size
in (Map.fromList [("a", showX a), ("b", showX b), ("c", showX c)], memory2)
let (db2, gen2) = emptyDatabase gen1
generateTests Barrett "barrett_gen" db2 $ \ size memory0 ->
let (m, memory1) = generateNum memory0 "m" size
k = computeK m
u = barrett m
in (Map.fromList [("m", showX m), ("k", showX k), ("u", showX u)], memory1)
let (db3, gen3) = emptyDatabase gen1
generateTests Barrett "barrett_reduce" db3 $ \ size memory0 ->
let (m, memory1) = generateNum memory0 "m" size
(x, memory2) = generateNum memory1 "x" (min size (2 * k * 64))
k = computeK m
u = barrett m
r = x `mod` m
res = Map.fromList [("m", showX m), ("x", showX x),
("k", showX k), ("u", showX u),
("r", showX r)]
in (res, memory2)
let (db4, gen4) = emptyDatabase gen2
generateTests Base "base" db4 $ \ size memory0 ->
let (x, memory1) = generateNum memory0 "x" size
(m, memory2) = generateNum memory1 "m" size
m' = m `mod` (fromIntegral size `div` 64)
r = x `mod` (2 ^ (64 * m'))
res = Map.fromList [("x", showX x), ("z", showB (x == 0)),
("e", showB (even x)), ("o", showB (odd x)),
("m", showX m'), ("r", showX r)]
in (res, memory2)
let (db5, gen5) = emptyDatabase gen3
generateTests Base "cmp" db5 $ \ size memory0 ->
let (a, memory1) = generateNum memory0 "a" size
(b, memory2) = generateNum memory1 "b" size
res = Map.fromList [("a", showX a), ("b", showX b),
("g", showB (a > b)), ("l", showB (a < b)),
("e", showB (a == b))]
in (res, memory2)
let (db6, gen6) = emptyDatabase gen4
generateTests DivMul "div" db6 $ \ size memory0 ->
let (a, memory1) = generateNum memory0 "a" size
(b, memory2) = generateNum memory1 "b" size
res = Map.fromList [("a", showX a), ("b", showX b), ("c", showX (a `div` b))]
in (res, memory2)
let (db7, gen7) = emptyDatabase gen5
generateTests DivMul "mul" db7 $ \ size memory0 ->
let (a, memory1) = generateNum memory0 "a" size
(b, memory2) = generateNum memory1 "b" size
c = a * b
d = modulate c size
res = Map.fromList [("a", showX a), ("b", showX b),
("c", showX c), ("d", showX d)]
in (res, memory2)
let (db8, gen8) = emptyDatabase gen6
generateTests Base "shiftl" db8 $ \ size memory0 ->
let (a, memory1) = generateNum memory0 "a" size
(l, memory2) = generateNum memory1 "l" size
l' = l `mod` fromIntegral (computeK a * 64)
r = modulate (a `shiftL` fromIntegral l') size
res = Map.fromList [("a", showX a), ("l", showX l'), ("r", showX r)]
in (res, memory2)
let (db9, gen9) = emptyDatabase gen6
generateTests Base "shiftr" db9 $ \ size memory0 ->
let (a, memory1) = generateNum memory0 "a" size
(l, memory2) = generateNum memory1 "l" size
l' = l `mod` fromIntegral (computeK a * 64)
r = modulate (a `shiftR` fromIntegral l') size
res = Map.fromList [("a", showX a), ("l", showX l'), ("r", showX r)]
in (res, memory2)
let (dbA, genA) = emptyDatabase gen7
generateTests Base "sub" dbA $ \ size memory0 ->
let (a, memory1) = generateNum memory0 "a" size
(b, memory2) = generateNum memory1 "b" size
c = modulate (a - b) size
in (Map.fromList [("a", showX a), ("b", showX b), ("c", showX c)], memory2)
main :: IO ()
main =
do args <- getArgs
let args' = if null args then ["invocs", "test"] else args
when ("invocs" `elem` args') generateInvocs
when ("tests" `elem` args') generateAllTheTests

4
src/lib.rs Normal file
View File

@@ -0,0 +1,4 @@
#![recursion_limit="1024"]
pub mod unsigned;
#[cfg(test)]
pub 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);
}
}

98
src/unsigned/add.rs Normal file
View File

@@ -0,0 +1,98 @@
pub fn addition(dest: &mut [u64], src: &[u64])
{
assert_eq!(dest.len(), src.len() + 1);
let mut carry: u128 = 0;
for i in 0..src.len() {
let x128 = dest[i] as u128;
let y128 = src[i] as u128;
let z128 = x128 + y128 + carry;
dest[i] = z128 as u64;
carry = z128 >> 64;
}
dest[src.len()] = carry as u64;
}
pub fn unsafe_addition(dest: &mut [u64], src: &[u64])
{
assert_eq!(dest.len(), src.len());
let mut carry: u128 = 0;
for i in 0..src.len() {
let x128 = dest[i] as u128;
let y128 = src[i] as u128;
let z128 = x128 + y128 + carry;
dest[i] = z128 as u64;
carry = z128 >> 64;
}
assert_eq!(carry, 0, "Unsafe overflow in AddAssign");
}
macro_rules! addition_impls
{
($base: ident, $bigger: ident) => {
impl AddAssign<$base> for $base {
fn add_assign(&mut self, rhs: $base) {
unsafe_addition(&mut self.value, &rhs.value);
}
}
impl<'a> AddAssign<&'a $base> for $base {
fn add_assign(&mut self, rhs: &$base) {
unsafe_addition(&mut self.value, &rhs.value);
}
}
impl Add<$base> for $base {
type Output = $bigger;
fn add(self, rhs: $base) -> $bigger
{
let mut dest = $bigger::zero();
&dest.value[0..rhs.value.len()].copy_from_slice(&self.value);
addition(&mut dest.value, &rhs.value);
dest
}
}
impl<'a> Add<&'a $base> for $base {
type Output = $bigger;
fn add(self, rhs: &$base) -> $bigger
{
let mut dest = $bigger::zero();
&dest.value[0..rhs.value.len()].copy_from_slice(&self.value);
addition(&mut dest.value, &rhs.value);
dest
}
}
impl<'a> Add<$base> for &'a $base {
type Output = $bigger;
fn add(self, rhs: $base) -> $bigger
{
let mut dest = $bigger::zero();
&dest.value[0..rhs.value.len()].copy_from_slice(&self.value);
addition(&mut dest.value, &rhs.value);
dest
}
}
impl<'a,'b> Add<&'a $base> for &'b $base {
type Output = $bigger;
fn add(self, rhs: &$base) -> $bigger
{
let mut dest = $bigger::zero();
&dest.value[0..rhs.value.len()].copy_from_slice(&self.value);
addition(&mut dest.value, &rhs.value);
dest
}
}
}
}
//addition_impls!(U192, U256);

59
src/unsigned/barrett.rs Normal file
View File

@@ -0,0 +1,59 @@
macro_rules! barrett_impl {
($bar: ident, $name: ident, $name64: ident, $dbl: ident, $dbl64: ident) => {
pub struct $bar {
pub(crate) k: usize,
pub(crate) m: $name64,
pub(crate) mu: $name64
}
impl $bar {
pub fn new(m: $name) -> $bar {
// Step #1: Figure out k
let mut k = 0;
for i in 0..m.value.len() {
if m.value[i] != 0 {
k = i;
}
}
k += 1;
// Step #2: Compute b
let mut b = $dbl64::zero();
b.value[2*k] = 1;
// Step #3: Divide b by m.
let bigm = $dbl64::from(&m);
let quot = b / &bigm;
let resm = $name64::from(&m);
let mu = $name64::from(&quot);
// Done!
$bar { k: k, m: resm, mu: mu }
}
pub fn reduce(&self, x: &$dbl) -> $name {
let m2: $dbl64 = $dbl64::from(&self.m);
// 1. q1←⌊x/bk1⌋, q2←q1 · μ, q3←⌊q2/bk+1⌋.
let q1: $name64 = $name64::from(x >> (self.k - 1));
let q2: $dbl64 = $dbl64::from(q1 * &self.mu);
let q3: $name64 = $name64::from(q2 >> (self.k + 1));
// 2. r1←x mod bk+1, r2←q3 · m mod bk+1, r←r1 r2.
let mut r: $dbl64 = $dbl64::from(x);
r.mask(self.k + 1);
let mut r2: $dbl64 = $dbl64::from(q3 * &self.m);
r2.mask(self.k + 1);
let went_negative = &r < &r2;
r -= &r2;
// 3. If r<0 then r←r+bk+1.
if went_negative {
let mut bk1 = $dbl64::zero();
bk1.value[self.k+1] = 1;
r += &bk1;
}
// 4. While r≥m do: r←rm.
while &r > &m2 {
r -= &m2;
}
// Done!
$name::from(&r)
}
}
};
}

83
src/unsigned/base.rs Normal file
View File

@@ -0,0 +1,83 @@
pub trait CryptoNum {
fn zero() -> Self;
fn is_zero(&self) -> bool;
fn is_even(&self) -> bool;
fn is_odd(&self) -> bool;
fn mask(&mut self, len: usize);
}
macro_rules! generate_base
{
($name: ident, $size: expr) => {
#[derive(Clone)]
pub struct $name {
pub(crate) value: [u64; $size]
}
impl CryptoNum for $name {
fn zero() -> $name {
$name{ value: [0; $size] }
}
fn is_zero(&self) -> bool {
self.value.iter().all(|&x| x == 0)
}
fn is_even(&self) -> bool {
(self.value[0] & 0x1) == 0
}
fn is_odd(&self) -> bool {
(self.value[0] & 0x1) == 1
}
fn mask(&mut self, len: usize) {
let dellen = min(len, $size);
for i in dellen..$size {
self.value[i] = 0;
}
}
}
}
}
#[cfg(test)]
macro_rules! generate_base_tests
{
($name: ident) => {
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(stringify!($name))?;
f.write_str("{")?;
f.debug_list().entries(self.value.iter()).finish()?;
f.write_str("}")
}
}
#[test]
#[allow(non_snake_case)]
fn $name() {
let fname = format!("testdata/base/{}.tests", stringify!($name));
run_test(fname.to_string(), 6, |case| {
let (neg0, xbytes) = case.get("x").unwrap();
let (neg1, mbytes) = case.get("m").unwrap();
let (neg2, zbytes) = case.get("z").unwrap();
let (neg3, ebytes) = case.get("e").unwrap();
let (neg4, obytes) = case.get("o").unwrap();
let (neg5, rbytes) = case.get("r").unwrap();
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5);
let mut x = $name::from_bytes(xbytes);
let m = $name::from_bytes(mbytes);
let z = 1 == zbytes[0];
let e = 1 == ebytes[0];
let o = 1 == obytes[0];
let r = $name::from_bytes(rbytes);
assert_eq!(x.is_zero(), z);
assert_eq!(x.is_even(), e);
assert_eq!(x.is_odd(), o);
x.mask(usize::from(&m));
assert_eq!(x, r);
});
}
}
}

42
src/unsigned/cmp.rs Normal file
View File

@@ -0,0 +1,42 @@
use std::cmp::*;
pub fn compare(a: &[u64], b: &[u64]) -> Ordering {
assert_eq!(a.len(), b.len(), "Incompatible numbers in comparison");
let mut i = (a.len() - 1) as isize;
while i >= 0 {
let iu = i as usize;
match a[iu].cmp(&b[iu]) {
Ordering::Greater => return Ordering::Greater,
Ordering::Less => return Ordering::Less,
Ordering::Equal => i -= 1
}
}
Ordering::Equal
}
macro_rules! cmp_impls {
($name: ident) => {
impl PartialEq for $name {
fn eq(&self, rhs: &$name) -> bool {
compare(&self.value, &rhs.value) == Ordering::Equal
}
}
impl Eq for $name {}
impl PartialOrd for $name {
fn partial_cmp(&self, rhs: &$name) -> Option<Ordering> {
Some(compare(&self.value, &rhs.value))
}
}
impl Ord for $name {
fn cmp(&self, rhs: &$name) -> Ordering {
compare(&self.value, &rhs.value)
}
}
}
}

70
src/unsigned/codec.rs Normal file
View File

@@ -0,0 +1,70 @@
pub trait Decoder {
fn from_bytes(x: &[u8]) -> Self;
}
pub trait Encoder {
fn to_bytes(&self) -> Vec<u8>;
}
pub(crate) fn raw_decoder(input: &[u8], output: &mut [u64])
{
let mut item = 0;
let mut shift = 0;
let mut idx = 0;
for v in input.iter().rev() {
item |= (*v as u64) << shift;
shift += 8;
if shift == 64 {
shift = 0;
output[idx] = item;
idx += 1;
item = 0;
}
}
if item != 0 {
output[idx] = item;
}
}
macro_rules! generate_decoder {
($name: ident) => {
impl Decoder for $name {
fn from_bytes(x: &[u8]) -> $name {
let mut res = $name::zero();
raw_decoder(x, &mut res.value);
res
}
}
}
}
macro_rules! generate_encoder {
($name: ident) => {
impl Encoder for $name {
fn to_bytes(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(self.value.len() * 8);
for v in self.value.iter().rev() {
let val = *v;
res.push( (val >> 56) as u8);
res.push( (val >> 48) as u8);
res.push( (val >> 40) as u8);
res.push( (val >> 32) as u8);
res.push( (val >> 24) as u8);
res.push( (val >> 16) as u8);
res.push( (val >> 8) as u8);
res.push( (val >> 0) as u8);
}
res
}
}
}
}
macro_rules! generate_codec
{
($name: ident) => {
generate_decoder!($name);
generate_encoder!($name);
}
}

View File

@@ -0,0 +1,83 @@
macro_rules! generate_base_conversions
{
($name: ident) => {
generate_base_type_convert!($name, u8);
generate_base_type_convert!($name, u16);
generate_base_type_convert!($name, u32);
generate_base_type_convert!($name, u64);
generate_base_type_convert!($name, usize);
impl From<u128> for $name {
fn from(x: u128) -> $name {
let mut res = $name::zero();
res.value[0] = x as u64;
res.value[1] = (x >> 64) as u64;
res
}
}
};
() => {};
}
macro_rules! conversion_impls
{
($name: ident, $other: ident) => {
impl<'a> From<&'a $other> for $name {
fn from(x: &$other) -> $name {
let mut res = $name::zero();
let len = res.value.len();
assert!(x.value.len() > res.value.len());
res.value.copy_from_slice(&x.value[0..len]);
res
}
}
impl<'a> From<&'a $name> for $other {
fn from(x: &$name) -> $other {
let mut res = $other::zero();
let len = x.value.len();
assert!(x.value.len() < res.value.len());
res.value[0..len].copy_from_slice(&x.value);
res
}
}
impl From<$other> for $name {
fn from(x: $other) -> $name {
$name::from(&x)
}
}
impl From<$name> for $other {
fn from(x: $name) -> $other {
$other::from(&x)
}
}
};
}
macro_rules! generate_base_type_convert
{
($name: ident, $base: ident) => {
impl From<$base> for $name {
fn from(x: $base) -> $name {
let mut res = $name::zero();
res.value[0] = x as u64;
res
}
}
impl From<$name> for $base {
fn from(x: $name) -> $base {
x.value[0] as $base
}
}
impl<'a> From<&'a $name> for $base {
fn from(x: &$name) -> $base {
x.value[0] as $base
}
}
}
}

222
src/unsigned/div.rs Normal file
View File

@@ -0,0 +1,222 @@
pub trait DivMod
where Self: Sized
{
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 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 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
}
}
}
}

1285
src/unsigned/invoc.rs Normal file

File diff suppressed because it is too large Load Diff

63
src/unsigned/mod.rs Normal file
View File

@@ -0,0 +1,63 @@
#[macro_use]
mod add;
#[macro_use]
mod barrett;
#[macro_use]
mod base;
#[macro_use]
mod cmp;
#[macro_use]
mod codec;
#[macro_use]
mod conversion;
#[macro_use]
mod div;
#[macro_use]
mod mul;
#[macro_use]
mod shifts;
#[macro_use]
mod sub;
use self::add::{addition,unsafe_addition};
use self::base::CryptoNum;
use self::cmp::compare;
use self::div::{DivMod,get_number_size};
use self::codec::{Encoder,Decoder,raw_decoder};
use self::mul::multiply;
use self::shifts::{shiftl,shiftr};
use self::sub::subtract;
use std::cmp::{Ordering,min};
use std::ops::{Add,AddAssign};
use std::ops::{Div,Mul,Rem};
use std::ops::{Shl,ShlAssign,Shr,ShrAssign};
use std::ops::{Sub,SubAssign};
#[cfg(test)]
use std::fmt;
macro_rules! generate_number
{
($name: ident, $size: expr) => {
generate_base!($name, $size);
generate_base_conversions!($name);
generate_codec!($name);
cmp_impls!($name);
subtraction_impls!($name, $size);
shift_impls!($name, $size);
};
($name: ident, $size: expr, $plus1: ident, $times2: ident) => {
generate_number!($name, $size);
addition_impls!($name, $plus1);
multiply_impls!($name, $times2);
div_impls!($name, $times2);
};
($name: ident, $size: expr, $plus1: ident, $times2: ident, $big: ident, $bar: ident) => {
generate_number!($name, $size, $plus1, $times2);
barrett_impl!($bar, $name, $plus1, $times2, $big);
}
}
include!("invoc.rs");

65
src/unsigned/mul.rs Normal file
View File

@@ -0,0 +1,65 @@
pub fn multiply(dest: &mut [u64], left: &[u64], right: &[u64])
{
let len = right.len();
assert_eq!(left.len(), len, "Uneven argument lengths in multiply");
assert_eq!(dest.len(), len*2, "Bad destination size in multiply");
for i in 0..len {
let mut carry = 0;
for j in 0..len {
let old = dest[i+j] as u128;
let l128 = left[j] as u128;
let r128 = right[i] as u128;
let uv = old + (l128 * r128) + carry;
dest[i+j] = uv as u64;
carry = uv >> 64;
}
dest[i+len] = carry as u64;
}
}
macro_rules! multiply_impls {
($name: ident, $dbl: ident) => {
impl Mul<$name> for $name {
type Output = $dbl;
fn mul(self, rhs: $name) -> $dbl {
let mut res = $dbl::zero();
multiply(&mut res.value, &self.value, &rhs.value);
res
}
}
impl<'a> Mul<$name> for &'a $name {
type Output = $dbl;
fn mul(self, rhs: $name) -> $dbl {
let mut res = $dbl::zero();
multiply(&mut res.value, &self.value, &rhs.value);
res
}
}
impl<'a> Mul<&'a $name> for $name {
type Output = $dbl;
fn mul(self, rhs: &$name) -> $dbl {
let mut res = $dbl::zero();
multiply(&mut res.value, &self.value, &rhs.value);
res
}
}
impl<'a,'b> Mul<&'a $name> for &'b $name {
type Output = $dbl;
fn mul(self, rhs: &$name) -> $dbl {
let mut res = $dbl::zero();
multiply(&mut res.value, &self.value, &rhs.value);
res
}
}
};
}

92
src/unsigned/shifts.rs Normal file
View File

@@ -0,0 +1,92 @@
pub(crate) fn shiftl(res: &mut [u64], copy: &[u64], amt: usize) {
let digits = amt / 64;
let bits = amt % 64;
let mut carry = 0;
let shift = 64 - bits;
for i in 0..res.len() {
let base = if i >= digits { copy[i-digits] } else { 0 };
let new_carry = if shift == 64 { 0 } else { base >> shift };
res[i] = (base << bits) | carry;
carry = new_carry;
}
}
pub(crate) fn shiftr(res: &mut [u64], copy: &[u64], amt: usize) {
let digits = amt / 64;
let bits = amt % 64;
let mut carry = 0;
let mask = !(0xFFFFFFFFFFFFFFFF << bits);
let shift = (64 - bits) as u32;
for (idx, val) in res.iter_mut().enumerate().rev() {
let target = idx + digits;
let base = if target >= copy.len() { 0 } else { copy[target] };
let (new_carry, _) = (base & mask).overflowing_shl(shift);
*val = (base >> bits) | carry;
carry = new_carry;
}
}
macro_rules! shift_impls
{
($name: ident, $size: expr) => {
impl ShlAssign<usize> for $name {
fn shl_assign(&mut self, amt: usize) {
let copy = self.value.clone();
shiftl(&mut self.value, &copy, amt);
}
}
impl Shl<usize> for $name {
type Output = $name;
fn shl(mut self, amt: usize) -> $name {
let copy = self.value.clone();
shiftl(&mut self.value, &copy, amt);
self
}
}
impl<'a> Shl<usize> for &'a $name {
type Output = $name;
fn shl(self, amt: usize) -> $name {
let mut res = $name{ value: self.value.clone() };
shiftl(&mut res.value, &self.value, amt);
res
}
}
impl ShrAssign<usize> for $name {
fn shr_assign(&mut self, amt: usize) {
let copy = self.value.clone();
shiftr(&mut self.value, &copy, amt);
}
}
impl Shr<usize> for $name {
type Output = $name;
fn shr(mut self, amt: usize) -> $name {
let copy = self.value.clone();
shiftr(&mut self.value, &copy, amt);
self
}
}
impl<'a> Shr<usize> for &'a $name {
type Output = $name;
fn shr(self, amt: usize) -> $name {
let mut res = $name{ value: self.value.clone() };
shiftr(&mut res.value, &self.value, amt);
res
}
}
}
}
//shift_impls!(U192, 3);

76
src/unsigned/sub.rs Normal file
View File

@@ -0,0 +1,76 @@
use unsigned::add::unsafe_addition;
pub fn subtract(res: &mut [u64], spare: &mut [u64], other: &[u64])
{
for i in 0..res.len() {
res[i] = !res[i];
}
spare[0] = 1;
unsafe_addition(res, &spare);
unsafe_addition(res, &other);
}
macro_rules! subtraction_impls
{
($name: ident, $size: expr) => {
impl SubAssign for $name {
fn sub_assign(&mut self, rhs: $name) {
let mut temp = [0; $size];
subtract(&mut self.value, &mut temp, &rhs.value);
}
}
impl<'a> SubAssign<&'a $name> for $name {
fn sub_assign(&mut self, rhs: &$name) {
let mut temp = [0; $size];
subtract(&mut self.value, &mut temp, &rhs.value);
}
}
impl Sub for $name {
type Output = $name;
fn sub(self, rhs: $name) -> $name {
let mut res = $name::zero();
let mut temp = [0; $size];
subtract(&mut res.value, &mut temp, &rhs.value);
res
}
}
impl<'a> Sub<$name> for &'a $name {
type Output = $name;
fn sub(self, rhs: $name) -> $name {
let mut res = $name::zero();
let mut temp = [0; $size];
subtract(&mut res.value, &mut temp, &rhs.value);
res
}
}
impl<'a> Sub<&'a $name> for $name {
type Output = $name;
fn sub(self, rhs: &$name) -> $name {
let mut res = $name::zero();
let mut temp = [0; $size];
subtract(&mut res.value, &mut temp, &rhs.value);
res
}
}
impl<'a,'b> Sub<&'a $name> for &'b $name {
type Output = $name;
fn sub(self, rhs: &$name) -> $name {
let mut res = $name::zero();
let mut temp = [0; $size];
subtract(&mut res.value, &mut temp, &rhs.value);
res
}
}
}
}
//subtraction_impls!(U192, 3);

3003
testdata/add/U1024.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U1088.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U1152.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U1216.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U12416.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U1280.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U15360.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U15424.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U15488.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U16384.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U16448.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U16512.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U1664.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U192.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U2048.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U2112.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U2176.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U2432.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U256.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U3072.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U30720.tests vendored Normal file

File diff suppressed because one or more lines are too long

3003
testdata/add/U30784.tests vendored Normal file

File diff suppressed because one or more lines are too long

3003
testdata/add/U30848.tests vendored Normal file

File diff suppressed because one or more lines are too long

3003
testdata/add/U3136.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U320.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U3200.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U32896.tests vendored Normal file

File diff suppressed because one or more lines are too long

3003
testdata/add/U384.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U4096.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U4160.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U4224.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U448.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U512.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U576.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U6144.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U61568.tests vendored Normal file

File diff suppressed because one or more lines are too long

3003
testdata/add/U6208.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U6272.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U640.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U704.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U768.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U7680.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U7744.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U7808.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U8192.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U8256.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U832.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U8320.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/add/U896.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/barrett_gen/U1024.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/barrett_gen/U15360.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/barrett_gen/U192.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/barrett_gen/U2048.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/barrett_gen/U256.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/barrett_gen/U3072.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/barrett_gen/U384.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/barrett_gen/U4096.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/barrett_gen/U512.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/barrett_gen/U576.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/barrett_gen/U7680.tests vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/barrett_gen/U8192.tests vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/barrett_reduce/U1024.tests vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/barrett_reduce/U15360.tests vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/barrett_reduce/U192.tests vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/barrett_reduce/U2048.tests vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/barrett_reduce/U256.tests vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/barrett_reduce/U3072.tests vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/barrett_reduce/U384.tests vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/barrett_reduce/U4096.tests vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/barrett_reduce/U512.tests vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/barrett_reduce/U576.tests vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/barrett_reduce/U7680.tests vendored Normal file

File diff suppressed because it is too large Load Diff

5005
testdata/barrett_reduce/U8192.tests vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/base/U1024.tests vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/base/U1088.tests vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/base/U1152.tests vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/base/U1216.tests vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/base/U12416.tests vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/base/U1280.tests vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/base/U15360.tests vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/base/U15424.tests vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/base/U15488.tests vendored Normal file

File diff suppressed because it is too large Load Diff

6006
testdata/base/U16384.tests vendored Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More