Initial commit!
This commit is contained in:
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
|
||||
generate.hi
|
||||
generate.o
|
||||
generate
|
||||
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "cryptonum"
|
||||
version = "0.1.0"
|
||||
authors = ["awick"]
|
||||
|
||||
[dependencies]
|
||||
243
generate.hs
Normal file
243
generate.hs
Normal 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
4
src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#![recursion_limit="1024"]
|
||||
pub mod unsigned;
|
||||
#[cfg(test)]
|
||||
pub mod testing;
|
||||
62
src/testing.rs
Normal file
62
src/testing.rs
Normal 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
98
src/unsigned/add.rs
Normal 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
59
src/unsigned/barrett.rs
Normal 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(");
|
||||
// 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/bk−1⌋, 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←r−m.
|
||||
while &r > &m2 {
|
||||
r -= &m2;
|
||||
}
|
||||
// Done!
|
||||
$name::from(&r)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
83
src/unsigned/base.rs
Normal file
83
src/unsigned/base.rs
Normal 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
42
src/unsigned/cmp.rs
Normal 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
70
src/unsigned/codec.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
83
src/unsigned/conversion.rs
Normal file
83
src/unsigned/conversion.rs
Normal 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
222
src/unsigned/div.rs
Normal 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
1285
src/unsigned/invoc.rs
Normal file
File diff suppressed because it is too large
Load Diff
63
src/unsigned/mod.rs
Normal file
63
src/unsigned/mod.rs
Normal 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
65
src/unsigned/mul.rs
Normal 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
92
src/unsigned/shifts.rs
Normal 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, ©, 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, ©, 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, ©, 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, ©, 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
76
src/unsigned/sub.rs
Normal 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Reference in New Issue
Block a user