ed25519 0.0.4.0 → 0.0.5.0
raw patch · 9 files changed
+188/−79 lines, 9 filesdep +directorydep +doctestdep +filepathdep ~QuickCheckdep ~bytestringdep ~criterionPVP ok
version bump matches the API change (PVP)
Dependencies added: directory, doctest, filepath
Dependency ranges changed: QuickCheck, bytestring, criterion, deepseq, ghc-prim, hlint
API changes (from Hackage documentation)
Files
- .travis.yml +2/−2
- CHANGELOG.md +8/−0
- benchmarks/bench.hs +44/−0
- benchmarks/bench1.hs +0/−44
- ed25519.cabal +26/−8
- src/Crypto/Sign/Ed25519.hs +68/−15
- tests/doctests.hs +29/−0
- tests/hlint.hs +8/−7
- tests/properties.hs +3/−3
.travis.yml view
@@ -83,7 +83,7 @@ - cabal --version - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]" - travis_retry cabal update- - cabal install --only-dependencies --enable-tests -f-test-hlint+ - cabal install --only-dependencies --enable-tests -f-test-hlint -f-test-doctests # Here starts the actual work to be performed for the package under # test; any command which exits with a non-zero exit code causes the@@ -91,7 +91,7 @@ script: - if [ -f configure.ac ]; then autoreconf -i; fi # -v2 provides useful information for debugging- - cabal configure --enable-tests -f-test-hlint -v2+ - cabal configure --enable-tests -f-test-hlint -f-test-doctests -v2 # this builds all libraries and executables # (including tests/benchmarks)
CHANGELOG.md view
@@ -1,3 +1,11 @@+0.0.5.0+-------++ * Added doctests and crash course introduction.+ * Fixed some bugs in the test harnesses.+ * Fixed some `hlint` gripes.+ * Minor touchups elsewhere.+ 0.0.4.0 -------
+ benchmarks/bench.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE CPP #-}+module Main+ ( main -- :: IO ()+ ) where++import Criterion.Main+import Crypto.Sign.Ed25519++import Data.Maybe (fromJust)+import Control.DeepSeq+import qualified Data.ByteString as B++--------------------------------------------------------------------------------++#if !MIN_VERSION_bytestring(0,10,0)+instance NFData B.ByteString+#endif++instance NFData SecretKey+instance NFData PublicKey++--------------------------------------------------------------------------------++main :: IO ()+main = do+ -- Don't use `createKeypair`, since that will incur a ton of calls+ -- to the OS to generate randomness. Simply generate a bogus Ed25519+ -- seed instead.+ let seed = B.pack [0..31]+ keys@(pk,sk) = fromJust (createKeypairFromSeed_ seed)++ -- Generate a dummy message to sign, and a signature to verify+ -- against.+ dummy = B.pack [0..255]+ msg = sign sk dummy+ defaultMain+ [ bench "deterministic key generation" $ nf createKeypairFromSeed_ seed+ , bench "signing a 256 byte message" $ nf (sign sk) dummy+ , bench "verifying a signature" $ nf (verify pk) msg+ , bench "roundtrip 256-byte sign/verify" $ nf (signBench keys) dummy+ ]++signBench :: (PublicKey, SecretKey) -> B.ByteString -> Bool+signBench (pk, sk) xs = verify pk (sign sk xs)
− benchmarks/bench1.hs
@@ -1,44 +0,0 @@-{-# LANGUAGE CPP #-}-module Main- ( main -- :: IO ()- ) where--import Criterion.Main-import Crypto.Sign.Ed25519--import Data.Maybe (fromJust)-import Control.DeepSeq-import qualified Data.ByteString as B------------------------------------------------------------------------------------#if !MIN_VERSION_bytestring(0,10,0)-instance NFData B.ByteString-#endif--instance NFData SecretKey-instance NFData PublicKey------------------------------------------------------------------------------------main :: IO ()-main = do- -- Don't use `createKeypair`, since that will incur a ton of calls- -- to the OS to generate randomness. Simply generate a bogus Ed25519- -- seed instead.- let seed = B.pack [0..31]- keys@(pk,sk) = fromJust (createKeypairFromSeed_ seed)-- -- Generate a dummy message to sign, and a signature to verify- -- against.- dummy = B.pack [0..255]- msg = sign sk dummy- defaultMain- [ bench "deterministic key generation" $ nf createKeypairFromSeed_ seed- , bench "signing a 256 byte message" $ nf (sign sk) dummy- , bench "verifying a signature" $ nf (verify pk) msg- , bench "roundtrip 256-byte sign/verify" $ nf (signBench keys) dummy- ]--signBench :: (PublicKey, SecretKey) -> B.ByteString -> Bool-signBench (pk, sk) xs = verify pk (sign sk xs)
ed25519.cabal view
@@ -1,5 +1,5 @@ name: ed25519-version: 0.0.4.0+version: 0.0.5.0 category: Cryptography license: MIT synopsis: Ed25519 cryptographic signatures@@ -47,6 +47,10 @@ default: True manual: True +flag test-doctests+ default: True+ manual: True+ flag no-donna default: True manual: True@@ -101,11 +105,10 @@ -- test-suite hlint- type: exitcode-stdio-1.0- main-is: hlint.hs- ghc-options: -w- hs-source-dirs: tests- default-language: Haskell2010+ type: exitcode-stdio-1.0+ main-is: hlint.hs+ hs-source-dirs: tests+ default-language: Haskell2010 if !flag(test-hlint) buildable: False@@ -114,10 +117,25 @@ base >= 4 && < 5, hlint >= 1.7 && < 1.10 +test-suite doctests+ type: exitcode-stdio-1.0+ main-is: doctests.hs+ hs-source-dirs: tests+ default-language: Haskell2010++ if !flag(test-doctests)+ buildable: False+ else+ build-depends:+ base >= 4 && < 5,+ filepath >= 1.0 && < 1.5,+ directory >= 1.0 && < 1.3,+ doctest >= 0.10 && < 0.11+ ------------------------------------------------------------------------------- -- Build pt 3: benchmarks -benchmark bench1+benchmark bench type: exitcode-stdio-1.0 build-depends: base >= 4 && < 5,@@ -128,4 +146,4 @@ default-language: Haskell2010 hs-source-dirs: benchmarks- main-is: bench1.hs+ main-is: bench.hs
src/Crypto/Sign/Ed25519.hs view
@@ -28,7 +28,7 @@ -- educational and should help adjust your expectations properly.) -- -- For more reading on the underlying implementation and theory--- (including how to get a copy of the software Ed25519 software),+-- (including how to get a copy of the Ed25519 software), -- visit <http://ed25519.cr.yp.to>. There are two papers that discuss -- the design of EdDSA/Ed25519 in detail: --@@ -41,12 +41,14 @@ -- be used with more curves (such as Ed41417, or Ed488), as well as -- defining the support for __message prehashing__. The original -- EdDSA is easily derived from the extended version through a few--- parameter defaults. (This package will not consider non-Ed25519+-- parameter defaults. (This package won't consider non-Ed25519 -- EdDSA systems any further.) ----- module Crypto.Sign.Ed25519- ( -- * Keypair creation+ ( -- * A crash course introduction+ -- $intro++ -- * Keypair creation -- $creatingkeys PublicKey(..) -- :: * , SecretKey(..) -- :: *@@ -67,7 +69,8 @@ , dverify -- :: PublicKey -> ByteString -> Signature -> Bool -- ** Deprecated interface -- | The below interface is deprecated but functionally- -- equivalent to the above; it simply has \"worse\" naming.+ -- equivalent to the above; it simply has \"worse\" naming and will+ -- eventually be removed. , sign' -- :: SecretKey -> ByteString -> Signature , verify' -- :: PublicKey -> ByteString -> Signature -> Bool @@ -108,6 +111,14 @@ import GHC.Generics (Generic) #endif +-- Doctest setup with some examples++-- $setup+-- >>> :set -XOverloadedStrings+-- >>> import Data.ByteString.Char8+-- >>> let hash x = x+-- >>> let readBigFile x = return x+ -------------------------------------------------------------------------------- -- Key creation @@ -229,9 +240,7 @@ -> (PublicKey, SecretKey) -- ^ Resulting keypair createKeypairFromSeed seed = fromMaybe (error "seed has incorrect length") (createKeypairFromSeed_ seed)-{-# DEPRECATED createKeypairFromSeed "This function is unsafe as it can \-@'fail'@ with an invalid input. This function will be replaced with \-@'createKeypairWithSeed_'@ in a future release." #-}+{-# DEPRECATED createKeypairFromSeed "This function is unsafe as it can @'fail'@ with an invalid input. Use @'createKeypairWithSeed_'@ instead." #-} -- | Derive the @'PublicKey'@ for a given @'SecretKey'@. This is a -- convenience which allows (for example) using @'createKeypair'@ and@@ -380,9 +389,7 @@ -> Signature -- ^ Message @'Signature'@, without the message sign' sk xs = dsign sk xs-{-# DEPRECATED sign' "@'sign''@ will be removed in a future release; \-use @'dsign'@ instead." #-}-+{-# DEPRECATED sign' "@'sign''@ will be removed in a future release; use @'dsign'@ instead." #-} -- | Verify a message with a detached @'Signature'@ against a given -- @'PublicKey'@. Simply an alias for @'dverify'@.@@ -397,8 +404,7 @@ -> Bool -- ^ Verification result verify' pk xs sig = dverify pk xs sig-{-# DEPRECATED verify' "@'verify''@ will be removed in a future release; \-use @'dverify'@ instead." #-}+{-# DEPRECATED verify' "@'verify''@ will be removed in a future release; use @'dverify'@ instead." #-} -------------------------------------------------------------------------------- -- FFI binding@@ -433,6 +439,53 @@ -------------------------------------------------------------------------------- -- Documentation and notes +-- $intro+--+-- The simplest use of this library is one where you probably need to+-- sign short messages, so they can be verified independently. That's+-- easily done by first creating a keypair with @'createKeypair'@, and+-- using @'sign'@ to create a signed message. Then, you can distribute+-- your public key and the signed message, and any recipient can+-- verify that message:+--+-- >>> (pk, sk) <- createKeypair+-- >>> let msg = sign sk "Hello world"+-- >>> verify pk msg+-- True+--+-- This interface is fine if your messages are small and simple binary+-- blobs you want to verify in an opaque manner, but internally it+-- creates a copy of the input message. Often, you'll want the+-- signature independently of the message, and that can be done with+-- @'dsign'@ and @'dverify'@. Naturally, verification fails if the+-- message is incorrect:+--+-- >>> (pk, sk) <- createKeypair+-- >>> let msg = "Hello world" :: ByteString+-- >>> let sig = dsign sk msg+-- >>> dverify pk msg sig+-- True+-- >>> dverify pk "Hello world" sig+-- True+-- >>> dverify pk "Goodbye world" sig+-- False+--+-- Finally, it's worth keeping in mind this package doesn't expose any+-- kind of incremental interface, and signing/verification can be+-- expensive. So, if you're dealing with __large inputs__, you can+-- hash the input with a robust, fast cryptographic hash, and then+-- sign that (for example, the @hash@ function below could be+-- __SHA-512__ or __BLAKE2b__):+--+-- >>> (pk, sk) <- createKeypair+-- >>> msg <- readBigFile "blob.tar.gz" :: IO ByteString+-- >>> let sig = dsign sk (hash msg)+-- >>> dverify pk (hash msg) sig+-- True+--+-- See the notes at the bottom of this module for more on message+-- prehashing (as it acts slightly differently in an EdDSA system).+ -- $security -- -- Included below are some notes on the security aspects of the@@ -473,7 +526,7 @@ -- level of Ed25519 is thus @2^((32*8)/2) = 2^128@, far beyond any -- attacker capability (modulo major breakthroughs for the ECDLP, -- which would likely catastrophically be applicable to other systems--- too.)+-- too). -- -- Ed25519 designed to meet the standard notion of unforgeability for -- a public-key signature scheme under chosen-message attacks. This@@ -729,7 +782,7 @@ -- loading the entire file up front to either sign, or verify it. This -- is especially unoptimal for possibly smaller, low-memory systems -- (where decompression, hashing or verification are all best done in--- constant space if possible.)+-- constant space if possible). -- -- Beware however, that if you do this sort of incremental hashing for -- large blobs, you are __taking untrusted data__ and hashing it
+ tests/doctests.hs view
@@ -0,0 +1,29 @@+module Main+ ( main -- :: IO ()+ ) where+import Control.Applicative+import Control.Monad+import Data.List+import System.Directory+import System.FilePath++import Test.DocTest++main :: IO ()+main = allSources >>= \sources -> doctest ("-isrc":sources)++allSources :: IO [FilePath]+allSources = liftM2 (++) (getFiles ".hs" "src")+ (getFiles ".o" "dist/build/src/cbits")++getFiles :: String -> FilePath -> IO [FilePath]+getFiles ext root = filter (isSuffixOf ext) <$> go root+ where+ go dir = do+ (dirs, files) <- getFilesAndDirectories dir+ (files ++) . concat <$> mapM go dirs++getFilesAndDirectories :: FilePath -> IO ([FilePath], [FilePath])+getFilesAndDirectories dir = do+ c <- fmap (dir </>) . filter (`notElem` ["..", "."]) <$> getDirectoryContents dir+ (,) <$> filterM doesDirectoryExist c <*> filterM doesFileExist c
tests/hlint.hs view
@@ -1,10 +1,11 @@-module Main where--import Data.Monoid-import Control.Monad-import Language.Haskell.HLint-import System.Environment-import System.Exit+module Main+ ( main -- :: IO ()+ ) where+import Control.Monad+import Data.Monoid+import Language.Haskell.HLint+import System.Environment+import System.Exit main :: IO () main = do
tests/properties.hs view
@@ -1,7 +1,7 @@ {-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE CPP #-} module Main- ( main -- :: IO ()+ ( main -- :: IO () ) where import Control.Monad import Data.ByteString (ByteString)@@ -62,7 +62,7 @@ main :: IO () main = do- args <- fmap (drop 1) getArgs+ args <- getArgs let n = if null args then 100 else read (head args) :: Int (results, passed) <- runTests n printf "Passed %d tests!\n" (sum passed)@@ -82,7 +82,7 @@ where wrap :: Testable prop => prop -> IO (Bool, Int) wrap prop = do- r <- quickCheckWithResult stdArgs{maxSize=ntests} prop+ r <- quickCheckWithResult stdArgs{maxSuccess=ntests} prop case r of Success n _ _ -> return (True, n) GaveUp n _ _ -> return (True, n)