Compare commits
9 Commits
master
...
generate_c
| Author | SHA1 | Date | |
|---|---|---|---|
| 84f6925f60 | |||
| 4ae957aac6 | |||
| f4a3cf69ad | |||
| d7665acf64 | |||
| 1d8907539d | |||
| 203c23e277 | |||
| aff88eb2f0 | |||
| ab465296f2 | |||
| fa872c951a |
@@ -2,7 +2,8 @@
|
||||
name = "cryptonum"
|
||||
version = "0.1.0"
|
||||
authors = ["awick"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
quickcheck = "^0.7.2"
|
||||
rand = "^0.6.0"
|
||||
quickcheck = "^0.8.5"
|
||||
# rand = "^0.6.0"
|
||||
2
generation/.gitignore
vendored
Normal file
2
generation/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.ghc.environment*
|
||||
dist-newstyle/
|
||||
13
generation/LICENSE
Normal file
13
generation/LICENSE
Normal file
@@ -0,0 +1,13 @@
|
||||
Copyright (c) 2019 Adam Wick
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
2
generation/Setup.hs
Normal file
2
generation/Setup.hs
Normal file
@@ -0,0 +1,2 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
31
generation/generation.cabal
Normal file
31
generation/generation.cabal
Normal file
@@ -0,0 +1,31 @@
|
||||
cabal-version: 2.0
|
||||
-- Initial package description 'generation.cabal' generated by 'cabal
|
||||
-- init'. For further documentation, see
|
||||
-- http://haskell.org/cabal/users-guide/
|
||||
|
||||
name: generation
|
||||
version: 0.1.0.0
|
||||
synopsis: Generates the cryptonum Rust library, based on requirements.
|
||||
homepage: http://github.com/acw/cryptonum
|
||||
license: ISC
|
||||
license-file: LICENSE
|
||||
author: Adam Wick
|
||||
maintainer: awick@uhsure.com
|
||||
copyright: 2019
|
||||
category: Math
|
||||
build-type: Simple
|
||||
extra-source-files: CHANGELOG.md
|
||||
|
||||
executable generation
|
||||
main-is: Main.hs
|
||||
other-modules: Base, BinaryOps, Compare, Conversions, CryptoNum, File, Gen, Testing
|
||||
-- other-extensions:
|
||||
build-depends: base ^>=4.12.0.0,
|
||||
containers,
|
||||
directory,
|
||||
filepath,
|
||||
mtl,
|
||||
random
|
||||
hs-source-dirs: src
|
||||
default-language: Haskell2010
|
||||
ghc-options: -Wall
|
||||
57
generation/src/Base.hs
Normal file
57
generation/src/Base.hs
Normal file
@@ -0,0 +1,57 @@
|
||||
module Base(
|
||||
base
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Monad(forM_)
|
||||
import File
|
||||
import Gen
|
||||
|
||||
base :: File
|
||||
base = File {
|
||||
predicate = \ _ _ -> True,
|
||||
outputName = "base",
|
||||
generator = declareBaseStructure,
|
||||
testGenerator = Nothing
|
||||
}
|
||||
|
||||
declareBaseStructure :: Word -> Gen ()
|
||||
declareBaseStructure bitsize =
|
||||
do let name = "U" ++ show bitsize
|
||||
entries = bitsize `div` 64
|
||||
top = entries - 1
|
||||
out "use core::fmt;"
|
||||
out "use quickcheck::{Arbitrary,Gen};"
|
||||
blank
|
||||
out "#[derive(Clone)]"
|
||||
wrapIndent ("pub struct " ++ name) $
|
||||
out ("pub(crate) value: [u64; " ++ show entries ++ "]")
|
||||
blank
|
||||
implFor "fmt::Debug" name $
|
||||
wrapIndent "fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result" $
|
||||
do out ("f.debug_tuple(" ++ show name ++ ")")
|
||||
forM_ [0..top] $ \ i ->
|
||||
out (" .field(&self.value[" ++ show i ++ "])")
|
||||
out " .finish()"
|
||||
blank
|
||||
implFor "fmt::UpperHex" name $
|
||||
wrapIndent "fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result" $
|
||||
do forM_ (reverse [1..top]) $ \ i ->
|
||||
out ("write!(f, \"{:X}\", self.value[" ++ show i ++ "])?;")
|
||||
out "write!(f, \"{:X}\", self.value[0])"
|
||||
blank
|
||||
implFor "fmt::LowerHex" name $
|
||||
wrapIndent "fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result" $
|
||||
do forM_ (reverse [1..top]) $ \ i ->
|
||||
out ("write!(f, \"{:x}\", self.value[" ++ show i ++ "])?;")
|
||||
out "write!(f, \"{:x}\", self.value[0])"
|
||||
blank
|
||||
implFor "Arbitrary" name $
|
||||
wrapIndent "fn arbitrary<G: Gen>(g: &mut G) -> Self" $
|
||||
do out (name ++ " {")
|
||||
indent $
|
||||
do out ("value: [")
|
||||
indent $ forM_ [0..top] $ \ _ ->
|
||||
out ("g.next_u64(),")
|
||||
out ("]")
|
||||
out ("}")
|
||||
171
generation/src/BinaryOps.hs
Normal file
171
generation/src/BinaryOps.hs
Normal file
@@ -0,0 +1,171 @@
|
||||
module BinaryOps(
|
||||
binaryOps
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Monad(forM_,replicateM_)
|
||||
import Data.Bits((.&.), (.|.), shiftL, xor)
|
||||
import File
|
||||
import Gen
|
||||
|
||||
binaryTestCount :: Int
|
||||
binaryTestCount = 3000
|
||||
|
||||
binaryOps :: File
|
||||
binaryOps = File {
|
||||
predicate = \ _ _ -> True,
|
||||
outputName = "binary",
|
||||
generator = declareBinaryOperators,
|
||||
testGenerator = Just testVectors
|
||||
}
|
||||
|
||||
declareBinaryOperators :: Word -> Gen ()
|
||||
declareBinaryOperators bitsize =
|
||||
do let name = "U" ++ show bitsize
|
||||
entries = bitsize `div` 64
|
||||
out "use core::ops::{BitAnd,BitAndAssign};"
|
||||
out "use core::ops::{BitOr,BitOrAssign};"
|
||||
out "use core::ops::{BitXor,BitXorAssign};"
|
||||
out "use core::ops::Not;"
|
||||
out "#[cfg(test)]"
|
||||
out "use crate::CryptoNum;"
|
||||
out "#[cfg(test)]"
|
||||
out "use quickcheck::quickcheck;"
|
||||
out ("use super::U" ++ show bitsize ++ ";")
|
||||
blank
|
||||
generateBinOps "BitAnd" name "bitand" "&=" entries
|
||||
blank
|
||||
generateBinOps "BitOr" name "bitor" "|=" entries
|
||||
blank
|
||||
generateBinOps "BitXor" name "bitxor" "^=" entries
|
||||
blank
|
||||
implFor "Not" name $
|
||||
do out "type Output = Self;"
|
||||
blank
|
||||
wrapIndent "fn not(mut self) -> Self" $
|
||||
do forM_ [0..entries-1] $ \ i ->
|
||||
out ("self.value[" ++ show i ++ "] = !self.value[" ++ show i ++ "];")
|
||||
out "self"
|
||||
blank
|
||||
implFor' "Not" ("&'a " ++ name) $
|
||||
do out ("type Output = " ++ name ++ ";")
|
||||
blank
|
||||
wrapIndent ("fn not(self) -> " ++ name) $
|
||||
do out "let mut output = self.clone();"
|
||||
forM_ [0..entries-1] $ \ i ->
|
||||
out ("output.value[" ++ show i ++ "] = !self.value[" ++ show i ++ "];")
|
||||
out "output"
|
||||
blank
|
||||
addBinaryLaws name entries
|
||||
|
||||
generateBinOps :: String -> String -> String -> String -> Word -> Gen ()
|
||||
generateBinOps trait name fun op entries =
|
||||
do implFor (trait ++ "Assign") name $
|
||||
wrapIndent ("fn " ++ fun ++ "_assign(&mut self, rhs: Self)") $
|
||||
forM_ [0..entries-1] $ \ i ->
|
||||
out ("self.value[" ++ show i ++ "] "++op++" rhs.value[" ++ show i ++ "];")
|
||||
blank
|
||||
implFor' (trait ++ "Assign<&'a " ++ name ++ ">") name $
|
||||
wrapIndent ("fn " ++ fun ++ "_assign(&mut self, rhs: &Self)") $
|
||||
forM_ [0..entries-1] $ \ i ->
|
||||
out ("self.value[" ++ show i ++ "] "++op++" rhs.value[" ++ show i ++ "];")
|
||||
blank
|
||||
generateBinOpsFromAssigns trait name fun op
|
||||
|
||||
generateBinOpsFromAssigns :: String -> String -> String -> String -> Gen ()
|
||||
generateBinOpsFromAssigns trait name fun op =
|
||||
do implFor trait name $
|
||||
do out "type Output = Self;"
|
||||
blank
|
||||
wrapIndent ("fn " ++ fun ++ "(mut self, rhs: Self) -> Self") $
|
||||
do out ("self " ++ op ++ " rhs;")
|
||||
out "self"
|
||||
blank
|
||||
implFor' (trait ++ "<&'a " ++ name ++ ">") name $
|
||||
do out "type Output = Self;"
|
||||
blank
|
||||
wrapIndent ("fn " ++ fun ++ "(mut self, rhs: &Self) -> Self") $
|
||||
do out ("self " ++ op ++ " rhs;")
|
||||
out "self"
|
||||
blank
|
||||
implFor' (trait ++ "<" ++ name ++ ">") ("&'a " ++ name) $
|
||||
do out ("type Output = " ++ name ++ ";")
|
||||
blank
|
||||
wrapIndent ("fn " ++ fun ++ "(self, mut rhs: " ++ name ++ ") -> " ++ name) $
|
||||
do out ("rhs " ++ op ++ " self;")
|
||||
out "rhs"
|
||||
blank
|
||||
implFor'' (trait ++ "<&'a " ++ name ++ ">") ("&'b " ++ name) $
|
||||
do out ("type Output = " ++ name ++ ";")
|
||||
blank
|
||||
wrapIndent ("fn " ++ fun ++ "(self, rhs: &" ++ name ++ ") -> " ++ name) $
|
||||
do out "let mut output = self.clone();"
|
||||
out ("output " ++ op ++ " rhs;")
|
||||
out "output"
|
||||
|
||||
addBinaryLaws :: String -> Word -> Gen ()
|
||||
addBinaryLaws name entries =
|
||||
do let args3 = "(a: " ++ name ++ ", b: " ++ name ++ ", c: " ++ name ++ ")"
|
||||
args2 = "(a: " ++ name ++ ", b: " ++ name ++ ")"
|
||||
out "#[cfg(test)]"
|
||||
wrapIndent "quickcheck!" $
|
||||
do wrapIndent ("fn and_associative" ++ args3 ++ " -> bool") $
|
||||
out ("((&a & &b) & &c) == (&a & (&b & &c))")
|
||||
blank
|
||||
wrapIndent ("fn and_commutative" ++ args2 ++ " -> bool") $
|
||||
out ("(&a & &b) == (&b & &a)")
|
||||
blank
|
||||
wrapIndent ("fn and_idempotent" ++ args2 ++ " -> bool") $
|
||||
out ("(&a & &b) == (&a & &b & &a)")
|
||||
blank
|
||||
wrapIndent ("fn xor_associative" ++ args3 ++ " -> bool") $
|
||||
out ("((&a ^ &b) ^ &c) == (&a ^ (&b ^ &c))")
|
||||
blank
|
||||
wrapIndent ("fn xor_commutative" ++ args2 ++ " -> bool") $
|
||||
out ("(&a ^ &b) == (&b ^ &a)")
|
||||
blank
|
||||
wrapIndent ("fn or_associative" ++ args3 ++ " -> bool") $
|
||||
out ("((&a | &b) | &c) == (&a | (&b | &c))")
|
||||
blank
|
||||
wrapIndent ("fn or_commutative" ++ args2 ++ " -> bool") $
|
||||
out ("(&a | &b) == (&b | &a)")
|
||||
blank
|
||||
wrapIndent ("fn or_idempotent" ++ args2 ++ " -> bool") $
|
||||
out ("(&a | &b) == (&a | &b | &a)")
|
||||
blank
|
||||
wrapIndent ("fn and_or_distribution" ++ args3 ++ "-> bool") $
|
||||
out ("(&a & (&b | &c)) == ((&a & &b) | (&a & &c))")
|
||||
blank
|
||||
wrapIndent ("fn xor_clears(a: " ++ name ++ ") -> bool") $
|
||||
out (name ++ "::zero() == (&a ^ &a)")
|
||||
blank
|
||||
wrapIndent ("fn double_neg_ident(a: " ++ name ++ ") -> bool") $
|
||||
out ("a == !!&a")
|
||||
blank
|
||||
wrapIndent ("fn and_ident(a: " ++ name ++ ") -> bool") $
|
||||
do out ("let ones = !" ++ name ++ "::zero();")
|
||||
out ("(&a & &ones) == a")
|
||||
blank
|
||||
wrapIndent ("fn or_ident(a: " ++ name ++ ") -> bool") $
|
||||
out ("(&a | " ++ name ++ "::zero()) == a")
|
||||
wrapIndent ("fn neg_as_xor(a: " ++ name ++ ") -> bool") $
|
||||
do out ("let ones = " ++ name ++ "{ value: [0xFFFFFFFFFFFFFFFFu64; "
|
||||
++ show entries ++ "] };")
|
||||
out ("!&a == (&ones ^ &a)")
|
||||
|
||||
|
||||
testVectors :: Word -> Gen ()
|
||||
testVectors bitsize = replicateM_ binaryTestCount $
|
||||
do a <- newNum False bitsize
|
||||
b <- newNum False bitsize
|
||||
let o = a .|. b
|
||||
c = a .&. b
|
||||
n = a `xor` ((1 `shiftL` fromIntegral bitsize) - 1)
|
||||
x = a `xor` b
|
||||
emitTestVariable 'a' a
|
||||
emitTestVariable 'b' b
|
||||
emitTestVariable 'c' c
|
||||
emitTestVariable 'o' o
|
||||
emitTestVariable 'n' n
|
||||
emitTestVariable 'x' x
|
||||
|
||||
61
generation/src/Compare.hs
Normal file
61
generation/src/Compare.hs
Normal file
@@ -0,0 +1,61 @@
|
||||
module Compare(comparisons)
|
||||
where
|
||||
|
||||
import Control.Monad(forM_)
|
||||
import File
|
||||
import Gen
|
||||
|
||||
comparisons :: File
|
||||
comparisons = File {
|
||||
predicate = \ _ _ -> True,
|
||||
outputName = "compare",
|
||||
generator = declareComparators,
|
||||
testGenerator = Nothing
|
||||
}
|
||||
|
||||
declareComparators :: Word -> Gen ()
|
||||
declareComparators bitsize =
|
||||
do let name = "U" ++ show bitsize
|
||||
entries = bitsize `div` 64
|
||||
top = entries - 1
|
||||
out "use core::cmp::{Eq,Ordering,PartialEq};"
|
||||
out "#[cfg(test)]"
|
||||
out "use quickcheck::quickcheck;"
|
||||
out ("use super::" ++ name ++ ";")
|
||||
blank
|
||||
implFor "PartialEq" name $
|
||||
wrapIndent "fn eq(&self, other: &Self) -> bool" $
|
||||
do forM_ (reverse [1..top]) $ \ i ->
|
||||
out ("self.value[" ++ show i ++ "] == other.value[" ++ show i ++ "] && ")
|
||||
out "self.value[0] == other.value[0]"
|
||||
blank
|
||||
implFor "Eq" name $ return ()
|
||||
blank
|
||||
implFor "Ord" name $
|
||||
wrapIndent "fn cmp(&self, other: &Self) -> Ordering" $
|
||||
do out ("self.value[" ++ show top ++ "].cmp(&other.value[" ++ show top ++ "])")
|
||||
forM_ (reverse [0..top-1]) $ \ i ->
|
||||
out (" .then(self.value[" ++ show i ++ "].cmp(&other.value[" ++ show i ++ "]))")
|
||||
blank
|
||||
implFor "PartialOrd" name $
|
||||
wrapIndent "fn partial_cmp(&self, other: &Self) -> Option<Ordering>" $
|
||||
out "Some(self.cmp(other))"
|
||||
blank
|
||||
out "#[cfg(test)]"
|
||||
wrapIndent "quickcheck!" $
|
||||
do let transFun n = "fn " ++ n ++ "(a: " ++ name ++ ", b: " ++ name ++
|
||||
", c: " ++ name ++ ") -> bool"
|
||||
wrapIndent (transFun "eq_is_transitive") $
|
||||
out ("if a == c { a == b && b == c } else { a != b || b != c }")
|
||||
blank
|
||||
wrapIndent (transFun "gt_is_transitive") $
|
||||
out ("if a > b && b > c { a > c } else { true }")
|
||||
blank
|
||||
wrapIndent (transFun "ge_is_transitive") $
|
||||
out ("if a >= b && b >= c { a >= c } else { true }")
|
||||
blank
|
||||
wrapIndent (transFun "lt_is_transitive") $
|
||||
out ("if a < b && b < c { a < c } else { true }")
|
||||
blank
|
||||
wrapIndent (transFun "le_is_transitive") $
|
||||
out ("if a <= b && b <= c { a <= c } else { true }")
|
||||
99
generation/src/Conversions.hs
Normal file
99
generation/src/Conversions.hs
Normal file
@@ -0,0 +1,99 @@
|
||||
module Conversions(
|
||||
conversions
|
||||
)
|
||||
where
|
||||
|
||||
import Data.List(intercalate)
|
||||
import File
|
||||
import Gen
|
||||
|
||||
conversions :: File
|
||||
conversions = File {
|
||||
predicate = \ _ _ -> True,
|
||||
outputName = "conversions",
|
||||
generator = declareConversions,
|
||||
testGenerator = Nothing
|
||||
}
|
||||
|
||||
declareConversions :: Word -> Gen ()
|
||||
declareConversions bitsize =
|
||||
do let name = "U" ++ show bitsize
|
||||
entries = bitsize `div` 64
|
||||
out "use core::convert::{From,TryFrom};"
|
||||
out "#[cfg(test)]"
|
||||
out "use quickcheck::quickcheck;"
|
||||
out ("use super::" ++ name ++ ";")
|
||||
blank
|
||||
buildUnsignedPrimConversions name entries "u8" >> blank
|
||||
buildUnsignedPrimConversions name entries "u16" >> blank
|
||||
buildUnsignedPrimConversions name entries "u32" >> blank
|
||||
buildUnsignedPrimConversions name entries "u64" >> blank
|
||||
buildUnsignedPrimConversions name entries "usize" >> blank
|
||||
buildSignedPrimConversions name entries "i8" >> blank
|
||||
buildSignedPrimConversions name entries "i16" >> blank
|
||||
buildSignedPrimConversions name entries "i32" >> blank
|
||||
buildSignedPrimConversions name entries "i64" >> blank
|
||||
buildSignedPrimConversions name entries "isize"
|
||||
blank
|
||||
out ("#[cfg(test)]")
|
||||
wrapIndent "quickcheck!" $
|
||||
do roundTripTest name "u8" >> blank
|
||||
roundTripTest name "u16" >> blank
|
||||
roundTripTest name "u32" >> blank
|
||||
roundTripTest name "u64" >> blank
|
||||
roundTripTest name "usize"
|
||||
|
||||
buildUnsignedPrimConversions :: String -> Word -> String -> Gen ()
|
||||
buildUnsignedPrimConversions name entries primtype =
|
||||
do implFor ("From<" ++ primtype ++ ">") name $
|
||||
wrapIndent ("fn from(x: " ++ primtype ++ ") -> Self") $
|
||||
do let zeroes = replicate (fromIntegral (entries - 1)) "0,"
|
||||
values = ("x as u64," : zeroes)
|
||||
out (name ++ " { value: [ ")
|
||||
indent $ printBy 8 values
|
||||
out ("] }")
|
||||
blank
|
||||
implFor ("From<" ++ name ++ ">") primtype $
|
||||
wrapIndent ("fn from(x: " ++ name ++ ") -> Self") $
|
||||
out ("x.value[0] as " ++ primtype)
|
||||
blank
|
||||
implFor' ("From<&'a " ++ name ++ ">") primtype $
|
||||
wrapIndent ("fn from(x: &" ++ name ++ ") -> Self") $
|
||||
out ("x.value[0] as " ++ primtype)
|
||||
|
||||
buildSignedPrimConversions :: String -> Word -> String -> Gen ()
|
||||
buildSignedPrimConversions name entries primtype =
|
||||
do implFor ("TryFrom<" ++ primtype ++ ">") name $
|
||||
do out ("type Error = &'static str;")
|
||||
blank
|
||||
wrapIndent ("fn try_from(x: " ++ primtype ++ ") -> Result<Self,Self::Error>") $
|
||||
do wrapIndent ("if x < 0") $
|
||||
out ("return Err(\"Attempt to convert negative number to " ++
|
||||
name ++ ".\");")
|
||||
blank
|
||||
let zeroes = replicate (fromIntegral (entries - 1)) "0,"
|
||||
values = ("x as u64," : zeroes)
|
||||
out ("Ok(" ++ name ++ " { value: [ ")
|
||||
indent $ printBy 8 values
|
||||
out ("] })")
|
||||
blank
|
||||
implFor ("From<" ++ name ++ ">") primtype $
|
||||
wrapIndent ("fn from(x: " ++ name ++ ") -> Self") $
|
||||
out ("x.value[0] as " ++ primtype)
|
||||
blank
|
||||
implFor' ("From<&'a " ++ name ++ ">") primtype $
|
||||
wrapIndent ("fn from(x: &" ++ name ++ ") -> Self") $
|
||||
out ("x.value[0] as " ++ primtype)
|
||||
|
||||
roundTripTest :: String -> String -> Gen ()
|
||||
roundTripTest name primtype =
|
||||
wrapIndent ("fn " ++ primtype ++ "_roundtrips(x: " ++ primtype ++ ") -> bool") $
|
||||
do out ("let big = " ++ name ++ "::from(x);");
|
||||
out ("let small = " ++ primtype ++ "::from(big);")
|
||||
out ("x == small")
|
||||
|
||||
printBy :: Int -> [String] -> Gen ()
|
||||
printBy amt xs
|
||||
| length xs <= amt = out (intercalate " " xs)
|
||||
| otherwise = printBy amt (take amt xs) >>
|
||||
printBy amt (drop amt xs)
|
||||
179
generation/src/CryptoNum.hs
Normal file
179
generation/src/CryptoNum.hs
Normal file
@@ -0,0 +1,179 @@
|
||||
module CryptoNum(
|
||||
cryptoNum
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Monad(forM_)
|
||||
import File
|
||||
import Gen
|
||||
|
||||
cryptoNum :: File
|
||||
cryptoNum = File {
|
||||
predicate = \ _ _ -> True,
|
||||
outputName = "cryptonum",
|
||||
generator = declareCryptoNumInstance,
|
||||
testGenerator = Nothing
|
||||
}
|
||||
|
||||
declareCryptoNumInstance :: Word -> Gen ()
|
||||
declareCryptoNumInstance bitsize =
|
||||
do let name = "U" ++ show bitsize
|
||||
entries = bitsize `div` 64
|
||||
top = entries - 1
|
||||
out "use core::cmp::min;"
|
||||
out "use crate::CryptoNum;"
|
||||
out "#[cfg(test)]"
|
||||
out "use crate::testing::{build_test_path,run_test};"
|
||||
out "#[cfg(test)]"
|
||||
out "use quickcheck::{Arbitrary,Gen,quickcheck};"
|
||||
out "#[cfg(test)]"
|
||||
out "use std::fmt;"
|
||||
out ("use super::" ++ name ++ ";")
|
||||
blank
|
||||
implFor "CryptoNum" name $
|
||||
do wrapIndent ("fn zero() -> Self") $
|
||||
out (name ++ "{ value: [0; " ++ show entries ++ "] }")
|
||||
blank
|
||||
wrapIndent ("fn is_zero(&self) -> bool") $
|
||||
do forM_ (reverse [1..top]) $ \ i ->
|
||||
out ("self.value[" ++ show i ++ "] == 0 &&")
|
||||
out "self.value[0] == 0"
|
||||
blank
|
||||
wrapIndent ("fn is_even(&self) -> bool") $
|
||||
out "self.value[0] & 0x1 == 0"
|
||||
blank
|
||||
wrapIndent ("fn is_odd(&self) -> bool") $
|
||||
out "self.value[0] & 0x1 == 1"
|
||||
blank
|
||||
wrapIndent ("fn bit_length() -> usize") $
|
||||
out (show bitsize)
|
||||
blank
|
||||
wrapIndent ("fn mask(&mut self, len: usize)") $
|
||||
do out ("let dellen = min(len, " ++ show entries ++ ");")
|
||||
wrapIndent ("for i in dellen.." ++ show entries) $
|
||||
out ("self.value[i] = 0;")
|
||||
blank
|
||||
wrapIndent ("fn testbit(&self, bit: usize) -> bool") $
|
||||
do out "let idx = bit / 64;"
|
||||
out "let offset = bit % 64;"
|
||||
wrapIndent ("if idx >= " ++ show entries) $
|
||||
out "return false;"
|
||||
out "(self.value[idx] & (1u64 << offset)) != 0"
|
||||
blank
|
||||
wrapIndent ("fn from_bytes(bytes: &[u8]) -> Self") $
|
||||
do out ("let biggest = min(" ++ show (bitsize `div` 8) ++ ", " ++
|
||||
"bytes.len()) - 1;")
|
||||
out ("let mut idx = biggest / 8;")
|
||||
out ("let mut shift = (biggest % 8) * 8;")
|
||||
out ("let mut i = 0;")
|
||||
out ("let mut res = " ++ name ++ "::zero();")
|
||||
blank
|
||||
wrapIndent ("while i <= biggest") $
|
||||
do out ("res.value[idx] |= (bytes[i] as u64) << shift;")
|
||||
out ("i += 1;")
|
||||
out ("if shift == 0 {")
|
||||
indent $
|
||||
do out "shift = 56;"
|
||||
out "if idx > 0 { idx -= 1; }"
|
||||
out ("} else {")
|
||||
indent $
|
||||
out "shift -= 8;"
|
||||
out "}"
|
||||
blank
|
||||
out "res"
|
||||
blank
|
||||
wrapIndent ("fn to_bytes(&self, bytes: &mut [u8])") $
|
||||
do let bytes = bitsize `div` 8
|
||||
out ("if bytes.len() == 0 { return; }")
|
||||
blank
|
||||
forM_ [0..bytes-1] $ \ idx ->
|
||||
do let (validx, shift) = byteShiftInfo idx
|
||||
out ("let byte" ++ show idx ++ " = (self.value[" ++
|
||||
show validx ++ "] >> " ++ show shift ++ ")" ++
|
||||
" as u8;")
|
||||
blank
|
||||
out ("let mut idx = min(bytes.len() - 1, " ++ show (bytes - 1) ++ ");")
|
||||
forM_ [0..bytes-2] $ \ i ->
|
||||
do out ("bytes[idx] = byte" ++ show i ++ ";")
|
||||
out ("if idx == 0 { return; }")
|
||||
out ("idx -= 1;")
|
||||
out ("bytes[idx] = byte" ++ show (bytes-1) ++ ";")
|
||||
blank
|
||||
let bytes = bitsize `div` 8
|
||||
struct = "Bytes" ++ show bytes
|
||||
out "#[cfg(test)]"
|
||||
out "#[derive(Clone)]"
|
||||
wrapIndent ("struct " ++ struct) $
|
||||
out ("value: [u8; " ++ show bytes ++ "]")
|
||||
blank
|
||||
out "#[cfg(test)]"
|
||||
implFor "PartialEq" struct $
|
||||
wrapIndent ("fn eq(&self, other: &Self) -> bool") $
|
||||
out "self.value.iter().zip(other.value.iter()).all(|(a,b)| a == b)"
|
||||
blank
|
||||
out "#[cfg(test)]"
|
||||
implFor "fmt::Debug" struct $
|
||||
wrapIndent ("fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result") $
|
||||
out "f.debug_list().entries(self.value.iter()).finish()"
|
||||
blank
|
||||
out "#[cfg(test)]"
|
||||
implFor "Arbitrary" struct $
|
||||
wrapIndent ("fn arbitrary<G: Gen>(g: &mut G) -> Self") $
|
||||
do out ("let mut res = " ++ struct ++ "{ value: [0; " ++ show bytes ++ "] };")
|
||||
out ("g.fill_bytes(&mut res.value);")
|
||||
out ("res")
|
||||
blank
|
||||
out "#[cfg(test)]"
|
||||
wrapIndent "quickcheck!" $
|
||||
do wrapIndent ("fn to_from_ident(x: " ++ name ++ ") -> bool") $
|
||||
do out ("let mut buffer = [0; " ++ show bytes ++ "];")
|
||||
out ("x.to_bytes(&mut buffer);");
|
||||
out ("let y = " ++ name ++ "::from_bytes(&buffer);")
|
||||
out ("x == y")
|
||||
blank
|
||||
wrapIndent ("fn from_to_ident(x: " ++ struct ++ ") -> bool") $
|
||||
do out ("let val = " ++ name ++ "::from_bytes(&x.value);")
|
||||
out ("let mut buffer = [0; " ++ show bytes ++ "];")
|
||||
out ("val.to_bytes(&mut buffer);")
|
||||
out ("buffer.iter().zip(x.value.iter()).all(|(a,b)| a == b)")
|
||||
blank
|
||||
out "#[cfg(test)]"
|
||||
out "#[allow(non_snake_case)]"
|
||||
out "#[test]"
|
||||
wrapIndent "fn KATs()" $
|
||||
do let name' = pad 5 '0' (show bitsize)
|
||||
out ("run_test(build_test_path(\"base\",\"" ++ name' ++ "\"), 8, |case| {")
|
||||
indent $
|
||||
do out ("let (neg0, xbytes) = case.get(\"x\").unwrap();")
|
||||
out ("let (neg1, mbytes) = case.get(\"m\").unwrap();")
|
||||
out ("let (neg2, zbytes) = case.get(\"z\").unwrap();")
|
||||
out ("let (neg3, ebytes) = case.get(\"e\").unwrap();")
|
||||
out ("let (neg4, obytes) = case.get(\"o\").unwrap();")
|
||||
out ("let (neg5, rbytes) = case.get(\"r\").unwrap();")
|
||||
out ("let (neg6, bbytes) = case.get(\"b\").unwrap();")
|
||||
out ("let (neg7, tbytes) = case.get(\"t\").unwrap();")
|
||||
out ("assert!(!neg0&&!neg1&&!neg2&&!neg3&&!neg4&&!neg5&&!neg6&&!neg7);")
|
||||
out ("let mut x = "++name++"::from_bytes(xbytes);")
|
||||
out ("let m = "++name++"::from_bytes(mbytes);")
|
||||
out ("let z = 1 == zbytes[0];")
|
||||
out ("let e = 1 == ebytes[0];")
|
||||
out ("let o = 1 == obytes[0];")
|
||||
out ("let r = "++name++"::from_bytes(rbytes);")
|
||||
out ("let b = usize::from("++name++"::from_bytes(bbytes));")
|
||||
out ("let t = 1 == tbytes[0];")
|
||||
out ("assert_eq!(x.is_zero(), z);")
|
||||
out ("assert_eq!(x.is_even(), e);")
|
||||
out ("assert_eq!(x.is_odd(), o);")
|
||||
out ("assert_eq!(x.testbit(b), t);")
|
||||
out ("x.mask(usize::from(&m));")
|
||||
out ("assert_eq!(x, r);")
|
||||
out ("});")
|
||||
|
||||
byteShiftInfo :: Word -> (Word, Word)
|
||||
byteShiftInfo idx =
|
||||
(idx `div` 8, (idx `mod` 8) * 8)
|
||||
|
||||
pad :: Int -> Char -> String -> String
|
||||
pad len c str
|
||||
| length str >= len = str
|
||||
| otherwise = pad len c (c:str)
|
||||
71
generation/src/File.hs
Normal file
71
generation/src/File.hs
Normal file
@@ -0,0 +1,71 @@
|
||||
module File(
|
||||
File(..),
|
||||
Task(..),
|
||||
addModuleTasks,
|
||||
makeTasks
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Monad(forM_)
|
||||
import Data.Char(toUpper)
|
||||
import Data.List(isPrefixOf)
|
||||
import qualified Data.Map.Strict as Map
|
||||
import Gen(Gen,blank,out)
|
||||
import System.FilePath(takeBaseName,takeDirectory,takeFileName,(</>))
|
||||
|
||||
data File = File {
|
||||
predicate :: Word -> [Word] -> Bool,
|
||||
outputName :: FilePath,
|
||||
generator :: Word -> Gen (),
|
||||
testGenerator :: Maybe (Word -> Gen ())
|
||||
}
|
||||
|
||||
data Task = Task {
|
||||
outputFile :: FilePath,
|
||||
fileGenerator :: Gen ()
|
||||
}
|
||||
|
||||
makeTasks :: FilePath -> FilePath ->
|
||||
Word -> [Word] ->
|
||||
File ->
|
||||
[Task]
|
||||
makeTasks srcBase testBase size allSizes file
|
||||
| predicate file size allSizes =
|
||||
let base = Task (srcBase </> ("u" ++ show size) </> outputName file <> ".rs") (generator file size)
|
||||
in case testGenerator file of
|
||||
Nothing -> [base]
|
||||
Just x ->
|
||||
[base, Task (testBase </> outputName file </> ("U" ++ show size ++ ".test")) (x size)]
|
||||
| otherwise = []
|
||||
|
||||
addModuleTasks :: FilePath -> [Task] -> [Task]
|
||||
addModuleTasks base baseTasks = unsignedTask : (baseTasks ++ moduleTasks)
|
||||
where
|
||||
moduleMap = foldr addModuleInfo Map.empty baseTasks
|
||||
addModuleInfo task map
|
||||
| base `isPrefixOf` outputFile task =
|
||||
Map.insertWith (++) (takeDirectory (outputFile task))
|
||||
[takeBaseName (outputFile task)]
|
||||
map
|
||||
| otherwise = map
|
||||
moduleTasks = Map.foldrWithKey generateModuleTask [] moduleMap
|
||||
generateModuleTask directory mods acc = acc ++ [Task {
|
||||
outputFile = directory </> "mod.rs",
|
||||
fileGenerator =
|
||||
do forM_ mods $ \ modle -> out ("mod " ++ modle ++ ";")
|
||||
blank
|
||||
out ("pub use base::" ++ upcase (takeFileName directory) ++ ";")
|
||||
}]
|
||||
unsignedTask = Task {
|
||||
outputFile = base </> "unsigned" </> "mod.rs",
|
||||
fileGenerator =
|
||||
do forM_ (Map.keys moduleMap) $ \ key ->
|
||||
out ("mod " ++ takeFileName key ++ ";")
|
||||
blank
|
||||
forM_ (Map.keys moduleMap) $ \ key ->
|
||||
out ("pub use " ++ takeFileName key ++ "::" ++
|
||||
upcase (takeFileName key) ++ ";")
|
||||
}
|
||||
|
||||
upcase :: String -> String
|
||||
upcase = map toUpper
|
||||
115
generation/src/Gen.hs
Normal file
115
generation/src/Gen.hs
Normal file
@@ -0,0 +1,115 @@
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
module Gen(
|
||||
Gen(Gen),
|
||||
runGen,
|
||||
gensym,
|
||||
indent,
|
||||
blank,
|
||||
out,
|
||||
wrapIndent,
|
||||
implFor,
|
||||
implFor',
|
||||
implFor'',
|
||||
newNum,
|
||||
TestVariable(..),
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Monad.RWS.Strict(RWS,evalRWS)
|
||||
import Control.Monad.State.Class(MonadState,get,put)
|
||||
import Control.Monad.Writer.Class(MonadWriter,tell)
|
||||
import Data.Bits(shiftL)
|
||||
import Data.List(replicate)
|
||||
import Data.Word(Word)
|
||||
import Numeric(showHex)
|
||||
import System.Random(StdGen, newStdGen, random, randomR)
|
||||
|
||||
newtype Gen a = Gen { unGen :: RWS () String GenState a}
|
||||
deriving (Applicative, Functor, Monad, MonadState GenState, MonadWriter String)
|
||||
|
||||
tabAmount :: Word
|
||||
tabAmount = 4
|
||||
|
||||
data GenState = GenState {
|
||||
indentAmount :: Word,
|
||||
gensymIndex :: Word,
|
||||
rng :: StdGen
|
||||
}
|
||||
|
||||
initGenState :: IO GenState
|
||||
initGenState =
|
||||
do rng0 <- newStdGen
|
||||
return GenState { indentAmount = 0, gensymIndex = 0, rng = rng0 }
|
||||
|
||||
runGen :: FilePath -> Gen a -> IO a
|
||||
runGen path action =
|
||||
do state0 <- initGenState
|
||||
let (res, contents) = evalRWS (unGen action) () state0
|
||||
writeFile path contents
|
||||
return res
|
||||
|
||||
gensym :: String -> Gen String
|
||||
gensym prefix =
|
||||
do gs <- get
|
||||
let gs' = gs{ gensymIndex = gensymIndex gs + 1 }
|
||||
put gs'
|
||||
return (prefix ++ show (gensymIndex gs))
|
||||
|
||||
indent :: Gen a -> Gen a
|
||||
indent action =
|
||||
do gs <- get
|
||||
put gs{ indentAmount = indentAmount gs + tabAmount }
|
||||
res <- action
|
||||
put gs
|
||||
return res
|
||||
|
||||
blank :: Gen ()
|
||||
blank = tell "\n"
|
||||
|
||||
out :: String -> Gen ()
|
||||
out val =
|
||||
do gs <- get
|
||||
tell (replicate (fromIntegral (indentAmount gs)) ' ')
|
||||
tell val
|
||||
tell "\n"
|
||||
|
||||
wrapIndent :: String -> Gen a -> Gen a
|
||||
wrapIndent val middle =
|
||||
do gs <- get
|
||||
tell (replicate (fromIntegral (indentAmount gs)) ' ')
|
||||
tell val
|
||||
tell " {\n"
|
||||
res <- indent middle
|
||||
tell (replicate (fromIntegral (indentAmount gs)) ' ')
|
||||
tell "}\n"
|
||||
return res
|
||||
|
||||
implFor :: String -> String -> Gen a -> Gen a
|
||||
implFor trait name middle =
|
||||
wrapIndent ("impl " ++ trait ++ " for " ++ name) middle
|
||||
|
||||
implFor' :: String -> String -> Gen a -> Gen a
|
||||
implFor' trait name middle =
|
||||
wrapIndent ("impl<'a> " ++ trait ++ " for " ++ name) middle
|
||||
|
||||
implFor'' :: String -> String -> Gen a -> Gen a
|
||||
implFor'' trait name middle =
|
||||
wrapIndent ("impl<'a,'b> " ++ trait ++ " for " ++ name) middle
|
||||
|
||||
newNum :: Bool -> Word -> Gen Integer
|
||||
newNum signed bits =
|
||||
do gs <- get
|
||||
let rng0 = rng gs
|
||||
let high = (1 `shiftL` fromIntegral bits) - 1
|
||||
let (v, rng1) = randomR (0, high) rng0
|
||||
let (sign, rng2) = random rng1
|
||||
let v' = if signed && sign then -v else v
|
||||
put gs{ rng = rng2 }
|
||||
return v'
|
||||
|
||||
class TestVariable a where
|
||||
emitTestVariable :: Char -> a -> Gen ()
|
||||
|
||||
instance TestVariable Integer where
|
||||
emitTestVariable c v =
|
||||
out ([c] ++ ": " ++ showHex v "")
|
||||
62
generation/src/Main.hs
Normal file
62
generation/src/Main.hs
Normal file
@@ -0,0 +1,62 @@
|
||||
module Main
|
||||
where
|
||||
|
||||
import Base(base)
|
||||
import BinaryOps(binaryOps)
|
||||
import Compare(comparisons)
|
||||
import Conversions(conversions)
|
||||
import CryptoNum(cryptoNum)
|
||||
import Control.Monad(forM_,unless)
|
||||
import Data.Word(Word)
|
||||
import File(File,Task(..),addModuleTasks,makeTasks)
|
||||
import Gen(runGen)
|
||||
import System.Directory(createDirectoryIfMissing)
|
||||
import System.Environment(getArgs)
|
||||
import System.Exit(die)
|
||||
import System.FilePath(takeDirectory,(</>))
|
||||
|
||||
lowestBitsize :: Word
|
||||
lowestBitsize = 192
|
||||
|
||||
highestBitsize :: Word
|
||||
highestBitsize = 512
|
||||
|
||||
bitsizes :: [Word]
|
||||
bitsizes = [lowestBitsize,lowestBitsize+64..highestBitsize]
|
||||
|
||||
unsignedFiles :: [File]
|
||||
unsignedFiles = [
|
||||
base
|
||||
, binaryOps
|
||||
, comparisons
|
||||
, conversions
|
||||
, cryptoNum
|
||||
]
|
||||
|
||||
signedFiles :: [File]
|
||||
signedFiles = [
|
||||
]
|
||||
|
||||
makeTasks' :: FilePath -> FilePath -> [File] -> [Task]
|
||||
makeTasks' srcPath testPath files =
|
||||
concatMap (\ sz -> concatMap (makeTasks srcPath testPath sz bitsizes) files) bitsizes
|
||||
|
||||
makeAllTasks :: FilePath -> FilePath -> [Task]
|
||||
makeAllTasks srcPath testPath = addModuleTasks srcPath $
|
||||
makeTasks' (srcPath </> "unsigned") testPath unsignedFiles ++
|
||||
makeTasks' (srcPath </> "signed") testPath signedFiles
|
||||
|
||||
main :: IO ()
|
||||
main =
|
||||
do args <- getArgs
|
||||
unless (length args == 1) $
|
||||
die ("generation takes exactly one argument, the target directory")
|
||||
let topLevel = head args
|
||||
srcPath = topLevel </> "src"
|
||||
testPath = topLevel </> "testdata"
|
||||
tasks = makeAllTasks srcPath testPath
|
||||
total = length tasks
|
||||
forM_ (zip [(1::Word)..] tasks) $ \ (i, task) ->
|
||||
do putStrLn ("[" ++ show i ++ "/" ++ show total ++ "] " ++ outputFile task)
|
||||
createDirectoryIfMissing True (takeDirectory (outputFile task))
|
||||
runGen (outputFile task) (fileGenerator task)
|
||||
4
generation/src/Testing.hs
Normal file
4
generation/src/Testing.hs
Normal file
@@ -0,0 +1,4 @@
|
||||
module Testing(
|
||||
)
|
||||
where
|
||||
|
||||
52
old/signed/mod.rs
Normal file
52
old/signed/mod.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
//! This module includes a large number of signed integer types for very
|
||||
//! large integers, designed to try to match good performance with a high
|
||||
//! assurance threshold.
|
||||
//!
|
||||
//! The types provided in this module, and the functions available for each
|
||||
//! of those types, is derived from standard bit widths for RSA, DSA, and
|
||||
//! Elliptic Curve encryption schemes. If this library does not include a
|
||||
//! function you would like for another cryptographic scheme, please reach
|
||||
//! out to the authors; in many cases, the relevant code can be automatically
|
||||
//! generated.
|
||||
//!
|
||||
#[macro_use]
|
||||
mod add;
|
||||
#[macro_use]
|
||||
mod base;
|
||||
#[macro_use]
|
||||
mod compare;
|
||||
#[macro_use]
|
||||
mod conversion;
|
||||
#[macro_use]
|
||||
mod div;
|
||||
#[macro_use]
|
||||
mod egcd;
|
||||
#[macro_use]
|
||||
mod moddiv;
|
||||
#[macro_use]
|
||||
mod modinv;
|
||||
#[macro_use]
|
||||
mod mul;
|
||||
#[macro_use]
|
||||
mod scale;
|
||||
#[macro_use]
|
||||
mod shift;
|
||||
#[macro_use]
|
||||
mod subtraction;
|
||||
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use std::cmp::{Ord,Ordering,PartialOrd};
|
||||
use std::fmt;
|
||||
use std::ops::{Add,AddAssign};
|
||||
use std::ops::{Div,DivAssign};
|
||||
use std::ops::{Mul,MulAssign};
|
||||
use std::ops::{Rem,RemAssign};
|
||||
use std::ops::{Shl,ShlAssign,Shr,ShrAssign};
|
||||
use std::ops::{Sub,SubAssign};
|
||||
use unsigned::*;
|
||||
|
||||
pub use self::egcd::EGCD;
|
||||
pub use self::moddiv::ModDiv;
|
||||
pub use self::modinv::ModInv;
|
||||
|
||||
include!("invoc.rs");
|
||||
75
src/lib.rs
75
src/lib.rs
@@ -1,49 +1,38 @@
|
||||
extern crate quickcheck;
|
||||
extern crate rand;
|
||||
|
||||
#![cfg_attr(not(test),no_std)]
|
||||
pub mod signed;
|
||||
pub mod unsigned;
|
||||
#[cfg(test)]
|
||||
pub mod testing;
|
||||
mod testing;
|
||||
|
||||
#[cfg(test)]
|
||||
mod arithmetic {
|
||||
use super::signed::*;
|
||||
use super::unsigned::*;
|
||||
|
||||
quickcheck! {
|
||||
fn commutivity_signed_add(x: I576, y: I576) -> bool {
|
||||
(&x + &y) == (&y + &x)
|
||||
}
|
||||
fn commutivity_unsigned_add(x: U576, y: U576) -> bool {
|
||||
(&x + &y) == (&y + &x)
|
||||
}
|
||||
fn commutivity_unsigned_mul(x: U192, y: U192) -> bool {
|
||||
(&x * &y) == (&y * &x)
|
||||
/// A trait definition for large numbers.
|
||||
pub trait CryptoNum {
|
||||
/// Generate a new value of the given type.
|
||||
fn zero() -> Self;
|
||||
/// Test if the number is zero.
|
||||
fn is_zero(&self) -> bool;
|
||||
/// Test if the number is even.
|
||||
fn is_even(&self) -> bool;
|
||||
/// Test if the number is odd.
|
||||
fn is_odd(&self) -> bool;
|
||||
/// The size of this number in bits.
|
||||
fn bit_length() -> usize;
|
||||
/// Mask off the high parts of the number. In particular, it
|
||||
/// zeros the bits above (len * 64).
|
||||
fn mask(&mut self, len: usize);
|
||||
/// Test if the given bit is zero, where bits are numbered in
|
||||
/// least-significant order (0 is the LSB, etc.).
|
||||
fn testbit(&self, bit: usize) -> bool;
|
||||
/// Convert a slice into a CryptoNum, assuming big-endian memory layout.
|
||||
/// If you pass in a slice bigger than the bit size of the numeric type,
|
||||
/// this will assume that the number is in the first `n` bits of the
|
||||
/// memory layout. If you pass in a smaller buffer, it will use the bits
|
||||
/// available as the low `n` bits of the number.
|
||||
fn from_bytes(bytes: &[u8]) -> Self;
|
||||
/// Write the cryptonum into the provide slice. If the provided slice
|
||||
/// is greater than or equal to `n` bits in length, `to_bytes` will
|
||||
/// write to the first `n` bits. If the slice is less than `n` bits
|
||||
/// in length, `to_bytes` will write the lower-order bits that fit
|
||||
/// into the provided slice.
|
||||
fn to_bytes(&self, bytes: &mut [u8]);
|
||||
}
|
||||
|
||||
fn associativity_unsigned_add(x: U192, y: U192, z: U192) -> bool {
|
||||
(U256::from(&x) + (&y + &z)) == ((&x + &y) + U256::from(&z))
|
||||
}
|
||||
fn associativity_unsigned_mul(x: U192, y: U192, z: U192) -> bool {
|
||||
(U384::from(&x) * (&y * &z)) == ((&x * &y) * U384::from(&z))
|
||||
}
|
||||
|
||||
fn identity_signed_add(x: I576) -> bool {
|
||||
(&x + I576::zero()) == I640::from(&x)
|
||||
}
|
||||
fn identity_unsigned_add(x: U576) -> bool {
|
||||
(&x + U576::zero()) == U640::from(&x)
|
||||
}
|
||||
fn identity_unsigned_mul(x: U192) -> bool {
|
||||
(&x * U192::from(1u64)) == U384::from(&x)
|
||||
}
|
||||
|
||||
fn additive_inverse(x: I576) -> bool {
|
||||
(&x + x.negate()) == I640::zero()
|
||||
}
|
||||
fn distribution(x: U192, y: U192, z: U192) -> bool {
|
||||
(U256::from(&x) * (&y + &z)) == U512::from((&x * &y) + (&x * &z))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
//! This module includes a large number of signed integer types for very
|
||||
//! large integers, designed to try to match good performance with a high
|
||||
//! assurance threshold.
|
||||
//!
|
||||
//! The types provided in this module, and the functions available for each
|
||||
//! of those types, is derived from standard bit widths for RSA, DSA, and
|
||||
//! Elliptic Curve encryption schemes. If this library does not include a
|
||||
//! function you would like for another cryptographic scheme, please reach
|
||||
//! out to the authors; in many cases, the relevant code can be automatically
|
||||
//! generated.
|
||||
//!
|
||||
#[macro_use]
|
||||
mod add;
|
||||
#[macro_use]
|
||||
mod base;
|
||||
#[macro_use]
|
||||
mod compare;
|
||||
#[macro_use]
|
||||
mod conversion;
|
||||
#[macro_use]
|
||||
mod div;
|
||||
#[macro_use]
|
||||
mod egcd;
|
||||
#[macro_use]
|
||||
mod moddiv;
|
||||
#[macro_use]
|
||||
mod modinv;
|
||||
#[macro_use]
|
||||
mod mul;
|
||||
#[macro_use]
|
||||
mod scale;
|
||||
#[macro_use]
|
||||
mod shift;
|
||||
#[macro_use]
|
||||
mod subtraction;
|
||||
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use std::cmp::{Ord,Ordering,PartialOrd};
|
||||
use std::fmt;
|
||||
use std::ops::{Add,AddAssign};
|
||||
use std::ops::{Div,DivAssign};
|
||||
use std::ops::{Mul,MulAssign};
|
||||
use std::ops::{Rem,RemAssign};
|
||||
use std::ops::{Shl,ShlAssign,Shr,ShrAssign};
|
||||
use std::ops::{Sub,SubAssign};
|
||||
use unsigned::*;
|
||||
|
||||
pub use self::egcd::EGCD;
|
||||
pub use self::moddiv::ModDiv;
|
||||
pub use self::modinv::ModInv;
|
||||
|
||||
include!("invoc.rs");
|
||||
@@ -1,16 +1,18 @@
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::str::Lines;
|
||||
|
||||
pub fn build_test_path(dir: &str, typename: &str) -> String
|
||||
pub fn build_test_path(dir: &str, typename: &str) -> PathBuf
|
||||
{
|
||||
let mut name = typename.to_string();
|
||||
name.remove(0);
|
||||
while name.len() < 5 {
|
||||
name.insert(0, '0');
|
||||
}
|
||||
format!("testdata/{}/{}.test", dir, name)
|
||||
let mut res = PathBuf::new();
|
||||
res.push(".");
|
||||
res.push("testdata");
|
||||
res.push(dir);
|
||||
res.push(typename);
|
||||
res.set_extension("test");
|
||||
res
|
||||
}
|
||||
|
||||
fn next_value_set(line: &str) -> (String, bool, Vec<u8>)
|
||||
@@ -58,9 +60,10 @@ fn next_test_case(contents: &mut Lines, lines: usize) ->
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn run_test<F>(fname: String, i: usize, f: F)
|
||||
pub fn run_test<F>(fname: PathBuf, i: usize, f: F)
|
||||
where F: Fn(HashMap<String,(bool,Vec<u8>)>)
|
||||
{
|
||||
println!("fname: {:?}", fname);
|
||||
let mut file = File::open(fname).unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user