From e46cfe56d1ca26cfb986d4cf477666fec7483c4e Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Tue, 14 Jan 2020 12:13:40 -1000 Subject: [PATCH] Support generating signed numbers. --- generation/Main.hs | 2 + generation/generation.cabal | 1 + generation/src/Add.hs | 4 +- generation/src/Base.hs | 1 - generation/src/BinaryOps.hs | 2 +- generation/src/Compare.hs | 2 +- generation/src/CryptoNum.hs | 2 +- generation/src/Division.hs | 2 +- generation/src/File.hs | 34 ++++--- generation/src/ModOps.hs | 2 +- generation/src/Multiply.hs | 4 +- generation/src/Scale.hs | 4 +- generation/src/Shift.hs | 2 +- generation/src/Signed.hs | 182 ++++++++++++++++++++++++++++++++++++ generation/src/Subtract.hs | 4 +- 15 files changed, 218 insertions(+), 30 deletions(-) create mode 100644 generation/src/Signed.hs diff --git a/generation/Main.hs b/generation/Main.hs index e821360..3ab8665 100644 --- a/generation/Main.hs +++ b/generation/Main.hs @@ -14,6 +14,7 @@ import ModOps(modulusOps) import Multiply(safeMultiplyOps, unsafeMultiplyOps) import Scale(safeScaleOps, unsafeScaleOps) import Shift(shiftOps) +import Signed(signedBaseOps) import Subtract(safeSubtractOps,unsafeSubtractOps) import System.Directory(createDirectoryIfMissing) import System.Environment(getArgs) @@ -53,6 +54,7 @@ unsignedFiles = [ signedFiles :: [File] signedFiles = [ + signedBaseOps ] allFiles :: [File] diff --git a/generation/generation.cabal b/generation/generation.cabal index 1b7ba21..a81afc7 100644 --- a/generation/generation.cabal +++ b/generation/generation.cabal @@ -45,6 +45,7 @@ library Multiply, Scale, Shift, + Signed, Subtract executable generation diff --git a/generation/src/Add.hs b/generation/src/Add.hs index 2e52b25..96e7184 100644 --- a/generation/src/Add.hs +++ b/generation/src/Add.hs @@ -43,7 +43,7 @@ declareSafeAddOperators bitsize _ = let sname = mkIdent ("U" ++ show bitsize) dname = mkIdent ("U" ++ show (bitsize + 64)) fullRippleAdd = makeRippleAdder True (bitsize `div` 64) "res" - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::Add; use crate::CryptoNum; @@ -119,7 +119,7 @@ declareUnsafeAddOperators :: Word -> [Word] -> SourceFile Span declareUnsafeAddOperators bitsize _ = let sname = mkIdent ("U" ++ show bitsize) fullRippleAdd = makeRippleAdder False (bitsize `div` 64) "self" - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::AddAssign; #[cfg(test)] diff --git a/generation/src/Base.hs b/generation/src/Base.hs index 99caf7b..05ea1a6 100644 --- a/generation/src/Base.hs +++ b/generation/src/Base.hs @@ -4,7 +4,6 @@ module Base( ) where --- This is a comment import File import Language.Rust.Data.Ident import Language.Rust.Data.Position diff --git a/generation/src/BinaryOps.hs b/generation/src/BinaryOps.hs index e999a60..46a405e 100644 --- a/generation/src/BinaryOps.hs +++ b/generation/src/BinaryOps.hs @@ -37,7 +37,7 @@ declareBinaryOperators bitsize _ = xorOps = generateBinOps "BitXor" struct_name "bitxor" BitXorOp entries baseNegationStmts = negationStatements "self" entries refNegationStmts = negationStatements "output" entries - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::{BitAnd,BitAndAssign}; use core::ops::{BitOr,BitOrAssign}; diff --git a/generation/src/Compare.hs b/generation/src/Compare.hs index 017fcd9..bfdfa11 100644 --- a/generation/src/Compare.hs +++ b/generation/src/Compare.hs @@ -30,7 +30,7 @@ declareComparators bitsize _ = entries = bitsize `div` 64 eqStatements = buildEqStatements 0 entries compareExp = buildCompareExp 0 entries - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::cmp::{Eq,Ordering,PartialEq}; #[cfg(test)] diff --git a/generation/src/CryptoNum.hs b/generation/src/CryptoNum.hs index 3305834..59e8796 100644 --- a/generation/src/CryptoNum.hs +++ b/generation/src/CryptoNum.hs @@ -43,7 +43,7 @@ declareCryptoNumInstance bitsize _ = Tree (Token mempty (LiteralTok (IntegerTok (show bytelen)) Nothing)) ]) entrieslit = toLit entries - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::cmp::min; #[cfg(test)] diff --git a/generation/src/Division.hs b/generation/src/Division.hs index f6bdff3..d5c1878 100644 --- a/generation/src/Division.hs +++ b/generation/src/Division.hs @@ -30,7 +30,7 @@ declareDivision size _ = let sname = mkIdent ("U" ++ show size) entries = size `div` 64 copyAssign = map doCopy [0..entries-1] - testFileLit = Lit [] (Str (testFile size) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True size) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::{Div, DivAssign}; use core::ops::{Rem, RemAssign}; diff --git a/generation/src/File.hs b/generation/src/File.hs index c86774e..f57d14f 100644 --- a/generation/src/File.hs +++ b/generation/src/File.hs @@ -35,8 +35,9 @@ data Task = Task { writer :: Handle -> IO () } -testFile :: Word -> FilePath -testFile size = "U" ++ show5 size ++ ".test" +testFile :: Bool -> Word -> FilePath +testFile True size = "U" ++ show5 size ++ ".test" +testFile False size = "I" ++ show5 size ++ ".test" show5 :: Word -> String show5 = go . show @@ -58,9 +59,10 @@ generateTasks rng files sizes = basicTasks ++ moduleTasks | otherwise = let (myg, theirg) = split g tasks = go theirg files' rest - signedBit = if isUnsigned file then "unsigned" else "signed" + (signedBit, prefix) | isUnsigned file = ("unsigned", "u") + | otherwise = ("signed", "i") mainTask = Task { - outputFile = "src" signedBit ("u" ++ show size) + outputFile = "src" signedBit (prefix ++ show size) outputName file ++ ".rs", writer = \ hndl -> writeSourceFile hndl (generator file size sizes) } @@ -69,16 +71,16 @@ generateTasks rng files sizes = basicTasks ++ moduleTasks mainTask : tasks Just caseGenerator -> let testTask = Task { - outputFile = "testdata" outputName file testFile size, + outputFile = "testdata" outputName file testFile (isUnsigned file) size, writer = \ hndl -> writeTestCase hndl (caseGenerator size myg) } in testTask : mainTask : tasks generateModules :: [Task] -> [Task] -generateModules tasks = Map.foldrWithKey maddModule [] fileMap ++ [unsignedTask] +generateModules tasks = Map.foldrWithKey maddModule [] fileMap ++ [signedTask, unsignedTask] where maddModule path mods acc - | "src/unsigned" `isPrefixOf` path = + | ("src/unsigned" `isPrefixOf` path) || ("src/signed" `isPrefixOf` path) = let (basePath, lowerName) = splitFileName (init path) upperName = map toUpper lowerName task = Task { @@ -97,26 +99,28 @@ generateModules tasks = Map.foldrWithKey maddModule [] fileMap ++ [unsignedTask] file = dropExtension fileext in Map.insertWith (++) dir [file] acc -- - unsignedTask = - let mods = Map.foldrWithKey topModule [] fileMap - pubuses = Map.foldrWithKey pubUse [] fileMap + signedTask = moduleTask "signed" + unsignedTask = moduleTask "unsigned" + moduleTask kind = + let mods = Map.foldrWithKey (topModule kind) [] fileMap + pubuses = Map.foldrWithKey (pubUse kind) [] fileMap in Task { - outputFile = "src" "unsigned.rs", + outputFile = "src" (kind ++ ".rs"), writer = \ hndl -> writeSourceFile hndl [sourceFile| $@{mods} $@{pubuses} |] } - topModule path _ acc - | "src/unsigned" `isPrefixOf` path = + topModule kind path _ acc + | ("src/" ++ kind) `isPrefixOf` path = let lowerName = takeFileName (init path) modl = mkIdent lowerName in [item| mod $$modl; |] : acc | otherwise = acc - pubUse path _ acc - | "src/unsigned" `isPrefixOf` path = + pubUse kind path _ acc + | ("src/" ++ kind) `isPrefixOf` path = let lowerName = takeFileName (init path) tname = mkIdent (map toUpper lowerName) modl = mkIdent lowerName diff --git a/generation/src/ModOps.hs b/generation/src/ModOps.hs index 1b72b2d..ca12033 100644 --- a/generation/src/ModOps.hs +++ b/generation/src/ModOps.hs @@ -29,7 +29,7 @@ declareModOps :: Word -> [Word] -> SourceFile Span declareModOps bitsize _ = let sname = mkIdent ("U" ++ show bitsize) bname = mkIdent ("U" ++ show (bitsize * 2)) - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::convert::TryFrom; use crate::unsigned::{$$sname, $$bname}; diff --git a/generation/src/Multiply.hs b/generation/src/Multiply.hs index 7295861..e09e5a2 100644 --- a/generation/src/Multiply.hs +++ b/generation/src/Multiply.hs @@ -45,7 +45,7 @@ declareSafeMulOperators bitsize _ = let sname = mkIdent ("U" ++ show bitsize) dname = mkIdent ("U" ++ show (bitsize * 2)) fullRippleMul = generateMultiplier True (bitsize `div` 64) "rhs" "res" - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::Mul; use crate::CryptoNum; @@ -121,7 +121,7 @@ declareUnsafeMulOperators :: Word -> [Word] -> SourceFile Span declareUnsafeMulOperators bitsize _ = let sname = mkIdent ("U" ++ show bitsize) halfRippleMul = generateMultiplier False (bitsize `div` 64) "rhs" "self" - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::MulAssign; #[cfg(test)] diff --git a/generation/src/Scale.hs b/generation/src/Scale.hs index 2049e40..1f8aedf 100644 --- a/generation/src/Scale.hs +++ b/generation/src/Scale.hs @@ -43,7 +43,7 @@ declareSafeScaleOperators bitsize _ = let sname = mkIdent ("U" ++ show bitsize) dname = mkIdent ("U" ++ show (bitsize + 64)) fullRippleScale = generateScaletiplier True (bitsize `div` 64) "rhs" "res" - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::Mul; use crate::CryptoNum; @@ -158,7 +158,7 @@ declareUnsafeScaleOperators :: Word -> [Word] -> SourceFile Span declareUnsafeScaleOperators bitsize _ = let sname = mkIdent ("U" ++ show bitsize) halfRippleScale = generateScaletiplier False (bitsize `div` 64) "rhs" "self" - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::MulAssign; #[cfg(test)] diff --git a/generation/src/Shift.hs b/generation/src/Shift.hs index 5b85554..338802a 100644 --- a/generation/src/Shift.hs +++ b/generation/src/Shift.hs @@ -35,7 +35,7 @@ declareShiftOperators bitsize _ = shlActualImpl = concatMap actualShlImplLines [1..entries-1] shrActualImpl = concatMap (actualShrImplLines entries) (reverse [0..entries-1]) resAssign = map reassignSelf [0..entries-1] - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| #[cfg(test)] use core::convert::TryFrom; diff --git a/generation/src/Signed.hs b/generation/src/Signed.hs new file mode 100644 index 0000000..219d41c --- /dev/null +++ b/generation/src/Signed.hs @@ -0,0 +1,182 @@ +{-# LANGUAGE QuasiQuotes #-} +module Signed(signedBaseOps) + where + +import File +import Language.Rust.Data.Ident +import Language.Rust.Data.Position +import Language.Rust.Quote +import Language.Rust.Syntax + + +signedBaseOps :: File +signedBaseOps = File { + predicate = const (const True), + outputName = "base", + isUnsigned = False, + generator = declareSigned, + testCase = Nothing +} + +declareSigned :: Word -> [Word] -> SourceFile Span +declareSigned bitsize _ = + let sname = mkIdent ("I" ++ show bitsize) + uname = mkIdent ("U" ++ show bitsize) + in [sourceFile| + use core::fmt; + use core::ops::{Neg, Not}; + use crate::CryptoNum; + use crate::unsigned::$$uname; + use quickcheck::{Arbitrary,Gen}; + #[cfg(test)] + use quickcheck::quickcheck; + + #[derive(Clone)] + pub struct $$sname { + contents: $$uname, + } + + impl Neg for $$sname { + type Output = $$sname; + + fn neg(mut self) -> $$sname { + for x in self.contents.value.iter_mut() { + *x = !*x; + } + let one = $$uname::from(1u64); + self.contents += one; + self + } + } + + impl<'a> Neg for &'a $$sname { + type Output = $$sname; + + fn neg(self) -> $$sname { + let res = self.clone(); + res.neg() + } + } + + impl Not for $$sname { + type Output = $$sname; + + fn not(mut self) -> $$sname { + for x in self.contents.value.iter_mut() { + *x = !*x; + } + self + } + } + + impl<'a> Not for &'a $$sname { + type Output = $$sname; + + fn not(self) -> $$sname { + self.clone().not() + } + } + + impl fmt::Debug for $$sname { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.contents) + } + } + + impl fmt::UpperHex for $$sname { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut temp = self.clone(); + + if temp.contents.value[temp.contents.value.len()-1] >> 63 == 1 { + write!(f, "-")?; + temp = !temp; + } + + write!(f, "{:X}", temp.contents) + } + } + + impl fmt::LowerHex for $$sname { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut temp = self.clone(); + + if temp.contents.value[temp.contents.value.len()-1] >> 63 == 1 { + write!(f, "-")?; + temp = !temp; + } + + write!(f, "{:x}", temp.contents) + } + } + + impl PartialEq for $$sname { + fn eq(&self, other: &$$sname) -> bool { + let mut all_equal = true; + + for (l, r) in self.contents.value.iter().zip(other.contents.value.iter()) { + all_equal &= *l == *r; + } + + all_equal + } + } + + impl Eq for $$sname { } + + impl Arbitrary for $$sname { + fn arbitrary(g: &mut G) -> $$sname { + $$sname{ + contents: $$uname::arbitrary(g), + } + } + } + + impl CryptoNum for $$sname { + fn zero() -> $$sname { + $$sname{ contents: $$uname::zero() } + } + fn is_zero(&self) -> bool { + self.contents.is_zero() + } + fn is_even(&self) -> bool { + self.contents.is_even() + } + fn is_odd(&self) -> bool { + self.contents.is_odd() + } + fn bit_length() -> usize { + $$uname::bit_length() + } + fn mask(&mut self, len: usize) { + self.contents.mask(len); + } + fn testbit(&self, bit: usize) -> bool { + self.contents.testbit(bit) + } + fn from_bytes(bytes: &[u8]) -> $$sname { + $$sname{ contents: $$uname::from_bytes(bytes) } + } + fn to_bytes(&self, bytes: &mut [u8]) { + self.contents.to_bytes(bytes); + } + } + + #[cfg(test)] + quickcheck! { + fn equality_reflexive(x: $$sname) -> bool { + &x == &x + } + + fn equality_symmetric(x: $$sname, y: $$sname) -> bool { + (&x == &y) == (&y == &x) + } + + fn double_not(x: $$sname) -> bool { + x == !!&x + } + + fn double_neg(x: $$sname) -> bool { + x == --&x + } + } + |] \ No newline at end of file diff --git a/generation/src/Subtract.hs b/generation/src/Subtract.hs index 0498dff..56a7ddb 100644 --- a/generation/src/Subtract.hs +++ b/generation/src/Subtract.hs @@ -43,7 +43,7 @@ declareSafeSubtractOperators bitsize _ = let sname = mkIdent ("U" ++ show bitsize) dname = mkIdent ("U" ++ show (bitsize + 64)) fullRippleSubtract = makeRippleSubtracter True (bitsize `div` 64) "res" - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::Sub; use crate::CryptoNum; @@ -110,7 +110,7 @@ declareUnsafeSubtractOperators :: Word -> [Word] -> SourceFile Span declareUnsafeSubtractOperators bitsize _ = let sname = mkIdent ("U" ++ show bitsize) fullRippleSubtract = makeRippleSubtracter False (bitsize `div` 64) "self" - testFileLit = Lit [] (Str (testFile bitsize) Cooked Unsuffixed mempty) mempty + testFileLit = Lit [] (Str (testFile True bitsize) Cooked Unsuffixed mempty) mempty in [sourceFile| use core::ops::SubAssign; #[cfg(test)]