diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000..a015bc44d --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,8 @@ +### NOTE +# Run `git config blame.ignoreRevsFile .git-blame-ignore-revs` +# from the repository's root to tell `git blame` to ignore +# the commits below. + +# `fourmolize` +# CommitDate: Wed Nov 20 18:01:24 2024 +0100 +db87b19be6ff702d3bf37cef259de456c48b7ffe diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f39ce05fb..070661f8a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -14,4 +14,5 @@ to the issue. --> [versioning process](https://github.com/intersectmbo/cardano-base/blob/master/RELEASING.md#versioning-process). - [ ] The version bounds in `.cabal` files for all affected packages are updated. **_If you change the bounds in a cabal file, that package itself must have a version increase._** (See [RELEASING.md](https://github.com/intersectmbo/cardano-base/blob/master/RELEASING.md#versioning-process)) +- [ ] Commits that only contain large amounts of formatting changes were added to `.git-blame-ignore-revs` - [ ] Self-reviewed the diff diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index 444433431..6313a04a7 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -191,3 +191,27 @@ jobs: uses: input-output-hk/actions/cache@latest with: ghc_version: ${{ matrix.ghc == '8.10.7' && 'ghc810' || matrix.ghc == '9.6.6' && 'ghc96' }} + + fourmolu: + runs-on: ubuntu-latest + + defaults: + run: + shell: bash + + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v4 + + - name: Install fourmolu + run: | + FOURMOLU_VERSION="0.16.2.0" + mkdir -p "$HOME/.local/bin" + curl -sL "https://github.com/fourmolu/fourmolu/releases/download/v${FOURMOLU_VERSION}/fourmolu-${FOURMOLU_VERSION}-linux-x86_64" -o "$HOME/.local/bin/fourmolu" + chmod a+x "$HOME/.local/bin/fourmolu" + echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Run fourmolu + run: ./scripts/fourmolize.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7ae35ec52..0240ebf04 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,6 +25,25 @@ infrastructure: We use trunk based developement. Normal development will branch off of master and be merged back to master. +### Recommended `git` configuration + +Once you cloned the repository, it is recommended to run the following +from the repository's root: +```bash +git config blame.ignoreRevsFile .git-blame-ignore-revs +``` +This way `git blame` will ignore the commits specified in the `.git-blame-ignore-revs` +file. This can come in handy if you want to exclude large commits +with only formatting changes. +You can ignore the above however, if you tend to look at `git blame` +through GitHub. In that case, you don't have to do anything, +as GitHub will pick up `.git-blame-ignore-revs` automatically and ignore +the specified commits. + +If you want to add further revisions to the `ignore-revs` file, +just prepend the full commit hash that you want `git blame` to ignore +and add the commit's title and date as a comment for clarity. + ### Releasing and versioning Packages from `cardano-base` are released to diff --git a/base-deriving-via/src/Data/DerivingVia.hs b/base-deriving-via/src/Data/DerivingVia.hs index eac43d814..eddb03f6e 100644 --- a/base-deriving-via/src/Data/DerivingVia.hs +++ b/base-deriving-via/src/Data/DerivingVia.hs @@ -1,19 +1,19 @@ -{-# LANGUAGE ConstraintKinds #-} -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE KindSignatures #-} -{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE UndecidableInstances #-} -- | Newtype wrappers for us in @deriving via@ clauses that " should " have -- been defined in @base@ and other packages we depend on but do not control -- -- We expected variations of these to eventually be defined upstream, but we'd -- like to use these concepts before that happens. -module Data.DerivingVia - ( InstantiatedAt (..) - ) +module Data.DerivingVia ( + InstantiatedAt (..), +) where import Data.Kind (Constraint, Type) @@ -37,11 +37,15 @@ infix 0 `InstantiatedAt` newtype InstantiatedAt (c :: Type -> Constraint) a = InstantiatedAt a deriving newtype (Eq, Ord, Show) -instance (Generic a, GSemigroup (Rep a)) - => Semigroup (InstantiatedAt Generic a) where +instance + (Generic a, GSemigroup (Rep a)) => + Semigroup (InstantiatedAt Generic a) + where InstantiatedAt l <> InstantiatedAt r = InstantiatedAt $ to $ gsappend (from l) (from r) -instance (Generic a, GSemigroup (Rep a), GMonoid (Rep a)) - => Monoid (InstantiatedAt Generic a) where +instance + (Generic a, GSemigroup (Rep a), GMonoid (Rep a)) => + Monoid (InstantiatedAt Generic a) + where mempty = InstantiatedAt $ to gmempty diff --git a/base-deriving-via/src/Data/DerivingVia/GHC/Generics/Monoid.hs b/base-deriving-via/src/Data/DerivingVia/GHC/Generics/Monoid.hs index 6a1638bc7..eb7650819 100644 --- a/base-deriving-via/src/Data/DerivingVia/GHC/Generics/Monoid.hs +++ b/base-deriving-via/src/Data/DerivingVia/GHC/Generics/Monoid.hs @@ -1,15 +1,15 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS -Wno-unticked-promoted-constructors #-} -- | "GHC.Generics" definition of 'mempty' -module Data.DerivingVia.GHC.Generics.Monoid - ( GMonoid (..) - ) +module Data.DerivingVia.GHC.Generics.Monoid ( + GMonoid (..), +) where import GHC.Generics @@ -33,10 +33,13 @@ instance GMonoid U1 where instance (GMonoid l, GMonoid r) => GMonoid (l :*: r) where gmempty = gmempty :*: gmempty -instance TypeError ( Text "No Generics definition of " - :<>: ShowType Monoid - :<>: Text " for types with multiple constructors " - :<>: ShowType (l :+: r) - ) - => GMonoid (l :+: r) where +instance + TypeError + ( Text "No Generics definition of " + :<>: ShowType Monoid + :<>: Text " for types with multiple constructors " + :<>: ShowType (l :+: r) + ) => + GMonoid (l :+: r) + where gmempty = error "GMonoid :+:" diff --git a/base-deriving-via/src/Data/DerivingVia/GHC/Generics/Semigroup.hs b/base-deriving-via/src/Data/DerivingVia/GHC/Generics/Semigroup.hs index 01fa5a0c7..0d6cd4da8 100644 --- a/base-deriving-via/src/Data/DerivingVia/GHC/Generics/Semigroup.hs +++ b/base-deriving-via/src/Data/DerivingVia/GHC/Generics/Semigroup.hs @@ -1,17 +1,17 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE EmptyCase #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE EmptyCase #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS -Wno-unticked-promoted-constructors #-} -- | "GHC.Generics" definition of '<>' -module Data.DerivingVia.GHC.Generics.Semigroup - ( GSemigroup (..) - ) +module Data.DerivingVia.GHC.Generics.Semigroup ( + GSemigroup (..), +) where import GHC.Generics @@ -35,10 +35,13 @@ instance GSemigroup U1 where instance (GSemigroup l, GSemigroup r) => GSemigroup (l :*: r) where gsappend (l1 :*: r1) (l2 :*: r2) = gsappend l1 l2 :*: gsappend r1 r2 -instance TypeError ( Text "No Generics definition of " - :<>: ShowType Semigroup - :<>: Text " for types with multiple constructors " - :<>: ShowType (l :+: r) - ) - => GSemigroup (l :+: r) where +instance + TypeError + ( Text "No Generics definition of " + :<>: ShowType Semigroup + :<>: Text " for types with multiple constructors " + :<>: ShowType (l :+: r) + ) => + GSemigroup (l :+: r) + where gsappend = error "GSemigroup :+:" diff --git a/cardano-binary/src/Cardano/Binary.hs b/cardano-binary/src/Cardano/Binary.hs index 641dd06e3..2139eecd4 100644 --- a/cardano-binary/src/Cardano/Binary.hs +++ b/cardano-binary/src/Cardano/Binary.hs @@ -1,9 +1,9 @@ -module Cardano.Binary - ( module X - ) +module Cardano.Binary ( + module X, +) where import Cardano.Binary.Deserialize as X -import Cardano.Binary.ToCBOR as X -import Cardano.Binary.Serialize as X import Cardano.Binary.FromCBOR as X +import Cardano.Binary.Serialize as X +import Cardano.Binary.ToCBOR as X diff --git a/cardano-binary/src/Cardano/Binary/Deserialize.hs b/cardano-binary/src/Cardano/Binary/Deserialize.hs index c0b132bbd..3ce729478 100644 --- a/cardano-binary/src/Cardano/Binary/Deserialize.hs +++ b/cardano-binary/src/Cardano/Binary/Deserialize.hs @@ -1,30 +1,28 @@ -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} -- | Deserialization primitives built on top of the @FromCBOR@ typeclass - -module Cardano.Binary.Deserialize - ( +module Cardano.Binary.Deserialize ( -- * Unsafe deserialization - unsafeDeserialize - , unsafeDeserialize' - , CBOR.Write.toStrictByteString + unsafeDeserialize, + unsafeDeserialize', + CBOR.Write.toStrictByteString, -- * Decoding - , decodeFull - , decodeFull' - , decodeFullDecoder - , decodeFullDecoder' + decodeFull, + decodeFull', + decodeFullDecoder, + decodeFullDecoder', -- * CBOR in CBOR - , decodeNestedCbor - , decodeNestedCborBytes - ) + decodeNestedCbor, + decodeNestedCborBytes, +) where import qualified Codec.CBOR.Decoding as D @@ -37,11 +35,10 @@ import Data.Bifunctor (bimap) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Lazy.Internal as BSL -import Data.Proxy (Proxy(Proxy)) +import Data.Proxy (Proxy (Proxy)) import Data.Text (Text) -import Cardano.Binary.FromCBOR (DecoderError(..), FromCBOR(..), cborError, toCborError) - +import Cardano.Binary.FromCBOR (DecoderError (..), FromCBOR (..), cborError, toCborError) -- | Deserialize a Haskell value from the external binary representation -- (which must have been made using 'serialize' or related function). @@ -61,58 +58,58 @@ unsafeDeserialize' = unsafeDeserialize . BSL.fromStrict -- failing if there are leftovers. In a nutshell, the `full` here implies -- the contract of this function is that what you feed as input needs to -- be consumed entirely. -decodeFull :: forall a . FromCBOR a => BSL.ByteString -> Either DecoderError a +decodeFull :: forall a. FromCBOR a => BSL.ByteString -> Either DecoderError a decodeFull = decodeFullDecoder (label $ Proxy @a) fromCBOR -decodeFull' :: forall a . FromCBOR a => BS.ByteString -> Either DecoderError a +decodeFull' :: forall a. FromCBOR a => BS.ByteString -> Either DecoderError a decodeFull' = decodeFull . BSL.fromStrict -decodeFullDecoder - :: Text - -- ^ Label for error reporting - -> (forall s . D.Decoder s a) - -- ^ The parser for the @ByteString@ to decode. It should decode the given +decodeFullDecoder :: + -- | Label for error reporting + Text -> + -- | The parser for the @ByteString@ to decode. It should decode the given -- @ByteString@ into a value of type @a@ - -> BSL.ByteString - -- ^ The @ByteString@ to decode - -> Either DecoderError a + (forall s. D.Decoder s a) -> + -- | The @ByteString@ to decode + BSL.ByteString -> + Either DecoderError a decodeFullDecoder lbl decoder bs0 = case deserialiseDecoder decoder bs0 of - Right (x, leftover) -> if BS.null leftover - then pure x - else Left $ DecoderErrorLeftover lbl leftover + Right (x, leftover) -> + if BS.null leftover + then pure x + else Left $ DecoderErrorLeftover lbl leftover Left (e, _) -> Left $ DecoderErrorDeserialiseFailure lbl e -decodeFullDecoder' - :: Text - -- ^ Label for error reporting - -> (forall s . D.Decoder s a) - -- ^ The parser for the @ByteString@ to decode. It should decode the given +decodeFullDecoder' :: + -- | Label for error reporting + Text -> + -- | The parser for the @ByteString@ to decode. It should decode the given -- @ByteString@ into a value of type @a@ - -> BS.ByteString - -- ^ The @ByteString@ to decode - -> Either DecoderError a + (forall s. D.Decoder s a) -> + -- | The @ByteString@ to decode + BS.ByteString -> + Either DecoderError a decodeFullDecoder' lbl decoder = decodeFullDecoder lbl decoder . BSL.fromStrict -- | Deserialise a 'LByteString' incrementally using the provided 'Decoder' -deserialiseDecoder - :: (forall s . D.Decoder s a) - -> BSL.ByteString - -> Either (Read.DeserialiseFailure, BS.ByteString) (a, BS.ByteString) +deserialiseDecoder :: + (forall s. D.Decoder s a) -> + BSL.ByteString -> + Either (Read.DeserialiseFailure, BS.ByteString) (a, BS.ByteString) deserialiseDecoder decoder bs0 = runST (supplyAllInput bs0 =<< Read.deserialiseIncremental decoder) -supplyAllInput - :: BSL.ByteString - -> Read.IDecode s a - -> ST s (Either (Read.DeserialiseFailure, BS.ByteString) (a, BS.ByteString)) +supplyAllInput :: + BSL.ByteString -> + Read.IDecode s a -> + ST s (Either (Read.DeserialiseFailure, BS.ByteString) (a, BS.ByteString)) supplyAllInput bs' (Read.Done bs _ x) = return (Right (x, bs <> BSL.toStrict bs')) supplyAllInput bs (Read.Partial k) = case bs of BSL.Chunk chunk bs' -> k (Just chunk) >>= supplyAllInput bs' - BSL.Empty -> k Nothing >>= supplyAllInput BSL.Empty + BSL.Empty -> k Nothing >>= supplyAllInput BSL.Empty supplyAllInput _ (Read.Fail bs _ exn) = return (Left (exn, bs)) - -------------------------------------------------------------------------------- -- Nested CBOR-in-CBOR -- https://tools.ietf.org/html/rfc7049#section-2.4.4.1 @@ -123,9 +120,11 @@ supplyAllInput _ (Read.Fail bs _ exn) = return (Left (exn, bs)) decodeNestedCborTag :: D.Decoder s () decodeNestedCborTag = do t <- D.decodeTag - when (t /= 24) $ cborError $ DecoderErrorUnknownTag - "decodeNestedCborTag" - (fromIntegral t) + when (t /= 24) $ + cborError $ + DecoderErrorUnknownTag + "decodeNestedCborTag" + (fromIntegral t) -- | Remove the the semantic tag 24 from the enclosed CBOR data item, -- decoding back the inner `ByteString` as a proper Haskell type. diff --git a/cardano-binary/src/Cardano/Binary/FromCBOR.hs b/cardano-binary/src/Cardano/Binary/FromCBOR.hs index e6ac5c951..3a4f6bbc2 100644 --- a/cardano-binary/src/Cardano/Binary/FromCBOR.hs +++ b/cardano-binary/src/Cardano/Binary/FromCBOR.hs @@ -1,48 +1,49 @@ -{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE BangPatterns #-} {-# LANGUAGE ExistentialQuantification #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE NumDecimals #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RankNTypes #-} - -module Cardano.Binary.FromCBOR - ( FromCBOR(..) - , DecoderError(..) - , enforceSize - , matchSize - , module D - , decodeMaybe - , fromCBORMaybe - , decodeNullMaybe - , decodeSeq - , decodeListWith - , decodeNominalDiffTime - , decodeNominalDiffTimeMicro - -- * Helper tools to build instances - , decodeMapSkel - , decodeCollection - , decodeCollectionWithLen - , cborError - , toCborError - ) +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NumDecimals #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} + +module Cardano.Binary.FromCBOR ( + FromCBOR (..), + DecoderError (..), + enforceSize, + matchSize, + module D, + decodeMaybe, + fromCBORMaybe, + decodeNullMaybe, + decodeSeq, + decodeListWith, + decodeNominalDiffTime, + decodeNominalDiffTimeMicro, + + -- * Helper tools to build instances + decodeMapSkel, + decodeCollection, + decodeCollectionWithLen, + cborError, + toCborError, +) where import Prelude hiding ((.)) +import Codec.CBOR.ByteArray as BA (ByteArray (BA)) import Codec.CBOR.Decoding as D -import Codec.CBOR.ByteArray as BA ( ByteArray(BA) ) -import Codec.CBOR.Term import Codec.CBOR.FlatTerm -import Control.Category (Category((.))) -import Control.Exception (Exception) -import Control.Monad (when, replicateM) import qualified Codec.CBOR.Read as CBOR.Read +import Codec.CBOR.Term +import Control.Category (Category ((.))) +import Control.Exception (Exception) +import Control.Monad (replicateM, when) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Short as SBS import Data.ByteString.Short.Internal (ShortByteString (SBS)) -import Data.Fixed (Fixed(..)) +import Data.Fixed (Fixed (..)) import Data.Int (Int32, Int64) import Data.List.NonEmpty (NonEmpty, nonEmpty) import qualified Data.Map as M @@ -50,26 +51,35 @@ import qualified Data.Primitive.ByteArray as Prim import Data.Ratio ((%)) import qualified Data.Sequence as Seq import qualified Data.Set as S -import Data.Tagged (Tagged(..)) +import Data.Tagged (Tagged (..)) import Data.Text (Text) -import qualified Data.Text as T -import Data.Time.Calendar.OrdinalDate ( fromOrdinalDate ) -import Data.Time.Clock (NominalDiffTime, UTCTime(..), secondsToNominalDiffTime, picosecondsToDiffTime) -import Data.Typeable ( Typeable, typeRep, Proxy ) +import qualified Data.Text as T +import Data.Time.Calendar.OrdinalDate (fromOrdinalDate) +import Data.Time.Clock ( + NominalDiffTime, + UTCTime (..), + picosecondsToDiffTime, + secondsToNominalDiffTime, + ) +import Data.Typeable (Proxy, Typeable, typeRep) import qualified Data.Vector as Vector import qualified Data.Vector.Generic as Vector.Generic import Data.Void (Void) -import Data.Word ( Word8, Word16, Word32, Word64 ) -import Formatting - ( bprint, int, shown, stext, build, formatToString ) -import qualified Formatting.Buildable as B (Buildable(..)) +import Data.Word (Word16, Word32, Word64, Word8) +import Formatting ( + bprint, + build, + formatToString, + int, + shown, + stext, + ) +import qualified Formatting.Buildable as B (Buildable (..)) import Numeric.Natural (Natural) - {- HLINT ignore "Reduce duplication" -} {- HLINT ignore "Redundant <$>" -} - class Typeable a => FromCBOR a where fromCBOR :: D.Decoder s a @@ -82,20 +92,19 @@ instance FromCBOR Term where instance FromCBOR TermToken where fromCBOR = decodeTermToken - -------------------------------------------------------------------------------- -- DecoderError -------------------------------------------------------------------------------- data DecoderError = DecoderErrorCanonicityViolation Text - | DecoderErrorCustom Text Text - -- ^ Custom decoding error, usually due to some validation failure + | -- | Custom decoding error, usually due to some validation failure + DecoderErrorCustom Text Text | DecoderErrorDeserialiseFailure Text CBOR.Read.DeserialiseFailure | DecoderErrorEmptyList Text | DecoderErrorLeftover Text BS.ByteString - | DecoderErrorSizeMismatch Text Int Int - -- ^ A size mismatch @DecoderErrorSizeMismatch label expectedSize actualSize@ + | -- | A size mismatch @DecoderErrorSizeMismatch label expectedSize actualSize@ + DecoderErrorSizeMismatch Text Int Int | DecoderErrorUnknownTag Text Word8 | DecoderErrorVoid deriving (Eq, Show) @@ -106,44 +115,56 @@ instance B.Buildable DecoderError where build = \case DecoderErrorCanonicityViolation lbl -> bprint ("Canonicity violation while decoding " . stext) lbl - - DecoderErrorCustom lbl err -> bprint - ("An error occured while decoding " . stext . ".\n" - . "Error: " . stext) - lbl - err - - DecoderErrorDeserialiseFailure lbl failure -> bprint - ( "Deserialisation failure while decoding " . stext . ".\n" - . "CBOR failed with error: " . shown - ) - lbl - failure - + DecoderErrorCustom lbl err -> + bprint + ( "An error occured while decoding " + . stext + . ".\n" + . "Error: " + . stext + ) + lbl + err + DecoderErrorDeserialiseFailure lbl failure -> + bprint + ( "Deserialisation failure while decoding " + . stext + . ".\n" + . "CBOR failed with error: " + . shown + ) + lbl + failure DecoderErrorEmptyList lbl -> bprint ("Found unexpected empty list while decoding " . stext) lbl - - DecoderErrorLeftover lbl leftover -> bprint - ( "Found unexpected leftover bytes while decoding " . stext . "./n" - . "Leftover: " . shown - ) - lbl - leftover - - DecoderErrorSizeMismatch lbl requested actual -> bprint - ( "Size mismatch when decoding " . stext . ".\n" - . "Expected " . int . ", but found " . int . "." - ) - lbl - requested - actual - + DecoderErrorLeftover lbl leftover -> + bprint + ( "Found unexpected leftover bytes while decoding " + . stext + . "./n" + . "Leftover: " + . shown + ) + lbl + leftover + DecoderErrorSizeMismatch lbl requested actual -> + bprint + ( "Size mismatch when decoding " + . stext + . ".\n" + . "Expected " + . int + . ", but found " + . int + . "." + ) + lbl + requested + actual DecoderErrorUnknownTag lbl t -> bprint ("Found unknown tag " . int . " while decoding " . stext) t lbl - DecoderErrorVoid -> bprint "Attempted to decode Void" - -------------------------------------------------------------------------------- -- Useful primitives -------------------------------------------------------------------------------- @@ -156,10 +177,12 @@ enforceSize lbl requestedSize = D.decodeListLen >>= matchSize lbl requestedSize -- | Compare two sizes, failing if they are not equal matchSize :: Text -> Int -> Int -> D.Decoder s () matchSize lbl requestedSize actualSize = - when (actualSize /= requestedSize) $ cborError $ DecoderErrorSizeMismatch - lbl - requestedSize - actualSize + when (actualSize /= requestedSize) $ + cborError $ + DecoderErrorSizeMismatch + lbl + requestedSize + actualSize -- | @'D.Decoder'@ for list. decodeListWith :: D.Decoder s a -> D.Decoder s [a] @@ -167,7 +190,6 @@ decodeListWith d = do D.decodeListLenIndef D.decodeSequenceLenIndef (flip (:)) [] reverse d - -------------------------------------------------------------------------------- -- Primitive types -------------------------------------------------------------------------------- @@ -178,7 +200,6 @@ instance FromCBOR () where instance FromCBOR Bool where fromCBOR = D.decodeBool - -------------------------------------------------------------------------------- -- Numeric data -------------------------------------------------------------------------------- @@ -237,15 +258,14 @@ decodeNominalDiffTimeMicro = fromRational . (% 1e6) <$> fromCBOR instance FromCBOR Natural where fromCBOR = do - !n <- fromCBOR - if n >= 0 - then return $! fromInteger n - else cborError $ DecoderErrorCustom "Natural" "got a negative number" + !n <- fromCBOR + if n >= 0 + then return $! fromInteger n + else cborError $ DecoderErrorCustom "Natural" "got a negative number" instance FromCBOR Void where fromCBOR = cborError DecoderErrorVoid - -------------------------------------------------------------------------------- -- Tagged -------------------------------------------------------------------------------- @@ -253,20 +273,18 @@ instance FromCBOR Void where instance (Typeable s, FromCBOR a) => FromCBOR (Tagged s a) where fromCBOR = Tagged <$> fromCBOR - -------------------------------------------------------------------------------- -- Containers -------------------------------------------------------------------------------- -instance (FromCBOR a, FromCBOR b) => FromCBOR (a,b) where +instance (FromCBOR a, FromCBOR b) => FromCBOR (a, b) where fromCBOR = do D.decodeListLenOf 2 !x <- fromCBOR !y <- fromCBOR return (x, y) -instance (FromCBOR a, FromCBOR b, FromCBOR c) => FromCBOR (a,b,c) where - +instance (FromCBOR a, FromCBOR b, FromCBOR c) => FromCBOR (a, b, c) where fromCBOR = do D.decodeListLenOf 3 !x <- fromCBOR @@ -274,7 +292,7 @@ instance (FromCBOR a, FromCBOR b, FromCBOR c) => FromCBOR (a,b,c) where !z <- fromCBOR return (x, y, z) -instance (FromCBOR a, FromCBOR b, FromCBOR c, FromCBOR d) => FromCBOR (a,b,c,d) where +instance (FromCBOR a, FromCBOR b, FromCBOR c, FromCBOR d) => FromCBOR (a, b, c, d) where fromCBOR = do D.decodeListLenOf 4 !a <- fromCBOR @@ -284,9 +302,9 @@ instance (FromCBOR a, FromCBOR b, FromCBOR c, FromCBOR d) => FromCBOR (a,b,c,d) return (a, b, c, d) instance - (FromCBOR a, FromCBOR b, FromCBOR c, FromCBOR d, FromCBOR e) - => FromCBOR (a, b, c, d, e) - where + (FromCBOR a, FromCBOR b, FromCBOR c, FromCBOR d, FromCBOR e) => + FromCBOR (a, b, c, d, e) + where fromCBOR = do D.decodeListLenOf 5 !a <- fromCBOR @@ -297,9 +315,9 @@ instance return (a, b, c, d, e) instance - (FromCBOR a, FromCBOR b, FromCBOR c, FromCBOR d, FromCBOR e, FromCBOR f) - => FromCBOR (a, b, c, d, e, f) - where + (FromCBOR a, FromCBOR b, FromCBOR c, FromCBOR d, FromCBOR e, FromCBOR f) => + FromCBOR (a, b, c, d, e, f) + where fromCBOR = do D.decodeListLenOf 6 !a <- fromCBOR @@ -318,8 +336,8 @@ instance , FromCBOR e , FromCBOR f , FromCBOR g - ) - => FromCBOR (a, b, c, d, e, f, g) + ) => + FromCBOR (a, b, c, d, e, f, g) where fromCBOR = do D.decodeListLenOf 7 @@ -341,8 +359,8 @@ instance , FromCBOR f , FromCBOR g , FromCBOR h - ) - => FromCBOR (a, b, c, d, e, f, g, h) + ) => + FromCBOR (a, b, c, d, e, f, g, h) where fromCBOR = do D.decodeListLenOf 8 @@ -387,10 +405,11 @@ instance (FromCBOR a, FromCBOR b) => FromCBOR (Either a b) where _ -> cborError $ DecoderErrorUnknownTag "Either" (fromIntegral t) instance FromCBOR a => FromCBOR (NonEmpty a) where - fromCBOR = nonEmpty <$> fromCBOR >>= toCborError . \case - Nothing -> Left $ DecoderErrorEmptyList "NonEmpty" - Just xs -> Right xs - + fromCBOR = + nonEmpty <$> fromCBOR + >>= toCborError . \case + Nothing -> Left $ DecoderErrorEmptyList "NonEmpty" + Just xs -> Right xs instance FromCBOR a => FromCBOR (Maybe a) where fromCBOR = decodeMaybe fromCBOR @@ -417,16 +436,15 @@ decodeNullMaybe decoder = do pure Nothing _ -> Just <$> decoder - -decodeContainerSkelWithReplicate - :: FromCBOR a - => D.Decoder s Int - -- ^ How to get the size of the container - -> (Int -> D.Decoder s a -> D.Decoder s container) - -- ^ replicateM for the container - -> ([container] -> container) - -- ^ concat for the container - -> D.Decoder s container +decodeContainerSkelWithReplicate :: + FromCBOR a => + -- | How to get the size of the container + D.Decoder s Int -> + -- | replicateM for the container + (Int -> D.Decoder s a -> D.Decoder s container) -> + -- | concat for the container + ([container] -> container) -> + D.Decoder s container decodeContainerSkelWithReplicate decodeLen replicateFun fromList = do -- Look at how much data we have at the moment and use it as the limit for -- the size of a single call to replicateFun. We don't want to use @@ -434,17 +452,17 @@ decodeContainerSkelWithReplicate decodeLen replicateFun fromList = do -- DOS attack (attacker providing a huge value for length). So if it's above -- our limit, we'll do manual chunking and then combine the containers into -- one. - size <- decodeLen + size <- decodeLen limit <- D.peekAvailable if size <= limit then replicateFun size fromCBOR else do - -- Take the max of limit and a fixed chunk size (note: limit can be - -- 0). This basically means that the attacker can make us allocate a - -- container of size 128 even though there's no actual input. + -- Take the max of limit and a fixed chunk size (note: limit can be + -- 0). This basically means that the attacker can make us allocate a + -- container of size 128 even though there's no actual input. let chunkSize = max limit 128 - (d, m) = size `divMod` chunkSize + (d, m) = size `divMod` chunkSize buildOne s = replicateFun s fromCBOR containers <- sequence $ buildOne m : replicate d (buildOne chunkSize) return $! fromList containers @@ -454,8 +472,8 @@ decodeContainerSkelWithReplicate decodeLen replicateFun fromList = do -- the previous one, to enfore these are sorted the correct way. -- See: https://tools.ietf.org/html/rfc7049#section-3.9 -- "[..]The keys in every map must be sorted lowest value to highest.[...]" -decodeMapSkel - :: (Ord k, FromCBOR k, FromCBOR v) => ([(k, v)] -> m) -> D.Decoder s m +decodeMapSkel :: + (Ord k, FromCBOR k, FromCBOR v) => ([(k, v)] -> m) -> D.Decoder s m decodeMapSkel fromDistinctAscList = do n <- D.decodeMapLen case n of @@ -464,32 +482,32 @@ decodeMapSkel fromDistinctAscList = do (firstKey, firstValue) <- decodeEntry fromDistinctAscList <$> decodeEntries (n - 1) firstKey [(firstKey, firstValue)] - where + where -- Decode a single (k,v). - decodeEntry :: (FromCBOR k, FromCBOR v) => D.Decoder s (k, v) - decodeEntry = do - !k <- fromCBOR - !v <- fromCBOR - return (k, v) - - -- Decode all the entries, enforcing canonicity by ensuring that the - -- previous key is smaller than the next one. - decodeEntries - :: (FromCBOR k, FromCBOR v, Ord k) - => Int - -> k - -> [(k, v)] - -> D.Decoder s [(k, v)] - decodeEntries 0 _ acc = pure $ reverse acc - decodeEntries !remainingPairs previousKey !acc = do - p@(newKey, _) <- decodeEntry - -- Order of keys needs to be strictly increasing, because otherwise it's - -- possible to supply lists with various amount of duplicate keys which - -- will result in the same map as long as the last value of the given - -- key on the list is the same in all of them. - if newKey > previousKey - then decodeEntries (remainingPairs - 1) newKey (p : acc) - else cborError $ DecoderErrorCanonicityViolation "Map" + decodeEntry :: (FromCBOR k, FromCBOR v) => D.Decoder s (k, v) + decodeEntry = do + !k <- fromCBOR + !v <- fromCBOR + return (k, v) + + -- Decode all the entries, enforcing canonicity by ensuring that the + -- previous key is smaller than the next one. + decodeEntries :: + (FromCBOR k, FromCBOR v, Ord k) => + Int -> + k -> + [(k, v)] -> + D.Decoder s [(k, v)] + decodeEntries 0 _ acc = pure $ reverse acc + decodeEntries !remainingPairs previousKey !acc = do + p@(newKey, _) <- decodeEntry + -- Order of keys needs to be strictly increasing, because otherwise it's + -- possible to supply lists with various amount of duplicate keys which + -- will result in the same map as long as the last value of the given + -- key on the list is the same in all of them. + if newKey > previousKey + then decodeEntries (remainingPairs - 1) newKey (p : acc) + else cborError $ DecoderErrorCanonicityViolation "Map" {-# INLINE decodeMapSkel #-} instance (Ord k, FromCBOR k, FromCBOR v) => FromCBOR (M.Map k v) where @@ -519,17 +537,17 @@ decodeSetSkel fromDistinctAscList = do _ -> do firstValue <- fromCBOR fromDistinctAscList <$> decodeEntries (n - 1) firstValue [firstValue] - where - decodeEntries :: (FromCBOR v, Ord v) => Int -> v -> [v] -> D.Decoder s [v] - decodeEntries 0 _ acc = pure $ reverse acc - decodeEntries !remainingEntries previousValue !acc = do - newValue <- fromCBOR - -- Order of values needs to be strictly increasing, because otherwise - -- it's possible to supply lists with various amount of duplicates which - -- will result in the same set. - if newValue > previousValue - then decodeEntries (remainingEntries - 1) newValue (newValue : acc) - else cborError $ DecoderErrorCanonicityViolation "Set" + where + decodeEntries :: (FromCBOR v, Ord v) => Int -> v -> [v] -> D.Decoder s [v] + decodeEntries 0 _ acc = pure $ reverse acc + decodeEntries !remainingEntries previousValue !acc = do + newValue <- fromCBOR + -- Order of values needs to be strictly increasing, because otherwise + -- it's possible to supply lists with various amount of duplicates which + -- will result in the same set. + if newValue > previousValue + then decodeEntries (remainingEntries - 1) newValue (newValue : acc) + else cborError $ DecoderErrorCanonicityViolation "Set" {-# INLINE decodeSetSkel #-} instance (Ord a, FromCBOR a) => FromCBOR (S.Set a) where @@ -538,10 +556,11 @@ instance (Ord a, FromCBOR a) => FromCBOR (S.Set a) where -- | Generic decoder for vectors. Its intended use is to allow easy -- definition of 'Serialise' instances for custom vector decodeVector :: (FromCBOR a, Vector.Generic.Vector v a) => D.Decoder s (v a) -decodeVector = decodeContainerSkelWithReplicate - D.decodeListLen - Vector.Generic.replicateM - Vector.Generic.concat +decodeVector = + decodeContainerSkelWithReplicate + D.decodeListLen + Vector.Generic.replicateM + Vector.Generic.concat {-# INLINE decodeVector #-} instance FromCBOR a => FromCBOR (Vector.Vector a) where @@ -582,9 +601,10 @@ instance FromCBOR UTCTime where year <- decodeInteger dayOfYear <- decodeInt timeOfDayPico <- decodeInteger - return $ UTCTime - (fromOrdinalDate year dayOfYear) - (picosecondsToDiffTime timeOfDayPico) + return $ + UTCTime + (fromOrdinalDate year dayOfYear) + (picosecondsToDiffTime timeOfDayPico) -- | Convert an 'Either'-encoded failure to a 'MonadFail' failure using the `B.Buildable` -- insatance diff --git a/cardano-binary/src/Cardano/Binary/Serialize.hs b/cardano-binary/src/Cardano/Binary/Serialize.hs index 8901bb45e..71bf939de 100644 --- a/cardano-binary/src/Cardano/Binary/Serialize.hs +++ b/cardano-binary/src/Cardano/Binary/Serialize.hs @@ -1,25 +1,24 @@ -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} -- | Serialization primitives built on top of the @ToCBOR@ typeclass - -module Cardano.Binary.Serialize - ( serialize - , serialize' - , serializeBuilder - , serializeEncoding - , serializeEncoding' +module Cardano.Binary.Serialize ( + serialize, + serialize', + serializeBuilder, + serializeEncoding, + serializeEncoding', -- * CBOR in CBOR - , encodeNestedCbor - , encodeNestedCborBytes - , nestedCborSizeExpr - , nestedCborBytesSizeExpr - ) + encodeNestedCbor, + encodeNestedCborBytes, + nestedCborSizeExpr, + nestedCborBytesSizeExpr, +) where import Prelude hiding ((.)) @@ -31,9 +30,14 @@ import Data.ByteString.Builder (Builder) import qualified Data.ByteString.Builder.Extra as Builder import qualified Data.ByteString.Lazy as BSL -import Cardano.Binary.ToCBOR - (Encoding, Size, ToCBOR(..), apMono, encodeTag, withWordSize) - +import Cardano.Binary.ToCBOR ( + Encoding, + Size, + ToCBOR (..), + apMono, + encodeTag, + withWordSize, + ) -- | Serialize a Haskell value with a 'ToCBOR' instance to an external binary -- representation. @@ -47,7 +51,7 @@ serialize = -- 1024 is the size of the first buffer, 4096 is the size of subsequent -- buffers. Chosen because they seem to give good performance. They are not -- sacred. - strategy = Builder.safeStrategy 1024 4096 + strategy = Builder.safeStrategy 1024 4096 -- | Serialize a Haskell value to an external binary representation. -- @@ -74,7 +78,6 @@ serializeEncoding' :: Encoding -> BS.ByteString serializeEncoding' = serialize' {-# DEPRECATED serializeEncoding' "Use `serialize'` instead, since `Encoding` has `ToCBOR` instance" #-} - -------------------------------------------------------------------------------- -- Nested CBOR-in-CBOR -- https://tools.ietf.org/html/rfc7049#section-2.4.4.1 @@ -98,4 +101,3 @@ nestedCborSizeExpr x = 2 + apMono "withWordSize" withWordSize x + x nestedCborBytesSizeExpr :: Size -> Size nestedCborBytesSizeExpr x = 2 + apMono "withWordSize" withWordSize x + x - diff --git a/cardano-binary/src/Cardano/Binary/ToCBOR.hs b/cardano-binary/src/Cardano/Binary/ToCBOR.hs index 93c50e852..100de3b38 100644 --- a/cardano-binary/src/Cardano/Binary/ToCBOR.hs +++ b/cardano-binary/src/Cardano/Binary/ToCBOR.hs @@ -1,85 +1,91 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE ConstrainedClassMethods #-} -{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE CPP #-} +{-# LANGUAGE ConstrainedClassMethods #-} +{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE ExistentialQuantification #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE MultiWayIf #-} -{-# LANGUAGE NumDecimals #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE Rank2Types #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} - -module Cardano.Binary.ToCBOR - ( ToCBOR(..) - , withWordSize - , module E - , encodeMaybe - , toCBORMaybe - , encodeNullMaybe - , encodeSeq - , encodeNominalDiffTime - , encodeNominalDiffTimeMicro - -- * Size of expressions - , Range(..) - , szEval - , Size - , Case(..) - , caseValue - , LengthOf(..) - , SizeOverride(..) - , isTodo - , szCases - , szLazy - , szGreedy - , szForce - , szWithCtx - , szSimplify - , apMono - , szBounds - ) +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiWayIf #-} +{-# LANGUAGE NumDecimals #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE Rank2Types #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} + +module Cardano.Binary.ToCBOR ( + ToCBOR (..), + withWordSize, + module E, + encodeMaybe, + toCBORMaybe, + encodeNullMaybe, + encodeSeq, + encodeNominalDiffTime, + encodeNominalDiffTimeMicro, + + -- * Size of expressions + Range (..), + szEval, + Size, + Case (..), + caseValue, + LengthOf (..), + SizeOverride (..), + isTodo, + szCases, + szLazy, + szGreedy, + szForce, + szWithCtx, + szSimplify, + apMono, + szBounds, +) where import Prelude hiding ((.)) -import Codec.CBOR.Encoding as E import Codec.CBOR.ByteArray.Sliced as BAS +import Codec.CBOR.Encoding as E import Codec.CBOR.Term -import Control.Category (Category((.))) +import Control.Category (Category ((.))) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BS.Lazy import qualified Data.ByteString.Short as SBS import Data.ByteString.Short.Internal (ShortByteString (SBS)) +import Data.Fixed (Fixed (..), Micro) import qualified Data.Primitive.ByteArray as Prim import qualified Data.Sequence as Seq -import Data.Fixed (Fixed(..), Micro) #if MIN_VERSION_recursion_schemes(5,2,0) import Data.Fix ( Fix(..) ) #else import Data.Functor.Foldable (Fix(..)) #endif +import Data.Foldable (foldMap', toList) import Data.Functor.Foldable (cata, project) -import Data.Foldable (toList, foldMap') import Data.Int (Int32, Int64) import Data.List.NonEmpty (NonEmpty) import qualified Data.Map as M -import Data.Ratio ( Ratio, denominator, numerator ) +import Data.Ratio (Ratio, denominator, numerator) import qualified Data.Set as S -import Data.Tagged (Tagged(..)) -import qualified Data.Text as Text +import Data.Tagged (Tagged (..)) import Data.Text (Text) +import qualified Data.Text as Text import Data.Text.Lazy.Builder (Builder) -import Data.Time.Calendar.OrdinalDate ( toOrdinalDate ) -import Data.Time.Clock (NominalDiffTime, nominalDiffTimeToSeconds, diffTimeToPicoseconds, UTCTime(..)) -import Data.Typeable ( Typeable, typeRep, TypeRep, Proxy(..) ) +import Data.Time.Calendar.OrdinalDate (toOrdinalDate) +import Data.Time.Clock ( + NominalDiffTime, + UTCTime (..), + diffTimeToPicoseconds, + nominalDiffTimeToSeconds, + ) +import Data.Typeable (Proxy (..), TypeRep, Typeable, typeRep) import qualified Data.Vector as Vector import qualified Data.Vector.Generic as Vector.Generic import Data.Void (Void, absurd) -import Data.Word ( Word8, Word16, Word32, Word64 ) +import Data.Word (Word16, Word32, Word64, Word8) import Foreign.Storable (sizeOf) import Formatting (bprint, build, shown, stext) -import qualified Formatting.Buildable as B (Buildable(..)) +import qualified Formatting.Buildable as B (Buildable (..)) import Numeric.Natural (Natural) class Typeable a => ToCBOR a where @@ -98,16 +104,15 @@ instance Typeable xs => ToCBOR (LengthOf xs) where toCBOR = error "The `LengthOf` type cannot be encoded!" -- | Default size expression for a list type. -defaultEncodedListSizeExpr - :: forall a - . ToCBOR a - => (forall t . ToCBOR t => Proxy t -> Size) - -> Proxy [a] - -> Size +defaultEncodedListSizeExpr :: + forall a. + ToCBOR a => + (forall t. ToCBOR t => Proxy t -> Size) -> + Proxy [a] -> + Size defaultEncodedListSizeExpr size _ = 2 + size (Proxy @(LengthOf [a])) * size (Proxy @a) - -------------------------------------------------------------------------------- -- Size expressions -------------------------------------------------------------------------------- @@ -121,42 +126,42 @@ type Size = Fix SizeF -- | The base functor for @Size@ expressions. data SizeF t - = AddF t t - -- ^ Sum of two sizes. - | MulF t t - -- ^ Product of two sizes. - | SubF t t - -- ^ Difference of two sizes. - | AbsF t - -- ^ Absolute value of a size. - | NegF t - -- ^ Negation of a size. - | SgnF t - -- ^ Signum of a size. - | CasesF [Case t] - -- ^ Case-selection for sizes. Used for sum types. - | ValueF Natural - -- ^ A constant value. - | ApF Text (Natural -> Natural) t - -- ^ Application of a monotonic function to a size. - | forall a. ToCBOR a => TodoF (forall x. ToCBOR x => Proxy x -> Size) (Proxy a) - -- ^ A suspended size calculation ("thunk"). This is used to delay the - -- computation of a size until some later point, which is useful for - -- progressively building more detailed size estimates for a type - -- from the outside in. For example, `szLazy` can be followed by - -- applications of `szForce` to reveal more detailed expressions - -- describing the size bounds on a type. + = -- | Sum of two sizes. + AddF t t + | -- | Product of two sizes. + MulF t t + | -- | Difference of two sizes. + SubF t t + | -- | Absolute value of a size. + AbsF t + | -- | Negation of a size. + NegF t + | -- | Signum of a size. + SgnF t + | -- | Case-selection for sizes. Used for sum types. + CasesF [Case t] + | -- | A constant value. + ValueF Natural + | -- | Application of a monotonic function to a size. + ApF Text (Natural -> Natural) t + | -- | A suspended size calculation ("thunk"). This is used to delay the + -- computation of a size until some later point, which is useful for + -- progressively building more detailed size estimates for a type + -- from the outside in. For example, `szLazy` can be followed by + -- applications of `szForce` to reveal more detailed expressions + -- describing the size bounds on a type. + forall a. ToCBOR a => TodoF (forall x. ToCBOR x => Proxy x -> Size) (Proxy a) instance Functor SizeF where fmap f = \case - AddF x y -> AddF (f x) (f y) - MulF x y -> MulF (f x) (f y) - SubF x y -> SubF (f x) (f y) - AbsF x -> AbsF (f x) - NegF x -> NegF (f x) - SgnF x -> SgnF (f x) + AddF x y -> AddF (f x) (f y) + MulF x y -> MulF (f x) (f y) + SubF x y -> SubF (f x) (f y) + AbsF x -> AbsF (f x) + NegF x -> NegF (f x) + SgnF x -> SgnF (f x) CasesF xs -> CasesF (map (fmap f) xs) - ValueF x -> ValueF x + ValueF x -> ValueF x ApF n g x -> ApF n g (f x) TodoF g x -> TodoF g x @@ -170,23 +175,23 @@ instance Num (Fix SizeF) where fromInteger = Fix . ValueF . fromInteger instance B.Buildable t => B.Buildable (SizeF t) where - build x_ - = let - showp2 :: (B.Buildable a, B.Buildable b) => a -> Text -> b -> Builder - showp2 = bprint ("(" . build . " " . stext . " " . build . ")") - in - case x_ of - AddF x y -> showp2 x "+" y - MulF x y -> showp2 x "*" y - SubF x y -> showp2 x "-" y - NegF x -> bprint ("-" . build) x - AbsF x -> bprint ("|" . build . "|") x - SgnF x -> bprint ("sgn(" . build . ")") x - CasesF xs -> - bprint ("{ " . build . "}") $ foldMap (bprint (build . " ")) xs - ValueF x -> bprint shown (toInteger x) - ApF n _ x -> bprint (stext . "(" . build . ")") n x - TodoF _ x -> bprint ("(_ :: " . shown . ")") (typeRep x) + build x_ = + let + showp2 :: (B.Buildable a, B.Buildable b) => a -> Text -> b -> Builder + showp2 = bprint ("(" . build . " " . stext . " " . build . ")") + in + case x_ of + AddF x y -> showp2 x "+" y + MulF x y -> showp2 x "*" y + SubF x y -> showp2 x "-" y + NegF x -> bprint ("-" . build) x + AbsF x -> bprint ("|" . build . "|") x + SgnF x -> bprint ("sgn(" . build . ")") x + CasesF xs -> + bprint ("{ " . build . "}") $ foldMap (bprint (build . " ")) xs + ValueF x -> bprint shown (toInteger x) + ApF n _ x -> bprint (stext . "(" . build . ")") n x + TodoF _ x -> bprint ("(_ :: " . shown . ")") (typeRep x) instance B.Buildable (Fix SizeF) where build x = bprint build (project @(Fix _) x) @@ -196,8 +201,8 @@ szCases :: [Case Size] -> Size szCases = Fix . CasesF -- | An individual labeled case. -data Case t = - Case Text t +data Case t + = Case Text t deriving (Functor) -- | Discard the label on a case. @@ -219,14 +224,15 @@ data Range b = Range instance (Ord b, Num b) => Num (Range b) where x + y = Range {lo = lo x + lo y, hi = hi x + hi y} x * y = - let products = [ u * v | u <- [lo x, hi x], v <- [lo y, hi y] ] - in Range {lo = minimum products, hi = maximum products} + let products = [u * v | u <- [lo x, hi x], v <- [lo y, hi y]] + in Range {lo = minimum products, hi = maximum products} x - y = Range {lo = lo x - hi y, hi = hi x - lo y} negate x = Range {lo = negate (hi x), hi = negate (lo x)} - abs x = if - | lo x <= 0 && hi x >= 0 -> Range {lo = 0, hi = max (hi x) (negate $ lo x)} - | lo x <= 0 && hi x <= 0 -> Range {lo = negate (hi x), hi = negate (lo x)} - | otherwise -> x + abs x = + if + | lo x <= 0 && hi x >= 0 -> Range {lo = 0, hi = max (hi x) (negate $ lo x)} + | lo x <= 0 && hi x <= 0 -> Range {lo = negate (hi x), hi = negate (lo x)} + | otherwise -> x signum x = Range {lo = signum (lo x), hi = signum (hi x)} fromInteger n = Range {lo = fromInteger n, hi = fromInteger n} @@ -236,57 +242,55 @@ instance B.Buildable (Range Natural) where -- | Fully evaluate a size expression by applying the given function to any -- suspended computations. @szEval g@ effectively turns each "thunk" -- of the form @TodoF f x@ into @g x@, then evaluates the result. -szEval - :: (forall t . ToCBOR t => (Proxy t -> Size) -> Proxy t -> Range Natural) - -> Size - -> Range Natural +szEval :: + (forall t. ToCBOR t => (Proxy t -> Size) -> Proxy t -> Range Natural) -> + Size -> + Range Natural szEval doit = cata $ \case - AddF x y -> x + y - MulF x y -> x * y - SubF x y -> x - y - NegF x -> negate x - AbsF x -> abs x - SgnF x -> signum x - CasesF xs -> Range - { lo = minimum (map (lo . caseValue) xs) - , hi = maximum (map (hi . caseValue) xs) - } - ValueF x -> Range {lo = x, hi = x} + AddF x y -> x + y + MulF x y -> x * y + SubF x y -> x - y + NegF x -> negate x + AbsF x -> abs x + SgnF x -> signum x + CasesF xs -> + Range + { lo = minimum (map (lo . caseValue) xs) + , hi = maximum (map (hi . caseValue) xs) + } + ValueF x -> Range {lo = x, hi = x} ApF _ f x -> Range {lo = f (lo x), hi = f (hi x)} TodoF f x -> doit f x -{-| Evaluate the expression lazily, by immediately creating a thunk - that will evaluate its contents lazily. - -> ghci> putStrLn $ pretty $ szLazy (Proxy @TxAux) -> (_ :: TxAux) --} +-- | Evaluate the expression lazily, by immediately creating a thunk +-- that will evaluate its contents lazily. +-- +-- > ghci> putStrLn $ pretty $ szLazy (Proxy @TxAux) +-- > (_ :: TxAux) szLazy :: ToCBOR a => (Proxy a -> Size) szLazy = todo (encodedSizeExpr szLazy) -{-| Evaluate an expression greedily. There may still be thunks in the - result, for types that did not provide a custom 'encodedSizeExpr' method - in their 'ToCBOR' instance. - -> ghci> putStrLn $ pretty $ szGreedy (Proxy @TxAux) -> (0 + { TxAux=(2 + ((0 + (((1 + (2 + ((_ :: LengthOf [TxIn]) * (2 + { TxInUtxo=(2 + ((1 + 34) + { minBound=1 maxBound=5 })) })))) + (2 + ((_ :: LengthOf [TxOut]) * (0 + { TxOut=(2 + ((0 + ((2 + ((2 + withWordSize((((1 + 30) + (_ :: Attributes AddrAttributes)) + 1))) + (((1 + 30) + (_ :: Attributes AddrAttributes)) + 1))) + { minBound=1 maxBound=5 })) + { minBound=1 maxBound=9 })) })))) + (_ :: Attributes ()))) + (_ :: Vector TxInWitness))) }) - --} +-- | Evaluate an expression greedily. There may still be thunks in the +-- result, for types that did not provide a custom 'encodedSizeExpr' method +-- in their 'ToCBOR' instance. +-- +-- > ghci> putStrLn $ pretty $ szGreedy (Proxy @TxAux) +-- > (0 + { TxAux=(2 + ((0 + (((1 + (2 + ((_ :: LengthOf [TxIn]) * (2 + { TxInUtxo=(2 + ((1 + 34) + { minBound=1 maxBound=5 })) })))) + (2 + ((_ :: LengthOf [TxOut]) * (0 + { TxOut=(2 + ((0 + ((2 + ((2 + withWordSize((((1 + 30) + (_ :: Attributes AddrAttributes)) + 1))) + (((1 + 30) + (_ :: Attributes AddrAttributes)) + 1))) + { minBound=1 maxBound=5 })) + { minBound=1 maxBound=9 })) })))) + (_ :: Attributes ()))) + (_ :: Vector TxInWitness))) }) szGreedy :: ToCBOR a => (Proxy a -> Size) szGreedy = encodedSizeExpr szGreedy -- | Is this expression a thunk? isTodo :: Size -> Bool isTodo (Fix (TodoF _ _)) = True -isTodo _ = False +isTodo _ = False -- | Create a "thunk" that will apply @f@ to @pxy@ when forced. -todo - :: forall a - . ToCBOR a - => (forall t . ToCBOR t => Proxy t -> Size) - -> Proxy a - -> Size +todo :: + forall a. + ToCBOR a => + (forall t. ToCBOR t => Proxy t -> Size) -> + Proxy a -> + Size todo f pxy = Fix (TodoF f pxy) -- | Apply a monotonically increasing function to the expression. @@ -296,86 +300,88 @@ todo f pxy = Fix (TodoF f pxy) -- * In all other cases, create a deferred application of @f@. apMono :: Text -> (Natural -> Natural) -> Size -> Size apMono n f = \case - Fix (ValueF x ) -> Fix (ValueF (f x)) + Fix (ValueF x) -> Fix (ValueF (f x)) Fix (CasesF cs) -> Fix (CasesF (map (fmap (apMono n f)) cs)) - x -> Fix (ApF n f x) + x -> Fix (ApF n f x) -- | Greedily compute the size bounds for a type, using the given context to -- override sizes for specific types. -szWithCtx :: (ToCBOR a) => M.Map TypeRep SizeOverride -> Proxy a -> Size +szWithCtx :: ToCBOR a => M.Map TypeRep SizeOverride -> Proxy a -> Size szWithCtx ctx pxy = case M.lookup (typeRep pxy) ctx of - Nothing -> normal + Nothing -> normal Just override -> case override of - SizeConstant sz -> sz - SizeExpression f -> f (szWithCtx ctx) - SelectCases names -> cata (selectCase names) normal - where - -- The non-override case - normal = encodedSizeExpr (szWithCtx ctx) pxy - - selectCase :: [Text] -> SizeF Size -> Size - selectCase names orig = case orig of - CasesF cs -> matchCase names cs (Fix orig) - _ -> Fix orig - - matchCase :: [Text] -> [Case Size] -> Size -> Size - matchCase names cs orig = - case filter (\(Case name _) -> name `elem` names) cs of - [] -> orig - [Case _ x] -> x - cs' -> Fix (CasesF cs') + SizeConstant sz -> sz + SizeExpression f -> f (szWithCtx ctx) + SelectCases names -> cata (selectCase names) normal + where + -- The non-override case + normal = encodedSizeExpr (szWithCtx ctx) pxy + + selectCase :: [Text] -> SizeF Size -> Size + selectCase names orig = case orig of + CasesF cs -> matchCase names cs (Fix orig) + _ -> Fix orig + + matchCase :: [Text] -> [Case Size] -> Size -> Size + matchCase names cs orig = + case filter (\(Case name _) -> name `elem` names) cs of + [] -> orig + [Case _ x] -> x + cs' -> Fix (CasesF cs') -- | Override mechanisms to be used with 'szWithCtx'. data SizeOverride - = SizeConstant Size - -- ^ Replace with a fixed @Size@. - | SizeExpression ((forall a. ToCBOR a => Proxy a -> Size) -> Size) - -- ^ Recursively compute the size. - | SelectCases [Text] - -- ^ Select only a specific case from a @CasesF@. + = -- | Replace with a fixed @Size@. + SizeConstant Size + | -- | Recursively compute the size. + SizeExpression ((forall a. ToCBOR a => Proxy a -> Size) -> Size) + | -- | Select only a specific case from a @CasesF@. + SelectCases [Text] -- | Simplify the given @Size@, resulting in either the simplified @Size@ or, -- if it was fully simplified, an explicit upper and lower bound. szSimplify :: Size -> Either Size (Range Natural) szSimplify = cata $ \case TodoF f pxy -> Left (todo f pxy) - ValueF x -> Right (Range {lo = x, hi = x}) - CasesF xs -> case mapM caseValue xs of + ValueF x -> Right (Range {lo = x, hi = x}) + CasesF xs -> case mapM caseValue xs of Right xs' -> Right (Range {lo = minimum (map lo xs'), hi = maximum (map hi xs')}) Left _ -> Left (szCases $ map (fmap toSize) xs) - AddF x y -> binOp (+) x y - MulF x y -> binOp (*) x y - SubF x y -> binOp (-) x y - NegF x -> unOp negate x - AbsF x -> unOp abs x - SgnF x -> unOp signum x + AddF x y -> binOp (+) x y + MulF x y -> binOp (*) x y + SubF x y -> binOp (-) x y + NegF x -> unOp negate x + AbsF x -> unOp abs x + SgnF x -> unOp signum x ApF _ f (Right x) -> Right (Range {lo = f (lo x), hi = f (hi x)}) - ApF n f (Left x) -> Left (apMono n f x) - where - binOp - :: (forall a . Num a => a -> a -> a) - -> Either Size (Range Natural) - -> Either Size (Range Natural) - -> Either Size (Range Natural) - binOp op (Right x) (Right y) = Right (op x y) - binOp op x y = Left (op (toSize x) (toSize y)) - - unOp - :: (forall a . Num a => a -> a) - -> Either Size (Range Natural) - -> Either Size (Range Natural) - unOp f = \case - Right x -> Right (f x) - Left x -> Left (f x) - - toSize :: Either Size (Range Natural) -> Size - toSize = \case - Left x -> x - Right r -> if lo r == hi r - then fromIntegral (lo r) - else szCases - [Case "lo" (fromIntegral $ lo r), Case "hi" (fromIntegral $ hi r)] + ApF n f (Left x) -> Left (apMono n f x) + where + binOp :: + (forall a. Num a => a -> a -> a) -> + Either Size (Range Natural) -> + Either Size (Range Natural) -> + Either Size (Range Natural) + binOp op (Right x) (Right y) = Right (op x y) + binOp op x y = Left (op (toSize x) (toSize y)) + + unOp :: + (forall a. Num a => a -> a) -> + Either Size (Range Natural) -> + Either Size (Range Natural) + unOp f = \case + Right x -> Right (f x) + Left x -> Left (f x) + + toSize :: Either Size (Range Natural) -> Size + toSize = \case + Left x -> x + Right r -> + if lo r == hi r + then fromIntegral (lo r) + else + szCases + [Case "lo" (fromIntegral $ lo r), Case "hi" (fromIntegral $ hi r)] -- | Force any thunks in the given @Size@ expression. -- @@ -383,14 +389,14 @@ szSimplify = cata $ \case -- > (0 + { TxAux=(2 + ((0 + (_ :: Tx)) + (_ :: Vector TxInWitness))) }) szForce :: Size -> Size szForce = cata $ \case - AddF x y -> x + y - MulF x y -> x * y - SubF x y -> x - y - NegF x -> negate x - AbsF x -> abs x - SgnF x -> signum x + AddF x y -> x + y + MulF x y -> x * y + SubF x y -> x - y + NegF x -> negate x + AbsF x -> abs x + SgnF x -> signum x CasesF xs -> Fix $ CasesF xs - ValueF x -> Fix (ValueF x) + ValueF x -> Fix (ValueF x) ApF n f x -> apMono n f x TodoF f x -> f x @@ -401,14 +407,12 @@ szBounds = szSimplify . szGreedy . pure withWordSize :: (Integral s, Integral a) => s -> a withWordSize x = let s = fromIntegral x :: Integer - in - if - | s <= 0x17 && s >= (-0x18) -> 1 - | s <= 0xff && s >= (-0x100) -> 2 - | s <= 0xffff && s >= (-0x10000) -> 3 - | s <= 0xffffffff && s >= (-0x100000000) -> 5 - | otherwise -> 9 - + in if + | s <= 0x17 && s >= (-0x18) -> 1 + | s <= 0xff && s >= (-0x100) -> 2 + | s <= 0xffff && s >= (-0x10000) -> 3 + | s <= 0xffffffff && s >= (-0x100000000) -> 5 + | otherwise -> 9 instance ToCBOR Encoding where toCBOR = id @@ -431,7 +435,6 @@ instance ToCBOR Bool where toCBOR = E.encodeBool encodedSizeExpr _ _ = 1 - -------------------------------------------------------------------------------- -- Numeric data -------------------------------------------------------------------------------- @@ -439,14 +442,15 @@ instance ToCBOR Bool where instance ToCBOR Integer where toCBOR = E.encodeInteger -encodedSizeRange :: forall a . (Integral a, Bounded a) => Proxy a -> Size -encodedSizeRange _ = szCases - [ mkCase "minBound" 0 -- min, in absolute value - , mkCase "maxBound" maxBound - ] - where - mkCase :: Text -> a -> Case Size - mkCase n x = Case n (fromIntegral $ (withWordSize :: a -> Integer) x) +encodedSizeRange :: forall a. (Integral a, Bounded a) => Proxy a -> Size +encodedSizeRange _ = + szCases + [ mkCase "minBound" 0 -- min, in absolute value + , mkCase "maxBound" maxBound + ] + where + mkCase :: Text -> a -> Case Size + mkCase n x = Case n (fromIntegral $ (withWordSize :: a -> Integer) x) instance ToCBOR Word where toCBOR = E.encodeWord @@ -509,7 +513,6 @@ instance ToCBOR Natural where instance ToCBOR Void where toCBOR = absurd - -------------------------------------------------------------------------------- -- Tagged -------------------------------------------------------------------------------- @@ -518,23 +521,22 @@ instance (Typeable s, ToCBOR a) => ToCBOR (Tagged s a) where toCBOR (Tagged a) = toCBOR a encodedSizeExpr size _ = encodedSizeExpr size (Proxy @a) - -------------------------------------------------------------------------------- -- Containers -------------------------------------------------------------------------------- -instance (ToCBOR a, ToCBOR b) => ToCBOR (a,b) where +instance (ToCBOR a, ToCBOR b) => ToCBOR (a, b) where toCBOR (a, b) = E.encodeListLen 2 <> toCBOR a <> toCBOR b encodedSizeExpr size _ = 1 + size (Proxy @a) + size (Proxy @b) -instance (ToCBOR a, ToCBOR b, ToCBOR c) => ToCBOR (a,b,c) where +instance (ToCBOR a, ToCBOR b, ToCBOR c) => ToCBOR (a, b, c) where toCBOR (a, b, c) = E.encodeListLen 3 <> toCBOR a <> toCBOR b <> toCBOR c encodedSizeExpr size _ = 1 + size (Proxy @a) + size (Proxy @b) + size (Proxy @c) -instance (ToCBOR a, ToCBOR b, ToCBOR c, ToCBOR d) => ToCBOR (a,b,c,d) where +instance (ToCBOR a, ToCBOR b, ToCBOR c, ToCBOR d) => ToCBOR (a, b, c, d) where toCBOR (a, b, c, d) = E.encodeListLen 4 <> toCBOR a <> toCBOR b <> toCBOR c <> toCBOR d @@ -542,9 +544,9 @@ instance (ToCBOR a, ToCBOR b, ToCBOR c, ToCBOR d) => ToCBOR (a,b,c,d) where 1 + size (Proxy @a) + size (Proxy @b) + size (Proxy @c) + size (Proxy @d) instance - (ToCBOR a, ToCBOR b, ToCBOR c, ToCBOR d, ToCBOR e) - => ToCBOR (a, b, c, d, e) - where + (ToCBOR a, ToCBOR b, ToCBOR c, ToCBOR d, ToCBOR e) => + ToCBOR (a, b, c, d, e) + where toCBOR (a, b, c, d, e) = E.encodeListLen 5 <> toCBOR a @@ -562,9 +564,9 @@ instance + size (Proxy @e) instance - (ToCBOR a, ToCBOR b, ToCBOR c, ToCBOR d, ToCBOR e, ToCBOR f) - => ToCBOR (a, b, c, d, e, f) - where + (ToCBOR a, ToCBOR b, ToCBOR c, ToCBOR d, ToCBOR e, ToCBOR f) => + ToCBOR (a, b, c, d, e, f) + where toCBOR (a, b, c, d, e, f) = E.encodeListLen 6 <> toCBOR a @@ -576,16 +578,16 @@ instance encodedSizeExpr size _ = 1 - + size (Proxy @a) - + size (Proxy @b) - + size (Proxy @c) - + size (Proxy @d) - + size (Proxy @e) - + size (Proxy @f) + + size (Proxy @a) + + size (Proxy @b) + + size (Proxy @c) + + size (Proxy @d) + + size (Proxy @e) + + size (Proxy @f) instance - (ToCBOR a, ToCBOR b, ToCBOR c, ToCBOR d, ToCBOR e, ToCBOR f, ToCBOR g) - => ToCBOR (a, b, c, d, e, f, g) + (ToCBOR a, ToCBOR b, ToCBOR c, ToCBOR d, ToCBOR e, ToCBOR f, ToCBOR g) => + ToCBOR (a, b, c, d, e, f, g) where toCBOR (a, b, c, d, e, f, g) = E.encodeListLen 7 @@ -599,17 +601,17 @@ instance encodedSizeExpr size _ = 1 - + size (Proxy @a) - + size (Proxy @b) - + size (Proxy @c) - + size (Proxy @d) - + size (Proxy @e) - + size (Proxy @f) - + size (Proxy @g) + + size (Proxy @a) + + size (Proxy @b) + + size (Proxy @c) + + size (Proxy @d) + + size (Proxy @e) + + size (Proxy @f) + + size (Proxy @g) instance - (ToCBOR a, ToCBOR b, ToCBOR c, ToCBOR d, ToCBOR e, ToCBOR f, ToCBOR g, ToCBOR h) - => ToCBOR (a, b, c, d, e, f, g, h) + (ToCBOR a, ToCBOR b, ToCBOR c, ToCBOR d, ToCBOR e, ToCBOR f, ToCBOR g, ToCBOR h) => + ToCBOR (a, b, c, d, e, f, g, h) where toCBOR (a, b, c, d, e, f, g, h) = E.encodeListLen 8 @@ -624,28 +626,30 @@ instance encodedSizeExpr size _ = 1 - + size (Proxy @a) - + size (Proxy @b) - + size (Proxy @c) - + size (Proxy @d) - + size (Proxy @e) - + size (Proxy @f) - + size (Proxy @g) - + size (Proxy @h) + + size (Proxy @a) + + size (Proxy @b) + + size (Proxy @c) + + size (Proxy @d) + + size (Proxy @e) + + size (Proxy @f) + + size (Proxy @g) + + size (Proxy @h) instance ToCBOR BS.ByteString where toCBOR = E.encodeBytes encodedSizeExpr size _ = let len = size (Proxy @(LengthOf BS.ByteString)) - in apMono "withWordSize@Int" (withWordSize @Int . fromIntegral) len + len + in apMono "withWordSize@Int" (withWordSize @Int . fromIntegral) len + len instance ToCBOR Text.Text where toCBOR = E.encodeString encodedSizeExpr size _ = let - bsLength = size (Proxy @(LengthOf Text)) - * szCases [Case "minChar" 1, Case "maxChar" 4] - in bsLength + apMono "withWordSize" withWordSize bsLength + bsLength = + size (Proxy @(LengthOf Text)) + * szCases [Case "minChar" 1, Case "maxChar" 4] + in + bsLength + apMono "withWordSize" withWordSize bsLength instance ToCBOR SBS.ShortByteString where toCBOR sbs@(SBS ba) = @@ -653,24 +657,25 @@ instance ToCBOR SBS.ShortByteString where encodedSizeExpr size _ = let len = size (Proxy @(LengthOf SBS.ShortByteString)) - in apMono "withWordSize@Int" (withWordSize @Int . fromIntegral) len + len + in apMono "withWordSize@Int" (withWordSize @Int . fromIntegral) len + len instance ToCBOR BS.Lazy.ByteString where toCBOR = toCBOR . BS.Lazy.toStrict encodedSizeExpr size _ = let len = size (Proxy @(LengthOf BS.Lazy.ByteString)) - in apMono "withWordSize@Int" (withWordSize @Int . fromIntegral) len + len + in apMono "withWordSize@Int" (withWordSize @Int . fromIntegral) len + len instance ToCBOR a => ToCBOR [a] where toCBOR xs = E.encodeListLenIndef <> foldr (\x r -> toCBOR x <> r) E.encodeBreak xs encodedSizeExpr size _ = encodedListSizeExpr size (Proxy @[a]) instance (ToCBOR a, ToCBOR b) => ToCBOR (Either a b) where - toCBOR (Left x) = E.encodeListLen 2 <> E.encodeWord 0 <> toCBOR x + toCBOR (Left x) = E.encodeListLen 2 <> E.encodeWord 0 <> toCBOR x toCBOR (Right x) = E.encodeListLen 2 <> E.encodeWord 1 <> toCBOR x - encodedSizeExpr size _ = szCases - [Case "Left" (2 + size (Proxy @a)), Case "Right" (2 + size (Proxy @b))] + encodedSizeExpr size _ = + szCases + [Case "Left" (2 + size (Proxy @a)), Case "Right" (2 + size (Proxy @b))] instance ToCBOR a => ToCBOR (NonEmpty a) where toCBOR = toCBOR . toList @@ -713,7 +718,7 @@ variableListLenEncoding len contents = encodeMaybe :: (a -> Encoding) -> Maybe a -> Encoding encodeMaybe encodeA = \case Nothing -> E.encodeListLen 0 - Just x -> E.encodeListLen 1 <> encodeA x + Just x -> E.encodeListLen 1 <> encodeA x toCBORMaybe :: (a -> Encoding) -> Maybe a -> Encoding toCBORMaybe = encodeMaybe @@ -727,44 +732,47 @@ encodeNullMaybe encodeValue = \case Nothing -> encodeNull Just x -> encodeValue x -encodeContainerSkel - :: (Word -> E.Encoding) - -> (container -> Int) - -> (accumFunc -> E.Encoding -> container -> E.Encoding) - -> accumFunc - -> container - -> E.Encoding +encodeContainerSkel :: + (Word -> E.Encoding) -> + (container -> Int) -> + (accumFunc -> E.Encoding -> container -> E.Encoding) -> + accumFunc -> + container -> + E.Encoding encodeContainerSkel encodeLen size foldFunction f c = encodeLen (fromIntegral (size c)) <> foldFunction f mempty c {-# INLINE encodeContainerSkel #-} -encodeMapSkel - :: (ToCBOR k, ToCBOR v) - => (m -> Int) - -> ((k -> v -> E.Encoding -> E.Encoding) -> E.Encoding -> m -> E.Encoding) - -> m - -> E.Encoding -encodeMapSkel size foldrWithKey = encodeContainerSkel - E.encodeMapLen - size - foldrWithKey - (\k v b -> toCBOR k <> toCBOR v <> b) +encodeMapSkel :: + (ToCBOR k, ToCBOR v) => + (m -> Int) -> + ((k -> v -> E.Encoding -> E.Encoding) -> E.Encoding -> m -> E.Encoding) -> + m -> + E.Encoding +encodeMapSkel size foldrWithKey = + encodeContainerSkel + E.encodeMapLen + size + foldrWithKey + (\k v b -> toCBOR k <> toCBOR v <> b) {-# INLINE encodeMapSkel #-} instance (Ord k, ToCBOR k, ToCBOR v) => ToCBOR (M.Map k v) where toCBOR = encodeMapSkel M.size M.foldrWithKey -encodeSetSkel - :: ToCBOR a - => (s -> Int) - -> ((a -> E.Encoding -> E.Encoding) -> E.Encoding -> s -> E.Encoding) - -> s - -> E.Encoding -encodeSetSkel size foldFunction = mappend encodeSetTag . encodeContainerSkel - E.encodeListLen - size - foldFunction - (\a b -> toCBOR a <> b) +encodeSetSkel :: + ToCBOR a => + (s -> Int) -> + ((a -> E.Encoding -> E.Encoding) -> E.Encoding -> s -> E.Encoding) -> + s -> + E.Encoding +encodeSetSkel size foldFunction = + mappend encodeSetTag + . encodeContainerSkel + E.encodeListLen + size + foldFunction + (\a b -> toCBOR a <> b) {-# INLINE encodeSetSkel #-} -- We stitch a `258` in from of a (Hash)Set, so that tools which @@ -786,32 +794,32 @@ instance (Ord a, ToCBOR a) => ToCBOR (S.Set a) where -- | Generic encoder for vectors. Its intended use is to allow easy -- definition of 'Serialise' instances for custom vector encodeVector :: (ToCBOR a, Vector.Generic.Vector v a) => v a -> E.Encoding -encodeVector = encodeContainerSkel - E.encodeListLen - Vector.Generic.length - Vector.Generic.foldr - (\a b -> toCBOR a <> b) +encodeVector = + encodeContainerSkel + E.encodeListLen + Vector.Generic.length + Vector.Generic.foldr + (\a b -> toCBOR a <> b) {-# INLINE encodeVector #-} - -instance (ToCBOR a) => ToCBOR (Vector.Vector a) where +instance ToCBOR a => ToCBOR (Vector.Vector a) where toCBOR = encodeVector {-# INLINE toCBOR #-} encodedSizeExpr size _ = 2 + size (Proxy @(LengthOf (Vector.Vector a))) * size (Proxy @a) - -------------------------------------------------------------------------------- -- Time -------------------------------------------------------------------------------- instance ToCBOR UTCTime where - toCBOR (UTCTime day timeOfDay) = mconcat [ - encodeListLen 3 - , encodeInteger year - , encodeInt dayOfYear - , encodeInteger timeOfDayPico - ] + toCBOR (UTCTime day timeOfDay) = + mconcat + [ encodeListLen 3 + , encodeInteger year + , encodeInt dayOfYear + , encodeInteger timeOfDayPico + ] where (year, dayOfYear) = toOrdinalDate day timeOfDayPico = diffTimeToPicoseconds timeOfDay diff --git a/cardano-binary/test/Test/Cardano/Binary/Failure.hs b/cardano-binary/test/Test/Cardano/Binary/Failure.hs index aa269a4c3..89ad6188f 100644 --- a/cardano-binary/test/Test/Cardano/Binary/Failure.hs +++ b/cardano-binary/test/Test/Cardano/Binary/Failure.hs @@ -1,10 +1,9 @@ -{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE BangPatterns #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TemplateHaskell #-} -module Test.Cardano.Binary.Failure - (tests) - where +module Test.Cardano.Binary.Failure (tests) +where import qualified Codec.CBOR.Read as CR @@ -17,8 +16,8 @@ import Cardano.Binary hiding (Range) import Hedgehog import qualified Hedgehog.Gen as Gen -import qualified Hedgehog.Range as Range import Hedgehog.Internal.Property (failWith) +import qualified Hedgehog.Range as Range {- HLINT ignore "Use record patterns" -} @@ -29,7 +28,7 @@ tests = checkParallel $$(discover) ------------------------- Generators ----------------------------- genInvalidNonEmptyCBOR :: Gen Encoding -- NonEmpty Bool -genInvalidNonEmptyCBOR = pure (toCBOR ([] :: [Bool])) +genInvalidNonEmptyCBOR = pure (toCBOR ([] :: [Bool])) genInvalidEitherCBOR :: Gen Encoding -- Either Bool Bool genInvalidEitherCBOR = do @@ -67,9 +66,10 @@ prop_shouldFailSetTag = property $ do prop_shouldFailSet :: Property prop_shouldFailSet = property $ do ls <- forAll $ Gen.list (Range.constant 0 20) (Gen.int Range.constantBounded) - let set = encodeTag 258 + let set = + encodeTag 258 <> encodeListLen (fromIntegral (length ls + 2)) - <> mconcat (toCBOR <$> (4:3:ls)) + <> mconcat (toCBOR <$> (4 : 3 : ls)) assertIsLeft (decode set :: Either DecoderError (Set Int)) prop_shouldFailNegativeNatural :: Property @@ -84,15 +84,15 @@ assertIsLeft :: (HasCallStack, MonadTest m) => Either DecoderError b -> m () assertIsLeft (Right _) = withFrozenCallStack $ failWith Nothing "This should have Left : failed" assertIsLeft (Left !x) = case x of DecoderErrorDeserialiseFailure _ (CR.DeserialiseFailure _ str) | not (null str) -> success - DecoderErrorCanonicityViolation _ -> success - DecoderErrorCustom _ _ -> success - DecoderErrorEmptyList _ -> success - DecoderErrorLeftover _ _ -> success - DecoderErrorSizeMismatch _ _ _ -> success + DecoderErrorCanonicityViolation _ -> success + DecoderErrorCustom _ _ -> success + DecoderErrorEmptyList _ -> success + DecoderErrorLeftover _ _ -> success + DecoderErrorSizeMismatch _ _ _ -> success DecoderErrorUnknownTag _ i | i > 0 -> success - _ -> success + _ -> success decode :: FromCBOR a => Encoding -> Either DecoderError a decode enc = - let encoded = serialize enc - in decodeFull encoded + let encoded = serialize enc + in decodeFull encoded diff --git a/cardano-binary/test/Test/Cardano/Binary/Helpers.hs b/cardano-binary/test/Test/Cardano/Binary/Helpers.hs index e3bea925a..2932c97d3 100644 --- a/cardano-binary/test/Test/Cardano/Binary/Helpers.hs +++ b/cardano-binary/test/Test/Cardano/Binary/Helpers.hs @@ -1,27 +1,25 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE ConstraintKinds #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} - +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -Wno-orphans #-} -module Test.Cardano.Binary.Helpers - ( +module Test.Cardano.Binary.Helpers ( -- * Binary test helpers - U - , U24 - , extensionProperty - , cborFlatTermValid + U, + U24, + extensionProperty, + cborFlatTermValid, -- * Static size estimates - , SizeTestConfig(..) - , cfg - , scfg - , sizeTest - ) + SizeTestConfig (..), + cfg, + scfg, + sizeTest, +) where import Codec.CBOR.FlatTerm (toFlatTerm, validFlatTerm) @@ -40,33 +38,32 @@ import qualified Hedgehog as HH import qualified Hedgehog.Gen as HH.Gen import Test.Hspec () import Test.Hspec.QuickCheck () -import Test.QuickCheck - ( Arbitrary(arbitrary) - , Gen - , Property - , choose - , forAll - , property - , (===) - ) +import Test.QuickCheck ( + Arbitrary (arbitrary), + Gen, + Property, + choose, + forAll, + property, + (===), + ) import Test.QuickCheck.Instances () -import Cardano.Binary - ( FromCBOR(..) - , Range(..) - , Size - , SizeOverride(..) - , ToCBOR(..) - , decodeListLenOf - , decodeNestedCborBytes - , encodeListLen - , encodeNestedCborBytes - , serialize - , szSimplify - , szWithCtx - , unsafeDeserialize - ) - +import Cardano.Binary ( + FromCBOR (..), + Range (..), + Size, + SizeOverride (..), + ToCBOR (..), + decodeListLenOf, + decodeNestedCborBytes, + encodeListLen, + encodeNestedCborBytes, + serialize, + szSimplify, + szWithCtx, + unsafeDeserialize, + ) -------------------------------------------------------------------------------- -- From/to tests @@ -86,9 +83,10 @@ data U = U Word8 BS.ByteString deriving (Show, Eq) instance ToCBOR U where toCBOR (U word8 bs) = - encodeListLen 2 <> toCBOR (word8 :: Word8) <> encodeNestedCborBytes - (LBS.fromStrict bs) - + encodeListLen 2 + <> toCBOR (word8 :: Word8) + <> encodeNestedCborBytes + (LBS.fromStrict bs) instance FromCBOR U where fromCBOR = do @@ -108,64 +106,66 @@ instance FromCBOR U24 where instance ToCBOR U24 where toCBOR (U24 word8 bs) = - encodeListLen 2 <> toCBOR (word8 :: Word8) <> encodeNestedCborBytes - (LBS.fromStrict bs) - + encodeListLen 2 + <> toCBOR (word8 :: Word8) + <> encodeNestedCborBytes + (LBS.fromStrict bs) -- | Given a data type which can be extended, verify we can indeed do so -- without breaking anything. This should work with every time which adopted -- the schema of having at least one constructor of the form: -- .... | Unknown Word8 ByteString -extensionProperty - :: forall a . (Arbitrary a, Eq a, Show a, FromCBOR a, ToCBOR a) => Property +extensionProperty :: + forall a. (Arbitrary a, Eq a, Show a, FromCBOR a, ToCBOR a) => Property extensionProperty = forAll @a (arbitrary :: Gen a) $ \input -> -{- This function works as follows: + {- This function works as follows: - 1. When we call `serialized`, we are implicitly assuming (as contract of this - function) that the input type would be of a shape such as: + 1. When we call `serialized`, we are implicitly assuming (as contract of this + function) that the input type would be of a shape such as: - data MyType = Constructor1 Int Bool - | Constructor2 String - | UnknownConstructor Word8 ByteString + data MyType = Constructor1 Int Bool + | Constructor2 String + | UnknownConstructor Word8 ByteString - Such type will be encoded, roughly, like this: + Such type will be encoded, roughly, like this: - encode (Constructor1 a b) = encodeWord 0 <> encodeNestedCbor (a,b) - encode (Constructor2 a b) = encodeWord 1 <> encodeNestedCbor a - encode (UnknownConstructor tag bs) = encodeWord tag <> encodeNestedCborBytes bs + encode (Constructor1 a b) = encodeWord 0 <> encodeNestedCbor (a,b) + encode (Constructor2 a b) = encodeWord 1 <> encodeNestedCbor a + encode (UnknownConstructor tag bs) = encodeWord tag <> encodeNestedCborBytes bs - In CBOR terms, we would produce something like this: + In CBOR terms, we would produce something like this: - + - 2. Now, when we call `unsafeDeserialize serialized`, we are effectively asking to produce as - output a value of type `U`. `U` is defined by only 1 constructor, it - being `U Word8 ByteString`, but this is still compatible with our `tag + cborDataItem` - format. So now we will have something like: + 2. Now, when we call `unsafeDeserialize serialized`, we are effectively asking to produce as + output a value of type `U`. `U` is defined by only 1 constructor, it + being `U Word8 ByteString`, but this is still compatible with our `tag + cborDataItem` + format. So now we will have something like: - U + U - (The has been removed as part of the decoding process). + (The has been removed as part of the decoding process). - 3. We now call `unsafeDeserialize (serialize u)`, which means: Can you produce a CBOR binary - from `U`, and finally try to decode it into a value of type `a`? This will work because - our intermediate encoding into `U` didn't touch the inital ``, so we will - be able to reconstruct the original object back. - More specifically, `serialize u` would produce once again: + 3. We now call `unsafeDeserialize (serialize u)`, which means: Can you produce a CBOR binary + from `U`, and finally try to decode it into a value of type `a`? This will work because + our intermediate encoding into `U` didn't touch the inital ``, so we will + be able to reconstruct the original object back. + More specifically, `serialize u` would produce once again: - + - (The has been added as part of the encoding process). + (The has been added as part of the encoding process). - `unsafeDeserialize` would then consume the tag (to understand which type constructor this corresponds to), - remove the token and finally proceed to deserialise the rest. + `unsafeDeserialize` would then consume the tag (to understand which type constructor this corresponds to), + remove the token and finally proceed to deserialise the rest. --} + -} let - serialized = serialize input -- Step 1 - (u :: U ) = unsafeDeserialize serialized -- Step 2 - (encoded :: a) = unsafeDeserialize (serialize u) -- Step 3 - in encoded === input + serialized = serialize input -- Step 1 + (u :: U) = unsafeDeserialize serialized -- Step 2 + (encoded :: a) = unsafeDeserialize (serialize u) -- Step 3 + in + encoded === input -------------------------------------------------------------------------------- -- Static size estimates @@ -176,36 +176,42 @@ bshow = unpack . toLazyText . bprint build -- | Configuration for a single test case. data SizeTestConfig a = SizeTestConfig - { debug :: a -> String -- ^ Pretty-print values - , gen :: HH.Gen a -- ^ Generator - , precise :: Bool -- ^ Must estimates be exact? - , addlCtx :: M.Map TypeRep SizeOverride -- ^ Additional size overrides - , computedCtx :: a -> M.Map TypeRep SizeOverride - -- ^ Size overrides computed from a concrete instance. - } + { debug :: a -> String + -- ^ Pretty-print values + , gen :: HH.Gen a + -- ^ Generator + , precise :: Bool + -- ^ Must estimates be exact? + , addlCtx :: M.Map TypeRep SizeOverride + -- ^ Additional size overrides + , computedCtx :: a -> M.Map TypeRep SizeOverride + -- ^ Size overrides computed from a concrete instance. + } -- | Default configuration, for @Buildable@ types. cfg :: Buildable a => SizeTestConfig a -cfg = SizeTestConfig - { debug = bshow - , gen = HH.Gen.discard - , precise = False - , addlCtx = M.empty - , computedCtx = const M.empty - } +cfg = + SizeTestConfig + { debug = bshow + , gen = HH.Gen.discard + , precise = False + , addlCtx = M.empty + , computedCtx = const M.empty + } -- | Default configuration, for @Show@able types. scfg :: Show a => SizeTestConfig a -scfg = SizeTestConfig - { debug = show - , gen = HH.Gen.discard - , precise = False - , addlCtx = M.empty - , computedCtx = const M.empty - } +scfg = + SizeTestConfig + { debug = show + , gen = HH.Gen.discard + , precise = False + , addlCtx = M.empty + , computedCtx = const M.empty + } -- | Create a test case from the given test configuration. -sizeTest :: forall a . ToCBOR a => SizeTestConfig a -> HH.Property +sizeTest :: forall a. ToCBOR a => SizeTestConfig a -> HH.Property sizeTest SizeTestConfig {..} = HH.property $ do x <- forAllWith debug gen @@ -219,9 +225,9 @@ sizeTest SizeTestConfig {..} = HH.property $ do annotate ("Value: " <> debug x) case szVerify ctx x of - Exact -> success + Exact -> success WithinBounds _ _ | not precise -> success - WithinBounds sz bounds -> do + WithinBounds sz bounds -> do badBounds sz bounds annotate "Bounds were not exact." failure @@ -236,19 +242,24 @@ sizeTest SizeTestConfig {..} = HH.property $ do -- | The possible results from @szVerify@, describing various ways -- a size can or cannot be found within a certain range. data ComparisonResult - = Exact -- ^ Size matched the bounds, and the bounds were exact. - | WithinBounds Natural (Range Natural) -- ^ Size matched the bounds, but the bounds are not exact. - | BoundsAreSymbolic Size -- ^ The bounds could not be reduced to a numerical range. - | OutOfBounds Natural (Range Natural) -- ^ The size fell outside of the bounds. + = -- | Size matched the bounds, and the bounds were exact. + Exact + | -- | Size matched the bounds, but the bounds are not exact. + WithinBounds Natural (Range Natural) + | -- | The bounds could not be reduced to a numerical range. + BoundsAreSymbolic Size + | -- | The size fell outside of the bounds. + OutOfBounds Natural (Range Natural) -- | For a given value @x :: a@ with @ToCBOR a@, check that the encoded size -- of @x@ falls within the statically-computed size range for @a@. szVerify :: ToCBOR a => M.Map TypeRep SizeOverride -> a -> ComparisonResult szVerify ctx x = case szSimplify (szWithCtx ctx (pure x)) of Left bounds -> BoundsAreSymbolic bounds - Right range | lo range <= sz && sz <= hi range -> - if lo range == hi range then Exact else WithinBounds sz range + Right range + | lo range <= sz && sz <= hi range -> + if lo range == hi range then Exact else WithinBounds sz range Right range -> OutOfBounds sz range - where - sz :: Natural - sz = fromIntegral $ LBS.length $ serialize x + where + sz :: Natural + sz = fromIntegral $ LBS.length $ serialize x diff --git a/cardano-binary/test/Test/Cardano/Binary/Helpers/GoldenRoundTrip.hs b/cardano-binary/test/Test/Cardano/Binary/Helpers/GoldenRoundTrip.hs index 55d215187..21d419fe5 100644 --- a/cardano-binary/test/Test/Cardano/Binary/Helpers/GoldenRoundTrip.hs +++ b/cardano-binary/test/Test/Cardano/Binary/Helpers/GoldenRoundTrip.hs @@ -1,49 +1,63 @@ -{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeApplications #-} -- | Golden and round-trip testing of 'FromCBOR' and 'ToCBOR' instances - -module Test.Cardano.Binary.Helpers.GoldenRoundTrip - ( goldenTestCBOR - , goldenTestCBORExplicit - , goldenTestExplicit - , roundTripsCBORShow - , roundTripsCBORBuildable - , compareHexDump - , deprecatedGoldenDecode - ) +module Test.Cardano.Binary.Helpers.GoldenRoundTrip ( + goldenTestCBOR, + goldenTestCBORExplicit, + goldenTestExplicit, + roundTripsCBORShow, + roundTripsCBORBuildable, + compareHexDump, + deprecatedGoldenDecode, +) where -import Test.Cardano.Prelude - (decodeBase16, encodeWithIndex, trippingBuildable) +import Test.Cardano.Prelude ( + decodeBase16, + encodeWithIndex, + trippingBuildable, + ) import qualified Codec.CBOR.Decoding as D -import Control.Monad.IO.Class (MonadIO(liftIO)) +import Control.Monad.IO.Class (MonadIO (liftIO)) import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Lazy.Char8 as BS +import Data.Proxy (Proxy (Proxy)) import Data.Text (Text) -import Data.Proxy (Proxy(Proxy)) -import Formatting.Buildable (Buildable(..)) +import Formatting.Buildable (Buildable (..)) import GHC.Stack (HasCallStack, withFrozenCallStack) -import Hedgehog - (MonadTest, Property, eval, property, success, tripping, withTests, (===)) +import Hedgehog ( + MonadTest, + Property, + eval, + property, + success, + tripping, + withTests, + (===), + ) import Hedgehog.Internal.Property (failWith) -import Hedgehog.Internal.Show - (LineDiff, lineDiff, mkValue, renderLineDiff, showPretty) - -import Cardano.Binary - ( Decoder - , DecoderError - , Encoding - , FromCBOR(..) - , ToCBOR(..) - , decodeFull - , decodeFullDecoder - , serialize - ) -import Text.Show.Pretty (Value(..)) - +import Hedgehog.Internal.Show ( + LineDiff, + lineDiff, + mkValue, + renderLineDiff, + showPretty, + ) + +import Cardano.Binary ( + Decoder, + DecoderError, + Encoding, + FromCBOR (..), + ToCBOR (..), + decodeFull, + decodeFullDecoder, + serialize, + ) +import Text.Show.Pretty (Value (..)) type HexDump = BSL.ByteString @@ -57,16 +71,18 @@ hexDumpDiff :: HexDump -> HexDump -> Maybe HexDumpDiff hexDumpDiff x y = do xs <- sequence (mkValue <$> BS.lines x) ys <- sequence (mkValue <$> BS.lines y) - pure $ concatMap (uncurry lineDiff) $ zipWithPadding - (String "") - (String "") - xs - ys + pure $ + concatMap (uncurry lineDiff) $ + zipWithPadding + (String "") + (String "") + xs + ys zipWithPadding :: a -> b -> [a] -> [b] -> [(a, b)] zipWithPadding a b (x : xs) (y : ys) = (x, y) : zipWithPadding a b xs ys -zipWithPadding a _ [] ys = zip (repeat a) ys -zipWithPadding _ b xs [] = zip xs (repeat b) +zipWithPadding a _ [] ys = zip (repeat a) ys +zipWithPadding _ b xs [] = zip xs (repeat b) -- | A custom version of '(===)' for 'HexDump's to get prettier diffs compareHexDump :: (MonadTest m, HasCallStack) => HexDump -> HexDump -> m () @@ -77,8 +93,11 @@ compareHexDump x y = do -- | Fail with a nice line diff of the two HexDumps failHexDumpDiff :: (MonadTest m, HasCallStack) => HexDump -> HexDump -> m () failHexDumpDiff x y = case hexDumpDiff x y of - Nothing -> withFrozenCallStack $ failWith Nothing $ Prelude.unlines - ["━━━ Not Equal ━━━", showPretty x, showPretty y] + Nothing -> + withFrozenCallStack $ + failWith Nothing $ + Prelude.unlines + ["━━━ Not Equal ━━━", showPretty x, showPretty y] Just dif -> withFrozenCallStack $ failWith Nothing $ renderHexDumpDiff dif -- | Check that the 'encode' and 'decode' function of the 'Bi' instances work as @@ -87,46 +106,44 @@ failHexDumpDiff x y = case hexDumpDiff x y of -- -- - The encoded data should coincide with the contents of the @fp@. -- - Decoding @fp@ should give as a result @x@ --- -goldenTestCBOR - :: forall a - . (FromCBOR a, ToCBOR a, Eq a, Show a, HasCallStack) - => a - -> FilePath - -> Property -goldenTestCBOR = withFrozenCallStack - $ goldenTestCBORExplicit (label $ Proxy @a) toCBOR fromCBOR - +goldenTestCBOR :: + forall a. + (FromCBOR a, ToCBOR a, Eq a, Show a, HasCallStack) => + a -> + FilePath -> + Property +goldenTestCBOR = + withFrozenCallStack $ + goldenTestCBORExplicit (label $ Proxy @a) toCBOR fromCBOR -- | Variant of 'goldenTestBi' using custom encode and decode functions. -- -- This is required for the encode/decode golden-tests for types that do no -- have a 'Bi' instance. --- -goldenTestCBORExplicit - :: forall a - . (Eq a, Show a, HasCallStack) - => Text - -- ^ Label for error reporting when decoding. - -> (a -> Encoding) - -> (forall s . Decoder s a) - -> a - -> FilePath - -> Property +goldenTestCBORExplicit :: + forall a. + (Eq a, Show a, HasCallStack) => + -- | Label for error reporting when decoding. + Text -> + (a -> Encoding) -> + (forall s. Decoder s a) -> + a -> + FilePath -> + Property goldenTestCBORExplicit eLabel enc dec = goldenTestExplicit (serialize . enc) fullDecoder where - fullDecoder :: BSL.ByteString -> Either DecoderError a - fullDecoder = decodeFullDecoder eLabel dec - -goldenTestExplicit - :: forall a - . (Eq a, Show a, HasCallStack) - => (a -> BS.ByteString) - -> (BS.ByteString -> Either DecoderError a) - -> a - -> FilePath - -> Property + fullDecoder :: BSL.ByteString -> Either DecoderError a + fullDecoder = decodeFullDecoder eLabel dec + +goldenTestExplicit :: + forall a. + (Eq a, Show a, HasCallStack) => + (a -> BS.ByteString) -> + (BS.ByteString -> Either DecoderError a) -> + a -> + FilePath -> + Property goldenTestExplicit encode decode x path = withFrozenCallStack $ do let bs' = encodeWithIndex . encode $ x withTests 1 . property $ do @@ -139,23 +156,23 @@ goldenTestExplicit encode decode x path = withFrozenCallStack $ do -- classes) by serializing it to a ByteString and back again and that also has -- a 'Show' instance. If the 'a' type has both 'Show' and 'Buildable' -- instances, it's best to use this version. -roundTripsCBORShow - :: (FromCBOR a, ToCBOR a, Eq a, MonadTest m, Show a, HasCallStack) - => a - -> m () +roundTripsCBORShow :: + (FromCBOR a, ToCBOR a, Eq a, MonadTest m, Show a, HasCallStack) => + a -> + m () roundTripsCBORShow x = withFrozenCallStack $ tripping x serialize decodeFull -- | Round trip (via ByteString) any instance of the 'FromCBOR' and 'ToCBOR' -- class that also has a 'Buildable' instance. -roundTripsCBORBuildable - :: (FromCBOR a, ToCBOR a, Eq a, MonadTest m, Buildable a, HasCallStack) - => a - -> m () +roundTripsCBORBuildable :: + (FromCBOR a, ToCBOR a, Eq a, MonadTest m, Buildable a, HasCallStack) => + a -> + m () roundTripsCBORBuildable a = withFrozenCallStack $ trippingBuildable a serialize decodeFull -deprecatedGoldenDecode - :: HasCallStack => Text -> (forall s . D.Decoder s ()) -> FilePath -> Property +deprecatedGoldenDecode :: + HasCallStack => Text -> (forall s. D.Decoder s ()) -> FilePath -> Property deprecatedGoldenDecode lbl decoder path = withFrozenCallStack $ withTests 1 . property $ do bs <- decodeBase16 <$> liftIO (BS.readFile path) diff --git a/cardano-binary/test/Test/Cardano/Binary/RoundTrip.hs b/cardano-binary/test/Test/Cardano/Binary/RoundTrip.hs index d77be4f40..e1ad7c974 100644 --- a/cardano-binary/test/Test/Cardano/Binary/RoundTrip.hs +++ b/cardano-binary/test/Test/Cardano/Binary/RoundTrip.hs @@ -1,23 +1,24 @@ -{-# LANGUAGE NumDecimals #-} -{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE NumDecimals #-} +{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} -module Test.Cardano.Binary.RoundTrip - ( tests - ) +module Test.Cardano.Binary.RoundTrip ( + tests, +) where -import Test.Cardano.Prelude ( eachOf, discoverRoundTrip ) +import Test.Cardano.Prelude (discoverRoundTrip, eachOf) +import Data.Fixed (E9, Fixed (..)) import Data.Ratio ((%)) -import Data.Fixed (E9, Fixed(..)) import Hedgehog (Property, Range, checkParallel) import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range -import Test.Cardano.Binary.Helpers.GoldenRoundTrip - (roundTripsCBORBuildable, roundTripsCBORShow) - +import Test.Cardano.Binary.Helpers.GoldenRoundTrip ( + roundTripsCBORBuildable, + roundTripsCBORShow, + ) tests :: IO Bool tests = checkParallel $$discoverRoundTrip @@ -30,10 +31,11 @@ roundTripBoolBi = eachOf 10 Gen.bool roundTripsCBORBuildable -- | Tests up to 'Integer's with multiple machine words using large upper bound roundTripIntegerBi :: Property -roundTripIntegerBi = eachOf - 1000 - (Gen.integral (Range.linearFrom 0 (-1e40) 1e40 :: Range Integer)) - roundTripsCBORBuildable +roundTripIntegerBi = + eachOf + 1000 + (Gen.integral (Range.linearFrom 0 (-1e40) 1e40 :: Range Integer)) + roundTripsCBORBuildable roundTripWordBi :: Property roundTripWordBi = @@ -79,39 +81,43 @@ roundTripRatioBi :: Property roundTripRatioBi = eachOf 1000 - (((%) :: Integer -> Integer -> Rational) - <$> Gen.integral (Range.constant (-2 ^ (128 :: Int)) (2 ^ (128 :: Int))) - <*> Gen.integral (Range.constant (-2 ^ (128 :: Int)) (2 ^ (128 :: Int))) + ( ((%) :: Integer -> Integer -> Rational) + <$> Gen.integral (Range.constant (-2 ^ (128 :: Int)) (2 ^ (128 :: Int))) + <*> Gen.integral (Range.constant (-2 ^ (128 :: Int)) (2 ^ (128 :: Int))) ) roundTripsCBORBuildable roundTripNanoBi :: Property -roundTripNanoBi = eachOf - 1000 - ((MkFixed :: Integer -> Fixed E9) <$> Gen.integral (Range.constantFrom 0 (-1e12) 1e12)) - roundTripsCBORShow +roundTripNanoBi = + eachOf + 1000 + ((MkFixed :: Integer -> Fixed E9) <$> Gen.integral (Range.constantFrom 0 (-1e12) 1e12)) + roundTripsCBORShow roundTripMapBi :: Property -roundTripMapBi = eachOf - 100 - (Gen.map - (Range.constant 0 50) - ((,) <$> Gen.int Range.constantBounded <*> Gen.int Range.constantBounded) - ) - roundTripsCBORShow +roundTripMapBi = + eachOf + 100 + ( Gen.map + (Range.constant 0 50) + ((,) <$> Gen.int Range.constantBounded <*> Gen.int Range.constantBounded) + ) + roundTripsCBORShow roundTripSetBi :: Property -roundTripSetBi = eachOf - 100 - (Gen.set (Range.constant 0 50) (Gen.int Range.constantBounded)) - roundTripsCBORShow +roundTripSetBi = + eachOf + 100 + (Gen.set (Range.constant 0 50) (Gen.int Range.constantBounded)) + roundTripsCBORShow roundTripByteStringBi :: Property roundTripByteStringBi = eachOf 100 (Gen.bytes $ Range.constant 0 100) roundTripsCBORShow roundTripTextBi :: Property -roundTripTextBi = eachOf - 100 - (Gen.text (Range.constant 0 100) Gen.unicode) - roundTripsCBORBuildable +roundTripTextBi = + eachOf + 100 + (Gen.text (Range.constant 0 100) Gen.unicode) + roundTripsCBORBuildable diff --git a/cardano-binary/test/Test/Cardano/Binary/Serialization.hs b/cardano-binary/test/Test/Cardano/Binary/Serialization.hs index c9055fc37..5a2879ed0 100644 --- a/cardano-binary/test/Test/Cardano/Binary/Serialization.hs +++ b/cardano-binary/test/Test/Cardano/Binary/Serialization.hs @@ -1,14 +1,14 @@ -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE NumDecimals #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE NumDecimals #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TemplateHaskell #-} -module Test.Cardano.Binary.Serialization - (tests) - where +{-# LANGUAGE TemplateHaskell #-} + +module Test.Cardano.Binary.Serialization (tests) +where import Cardano.Binary hiding (Range) -import Codec.CBOR.Encoding as E import Codec.CBOR.Decoding as D +import Codec.CBOR.Encoding as E import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BS.Lazy @@ -33,38 +33,39 @@ tests :: IO Bool tests = checkParallel $$(discover) data TestStruct = TestStruct - { tsUnit :: () - , tsBool :: !Bool - , tsInteger :: !Integer - , tsWord :: !Word - , tsWord8 :: !Word8 - , tsWord16 :: !Word16 - , tsWord32 :: !Word32 - , tsWord64 :: !Word64 - , tsInt :: !Int - , tsFloat :: !Float - , tsInt32 :: !Int32 - , tsInt64 :: !Int64 - , tsTupleBoolBool :: !(Bool, Bool) - , tsTupleBoolBoolBool :: !(Bool, Bool, Bool) + { tsUnit :: () + , tsBool :: !Bool + , tsInteger :: !Integer + , tsWord :: !Word + , tsWord8 :: !Word8 + , tsWord16 :: !Word16 + , tsWord32 :: !Word32 + , tsWord64 :: !Word64 + , tsInt :: !Int + , tsFloat :: !Float + , tsInt32 :: !Int32 + , tsInt64 :: !Int64 + , tsTupleBoolBool :: !(Bool, Bool) + , tsTupleBoolBoolBool :: !(Bool, Bool, Bool) , tsTupleBoolBoolBoolBool :: !(Bool, Bool, Bool, Bool) - , tsByteString :: !BS.ByteString - , tsText :: !Text - , tsListBool :: ![Bool] - , tsEitherBoolBool :: !(Either Bool Bool) - , tsNonEmptyBool :: !(NonEmpty Bool) - , tsMaybeBool :: !(Maybe Bool) - , tsMapBoolBool :: !(Map Bool Bool) - , tsSetBool :: !(Set Bool) - , tsVectorBool :: !(V.Vector Bool) - , tsLByteString :: BS.Lazy.ByteString - , tsSByteString :: BS.Short.ShortByteString - , tsUTCTime :: Time.UTCTime + , tsByteString :: !BS.ByteString + , tsText :: !Text + , tsListBool :: ![Bool] + , tsEitherBoolBool :: !(Either Bool Bool) + , tsNonEmptyBool :: !(NonEmpty Bool) + , tsMaybeBool :: !(Maybe Bool) + , tsMapBoolBool :: !(Map Bool Bool) + , tsSetBool :: !(Set Bool) + , tsVectorBool :: !(V.Vector Bool) + , tsLByteString :: BS.Lazy.ByteString + , tsSByteString :: BS.Short.ShortByteString + , tsUTCTime :: Time.UTCTime } deriving (Show, Eq) genTestStruct :: Gen TestStruct -genTestStruct = TestStruct +genTestStruct = + TestStruct <$> pure () <*> Gen.bool <*> Gen.integral (Range.linearFrom 0 (-1e40) 1e40 :: Range Integer) @@ -94,34 +95,35 @@ genTestStruct = TestStruct <*> genUTCTime instance ToCBOR TestStruct where - toCBOR ts = E.encodeListLen 1 - <> toCBOR (tsUnit ts) - <> toCBOR (tsBool ts) - <> toCBOR (tsInteger ts) - <> toCBOR (tsWord ts) - <> toCBOR (tsWord8 ts) - <> toCBOR (tsWord16 ts) - <> toCBOR (tsWord32 ts) - <> toCBOR (tsWord64 ts) - <> toCBOR (tsInt ts) - <> toCBOR (tsFloat ts) - <> toCBOR (tsInt32 ts) - <> toCBOR (tsInt64 ts) - <> toCBOR (tsTupleBoolBool ts) - <> toCBOR (tsTupleBoolBoolBool ts) - <> toCBOR (tsTupleBoolBoolBoolBool ts) - <> toCBOR (tsByteString ts) - <> toCBOR (tsText ts) - <> toCBOR (tsListBool ts) - <> toCBOR (tsEitherBoolBool ts) - <> toCBOR (tsNonEmptyBool ts) - <> toCBOR (tsMaybeBool ts) - <> toCBOR (tsMapBoolBool ts) - <> toCBOR (tsSetBool ts) - <> toCBOR (tsVectorBool ts) - <> toCBOR (tsLByteString ts) - <> toCBOR (tsSByteString ts) - <> toCBOR (tsUTCTime ts) + toCBOR ts = + E.encodeListLen 1 + <> toCBOR (tsUnit ts) + <> toCBOR (tsBool ts) + <> toCBOR (tsInteger ts) + <> toCBOR (tsWord ts) + <> toCBOR (tsWord8 ts) + <> toCBOR (tsWord16 ts) + <> toCBOR (tsWord32 ts) + <> toCBOR (tsWord64 ts) + <> toCBOR (tsInt ts) + <> toCBOR (tsFloat ts) + <> toCBOR (tsInt32 ts) + <> toCBOR (tsInt64 ts) + <> toCBOR (tsTupleBoolBool ts) + <> toCBOR (tsTupleBoolBoolBool ts) + <> toCBOR (tsTupleBoolBoolBoolBool ts) + <> toCBOR (tsByteString ts) + <> toCBOR (tsText ts) + <> toCBOR (tsListBool ts) + <> toCBOR (tsEitherBoolBool ts) + <> toCBOR (tsNonEmptyBool ts) + <> toCBOR (tsMaybeBool ts) + <> toCBOR (tsMapBoolBool ts) + <> toCBOR (tsSetBool ts) + <> toCBOR (tsVectorBool ts) + <> toCBOR (tsLByteString ts) + <> toCBOR (tsSByteString ts) + <> toCBOR (tsUTCTime ts) instance FromCBOR TestStruct where fromCBOR = do @@ -156,14 +158,16 @@ instance FromCBOR TestStruct where <*> fromCBOR genUTCTime :: Gen Time.UTCTime -genUTCTime = Time.UTCTime - <$> genDay - <*> genDiffTimeOfDay +genUTCTime = + Time.UTCTime + <$> genDay + <*> genDiffTimeOfDay where - -- UTC time takes a DiffTime s.t. 0 <= t < 86401s - genDiffTimeOfDay :: Gen Time.DiffTime - genDiffTimeOfDay = Time.picosecondsToDiffTime <$> - Gen.integral (Range.constantFrom 0 0 ((86401e12) - 1)) + -- UTC time takes a DiffTime s.t. 0 <= t < 86401s + genDiffTimeOfDay :: Gen Time.DiffTime + genDiffTimeOfDay = + Time.picosecondsToDiffTime + <$> Gen.integral (Range.constantFrom 0 0 ((86401e12) - 1)) genDay :: Gen Time.Day genDay = Time.fromOrdinalDate <$> genYear <*> genDayOfYear @@ -189,7 +193,7 @@ prop_decodeContainerSkelWithReplicate :: Property prop_decodeContainerSkelWithReplicate = property $ assert $ case decode vec of Right _ -> True - _ -> False + _ -> False where decode :: Encoding -> Either DecoderError (V.Vector ()) decode enc = decodeFull (serialize enc) diff --git a/cardano-binary/test/Test/Cardano/Binary/SizeBounds.hs b/cardano-binary/test/Test/Cardano/Binary/SizeBounds.hs index 52b2dafc0..737a0f6e5 100644 --- a/cardano-binary/test/Test/Cardano/Binary/SizeBounds.hs +++ b/cardano-binary/test/Test/Cardano/Binary/SizeBounds.hs @@ -1,159 +1,200 @@ {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeApplications #-} -module Test.Cardano.Binary.SizeBounds - ( tests - ) +module Test.Cardano.Binary.SizeBounds ( + tests, +) where import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS import qualified Data.Map as M -import Data.Proxy (Proxy(Proxy)) -import Data.Tagged (Tagged(..)) -import Data.Typeable (typeRep) +import Data.Proxy (Proxy (Proxy)) +import Data.Tagged (Tagged (..)) import qualified Data.Text as T +import Data.Typeable (typeRep) import Data.Word (Word32, Word8) import Cardano.Binary -import Hedgehog (Gen, Group(..), checkParallel) +import Hedgehog (Gen, Group (..), checkParallel) import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range import Test.Cardano.Binary.Helpers - tests :: IO Bool -tests - = let - listOf :: Gen a -> Gen [a] - listOf = Gen.list (Range.linear 0 300) - in checkParallel $ Group - "Encoded size bounds for core types." - [ ("()" , sizeTest $ scfg { gen = pure (), precise = True }) - , ("Bool" , sizeTest $ cfg { gen = Gen.bool, precise = True }) - , ("Word" , sizeTest $ cfg { gen = Gen.word Range.exponentialBounded }) - , ("Word8" , sizeTest $ cfg { gen = Gen.word8 Range.exponentialBounded }) - , ("Word16", sizeTest $ cfg { gen = Gen.word16 Range.exponentialBounded }) - , ("Word32", sizeTest $ cfg { gen = Gen.word32 Range.exponentialBounded }) - , ("Word64", sizeTest $ cfg { gen = Gen.word64 Range.exponentialBounded }) - , ("Int" , sizeTest $ cfg { gen = Gen.int Range.exponentialBounded }) - , ( "Int (precision)" - , sizeTest $ cfg - { gen = Gen.int Range.exponentialBounded - , computedCtx = \x -> M.fromList - [ ( typeRep (Proxy @Int) - , SizeConstant $ fromIntegral (withWordSize x :: Integer) - ) - ] - , precise = True - } - ) - , ( "Float" - , sizeTest - $ cfg { gen = Gen.float (Range.exponentialFloat (-1000000) 1000000) } - ) - , ("Int32", sizeTest $ cfg { gen = Gen.int32 Range.exponentialBounded }) - , ("Int64", sizeTest $ cfg { gen = Gen.int64 Range.exponentialBounded }) - , ( "Tagged () Word32" - , sizeTest $ (scfg @(Tagged () Word32)) - { gen = Tagged <$> Gen.word32 Range.exponentialBounded - } - ) - , ( "(Bool, Bool)" - , sizeTest - $ scfg { gen = (,) <$> Gen.bool <*> Gen.bool, precise = True } - ) - , ( "(Bool, Bool, Bool)" - , sizeTest $ scfg - { gen = (,,) <$> Gen.bool <*> Gen.bool <*> Gen.bool - , precise = True - } - ) - , ( "(Bool, Bool, Bool, Bool)" - , sizeTest $ scfg - { gen = (,,,) <$> Gen.bool <*> Gen.bool <*> Gen.bool <*> Gen.bool - , precise = True - } - ) - , ( "ByteString" - , sizeTest $ (scfg @BS.ByteString) - { debug = show . (BS.unpack :: BS.ByteString -> [Word8]) - , gen = Gen.bytes (Range.linear 0 1000) - , computedCtx = \bs -> M.fromList - [ ( typeRep (Proxy @(LengthOf BS.ByteString)) - , SizeConstant $ fromIntegral $ BS.length bs - ) - ] - , precise = True - } - ) - , ( "Lazy.ByteString" - , sizeTest $ (scfg @LBS.ByteString) - { debug = show . (LBS.unpack :: LBS.ByteString -> [Word8]) - , computedCtx = \bs -> M.fromList - [ ( typeRep (Proxy @(LengthOf LBS.ByteString)) - , SizeConstant $ fromIntegral $ LBS.length bs - ) - ] - , gen = LBS.fromStrict <$> Gen.bytes (Range.linear 0 1000) - , precise = True - } - ) - , ( "Text" - , sizeTest $ cfg - { gen = Gen.text (Range.linear 0 1000) Gen.latin1 - , computedCtx = \bs -> M.fromList - [ ( typeRep (Proxy @(LengthOf T.Text)) - , SizeConstant $ fromIntegral $ T.length bs - ) - ] - } - ) - , ( "Text 2" - , sizeTest $ cfg - { gen = Gen.text (Range.linear 0 1000) Gen.unicode - , computedCtx = \bs -> M.fromList - [ ( typeRep (Proxy @(LengthOf T.Text)) - , SizeConstant $ fromIntegral $ T.length bs - ) - ] - } - ) - , ( "[Bool]" - , sizeTest $ scfg - { gen = listOf Gen.bool - , computedCtx = \bs -> M.fromList - [ ( typeRep (Proxy @(LengthOf [Bool])) - , SizeConstant $ fromIntegral $ length bs - ) - ] - , precise = True - } - ) - , ( "NonEmpty Bool" - , sizeTest $ scfg - { gen = listOf Gen.bool - , computedCtx = \bs -> M.fromList - [ ( typeRep (Proxy @(LengthOf [Bool])) - , SizeConstant $ fromIntegral $ length bs - ) - ] - , precise = True - } - ) - , ( "Either Bool Bool" - , sizeTest $ (scfg @(Either Bool Bool)) - { gen = Left <$> Gen.bool - , precise = True - } - ) - , ( "Either Bool Bool" - , sizeTest $ (scfg @(Either Bool Bool)) - { gen = Right <$> Gen.bool - , precise = True - } - ) - , ("Maybe Bool", sizeTest $ cfg { gen = Gen.bool, precise = True }) - ] +tests = + let + listOf :: Gen a -> Gen [a] + listOf = Gen.list (Range.linear 0 300) + in + checkParallel $ + Group + "Encoded size bounds for core types." + [ ("()", sizeTest $ scfg {gen = pure (), precise = True}) + , ("Bool", sizeTest $ cfg {gen = Gen.bool, precise = True}) + , ("Word", sizeTest $ cfg {gen = Gen.word Range.exponentialBounded}) + , ("Word8", sizeTest $ cfg {gen = Gen.word8 Range.exponentialBounded}) + , ("Word16", sizeTest $ cfg {gen = Gen.word16 Range.exponentialBounded}) + , ("Word32", sizeTest $ cfg {gen = Gen.word32 Range.exponentialBounded}) + , ("Word64", sizeTest $ cfg {gen = Gen.word64 Range.exponentialBounded}) + , ("Int", sizeTest $ cfg {gen = Gen.int Range.exponentialBounded}) + , + ( "Int (precision)" + , sizeTest $ + cfg + { gen = Gen.int Range.exponentialBounded + , computedCtx = \x -> + M.fromList + [ + ( typeRep (Proxy @Int) + , SizeConstant $ fromIntegral (withWordSize x :: Integer) + ) + ] + , precise = True + } + ) + , + ( "Float" + , sizeTest $ + cfg {gen = Gen.float (Range.exponentialFloat (-1000000) 1000000)} + ) + , ("Int32", sizeTest $ cfg {gen = Gen.int32 Range.exponentialBounded}) + , ("Int64", sizeTest $ cfg {gen = Gen.int64 Range.exponentialBounded}) + , + ( "Tagged () Word32" + , sizeTest $ + (scfg @(Tagged () Word32)) + { gen = Tagged <$> Gen.word32 Range.exponentialBounded + } + ) + , + ( "(Bool, Bool)" + , sizeTest $ + scfg {gen = (,) <$> Gen.bool <*> Gen.bool, precise = True} + ) + , + ( "(Bool, Bool, Bool)" + , sizeTest $ + scfg + { gen = (,,) <$> Gen.bool <*> Gen.bool <*> Gen.bool + , precise = True + } + ) + , + ( "(Bool, Bool, Bool, Bool)" + , sizeTest $ + scfg + { gen = (,,,) <$> Gen.bool <*> Gen.bool <*> Gen.bool <*> Gen.bool + , precise = True + } + ) + , + ( "ByteString" + , sizeTest $ + (scfg @BS.ByteString) + { debug = show . (BS.unpack :: BS.ByteString -> [Word8]) + , gen = Gen.bytes (Range.linear 0 1000) + , computedCtx = \bs -> + M.fromList + [ + ( typeRep (Proxy @(LengthOf BS.ByteString)) + , SizeConstant $ fromIntegral $ BS.length bs + ) + ] + , precise = True + } + ) + , + ( "Lazy.ByteString" + , sizeTest $ + (scfg @LBS.ByteString) + { debug = show . (LBS.unpack :: LBS.ByteString -> [Word8]) + , computedCtx = \bs -> + M.fromList + [ + ( typeRep (Proxy @(LengthOf LBS.ByteString)) + , SizeConstant $ fromIntegral $ LBS.length bs + ) + ] + , gen = LBS.fromStrict <$> Gen.bytes (Range.linear 0 1000) + , precise = True + } + ) + , + ( "Text" + , sizeTest $ + cfg + { gen = Gen.text (Range.linear 0 1000) Gen.latin1 + , computedCtx = \bs -> + M.fromList + [ + ( typeRep (Proxy @(LengthOf T.Text)) + , SizeConstant $ fromIntegral $ T.length bs + ) + ] + } + ) + , + ( "Text 2" + , sizeTest $ + cfg + { gen = Gen.text (Range.linear 0 1000) Gen.unicode + , computedCtx = \bs -> + M.fromList + [ + ( typeRep (Proxy @(LengthOf T.Text)) + , SizeConstant $ fromIntegral $ T.length bs + ) + ] + } + ) + , + ( "[Bool]" + , sizeTest $ + scfg + { gen = listOf Gen.bool + , computedCtx = \bs -> + M.fromList + [ + ( typeRep (Proxy @(LengthOf [Bool])) + , SizeConstant $ fromIntegral $ length bs + ) + ] + , precise = True + } + ) + , + ( "NonEmpty Bool" + , sizeTest $ + scfg + { gen = listOf Gen.bool + , computedCtx = \bs -> + M.fromList + [ + ( typeRep (Proxy @(LengthOf [Bool])) + , SizeConstant $ fromIntegral $ length bs + ) + ] + , precise = True + } + ) + , + ( "Either Bool Bool" + , sizeTest $ + (scfg @(Either Bool Bool)) + { gen = Left <$> Gen.bool + , precise = True + } + ) + , + ( "Either Bool Bool" + , sizeTest $ + (scfg @(Either Bool Bool)) + { gen = Right <$> Gen.bool + , precise = True + } + ) + , ("Maybe Bool", sizeTest $ cfg {gen = Gen.bool, precise = True}) + ] diff --git a/cardano-binary/test/test.hs b/cardano-binary/test/test.hs index c11f2f626..784155f05 100644 --- a/cardano-binary/test/test.hs +++ b/cardano-binary/test/test.hs @@ -1,10 +1,10 @@ -import Prelude import Test.Cardano.Prelude (runTests) +import Prelude +import qualified Test.Cardano.Binary.Failure import qualified Test.Cardano.Binary.RoundTrip -import qualified Test.Cardano.Binary.SizeBounds import qualified Test.Cardano.Binary.Serialization -import qualified Test.Cardano.Binary.Failure +import qualified Test.Cardano.Binary.SizeBounds -- | Main testing action main :: IO () diff --git a/cardano-binary/testlib/Test/Cardano/Binary/TreeDiff.hs b/cardano-binary/testlib/Test/Cardano/Binary/TreeDiff.hs index e7441ed69..a77ca755e 100644 --- a/cardano-binary/testlib/Test/Cardano/Binary/TreeDiff.hs +++ b/cardano-binary/testlib/Test/Cardano/Binary/TreeDiff.hs @@ -1,7 +1,6 @@ +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} -{-# LANGUAGE LambdaCase #-} - {-# OPTIONS_GHC -Wno-orphans #-} module Test.Cardano.Binary.TreeDiff where @@ -9,11 +8,11 @@ module Test.Cardano.Binary.TreeDiff where import qualified Cardano.Binary as Plain import qualified Codec.CBOR.Read as CBOR import qualified Codec.CBOR.Term as CBOR +import Data.Bifunctor (bimap) import qualified Data.ByteString as BS import qualified Data.ByteString.Base16 as Base16 import qualified Data.ByteString.Char8 as BS8 import qualified Data.ByteString.Lazy as BSL -import Data.Bifunctor (bimap) import Data.TreeDiff import Formatting (build, formatToString) import qualified Formatting.Buildable as B (Buildable (..)) diff --git a/cardano-crypto-class/memory-example/Main.hs b/cardano-crypto-class/memory-example/Main.hs index f17068cf0..fc2835af8 100644 --- a/cardano-crypto-class/memory-example/Main.hs +++ b/cardano-crypto-class/memory-example/Main.hs @@ -1,10 +1,11 @@ {-# LANGUAGE CPP #-} -{-# LANGUAGE RankNTypes #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeApplications #-} - -- traceMLockedForeignPtr is deprecated {-# OPTIONS_GHC -Wno-deprecations #-} + +{- FOURMOLU_DISABLE -} module Main (main) where import Data.Proxy (Proxy (..)) diff --git a/cardano-crypto-class/src/Cardano/Crypto/DSIGN.hs b/cardano-crypto-class/src/Cardano/Crypto/DSIGN.hs index f82880315..23533a085 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/DSIGN.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/DSIGN.hs @@ -1,8 +1,9 @@ {-# LANGUAGE CPP #-} + -- | Digital signatures. -module Cardano.Crypto.DSIGN - ( module X - ) +module Cardano.Crypto.DSIGN ( + module X, +) where import Cardano.Crypto.DSIGN.Class as X diff --git a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Class.hs b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Class.hs index 76e656747..87a9a0bbb 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Class.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Class.hs @@ -12,53 +12,51 @@ {-# LANGUAGE UndecidableInstances #-} -- | Abstract digital signatures. -module Cardano.Crypto.DSIGN.Class - ( - -- * DSIGN algorithm class - DSIGNAlgorithm (..) - , Seed - , seedSizeDSIGN - , sizeVerKeyDSIGN - , sizeSignKeyDSIGN - , sizeSigDSIGN - - -- * MLocked DSIGN algorithm class - , DSIGNMAlgorithm (..) - - , genKeyDSIGNM - , cloneKeyDSIGNM - , getSeedDSIGNM - , forgetSignKeyDSIGNM - - -- * 'SignedDSIGN' wrapper - , SignedDSIGN (..) - , signedDSIGN - , verifySignedDSIGN - - -- * CBOR encoding and decoding - , encodeVerKeyDSIGN - , decodeVerKeyDSIGN - , encodeSignKeyDSIGN - , decodeSignKeyDSIGN - , encodeSigDSIGN - , decodeSigDSIGN - , encodeSignedDSIGN - , decodeSignedDSIGN - - -- * Encoded 'Size' expresssions - , encodedVerKeyDSIGNSizeExpr - , encodedSignKeyDSIGNSizeExpr - , encodedSigDSIGNSizeExpr +module Cardano.Crypto.DSIGN.Class ( + -- * DSIGN algorithm class + DSIGNAlgorithm (..), + Seed, + seedSizeDSIGN, + sizeVerKeyDSIGN, + sizeSignKeyDSIGN, + sizeSigDSIGN, + + -- * MLocked DSIGN algorithm class + DSIGNMAlgorithm (..), + genKeyDSIGNM, + cloneKeyDSIGNM, + getSeedDSIGNM, + forgetSignKeyDSIGNM, + + -- * 'SignedDSIGN' wrapper + SignedDSIGN (..), + signedDSIGN, + verifySignedDSIGN, + + -- * CBOR encoding and decoding + encodeVerKeyDSIGN, + decodeVerKeyDSIGN, + encodeSignKeyDSIGN, + decodeSignKeyDSIGN, + encodeSigDSIGN, + decodeSigDSIGN, + encodeSignedDSIGN, + decodeSignedDSIGN, + + -- * Encoded 'Size' expresssions + encodedVerKeyDSIGNSizeExpr, + encodedSignKeyDSIGNSizeExpr, + encodedSigDSIGNSizeExpr, -- * Helper - , failSizeCheck - - -- * Unsound CBOR encoding and decoding of MLocked DSIGN keys - , UnsoundDSIGNMAlgorithm (..) - , encodeSignKeyDSIGNM - , decodeSignKeyDSIGNM - , rawDeserialiseSignKeyDSIGNM - ) + failSizeCheck, + + -- * Unsound CBOR encoding and decoding of MLocked DSIGN keys + UnsoundDSIGNMAlgorithm (..), + encodeSignKeyDSIGNM, + decodeSignKeyDSIGNM, + rawDeserialiseSignKeyDSIGNM, +) where import Control.DeepSeq (NFData) @@ -67,54 +65,53 @@ import Control.Monad.Class.MonadThrow (MonadThrow) import Data.ByteString (ByteString) import qualified Data.ByteString as BS import Data.Kind (Type) -import Data.Proxy (Proxy(..)) +import Data.Proxy (Proxy (..)) import Data.Typeable (Typeable) import GHC.Exts (Constraint) import GHC.Generics (Generic) import GHC.Stack -import GHC.TypeLits (KnownNat, Nat, natVal, TypeError, ErrorMessage (..)) +import GHC.TypeLits (ErrorMessage (..), KnownNat, Nat, TypeError, natVal) import NoThunks.Class (NoThunks) -import Cardano.Binary (Decoder, decodeBytes, Encoding, encodeBytes, Size, withWordSize) +import Cardano.Binary (Decoder, Encoding, Size, decodeBytes, encodeBytes, withWordSize) -import Cardano.Crypto.Hash.Class (HashAlgorithm, Hash, hashWith) +import Cardano.Crypto.Hash.Class (Hash, HashAlgorithm, hashWith) import Cardano.Crypto.Libsodium (MLockedAllocator, mlockedMalloc) import Cardano.Crypto.Libsodium.MLockedSeed import Cardano.Crypto.Seed import Cardano.Crypto.Util (Empty) - - -- | The pure DSIGN API, which supports the full set of DSIGN operations, but -- does not allow for secure forgetting of private keys. -class ( Typeable v - , Show (VerKeyDSIGN v) - , Eq (VerKeyDSIGN v) - , Show (SignKeyDSIGN v) - , Show (SigDSIGN v) - , Eq (SigDSIGN v) - , NoThunks (SigDSIGN v) - , NoThunks (SignKeyDSIGN v) - , NoThunks (VerKeyDSIGN v) - , KnownNat (SeedSizeDSIGN v) - , KnownNat (SizeVerKeyDSIGN v) - , KnownNat (SizeSignKeyDSIGN v) - , KnownNat (SizeSigDSIGN v) - ) - => DSIGNAlgorithm v where - - type SeedSizeDSIGN v :: Nat - type SizeVerKeyDSIGN v :: Nat +class + ( Typeable v + , Show (VerKeyDSIGN v) + , Eq (VerKeyDSIGN v) + , Show (SignKeyDSIGN v) + , Show (SigDSIGN v) + , Eq (SigDSIGN v) + , NoThunks (SigDSIGN v) + , NoThunks (SignKeyDSIGN v) + , NoThunks (VerKeyDSIGN v) + , KnownNat (SeedSizeDSIGN v) + , KnownNat (SizeVerKeyDSIGN v) + , KnownNat (SizeSignKeyDSIGN v) + , KnownNat (SizeSigDSIGN v) + ) => + DSIGNAlgorithm v + where + type SeedSizeDSIGN v :: Nat + type SizeVerKeyDSIGN v :: Nat type SizeSignKeyDSIGN v :: Nat - type SizeSigDSIGN v :: Nat + type SizeSigDSIGN v :: Nat -- -- Key and signature types -- - data VerKeyDSIGN v :: Type + data VerKeyDSIGN v :: Type data SignKeyDSIGN v :: Type - data SigDSIGN v :: Type + data SigDSIGN v :: Type -- -- Metadata and basic key operations @@ -127,7 +124,6 @@ class ( Typeable v hashVerKeyDSIGN :: HashAlgorithm h => VerKeyDSIGN v -> Hash h (VerKeyDSIGN v) hashVerKeyDSIGN = hashWith rawSerialiseVerKeyDSIGN - -- -- Core algorithm operations -- @@ -136,26 +132,26 @@ class ( Typeable v -- -- Unit by default (no context required) type ContextDSIGN v :: Type + type ContextDSIGN v = () type Signable v :: Type -> Constraint type Signable v = Empty - signDSIGN - :: (Signable v a, HasCallStack) - => ContextDSIGN v - -> a - -> SignKeyDSIGN v - -> SigDSIGN v - - verifyDSIGN - :: (Signable v a, HasCallStack) - => ContextDSIGN v - -> VerKeyDSIGN v - -> a - -> SigDSIGN v - -> Either String () - + signDSIGN :: + (Signable v a, HasCallStack) => + ContextDSIGN v -> + a -> + SignKeyDSIGN v -> + SigDSIGN v + + verifyDSIGN :: + (Signable v a, HasCallStack) => + ContextDSIGN v -> + VerKeyDSIGN v -> + a -> + SigDSIGN v -> + Either String () -- -- Key generation @@ -170,40 +166,44 @@ class ( Typeable v -- Serialisation/(de)serialisation in fixed-size raw format -- - rawSerialiseVerKeyDSIGN :: VerKeyDSIGN v -> ByteString - rawSerialiseSignKeyDSIGN :: SignKeyDSIGN v -> ByteString - rawSerialiseSigDSIGN :: SigDSIGN v -> ByteString + rawSerialiseVerKeyDSIGN :: VerKeyDSIGN v -> ByteString + rawSerialiseSignKeyDSIGN :: SignKeyDSIGN v -> ByteString + rawSerialiseSigDSIGN :: SigDSIGN v -> ByteString - rawDeserialiseVerKeyDSIGN :: ByteString -> Maybe (VerKeyDSIGN v) + rawDeserialiseVerKeyDSIGN :: ByteString -> Maybe (VerKeyDSIGN v) rawDeserialiseSignKeyDSIGN :: ByteString -> Maybe (SignKeyDSIGN v) - rawDeserialiseSigDSIGN :: ByteString -> Maybe (SigDSIGN v) + rawDeserialiseSigDSIGN :: ByteString -> Maybe (SigDSIGN v) -- -- Do not provide Ord instances for keys, see #38 -- -instance ( TypeError ('Text "Ord not supported for signing keys, use the hash instead") - , Eq (SignKeyDSIGN v) - ) - => Ord (SignKeyDSIGN v) where - compare = error "unsupported" +instance + ( TypeError ('Text "Ord not supported for signing keys, use the hash instead") + , Eq (SignKeyDSIGN v) + ) => + Ord (SignKeyDSIGN v) + where + compare = error "unsupported" -instance ( TypeError ('Text "Ord not supported for verification keys, use the hash instead") - , Eq (VerKeyDSIGN v) - ) - => Ord (VerKeyDSIGN v) where - compare = error "unsupported" +instance + ( TypeError ('Text "Ord not supported for verification keys, use the hash instead") + , Eq (VerKeyDSIGN v) + ) => + Ord (VerKeyDSIGN v) + where + compare = error "unsupported" -- | The upper bound on the 'Seed' size needed by 'genKeyDSIGN' seedSizeDSIGN :: forall v proxy. DSIGNAlgorithm v => proxy v -> Word seedSizeDSIGN _ = fromInteger (natVal (Proxy @(SeedSizeDSIGN v))) -sizeVerKeyDSIGN :: forall v proxy. DSIGNAlgorithm v => proxy v -> Word -sizeVerKeyDSIGN _ = fromInteger (natVal (Proxy @(SizeVerKeyDSIGN v))) -sizeSignKeyDSIGN :: forall v proxy. DSIGNAlgorithm v => proxy v -> Word +sizeVerKeyDSIGN :: forall v proxy. DSIGNAlgorithm v => proxy v -> Word +sizeVerKeyDSIGN _ = fromInteger (natVal (Proxy @(SizeVerKeyDSIGN v))) +sizeSignKeyDSIGN :: forall v proxy. DSIGNAlgorithm v => proxy v -> Word sizeSignKeyDSIGN _ = fromInteger (natVal (Proxy @(SizeSignKeyDSIGN v))) -sizeSigDSIGN :: forall v proxy. DSIGNAlgorithm v => proxy v -> Word -sizeSigDSIGN _ = fromInteger (natVal (Proxy @(SizeSigDSIGN v))) +sizeSigDSIGN :: forall v proxy. DSIGNAlgorithm v => proxy v -> Word +sizeSigDSIGN _ = fromInteger (natVal (Proxy @(SizeSigDSIGN v))) -- -- Convenient CBOR encoding/decoding @@ -261,31 +261,32 @@ failSizeCheck fname name bs expectedSize {-# NOINLINE failSizeCheck #-} newtype SignedDSIGN v a = SignedDSIGN (SigDSIGN v) - deriving Generic + deriving (Generic) deriving instance DSIGNAlgorithm v => Show (SignedDSIGN v a) -deriving instance DSIGNAlgorithm v => Eq (SignedDSIGN v a) +deriving instance DSIGNAlgorithm v => Eq (SignedDSIGN v a) deriving instance NFData (SigDSIGN v) => NFData (SignedDSIGN v a) instance DSIGNAlgorithm v => NoThunks (SignedDSIGN v a) - -- use generic instance - -signedDSIGN - :: (DSIGNAlgorithm v, Signable v a) - => ContextDSIGN v - -> a - -> SignKeyDSIGN v - -> SignedDSIGN v a + +-- use generic instance + +signedDSIGN :: + (DSIGNAlgorithm v, Signable v a) => + ContextDSIGN v -> + a -> + SignKeyDSIGN v -> + SignedDSIGN v a signedDSIGN ctxt a key = SignedDSIGN (signDSIGN ctxt a key) -verifySignedDSIGN - :: (DSIGNAlgorithm v, Signable v a, HasCallStack) - => ContextDSIGN v - -> VerKeyDSIGN v - -> a - -> SignedDSIGN v a - -> Either String () +verifySignedDSIGN :: + (DSIGNAlgorithm v, Signable v a, HasCallStack) => + ContextDSIGN v -> + VerKeyDSIGN v -> + a -> + SignedDSIGN v a -> + Either String () verifySignedDSIGN ctxt key a (SignedDSIGN s) = verifyDSIGN ctxt key a s encodeSignedDSIGN :: DSIGNAlgorithm v => SignedDSIGN v a -> Encoding @@ -301,36 +302,32 @@ decodeSignedDSIGN = SignedDSIGN <$> decodeSigDSIGN -- | 'Size' expression for 'VerKeyDSIGN' which is using 'sizeVerKeyDSIGN' -- encoded as 'Size'. --- encodedVerKeyDSIGNSizeExpr :: forall v. DSIGNAlgorithm v => Proxy (VerKeyDSIGN v) -> Size encodedVerKeyDSIGNSizeExpr _proxy = - -- 'encodeBytes' envelope - fromIntegral ((withWordSize :: Word -> Integer) (sizeVerKeyDSIGN (Proxy :: Proxy v))) - -- payload + -- 'encodeBytes' envelope + fromIntegral ((withWordSize :: Word -> Integer) (sizeVerKeyDSIGN (Proxy :: Proxy v))) + -- payload + fromIntegral (sizeVerKeyDSIGN (Proxy :: Proxy v)) -- | 'Size' expression for 'SignKeyDSIGN' which is using 'sizeSignKeyDSIGN' -- encoded as 'Size'. --- encodedSignKeyDSIGNSizeExpr :: forall v. DSIGNAlgorithm v => Proxy (SignKeyDSIGN v) -> Size encodedSignKeyDSIGNSizeExpr _proxy = - -- 'encodeBytes' envelope - fromIntegral ((withWordSize :: Word -> Integer) (sizeSignKeyDSIGN (Proxy :: Proxy v))) - -- payload + -- 'encodeBytes' envelope + fromIntegral ((withWordSize :: Word -> Integer) (sizeSignKeyDSIGN (Proxy :: Proxy v))) + -- payload + fromIntegral (sizeSignKeyDSIGN (Proxy :: Proxy v)) -- | 'Size' expression for 'SigDSIGN' which is using 'sizeSigDSIGN' encoded as -- 'Size'. --- encodedSigDSIGNSizeExpr :: forall v. DSIGNAlgorithm v => Proxy (SigDSIGN v) -> Size encodedSigDSIGNSizeExpr _proxy = - -- 'encodeBytes' envelope - fromIntegral ((withWordSize :: Word -> Integer) (sizeSigDSIGN (Proxy :: Proxy v))) - -- payload + -- 'encodeBytes' envelope + fromIntegral ((withWordSize :: Word -> Integer) (sizeSigDSIGN (Proxy :: Proxy v))) + -- payload + fromIntegral (sizeSigDSIGN (Proxy :: Proxy v)) class (DSIGNAlgorithm v, NoThunks (SignKeyDSIGNM v)) => DSIGNMAlgorithm v where - data SignKeyDSIGNM v :: Type deriveVerKeyDSIGNM :: (MonadThrow m, MonadST m) => SignKeyDSIGNM v -> m (VerKeyDSIGN v) @@ -339,45 +336,46 @@ class (DSIGNAlgorithm v, NoThunks (SignKeyDSIGNM v)) => DSIGNMAlgorithm v where -- Core algorithm operations -- - signDSIGNM - :: (Signable v a, MonadST m, MonadThrow m) - => ContextDSIGN v - -> a - -> SignKeyDSIGNM v - -> m (SigDSIGN v) + signDSIGNM :: + (Signable v a, MonadST m, MonadThrow m) => + ContextDSIGN v -> + a -> + SignKeyDSIGNM v -> + m (SigDSIGN v) -- -- Key generation -- - genKeyDSIGNMWith :: (MonadST m, MonadThrow m) - => MLockedAllocator m - -> MLockedSeed (SeedSizeDSIGN v) - -> m (SignKeyDSIGNM v) + genKeyDSIGNMWith :: + (MonadST m, MonadThrow m) => + MLockedAllocator m -> + MLockedSeed (SeedSizeDSIGN v) -> + m (SignKeyDSIGNM v) cloneKeyDSIGNMWith :: MonadST m => MLockedAllocator m -> SignKeyDSIGNM v -> m (SignKeyDSIGNM v) - getSeedDSIGNMWith :: (MonadST m, MonadThrow m) - => MLockedAllocator m - -> Proxy v - -> SignKeyDSIGNM v - -> m (MLockedSeed (SeedSizeDSIGN v)) + getSeedDSIGNMWith :: + (MonadST m, MonadThrow m) => + MLockedAllocator m -> + Proxy v -> + SignKeyDSIGNM v -> + m (MLockedSeed (SeedSizeDSIGN v)) -- -- Secure forgetting -- - forgetSignKeyDSIGNMWith :: (MonadST m, MonadThrow m) => MLockedAllocator m -> SignKeyDSIGNM v -> m () - + forgetSignKeyDSIGNMWith :: + (MonadST m, MonadThrow m) => MLockedAllocator m -> SignKeyDSIGNM v -> m () forgetSignKeyDSIGNM :: (DSIGNMAlgorithm v, MonadST m, MonadThrow m) => SignKeyDSIGNM v -> m () forgetSignKeyDSIGNM = forgetSignKeyDSIGNMWith mlockedMalloc - genKeyDSIGNM :: - (DSIGNMAlgorithm v, MonadST m, MonadThrow m) - => MLockedSeed (SeedSizeDSIGN v) - -> m (SignKeyDSIGNM v) + (DSIGNMAlgorithm v, MonadST m, MonadThrow m) => + MLockedSeed (SeedSizeDSIGN v) -> + m (SignKeyDSIGNM v) genKeyDSIGNM = genKeyDSIGNMWith mlockedMalloc cloneKeyDSIGNM :: @@ -385,13 +383,12 @@ cloneKeyDSIGNM :: cloneKeyDSIGNM = cloneKeyDSIGNMWith mlockedMalloc getSeedDSIGNM :: - (DSIGNMAlgorithm v, MonadST m, MonadThrow m) - => Proxy v - -> SignKeyDSIGNM v - -> m (MLockedSeed (SeedSizeDSIGN v)) + (DSIGNMAlgorithm v, MonadST m, MonadThrow m) => + Proxy v -> + SignKeyDSIGNM v -> + m (MLockedSeed (SeedSizeDSIGN v)) getSeedDSIGNM = getSeedDSIGNMWith mlockedMalloc - -- | Unsound operations on DSIGNM sign keys. These operations violate secure -- forgetting constraints by leaking secrets to unprotected memory. Consider -- using the 'DirectSerialise' / 'DirectDeserialise' APIs instead. @@ -407,22 +404,23 @@ class DSIGNMAlgorithm v => UnsoundDSIGNMAlgorithm v where (MonadST m, MonadThrow m) => MLockedAllocator m -> ByteString -> m (Maybe (SignKeyDSIGNM v)) rawDeserialiseSignKeyDSIGNM :: - (UnsoundDSIGNMAlgorithm v, MonadST m, MonadThrow m) - => ByteString - -> m (Maybe (SignKeyDSIGNM v)) + (UnsoundDSIGNMAlgorithm v, MonadST m, MonadThrow m) => + ByteString -> + m (Maybe (SignKeyDSIGNM v)) rawDeserialiseSignKeyDSIGNM = rawDeserialiseSignKeyDSIGNMWith mlockedMalloc - -- -- Do not provide Ord instances for keys, see #38 -- -instance ( TypeError ('Text "Ord not supported for signing keys, use the hash instead") - , Eq (SignKeyDSIGNM v) - ) - => Ord (SignKeyDSIGNM v) where - compare = error "unsupported" +instance + ( TypeError ('Text "Ord not supported for signing keys, use the hash instead") + , Eq (SignKeyDSIGNM v) + ) => + Ord (SignKeyDSIGNM v) + where + compare = error "unsupported" -- -- Convenient CBOR encoding/decoding @@ -431,23 +429,29 @@ instance ( TypeError ('Text "Ord not supported for signing keys, use the hash in -- encodeSignKeyDSIGNM :: - (UnsoundDSIGNMAlgorithm v, MonadST m, MonadThrow m) - => SignKeyDSIGNM v - -> m Encoding + (UnsoundDSIGNMAlgorithm v, MonadST m, MonadThrow m) => + SignKeyDSIGNM v -> + m Encoding encodeSignKeyDSIGNM = fmap encodeBytes . rawSerialiseSignKeyDSIGNM -decodeSignKeyDSIGNM :: forall m v s - . (UnsoundDSIGNMAlgorithm v, MonadST m, MonadThrow m) - => Decoder s (m (SignKeyDSIGNM v)) +decodeSignKeyDSIGNM :: + forall m v s. + (UnsoundDSIGNMAlgorithm v, MonadST m, MonadThrow m) => + Decoder s (m (SignKeyDSIGNM v)) decodeSignKeyDSIGNM = do - bs <- decodeBytes - return $ rawDeserialiseSignKeyDSIGNM bs >>= \case + bs <- decodeBytes + return $ + rawDeserialiseSignKeyDSIGNM bs >>= \case Just vk -> return vk Nothing - | actual /= expected - -> error ("decodeSignKeyDSIGNM: wrong length, expected " ++ - show expected ++ " bytes but got " ++ show actual) + | actual /= expected -> + error + ( "decodeSignKeyDSIGNM: wrong length, expected " + ++ show expected + ++ " bytes but got " + ++ show actual + ) | otherwise -> error "decodeSignKeyDSIGNM: cannot decode key" where expected = fromIntegral (sizeSignKeyDSIGN (Proxy :: Proxy v)) - actual = BS.length bs + actual = BS.length bs diff --git a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/EcdsaSecp256k1.hs b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/EcdsaSecp256k1.hs index efc06f839..0765bd0bb 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/EcdsaSecp256k1.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/EcdsaSecp256k1.hs @@ -1,14 +1,14 @@ -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingVia #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE RankNTypes #-} -{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -- Needed to ensure that our hash is the right size {-# OPTIONS_GHC -Wno-redundant-constraints #-} @@ -32,85 +32,87 @@ module Cardano.Crypto.DSIGN.EcdsaSecp256k1 ( EcdsaSecp256k1DSIGN, VerKeyDSIGN (..), SignKeyDSIGN (..), - SigDSIGN (..) - ) where + SigDSIGN (..), +) where -import Foreign.ForeignPtr (withForeignPtr) -import Foreign.Storable (poke, peek) -import Foreign.C.Types (CSize) -import Foreign.Marshal.Alloc (alloca) -import Foreign.Ptr (castPtr, nullPtr, Ptr) -import Control.Monad (when, void, unless) -import Cardano.Crypto.Hash.Class (HashAlgorithm (SizeHash, digest)) -import Data.Proxy (Proxy) -import Cardano.Binary (FromCBOR (fromCBOR), ToCBOR (toCBOR, encodedSizeExpr)) -import Data.ByteString (ByteString) -import Crypto.Random (getRandomBytes) -import Cardano.Crypto.Seed (runMonadRandomWithSeed) -import Data.Kind (Type) -import GHC.Generics (Generic) -import Control.DeepSeq (NFData) -import NoThunks.Class (NoThunks) +import Cardano.Binary (FromCBOR (fromCBOR), ToCBOR (encodedSizeExpr, toCBOR)) import Cardano.Crypto.DSIGN.Class ( - DSIGNAlgorithm (VerKeyDSIGN, - SignKeyDSIGN, - SigDSIGN, - SeedSizeDSIGN, - SizeSigDSIGN, - SizeSignKeyDSIGN, - SizeVerKeyDSIGN, - algorithmNameDSIGN, - deriveVerKeyDSIGN, - signDSIGN, - verifyDSIGN, - genKeyDSIGN, - rawSerialiseSigDSIGN, - Signable, - rawSerialiseVerKeyDSIGN, - rawSerialiseSignKeyDSIGN, - rawDeserialiseVerKeyDSIGN, - rawDeserialiseSignKeyDSIGN, - rawDeserialiseSigDSIGN), - encodeVerKeyDSIGN, - encodedVerKeyDSIGNSizeExpr, - decodeVerKeyDSIGN, - encodeSignKeyDSIGN, - encodedSignKeyDSIGNSizeExpr, + DSIGNAlgorithm ( + SeedSizeDSIGN, + SigDSIGN, + SignKeyDSIGN, + Signable, + SizeSigDSIGN, + SizeSignKeyDSIGN, + SizeVerKeyDSIGN, + VerKeyDSIGN, + algorithmNameDSIGN, + deriveVerKeyDSIGN, + genKeyDSIGN, + rawDeserialiseSigDSIGN, + rawDeserialiseSignKeyDSIGN, + rawDeserialiseVerKeyDSIGN, + rawSerialiseSigDSIGN, + rawSerialiseSignKeyDSIGN, + rawSerialiseVerKeyDSIGN, + signDSIGN, + verifyDSIGN + ), + decodeSigDSIGN, decodeSignKeyDSIGN, + decodeVerKeyDSIGN, encodeSigDSIGN, + encodeSignKeyDSIGN, + encodeVerKeyDSIGN, encodedSigDSIGNSizeExpr, - decodeSigDSIGN - ) -import Cardano.Crypto.SECP256K1.Constants ( - SECP256K1_ECDSA_PRIVKEY_BYTES, - SECP256K1_ECDSA_SIGNATURE_BYTES, - SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL, - SECP256K1_ECDSA_PUBKEY_BYTES, - SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL, - SECP256K1_ECDSA_MESSAGE_BYTES, - ) + encodedSignKeyDSIGNSizeExpr, + encodedVerKeyDSIGNSizeExpr, + ) +import Cardano.Crypto.Hash.Class (HashAlgorithm (SizeHash, digest)) import Cardano.Crypto.PinnedSizedBytes ( PinnedSizedBytes, - psbUseAsSizedPtr, + psbCreateLen, psbCreateSized, + psbCreateSizedResult, psbFromByteStringCheck, psbToByteString, - psbCreateLen, - psbCreateSizedResult, psbUseAsCPtrLen, - ) -import System.IO.Unsafe (unsafeDupablePerformIO) + psbUseAsSizedPtr, + ) import Cardano.Crypto.SECP256K1.C ( - secpEcPubkeyCreate, secpCtxPtr, - secpEcdsaSign, - secpEcdsaVerify, - secpEcdsaSignatureSerializeCompact, - secpEcPubkeySerialize, secpEcCompressed, - secpEcdsaSignatureParseCompact, + secpEcPubkeyCreate, secpEcPubkeyParse, - ) + secpEcPubkeySerialize, + secpEcdsaSign, + secpEcdsaSignatureParseCompact, + secpEcdsaSignatureSerializeCompact, + secpEcdsaVerify, + ) +import Cardano.Crypto.SECP256K1.Constants ( + SECP256K1_ECDSA_MESSAGE_BYTES, + SECP256K1_ECDSA_PRIVKEY_BYTES, + SECP256K1_ECDSA_PUBKEY_BYTES, + SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL, + SECP256K1_ECDSA_SIGNATURE_BYTES, + SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL, + ) +import Cardano.Crypto.Seed (runMonadRandomWithSeed) +import Control.DeepSeq (NFData) +import Control.Monad (unless, void, when) +import Crypto.Random (getRandomBytes) +import Data.ByteString (ByteString) +import Data.Kind (Type) +import Data.Proxy (Proxy) +import Foreign.C.Types (CSize) +import Foreign.ForeignPtr (withForeignPtr) +import Foreign.Marshal.Alloc (alloca) +import Foreign.Ptr (Ptr, castPtr, nullPtr) +import Foreign.Storable (peek, poke) +import GHC.Generics (Generic) +import NoThunks.Class (NoThunks) +import System.IO.Unsafe (unsafeDupablePerformIO) -- | As ECDSA signatures on the SECP256k1 curve sign 32-byte hashes, rather than -- whole messages, we provide a helper (opaque) newtype to ensure that the size @@ -123,8 +125,8 @@ import Cardano.Crypto.SECP256K1.C ( -- give you the message itself to verify, rather than the hash of the message -- used to compute the signature. newtype MessageHash = MH (PinnedSizedBytes SECP256K1_ECDSA_MESSAGE_BYTES) - deriving Eq via (PinnedSizedBytes SECP256K1_ECDSA_MESSAGE_BYTES) - deriving stock Show + deriving (Eq) via (PinnedSizedBytes SECP256K1_ECDSA_MESSAGE_BYTES) + deriving stock (Show) -- | Take a blob of bytes (which is presumed to be a 32-byte hash), verify its -- length, and package it into a 'MessageHash' if that length is exactly 32. @@ -136,133 +138,140 @@ fromMessageHash :: MessageHash -> ByteString fromMessageHash (MH psb) = psbToByteString psb -- | A helper to use with the 'HashAlgorithm' API, as this can ensure sizing. -hashAndPack :: forall (h :: Type) . +hashAndPack :: + forall (h :: Type). (HashAlgorithm h, SizeHash h ~ SECP256K1_ECDSA_MESSAGE_BYTES) => Proxy h -> ByteString -> MessageHash hashAndPack p bs = case psbFromByteStringCheck . digest p $ bs of - Nothing -> error $ "hashAndPack: unexpected mismatch of guaranteed hash length\n" <> - "Please report this, it's a bug!" + Nothing -> + error $ + "hashAndPack: unexpected mismatch of guaranteed hash length\n" + <> "Please report this, it's a bug!" Just psb -> MH psb data EcdsaSecp256k1DSIGN instance DSIGNAlgorithm EcdsaSecp256k1DSIGN where - type SeedSizeDSIGN EcdsaSecp256k1DSIGN = SECP256K1_ECDSA_PRIVKEY_BYTES - type SizeSigDSIGN EcdsaSecp256k1DSIGN = SECP256K1_ECDSA_SIGNATURE_BYTES - type SizeSignKeyDSIGN EcdsaSecp256k1DSIGN = SECP256K1_ECDSA_PRIVKEY_BYTES - type SizeVerKeyDSIGN EcdsaSecp256k1DSIGN = SECP256K1_ECDSA_PUBKEY_BYTES - type Signable EcdsaSecp256k1DSIGN = ((~) MessageHash) - newtype VerKeyDSIGN EcdsaSecp256k1DSIGN = - VerKeyEcdsaSecp256k1 (PinnedSizedBytes SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL) - deriving newtype (Eq, NFData) - deriving stock (Show, Generic) - deriving anyclass (NoThunks) - newtype SignKeyDSIGN EcdsaSecp256k1DSIGN = - SignKeyEcdsaSecp256k1 (PinnedSizedBytes SECP256K1_ECDSA_PRIVKEY_BYTES) - deriving newtype (Eq, NFData) - deriving stock (Show, Generic) - deriving anyclass (NoThunks) - newtype SigDSIGN EcdsaSecp256k1DSIGN = - SigEcdsaSecp256k1 (PinnedSizedBytes SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL) - deriving newtype (Eq, NFData) - deriving stock (Show, Generic) - deriving anyclass (NoThunks) - algorithmNameDSIGN _ = "ecdsa-secp256k1" - {-# NOINLINE deriveVerKeyDSIGN #-} - deriveVerKeyDSIGN (SignKeyEcdsaSecp256k1 skBytes) = - VerKeyEcdsaSecp256k1 <$> unsafeDupablePerformIO . psbUseAsSizedPtr skBytes $ - \skp -> psbCreateSized $ \vkp -> + type SeedSizeDSIGN EcdsaSecp256k1DSIGN = SECP256K1_ECDSA_PRIVKEY_BYTES + type SizeSigDSIGN EcdsaSecp256k1DSIGN = SECP256K1_ECDSA_SIGNATURE_BYTES + type SizeSignKeyDSIGN EcdsaSecp256k1DSIGN = SECP256K1_ECDSA_PRIVKEY_BYTES + type SizeVerKeyDSIGN EcdsaSecp256k1DSIGN = SECP256K1_ECDSA_PUBKEY_BYTES + type Signable EcdsaSecp256k1DSIGN = ((~) MessageHash) + newtype VerKeyDSIGN EcdsaSecp256k1DSIGN + = VerKeyEcdsaSecp256k1 (PinnedSizedBytes SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL) + deriving newtype (Eq, NFData) + deriving stock (Show, Generic) + deriving anyclass (NoThunks) + newtype SignKeyDSIGN EcdsaSecp256k1DSIGN + = SignKeyEcdsaSecp256k1 (PinnedSizedBytes SECP256K1_ECDSA_PRIVKEY_BYTES) + deriving newtype (Eq, NFData) + deriving stock (Show, Generic) + deriving anyclass (NoThunks) + newtype SigDSIGN EcdsaSecp256k1DSIGN + = SigEcdsaSecp256k1 (PinnedSizedBytes SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL) + deriving newtype (Eq, NFData) + deriving stock (Show, Generic) + deriving anyclass (NoThunks) + algorithmNameDSIGN _ = "ecdsa-secp256k1" + {-# NOINLINE deriveVerKeyDSIGN #-} + deriveVerKeyDSIGN (SignKeyEcdsaSecp256k1 skBytes) = + VerKeyEcdsaSecp256k1 <$> unsafeDupablePerformIO . psbUseAsSizedPtr skBytes $ + \skp -> psbCreateSized $ \vkp -> + withForeignPtr secpCtxPtr $ \ctx -> do + res <- secpEcPubkeyCreate ctx vkp skp + when + (res /= 1) + (error "deriveVerKeyDSIGN: Failed to derive VerKeyDSIGN EcdsaSecp256k1DSIGN") + {-# NOINLINE signDSIGN #-} + signDSIGN () (MH psb) (SignKeyEcdsaSecp256k1 skBytes) = + SigEcdsaSecp256k1 <$> unsafeDupablePerformIO . psbUseAsSizedPtr psb $ \psp -> do + psbUseAsSizedPtr skBytes $ \skp -> + psbCreateSized $ \sigp -> + withForeignPtr secpCtxPtr $ \ctx -> do + -- The two nullPtr arguments correspond to nonces and extra nonce + -- data. We use neither, so we pass nullPtrs to indicate this to the + -- C API. + res <- secpEcdsaSign ctx sigp psp skp nullPtr nullPtr + when + (res /= 1) + (error "signDSIGN: Failed to sign EcdsaSecp256k1DSIGN message") + {-# NOINLINE verifyDSIGN #-} + verifyDSIGN () (VerKeyEcdsaSecp256k1 vkBytes) (MH psb) (SigEcdsaSecp256k1 sigBytes) = + unsafeDupablePerformIO . psbUseAsSizedPtr psb $ \psp -> do + psbUseAsSizedPtr sigBytes $ \sigp -> + psbUseAsSizedPtr vkBytes $ \vkp -> + withForeignPtr secpCtxPtr $ \ctx -> do + let res = secpEcdsaVerify ctx sigp psp vkp + pure $ case res of + 0 -> Left "verifyDSIGN: Incorrect or unparseable SigDSIGN EcdsaSecp256k1DSIGN" + _ -> Right () + genKeyDSIGN seed = runMonadRandomWithSeed seed $ do + bs <- getRandomBytes 32 + case psbFromByteStringCheck bs of + Nothing -> error "genKeyDSIGN: Failed to generate SignKeyDSIGN EcdsaSecp256k1DSIGN unexpectedly" + Just psb -> pure $ SignKeyEcdsaSecp256k1 psb + {-# NOINLINE rawSerialiseSigDSIGN #-} + rawSerialiseSigDSIGN (SigEcdsaSecp256k1 psb) = + psbToByteString @SECP256K1_ECDSA_SIGNATURE_BYTES . unsafeDupablePerformIO $ do + psbUseAsSizedPtr psb $ \psp -> + psbCreateSized $ \dstp -> + withForeignPtr secpCtxPtr $ \ctx -> + void $ secpEcdsaSignatureSerializeCompact ctx dstp psp + {-# NOINLINE rawSerialiseVerKeyDSIGN #-} + rawSerialiseVerKeyDSIGN (VerKeyEcdsaSecp256k1 psb) = + psbToByteString . unsafeDupablePerformIO . psbUseAsSizedPtr psb $ \psp -> + psbCreateLen @SECP256K1_ECDSA_PUBKEY_BYTES $ \ptr len -> do + let dstp = castPtr ptr + -- This is necessary because of how the C API handles checking writes: + -- maximum permissible length is given as a pointer, which is + -- overwritten to indicate the number of bytes we actually wrote; if + -- we get a mismatch, then the serialization failed. While an odd + -- choice, we have to go with it. + alloca $ \(lenPtr :: Ptr CSize) -> do + poke lenPtr len withForeignPtr secpCtxPtr $ \ctx -> do - res <- secpEcPubkeyCreate ctx vkp skp - when (res /= 1) - (error "deriveVerKeyDSIGN: Failed to derive VerKeyDSIGN EcdsaSecp256k1DSIGN") - {-# NOINLINE signDSIGN #-} - signDSIGN () (MH psb) (SignKeyEcdsaSecp256k1 skBytes) = - SigEcdsaSecp256k1 <$> unsafeDupablePerformIO . psbUseAsSizedPtr psb $ \psp -> do - psbUseAsSizedPtr skBytes $ \skp -> - psbCreateSized $ \sigp -> - withForeignPtr secpCtxPtr $ \ctx -> do - -- The two nullPtr arguments correspond to nonces and extra nonce - -- data. We use neither, so we pass nullPtrs to indicate this to the - -- C API. - res <- secpEcdsaSign ctx sigp psp skp nullPtr nullPtr - when (res /= 1) - (error "signDSIGN: Failed to sign EcdsaSecp256k1DSIGN message") - {-# NOINLINE verifyDSIGN #-} - verifyDSIGN () (VerKeyEcdsaSecp256k1 vkBytes) (MH psb) (SigEcdsaSecp256k1 sigBytes) = - unsafeDupablePerformIO . psbUseAsSizedPtr psb $ \psp -> do - psbUseAsSizedPtr sigBytes $ \sigp -> - psbUseAsSizedPtr vkBytes $ \vkp -> - withForeignPtr secpCtxPtr $ \ctx -> do - let res = secpEcdsaVerify ctx sigp psp vkp - pure $ case res of - 0 -> Left "verifyDSIGN: Incorrect or unparseable SigDSIGN EcdsaSecp256k1DSIGN" - _ -> Right () - genKeyDSIGN seed = runMonadRandomWithSeed seed $ do - bs <- getRandomBytes 32 - case psbFromByteStringCheck bs of - Nothing -> error "genKeyDSIGN: Failed to generate SignKeyDSIGN EcdsaSecp256k1DSIGN unexpectedly" - Just psb -> pure $ SignKeyEcdsaSecp256k1 psb - {-# NOINLINE rawSerialiseSigDSIGN #-} - rawSerialiseSigDSIGN (SigEcdsaSecp256k1 psb) = - psbToByteString @SECP256K1_ECDSA_SIGNATURE_BYTES . unsafeDupablePerformIO $ do - psbUseAsSizedPtr psb $ \psp -> - psbCreateSized $ \dstp -> - withForeignPtr secpCtxPtr $ \ctx -> - void $ secpEcdsaSignatureSerializeCompact ctx dstp psp - {-# NOINLINE rawSerialiseVerKeyDSIGN #-} - rawSerialiseVerKeyDSIGN (VerKeyEcdsaSecp256k1 psb) = - psbToByteString . unsafeDupablePerformIO . psbUseAsSizedPtr psb $ \psp -> - psbCreateLen @SECP256K1_ECDSA_PUBKEY_BYTES $ \ptr len -> do - let dstp = castPtr ptr - -- This is necessary because of how the C API handles checking writes: - -- maximum permissible length is given as a pointer, which is - -- overwritten to indicate the number of bytes we actually wrote; if - -- we get a mismatch, then the serialization failed. While an odd - -- choice, we have to go with it. - alloca $ \(lenPtr :: Ptr CSize) -> do - poke lenPtr len - withForeignPtr secpCtxPtr $ \ctx -> do - ret <- secpEcPubkeySerialize ctx dstp lenPtr psp secpEcCompressed - writtenLen <- peek lenPtr - unless (writtenLen == len) - (error "rawSerializeVerKeyDSIGN: Did not write correct length for VerKeyDSIGN EcdsaSecp256k1DSIGN") - -- This should never happen, since `secpEcPubkeySerialize` in the current - -- version of `secp256k1` library always returns 1: - unless (ret == 1) - (error "rawSerializeVerKeyDSIGN: Failed for unknown reason") - rawSerialiseSignKeyDSIGN (SignKeyEcdsaSecp256k1 psb) = psbToByteString psb - {-# NOINLINE rawDeserialiseSigDSIGN #-} - rawDeserialiseSigDSIGN bs = - SigEcdsaSecp256k1 <$> (psbFromByteStringCheck bs >>= go) - where - go :: - PinnedSizedBytes SECP256K1_ECDSA_SIGNATURE_BYTES -> - Maybe (PinnedSizedBytes SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL) - go psb = unsafeDupablePerformIO . psbUseAsSizedPtr psb $ \psp -> do - (sigPsb, res) <- psbCreateSizedResult $ \sigp -> - withForeignPtr secpCtxPtr $ \ctx -> - secpEcdsaSignatureParseCompact ctx sigp psp - pure $ case res of - 1 -> pure sigPsb - _ -> Nothing - {-# NOINLINE rawDeserialiseVerKeyDSIGN #-} - rawDeserialiseVerKeyDSIGN bs = - VerKeyEcdsaSecp256k1 <$> (psbFromByteStringCheck bs >>= go) - where - go :: - PinnedSizedBytes SECP256K1_ECDSA_PUBKEY_BYTES -> - Maybe (PinnedSizedBytes SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL) - go psb = unsafeDupablePerformIO . psbUseAsCPtrLen psb $ \p srcLen -> do - let srcp = castPtr p - (vkPsb, res) <- psbCreateSizedResult $ \vkp -> - withForeignPtr secpCtxPtr $ \ctx -> - secpEcPubkeyParse ctx vkp srcp srcLen - pure $ case res of - 1 -> pure vkPsb - _ -> Nothing - rawDeserialiseSignKeyDSIGN bs = - SignKeyEcdsaSecp256k1 <$> psbFromByteStringCheck bs + ret <- secpEcPubkeySerialize ctx dstp lenPtr psp secpEcCompressed + writtenLen <- peek lenPtr + unless + (writtenLen == len) + (error "rawSerializeVerKeyDSIGN: Did not write correct length for VerKeyDSIGN EcdsaSecp256k1DSIGN") + -- This should never happen, since `secpEcPubkeySerialize` in the current + -- version of `secp256k1` library always returns 1: + unless + (ret == 1) + (error "rawSerializeVerKeyDSIGN: Failed for unknown reason") + rawSerialiseSignKeyDSIGN (SignKeyEcdsaSecp256k1 psb) = psbToByteString psb + {-# NOINLINE rawDeserialiseSigDSIGN #-} + rawDeserialiseSigDSIGN bs = + SigEcdsaSecp256k1 <$> (psbFromByteStringCheck bs >>= go) + where + go :: + PinnedSizedBytes SECP256K1_ECDSA_SIGNATURE_BYTES -> + Maybe (PinnedSizedBytes SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL) + go psb = unsafeDupablePerformIO . psbUseAsSizedPtr psb $ \psp -> do + (sigPsb, res) <- psbCreateSizedResult $ \sigp -> + withForeignPtr secpCtxPtr $ \ctx -> + secpEcdsaSignatureParseCompact ctx sigp psp + pure $ case res of + 1 -> pure sigPsb + _ -> Nothing + {-# NOINLINE rawDeserialiseVerKeyDSIGN #-} + rawDeserialiseVerKeyDSIGN bs = + VerKeyEcdsaSecp256k1 <$> (psbFromByteStringCheck bs >>= go) + where + go :: + PinnedSizedBytes SECP256K1_ECDSA_PUBKEY_BYTES -> + Maybe (PinnedSizedBytes SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL) + go psb = unsafeDupablePerformIO . psbUseAsCPtrLen psb $ \p srcLen -> do + let srcp = castPtr p + (vkPsb, res) <- psbCreateSizedResult $ \vkp -> + withForeignPtr secpCtxPtr $ \ctx -> + secpEcPubkeyParse ctx vkp srcp srcLen + pure $ case res of + 1 -> pure vkPsb + _ -> Nothing + rawDeserialiseSignKeyDSIGN bs = + SignKeyEcdsaSecp256k1 <$> psbFromByteStringCheck bs instance ToCBOR (VerKeyDSIGN EcdsaSecp256k1DSIGN) where toCBOR = encodeVerKeyDSIGN diff --git a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed25519.hs b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed25519.hs index b17a70a0e..bf4bc8438 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed25519.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed25519.hs @@ -10,7 +10,6 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} - -- According to the documentation for unsafePerformIO: -- -- > Make sure that the either you switch off let-floating @@ -24,62 +23,59 @@ {-# OPTIONS_GHC -fno-full-laziness #-} -- | Ed25519 digital signatures. -module Cardano.Crypto.DSIGN.Ed25519 - ( Ed25519DSIGN - , SigDSIGN (..) - , SignKeyDSIGN (..) - , SignKeyDSIGNM (..) - , VerKeyDSIGN (..) - ) +module Cardano.Crypto.DSIGN.Ed25519 ( + Ed25519DSIGN, + SigDSIGN (..), + SignKeyDSIGN (..), + SignKeyDSIGNM (..), + VerKeyDSIGN (..), +) where import Control.DeepSeq (NFData (..), rwhnf) -import Control.Monad ((<$!>), unless, guard) +import Control.Monad (guard, unless, (<$!>)) import Control.Monad.Class.MonadST (MonadST (..)) import Control.Monad.Class.MonadThrow (MonadThrow (..), throwIO) import Control.Monad.ST (ST) import Control.Monad.ST.Unsafe (unsafeIOToST) import qualified Data.ByteString as BS import Data.Proxy -import Foreign.C.Error (errnoToIOError, getErrno, Errno) +import Foreign.C.Error (Errno, errnoToIOError, getErrno) import Foreign.Ptr (castPtr, nullPtr) import GHC.Generics (Generic) import GHC.IO.Exception (ioException) -import GHC.TypeLits (TypeError, ErrorMessage (..)) +import GHC.TypeLits (ErrorMessage (..), TypeError) import NoThunks.Class (NoThunks) import System.IO.Unsafe (unsafeDupablePerformIO) - import Cardano.Binary (FromCBOR (..), ToCBOR (..)) import Cardano.Crypto.DSIGN.Class -import Cardano.Crypto.Libsodium - ( MLockedSizedBytes - , mlsbToByteString - , mlsbFromByteStringCheckWith - , mlsbUseAsSizedPtr - , mlsbNewWith - , mlsbFinalize - , mlsbCopyWith - ) +import Cardano.Crypto.DirectSerialise +import Cardano.Crypto.Libsodium ( + MLockedSizedBytes, + mlsbCopyWith, + mlsbFinalize, + mlsbFromByteStringCheckWith, + mlsbNewWith, + mlsbToByteString, + mlsbUseAsSizedPtr, + ) import Cardano.Crypto.Libsodium.C import Cardano.Crypto.Libsodium.MLockedSeed -import Cardano.Crypto.PinnedSizedBytes - ( PinnedSizedBytes - , psbUseAsSizedPtr - , psbUseAsCPtrLen - , psbToByteString - , psbFromByteStringCheck - , psbCreate - , psbCreateSized - , psbCreateSizedResult - ) +import Cardano.Crypto.PinnedSizedBytes ( + PinnedSizedBytes, + psbCreate, + psbCreateSized, + psbCreateSizedResult, + psbFromByteStringCheck, + psbToByteString, + psbUseAsCPtrLen, + psbUseAsSizedPtr, + ) import Cardano.Crypto.Seed -import Cardano.Crypto.Util (SignableRepresentation(..)) +import Cardano.Crypto.Util (SignableRepresentation (..)) import Cardano.Foreign -import Cardano.Crypto.DirectSerialise - - data Ed25519DSIGN @@ -87,8 +83,10 @@ instance NoThunks (VerKeyDSIGN Ed25519DSIGN) instance NoThunks (SignKeyDSIGN Ed25519DSIGN) instance NoThunks (SigDSIGN Ed25519DSIGN) -deriving via (MLockedSizedBytes (SizeSignKeyDSIGN Ed25519DSIGN)) - instance NoThunks (SignKeyDSIGNM Ed25519DSIGN) +deriving via + (MLockedSizedBytes (SizeSignKeyDSIGN Ed25519DSIGN)) + instance + NoThunks (SignKeyDSIGNM Ed25519DSIGN) instance NFData (SignKeyDSIGNM Ed25519DSIGN) where rnf = rwhnf @@ -103,9 +101,11 @@ cOrThrowError :: String -> String -> IO Int -> IO () cOrThrowError contextDesc cFunName action = do res <- action unless (res == 0) $ do - errno <- getErrno - ioException $ errnoToIOError (contextDesc ++ ": " ++ cFunName) errno Nothing Nothing + errno <- getErrno + ioException $ errnoToIOError (contextDesc ++ ": " ++ cFunName) errno Nothing Nothing + -- + -- | Convert C-style return code / errno error reporting into Haskell -- exceptions. -- @@ -115,10 +115,11 @@ cOrThrowError contextDesc cFunName action = do cOrError :: MonadST m => (forall s. ST s Int) -> m (Maybe Errno) cOrError action = stToIO $ do res <- action - if res == 0 then - return Nothing - else - Just <$> unsafeIOToST getErrno + if res == 0 + then + return Nothing + else + Just <$> unsafeIOToST getErrno -- | Throws an error when 'Just' an 'Errno' is given. throwOnErrno :: MonadThrow m => String -> String -> Maybe Errno -> m () @@ -127,151 +128,158 @@ throwOnErrno contextDesc cFunName maybeErrno = do Just errno -> throwIO $ errnoToIOError (contextDesc ++ ": " ++ cFunName) errno Nothing Nothing Nothing -> return () - instance DSIGNAlgorithm Ed25519DSIGN where - -- | Seed size is 32 octets, the same as sign key size, because generating - -- a sign key is literally just taking a chunk from the seed. We use - -- SEEDBYTES to define both the seed size and the sign key size. - type SeedSizeDSIGN Ed25519DSIGN = CRYPTO_SIGN_ED25519_SEEDBYTES - -- | Ed25519 key size is 32 octets - -- (per ) - type SizeVerKeyDSIGN Ed25519DSIGN = CRYPTO_SIGN_ED25519_PUBLICKEYBYTES - -- | Ed25519 secret key size is 32 octets; however, libsodium packs both - -- the secret key and the public key into a 64-octet compound and exposes - -- that as the secret key; the actual 32-octet secret key is called - -- \"seed\" in libsodium. For backwards compatibility reasons and - -- efficiency, we use the 64-octet compounds internally (this is what - -- libsodium expects), but we only serialize the 32-octet secret key part - -- (the libsodium \"seed\"). And because of this, we need to define the - -- sign key size to be SEEDBYTES (which is 32), not PRIVATEKEYBYTES (which - -- would be 64). - type SizeSignKeyDSIGN Ed25519DSIGN = CRYPTO_SIGN_ED25519_SEEDBYTES - -- | Ed25519 signature size is 64 octets - type SizeSigDSIGN Ed25519DSIGN = CRYPTO_SIGN_ED25519_BYTES - - -- - -- Key and signature types - -- - - newtype VerKeyDSIGN Ed25519DSIGN = VerKeyEd25519DSIGN (PinnedSizedBytes (SizeVerKeyDSIGN Ed25519DSIGN)) - deriving (Show, Eq, Generic) - deriving newtype NFData - - -- Note that the size of the internal key data structure is the SECRET KEY - -- bytes as per libsodium, while the declared key size (for serialization) - -- is libsodium's SEED bytes. We expand 32-octet keys to 64-octet ones - -- during deserialization, and we delete the 32 octets that contain the - -- public key from the secret key before serializing. - newtype SignKeyDSIGN Ed25519DSIGN = SignKeyEd25519DSIGN (PinnedSizedBytes CRYPTO_SIGN_ED25519_SECRETKEYBYTES) - deriving (Show, Eq, Generic) - deriving newtype NFData - - newtype SigDSIGN Ed25519DSIGN = SigEd25519DSIGN (PinnedSizedBytes (SizeSigDSIGN Ed25519DSIGN)) - deriving (Show, Eq, Generic) - deriving newtype NFData - - -- - -- Metadata and basic key operations - -- - - algorithmNameDSIGN _ = "ed25519" - - deriveVerKeyDSIGN (SignKeyEd25519DSIGN sk) = - VerKeyEd25519DSIGN $ - unsafeDupablePerformIO $ + -- \| Seed size is 32 octets, the same as sign key size, because generating + -- a sign key is literally just taking a chunk from the seed. We use + -- SEEDBYTES to define both the seed size and the sign key size. + type SeedSizeDSIGN Ed25519DSIGN = CRYPTO_SIGN_ED25519_SEEDBYTES + + -- \| Ed25519 key size is 32 octets + -- (per ) + type SizeVerKeyDSIGN Ed25519DSIGN = CRYPTO_SIGN_ED25519_PUBLICKEYBYTES + + -- \| Ed25519 secret key size is 32 octets; however, libsodium packs both + -- the secret key and the public key into a 64-octet compound and exposes + -- that as the secret key; the actual 32-octet secret key is called + -- \"seed\" in libsodium. For backwards compatibility reasons and + -- efficiency, we use the 64-octet compounds internally (this is what + -- libsodium expects), but we only serialize the 32-octet secret key part + -- (the libsodium \"seed\"). And because of this, we need to define the + -- sign key size to be SEEDBYTES (which is 32), not PRIVATEKEYBYTES (which + -- would be 64). + type SizeSignKeyDSIGN Ed25519DSIGN = CRYPTO_SIGN_ED25519_SEEDBYTES + + -- \| Ed25519 signature size is 64 octets + type SizeSigDSIGN Ed25519DSIGN = CRYPTO_SIGN_ED25519_BYTES + + -- + -- Key and signature types + -- + + newtype VerKeyDSIGN Ed25519DSIGN = VerKeyEd25519DSIGN (PinnedSizedBytes (SizeVerKeyDSIGN Ed25519DSIGN)) + deriving (Show, Eq, Generic) + deriving newtype (NFData) + + -- Note that the size of the internal key data structure is the SECRET KEY + -- bytes as per libsodium, while the declared key size (for serialization) + -- is libsodium's SEED bytes. We expand 32-octet keys to 64-octet ones + -- during deserialization, and we delete the 32 octets that contain the + -- public key from the secret key before serializing. + newtype SignKeyDSIGN Ed25519DSIGN + = SignKeyEd25519DSIGN (PinnedSizedBytes CRYPTO_SIGN_ED25519_SECRETKEYBYTES) + deriving (Show, Eq, Generic) + deriving newtype (NFData) + + newtype SigDSIGN Ed25519DSIGN = SigEd25519DSIGN (PinnedSizedBytes (SizeSigDSIGN Ed25519DSIGN)) + deriving (Show, Eq, Generic) + deriving newtype (NFData) + + -- + -- Metadata and basic key operations + -- + + algorithmNameDSIGN _ = "ed25519" + + deriveVerKeyDSIGN (SignKeyEd25519DSIGN sk) = + VerKeyEd25519DSIGN $ + unsafeDupablePerformIO $ psbUseAsSizedPtr sk $ \skPtr -> - psbCreateSized $ \pkPtr -> - cOrThrowError "deriveVerKeyDSIGN @Ed25519DSIGN" "c_crypto_sign_ed25519_sk_to_pk" - $ c_crypto_sign_ed25519_sk_to_pk pkPtr skPtr + psbCreateSized $ \pkPtr -> + cOrThrowError "deriveVerKeyDSIGN @Ed25519DSIGN" "c_crypto_sign_ed25519_sk_to_pk" $ + c_crypto_sign_ed25519_sk_to_pk pkPtr skPtr - -- - -- Core algorithm operations - -- + -- + -- Core algorithm operations + -- - type Signable Ed25519DSIGN = SignableRepresentation + type Signable Ed25519DSIGN = SignableRepresentation - signDSIGN () a (SignKeyEd25519DSIGN sk) = - let bs = getSignableRepresentation a - in SigEd25519DSIGN $ unsafeDupablePerformIO $ + signDSIGN () a (SignKeyEd25519DSIGN sk) = + let bs = getSignableRepresentation a + in SigEd25519DSIGN $ + unsafeDupablePerformIO $ BS.useAsCStringLen bs $ \(ptr, len) -> - psbUseAsSizedPtr sk $ \skPtr -> - allocaSized $ \pkPtr -> do - cOrThrowError "signDSIGN @Ed25519DSIGN" "c_crypto_sign_ed25519_sk_to_pk" - $ c_crypto_sign_ed25519_sk_to_pk pkPtr skPtr - psbCreateSized $ \sigPtr -> do - cOrThrowError "signDSIGN @Ed25519DSIGN" "c_crypto_sign_ed25519_detached" - $ c_crypto_sign_ed25519_detached sigPtr nullPtr (castPtr ptr) (fromIntegral len) skPtr - - verifyDSIGN () (VerKeyEd25519DSIGN vk) a (SigEd25519DSIGN sig) = - let bs = getSignableRepresentation a - in unsafeDupablePerformIO $ + psbUseAsSizedPtr sk $ \skPtr -> + allocaSized $ \pkPtr -> do + cOrThrowError "signDSIGN @Ed25519DSIGN" "c_crypto_sign_ed25519_sk_to_pk" $ + c_crypto_sign_ed25519_sk_to_pk pkPtr skPtr + psbCreateSized $ \sigPtr -> do + cOrThrowError "signDSIGN @Ed25519DSIGN" "c_crypto_sign_ed25519_detached" $ + c_crypto_sign_ed25519_detached sigPtr nullPtr (castPtr ptr) (fromIntegral len) skPtr + + verifyDSIGN () (VerKeyEd25519DSIGN vk) a (SigEd25519DSIGN sig) = + let bs = getSignableRepresentation a + in unsafeDupablePerformIO $ BS.useAsCStringLen bs $ \(ptr, len) -> - psbUseAsSizedPtr vk $ \vkPtr -> - psbUseAsSizedPtr sig $ \sigPtr -> do - res <- c_crypto_sign_ed25519_verify_detached sigPtr (castPtr ptr) (fromIntegral len) vkPtr - if res == 0 - then return (Right ()) - else do - -- errno <- getErrno - return (Left "Verification failed") - - -- - -- Key generation - -- - genKeyDSIGN seed = SignKeyEd25519DSIGN $ + psbUseAsSizedPtr vk $ \vkPtr -> + psbUseAsSizedPtr sig $ \sigPtr -> do + res <- c_crypto_sign_ed25519_verify_detached sigPtr (castPtr ptr) (fromIntegral len) vkPtr + if res == 0 + then return (Right ()) + else do + -- errno <- getErrno + return (Left "Verification failed") + + -- + -- Key generation + -- + genKeyDSIGN seed = + SignKeyEd25519DSIGN $ let (sb, _) = getBytesFromSeedT (seedSizeDSIGN (Proxy @Ed25519DSIGN)) seed - in unsafeDupablePerformIO $ do - psbCreateSized $ \skPtr -> - BS.useAsCStringLen sb $ \(seedPtr, _) -> - allocaSized $ \pkPtr -> do - cOrThrowError "genKeyDSIGN @Ed25519DSIGN" "c_crypto_sign_ed25519_seed_keypair" - $ c_crypto_sign_ed25519_seed_keypair pkPtr skPtr (SizedPtr . castPtr $ seedPtr) - -- - -- raw serialise/deserialise - -- - - rawSerialiseVerKeyDSIGN (VerKeyEd25519DSIGN vk) = psbToByteString vk - rawSerialiseSignKeyDSIGN (SignKeyEd25519DSIGN sk) = - psbToByteString @(SeedSizeDSIGN Ed25519DSIGN) $ unsafeDupablePerformIO $ do - psbCreateSized $ \seedPtr -> - psbUseAsSizedPtr sk $ \skPtr -> - cOrThrowError "deriveVerKeyDSIGN @Ed25519DSIGN" "c_crypto_sign_ed25519_sk_to_seed" - $ c_crypto_sign_ed25519_sk_to_seed seedPtr skPtr - - rawSerialiseSigDSIGN (SigEd25519DSIGN sig) = psbToByteString sig - - rawDeserialiseVerKeyDSIGN = fmap VerKeyEd25519DSIGN . psbFromByteStringCheck - {-# INLINE rawDeserialiseVerKeyDSIGN #-} - rawDeserialiseSignKeyDSIGN bs = do - guard (fromIntegral (BS.length bs) == seedSizeDSIGN (Proxy @Ed25519DSIGN)) - pure . genKeyDSIGN . mkSeedFromBytes $ bs - rawDeserialiseSigDSIGN = fmap SigEd25519DSIGN . psbFromByteStringCheck - {-# INLINE rawDeserialiseSigDSIGN #-} + in unsafeDupablePerformIO $ do + psbCreateSized $ \skPtr -> + BS.useAsCStringLen sb $ \(seedPtr, _) -> + allocaSized $ \pkPtr -> do + cOrThrowError "genKeyDSIGN @Ed25519DSIGN" "c_crypto_sign_ed25519_seed_keypair" $ + c_crypto_sign_ed25519_seed_keypair pkPtr skPtr (SizedPtr . castPtr $ seedPtr) + + -- + -- raw serialise/deserialise + -- + + rawSerialiseVerKeyDSIGN (VerKeyEd25519DSIGN vk) = psbToByteString vk + rawSerialiseSignKeyDSIGN (SignKeyEd25519DSIGN sk) = + psbToByteString @(SeedSizeDSIGN Ed25519DSIGN) $ unsafeDupablePerformIO $ do + psbCreateSized $ \seedPtr -> + psbUseAsSizedPtr sk $ \skPtr -> + cOrThrowError "deriveVerKeyDSIGN @Ed25519DSIGN" "c_crypto_sign_ed25519_sk_to_seed" $ + c_crypto_sign_ed25519_sk_to_seed seedPtr skPtr + + rawSerialiseSigDSIGN (SigEd25519DSIGN sig) = psbToByteString sig + + rawDeserialiseVerKeyDSIGN = fmap VerKeyEd25519DSIGN . psbFromByteStringCheck + {-# INLINE rawDeserialiseVerKeyDSIGN #-} + rawDeserialiseSignKeyDSIGN bs = do + guard (fromIntegral (BS.length bs) == seedSizeDSIGN (Proxy @Ed25519DSIGN)) + pure . genKeyDSIGN . mkSeedFromBytes $ bs + rawDeserialiseSigDSIGN = fmap SigEd25519DSIGN . psbFromByteStringCheck + {-# INLINE rawDeserialiseSigDSIGN #-} instance DSIGNMAlgorithm Ed25519DSIGN where - -- Note that the size of the internal key data structure is the SECRET KEY - -- bytes as per libsodium, while the declared key size (for serialization) - -- is libsodium's SEED bytes. We expand 32-octet keys to 64-octet ones - -- during deserialization, and we delete the 32 octets that contain the - -- public key from the secret key before serializing. - newtype SignKeyDSIGNM Ed25519DSIGN = SignKeyEd25519DSIGNM (MLockedSizedBytes CRYPTO_SIGN_ED25519_SECRETKEYBYTES) - deriving (Show) - - deriveVerKeyDSIGNM (SignKeyEd25519DSIGNM sk) = - VerKeyEd25519DSIGN <$!> do - mlsbUseAsSizedPtr sk $ \skPtr -> do - (psb, maybeErrno) <- - psbCreateSizedResult $ \pkPtr -> - stToIO $ do - cOrError $ unsafeIOToST $ + -- Note that the size of the internal key data structure is the SECRET KEY + -- bytes as per libsodium, while the declared key size (for serialization) + -- is libsodium's SEED bytes. We expand 32-octet keys to 64-octet ones + -- during deserialization, and we delete the 32 octets that contain the + -- public key from the secret key before serializing. + newtype SignKeyDSIGNM Ed25519DSIGN + = SignKeyEd25519DSIGNM (MLockedSizedBytes CRYPTO_SIGN_ED25519_SECRETKEYBYTES) + deriving (Show) + + deriveVerKeyDSIGNM (SignKeyEd25519DSIGNM sk) = + VerKeyEd25519DSIGN <$!> do + mlsbUseAsSizedPtr sk $ \skPtr -> do + (psb, maybeErrno) <- + psbCreateSizedResult $ \pkPtr -> + stToIO $ do + cOrError $ + unsafeIOToST $ c_crypto_sign_ed25519_sk_to_pk pkPtr skPtr - throwOnErrno "deriveVerKeyDSIGN @Ed25519DSIGN" "c_crypto_sign_ed25519_sk_to_pk" maybeErrno - return psb + throwOnErrno "deriveVerKeyDSIGN @Ed25519DSIGN" "c_crypto_sign_ed25519_sk_to_pk" maybeErrno + return psb - - signDSIGNM () a (SignKeyEd25519DSIGNM sk) = - let bs = getSignableRepresentation a - in SigEd25519DSIGN <$!> do + signDSIGNM () a (SignKeyEd25519DSIGNM sk) = + let bs = getSignableRepresentation a + in SigEd25519DSIGN <$!> do mlsbUseAsSizedPtr sk $ \skPtr -> do (psb, maybeErrno) <- psbCreateSizedResult $ \sigPtr -> @@ -282,62 +290,66 @@ instance DSIGNMAlgorithm Ed25519DSIGN where throwOnErrno "signDSIGNM @Ed25519DSIGN" "c_crypto_sign_ed25519_detached" maybeErrno return psb - -- - -- Key generation - -- - {-# NOINLINE genKeyDSIGNMWith #-} - genKeyDSIGNMWith allocator seed = SignKeyEd25519DSIGNM <$!> do + -- + -- Key generation + -- + {-# NOINLINE genKeyDSIGNMWith #-} + genKeyDSIGNMWith allocator seed = + SignKeyEd25519DSIGNM <$!> do sk <- mlsbNewWith allocator mlsbUseAsSizedPtr sk $ \skPtr -> mlockedSeedUseAsCPtr seed $ \seedPtr -> do maybeErrno <- stToIO $ allocaSizedST $ \pkPtr -> do - cOrError $ unsafeIOToST $ + cOrError $ + unsafeIOToST $ c_crypto_sign_ed25519_seed_keypair pkPtr skPtr (SizedPtr . castPtr $ seedPtr) throwOnErrno "genKeyDSIGNM @Ed25519DSIGN" "c_crypto_sign_ed25519_seed_keypair" maybeErrno return sk - where - allocaSizedST k = - unsafeIOToST $ allocaSized $ \ptr -> stToIO $ k ptr - - cloneKeyDSIGNMWith allocator (SignKeyEd25519DSIGNM sk) = - SignKeyEd25519DSIGNM <$!> mlsbCopyWith allocator sk - - getSeedDSIGNMWith allocator _ (SignKeyEd25519DSIGNM sk) = do - seed <- mlockedSeedNewWith allocator - mlsbUseAsSizedPtr sk $ \skPtr -> - mlockedSeedUseAsSizedPtr seed $ \seedPtr -> do - maybeErrno <- - stToIO $ cOrError $ unsafeIOToST $ - c_crypto_sign_ed25519_sk_to_seed seedPtr skPtr - throwOnErrno "genKeyDSIGNM @Ed25519DSIGN" "c_crypto_sign_ed25519_seed_keypair" maybeErrno - return seed - - -- - -- Secure forgetting - -- - forgetSignKeyDSIGNMWith _ (SignKeyEd25519DSIGNM sk) = mlsbFinalize sk + where + allocaSizedST k = + unsafeIOToST $ allocaSized $ \ptr -> stToIO $ k ptr + + cloneKeyDSIGNMWith allocator (SignKeyEd25519DSIGNM sk) = + SignKeyEd25519DSIGNM <$!> mlsbCopyWith allocator sk + + getSeedDSIGNMWith allocator _ (SignKeyEd25519DSIGNM sk) = do + seed <- mlockedSeedNewWith allocator + mlsbUseAsSizedPtr sk $ \skPtr -> + mlockedSeedUseAsSizedPtr seed $ \seedPtr -> do + maybeErrno <- + stToIO $ + cOrError $ + unsafeIOToST $ + c_crypto_sign_ed25519_sk_to_seed seedPtr skPtr + throwOnErrno "genKeyDSIGNM @Ed25519DSIGN" "c_crypto_sign_ed25519_seed_keypair" maybeErrno + return seed + + -- + -- Secure forgetting + -- + forgetSignKeyDSIGNMWith _ (SignKeyEd25519DSIGNM sk) = mlsbFinalize sk instance UnsoundDSIGNMAlgorithm Ed25519DSIGN where - -- - -- Ser/deser (dangerous - do not use in production code) - -- - rawSerialiseSignKeyDSIGNM sk = do - seed <- getSeedDSIGNM (Proxy @Ed25519DSIGN) sk - -- We need to copy the seed into unsafe memory and finalize the MLSB, in - -- order to avoid leaking mlocked memory. This will, however, expose the - -- secret seed to the unprotected Haskell heap (see 'mlsbToByteString'). - raw <- mlsbToByteString . mlockedSeedMLSB $ seed - mlockedSeedFinalize seed - return raw - - rawDeserialiseSignKeyDSIGNMWith allocator raw = do - mseed <- fmap MLockedSeed <$> mlsbFromByteStringCheckWith allocator raw - case mseed of - Nothing -> return Nothing - Just seed -> do - sk <- Just <$> genKeyDSIGNMWith allocator seed - mlockedSeedFinalize seed - return sk + -- + -- Ser/deser (dangerous - do not use in production code) + -- + rawSerialiseSignKeyDSIGNM sk = do + seed <- getSeedDSIGNM (Proxy @Ed25519DSIGN) sk + -- We need to copy the seed into unsafe memory and finalize the MLSB, in + -- order to avoid leaking mlocked memory. This will, however, expose the + -- secret seed to the unprotected Haskell heap (see 'mlsbToByteString'). + raw <- mlsbToByteString . mlockedSeedMLSB $ seed + mlockedSeedFinalize seed + return raw + + rawDeserialiseSignKeyDSIGNMWith allocator raw = do + mseed <- fmap MLockedSeed <$> mlsbFromByteStringCheckWith allocator raw + case mseed of + Nothing -> return Nothing + Just seed -> do + sk <- Just <$> genKeyDSIGNMWith allocator seed + mlockedSeedFinalize seed + return sk instance ToCBOR (VerKeyDSIGN Ed25519DSIGN) where toCBOR = encodeVerKeyDSIGN @@ -360,14 +372,17 @@ instance ToCBOR (SigDSIGN Ed25519DSIGN) where instance FromCBOR (SigDSIGN Ed25519DSIGN) where fromCBOR = decodeSigDSIGN - -instance TypeError ('Text "CBOR encoding would violate mlocking guarantees") - => ToCBOR (SignKeyDSIGNM Ed25519DSIGN) where +instance + TypeError ('Text "CBOR encoding would violate mlocking guarantees") => + ToCBOR (SignKeyDSIGNM Ed25519DSIGN) + where toCBOR = error "unsupported" encodedSizeExpr _ = error "unsupported" -instance TypeError ('Text "CBOR decoding would violate mlocking guarantees") - => FromCBOR (SignKeyDSIGNM Ed25519DSIGN) where +instance + TypeError ('Text "CBOR decoding would violate mlocking guarantees") => + FromCBOR (SignKeyDSIGNM Ed25519DSIGN) + where fromCBOR = error "unsupported" instance DirectSerialise (SignKeyDSIGNM Ed25519DSIGN) where @@ -380,10 +395,11 @@ instance DirectSerialise (SignKeyDSIGNM Ed25519DSIGN) where bracket (getSeedDSIGNM (Proxy @Ed25519DSIGN) sk) mlockedSeedFinalize - (\seed -> mlockedSeedUseAsCPtr seed $ \ptr -> + ( \seed -> mlockedSeedUseAsCPtr seed $ \ptr -> push (castPtr ptr) - (fromIntegral $ seedSizeDSIGN (Proxy @Ed25519DSIGN))) + (fromIntegral $ seedSizeDSIGN (Proxy @Ed25519DSIGN)) + ) instance DirectDeserialise (SignKeyDSIGNM Ed25519DSIGN) where -- /Note:/ We only serialize the 32-byte seed, not the full 64-byte key. See @@ -392,7 +408,7 @@ instance DirectDeserialise (SignKeyDSIGNM Ed25519DSIGN) where bracket mlockedSeedNew mlockedSeedFinalize - (\seed -> do + ( \seed -> do mlockedSeedUseAsCPtr seed $ \ptr -> do pull (castPtr ptr) diff --git a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed25519ML.hs b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed25519ML.hs index 097fa5e5e..69846daf9 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed25519ML.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed25519ML.hs @@ -3,71 +3,73 @@ {-# LANGUAGE DerivingVia #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeApplications #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} -- | Ed25519 digital signatures. This flavor of Ed25519 stores secrets in -- mlocked memory to make sure they cannot leak to disk via swapping. -module Cardano.Crypto.DSIGN.Ed25519ML - ( Ed25519DSIGNM - , SigDSIGNM (..) - , SignKeyDSIGNM (..) - , VerKeyDSIGNM (..) - ) +module Cardano.Crypto.DSIGN.Ed25519ML ( + Ed25519DSIGNM, + SigDSIGNM (..), + SignKeyDSIGNM (..), + VerKeyDSIGNM (..), +) where import Control.DeepSeq (NFData (..), rwhnf) -import GHC.Generics (Generic) -import GHC.TypeLits (TypeError, ErrorMessage (..)) -import NoThunks.Class (NoThunks) -import System.IO.Unsafe (unsafeDupablePerformIO) -import Foreign.C.Error (errnoToIOError, getErrno, Errno) -import Foreign.Ptr (castPtr, nullPtr) -import qualified Data.ByteString as BS -import Data.Proxy import Control.Monad ((<$!>)) -import Control.Monad.Class.MonadThrow (MonadThrow (..), throwIO) import Control.Monad.Class.MonadST (MonadST (..)) +import Control.Monad.Class.MonadThrow (MonadThrow (..), throwIO) import Control.Monad.ST (ST, stToIO) import Control.Monad.ST.Unsafe (unsafeIOToST) +import qualified Data.ByteString as BS +import Data.Proxy +import Foreign.C.Error (Errno, errnoToIOError, getErrno) +import Foreign.Ptr (castPtr, nullPtr) +import GHC.Generics (Generic) +import GHC.TypeLits (ErrorMessage (..), TypeError) +import NoThunks.Class (NoThunks) +import System.IO.Unsafe (unsafeDupablePerformIO) import Cardano.Binary (FromCBOR (..), ToCBOR (..)) -import Cardano.Foreign +import Cardano.Crypto.Libsodium ( + MLockedSizedBytes, + mlsbCopyWith, + mlsbFinalize, + mlsbFromByteStringCheckWith, + mlsbNewWith, + mlsbToByteString, + mlsbUseAsSizedPtr, + ) import Cardano.Crypto.Libsodium.C -import Cardano.Crypto.Libsodium - ( MLockedSizedBytes - , mlsbToByteString - , mlsbFromByteStringCheckWith - , mlsbUseAsSizedPtr - , mlsbNewWith - , mlsbFinalize - , mlsbCopyWith - ) -import Cardano.Crypto.PinnedSizedBytes - ( PinnedSizedBytes - , psbUseAsSizedPtr - , psbToByteString - , psbFromByteStringCheck - , psbCreateSizedResult - ) +import Cardano.Crypto.PinnedSizedBytes ( + PinnedSizedBytes, + psbCreateSizedResult, + psbFromByteStringCheck, + psbToByteString, + psbUseAsSizedPtr, + ) +import Cardano.Foreign import Cardano.Crypto.DSIGNM.Class import Cardano.Crypto.Libsodium.MLockedSeed -import Cardano.Crypto.Util (SignableRepresentation(..)) +import Cardano.Crypto.Util (SignableRepresentation (..)) data Ed25519DSIGNM instance NoThunks (VerKeyDSIGNM Ed25519DSIGNM) instance NoThunks (SigDSIGNM Ed25519DSIGNM) -deriving via (MLockedSizedBytes (SizeSignKeyDSIGNM Ed25519DSIGNM)) - instance NoThunks (SignKeyDSIGNM Ed25519DSIGNM) +deriving via + (MLockedSizedBytes (SizeSignKeyDSIGNM Ed25519DSIGNM)) + instance + NoThunks (SignKeyDSIGNM Ed25519DSIGNM) instance NFData (SignKeyDSIGNM Ed25519DSIGNM) where rnf = rwhnf @@ -82,10 +84,11 @@ cOrError :: MonadST m => (forall s. ST s Int) -> m (Maybe Errno) cOrError action = do withLiftST $ \fromST -> fromST $ do res <- action - if res == 0 then - return Nothing - else - Just <$> unsafeIOToST getErrno + if res == 0 + then + return Nothing + else + Just <$> unsafeIOToST getErrno -- | Throws an error when 'Just' an 'Errno' is given. throwOnErrno :: MonadThrow m => String -> String -> Maybe Errno -> m () @@ -95,75 +98,79 @@ throwOnErrno contextDesc cFunName maybeErrno = do Nothing -> return () instance DSIGNMAlgorithmBase Ed25519DSIGNM where - type SeedSizeDSIGNM Ed25519DSIGNM = CRYPTO_SIGN_ED25519_SEEDBYTES - -- | Ed25519 key size is 32 octets - -- (per ) - type SizeVerKeyDSIGNM Ed25519DSIGNM = CRYPTO_SIGN_ED25519_PUBLICKEYBYTES - -- | Ed25519 secret key size is 32 octets; however, libsodium packs both - -- the secret key and the public key into a 64-octet compound and exposes - -- that as the secret key; the actual 32-octet secret key is called - -- \"seed\" in libsodium. For backwards compatibility reasons and - -- efficiency, we use the 64-octet compounds internally (this is what - -- libsodium expects), but we only serialize the 32-octet secret key part - -- (the libsodium \"seed\"). - type SizeSignKeyDSIGNM Ed25519DSIGNM = CRYPTO_SIGN_ED25519_SEEDBYTES - -- | Ed25519 signature size is 64 octets - type SizeSigDSIGNM Ed25519DSIGNM = CRYPTO_SIGN_ED25519_BYTES - - -- - -- Key and signature types - -- - - newtype VerKeyDSIGNM Ed25519DSIGNM = VerKeyEd25519DSIGNM (PinnedSizedBytes (SizeVerKeyDSIGNM Ed25519DSIGNM)) - deriving (Show, Eq, Generic) - deriving newtype NFData - - -- Note that the size of the internal key data structure is the SECRET KEY - -- bytes as per libsodium, while the declared key size (for serialization) - -- is libsodium's SEED bytes. We expand 32-octet keys to 64-octet ones - -- during deserialization, and we delete the 32 octets that contain the - -- public key from the secret key before serializing. - newtype SignKeyDSIGNM Ed25519DSIGNM = SignKeyEd25519DSIGNM (MLockedSizedBytes CRYPTO_SIGN_ED25519_SECRETKEYBYTES) - deriving (Show) - - newtype SigDSIGNM Ed25519DSIGNM = SigEd25519DSIGNM (PinnedSizedBytes (SizeSigDSIGNM Ed25519DSIGNM)) - deriving (Show, Eq, Generic) - deriving newtype NFData - - -- - -- Metadata and basic key operations - -- - - algorithmNameDSIGNM _ = "ed25519-ml" - - -- - -- Core algorithm operations - -- - - type SignableM Ed25519DSIGNM = SignableRepresentation - - verifyDSIGNM () (VerKeyEd25519DSIGNM vk) a (SigEd25519DSIGNM sig) = - let bs = getSignableRepresentation a - in unsafeDupablePerformIO $ + type SeedSizeDSIGNM Ed25519DSIGNM = CRYPTO_SIGN_ED25519_SEEDBYTES + + -- \| Ed25519 key size is 32 octets + -- (per ) + type SizeVerKeyDSIGNM Ed25519DSIGNM = CRYPTO_SIGN_ED25519_PUBLICKEYBYTES + + -- \| Ed25519 secret key size is 32 octets; however, libsodium packs both + -- the secret key and the public key into a 64-octet compound and exposes + -- that as the secret key; the actual 32-octet secret key is called + -- \"seed\" in libsodium. For backwards compatibility reasons and + -- efficiency, we use the 64-octet compounds internally (this is what + -- libsodium expects), but we only serialize the 32-octet secret key part + -- (the libsodium \"seed\"). + type SizeSignKeyDSIGNM Ed25519DSIGNM = CRYPTO_SIGN_ED25519_SEEDBYTES + + -- \| Ed25519 signature size is 64 octets + type SizeSigDSIGNM Ed25519DSIGNM = CRYPTO_SIGN_ED25519_BYTES + + -- + -- Key and signature types + -- + + newtype VerKeyDSIGNM Ed25519DSIGNM = VerKeyEd25519DSIGNM (PinnedSizedBytes (SizeVerKeyDSIGNM Ed25519DSIGNM)) + deriving (Show, Eq, Generic) + deriving newtype (NFData) + + -- Note that the size of the internal key data structure is the SECRET KEY + -- bytes as per libsodium, while the declared key size (for serialization) + -- is libsodium's SEED bytes. We expand 32-octet keys to 64-octet ones + -- during deserialization, and we delete the 32 octets that contain the + -- public key from the secret key before serializing. + newtype SignKeyDSIGNM Ed25519DSIGNM + = SignKeyEd25519DSIGNM (MLockedSizedBytes CRYPTO_SIGN_ED25519_SECRETKEYBYTES) + deriving (Show) + + newtype SigDSIGNM Ed25519DSIGNM = SigEd25519DSIGNM (PinnedSizedBytes (SizeSigDSIGNM Ed25519DSIGNM)) + deriving (Show, Eq, Generic) + deriving newtype (NFData) + + -- + -- Metadata and basic key operations + -- + + algorithmNameDSIGNM _ = "ed25519-ml" + + -- + -- Core algorithm operations + -- + + type SignableM Ed25519DSIGNM = SignableRepresentation + + verifyDSIGNM () (VerKeyEd25519DSIGNM vk) a (SigEd25519DSIGNM sig) = + let bs = getSignableRepresentation a + in unsafeDupablePerformIO $ BS.useAsCStringLen bs $ \(ptr, len) -> - psbUseAsSizedPtr vk $ \vkPtr -> - psbUseAsSizedPtr sig $ \sigPtr -> do - res <- c_crypto_sign_ed25519_verify_detached sigPtr (castPtr ptr) (fromIntegral len) vkPtr - if res == 0 - then - return (Right ()) - else - return (Left "Verification failed") + psbUseAsSizedPtr vk $ \vkPtr -> + psbUseAsSizedPtr sig $ \sigPtr -> do + res <- c_crypto_sign_ed25519_verify_detached sigPtr (castPtr ptr) (fromIntegral len) vkPtr + if res == 0 + then + return (Right ()) + else + return (Left "Verification failed") - -- - -- raw serialise/deserialise - -- + -- + -- raw serialise/deserialise + -- - rawSerialiseVerKeyDSIGNM (VerKeyEd25519DSIGNM vk) = psbToByteString vk - rawSerialiseSigDSIGNM (SigEd25519DSIGNM sig) = psbToByteString sig + rawSerialiseVerKeyDSIGNM (VerKeyEd25519DSIGNM vk) = psbToByteString vk + rawSerialiseSigDSIGNM (SigEd25519DSIGNM sig) = psbToByteString sig - rawDeserialiseVerKeyDSIGNM = fmap VerKeyEd25519DSIGNM . psbFromByteStringCheck - rawDeserialiseSigDSIGNM = fmap SigEd25519DSIGNM . psbFromByteStringCheck + rawDeserialiseVerKeyDSIGNM = fmap VerKeyEd25519DSIGNM . psbFromByteStringCheck + rawDeserialiseSigDSIGNM = fmap SigEd25519DSIGNM . psbFromByteStringCheck -- Note on the use of 'MonadST' and 'unsafeIOToST' here. -- @@ -191,21 +198,21 @@ instance DSIGNMAlgorithmBase Ed25519DSIGNM where -- - 'getErrno'; however, 'ST' guarantees sequentiality in the context where -- we use 'getErrno', so this is fine. instance DSIGNMAlgorithm Ed25519DSIGNM where - deriveVerKeyDSIGNM (SignKeyEd25519DSIGNM sk) = - VerKeyEd25519DSIGNM <$!> do - mlsbUseAsSizedPtr sk $ \skPtr -> do - (psb, maybeErrno) <- - psbCreateSizedResult $ \pkPtr -> - withLiftST $ \fromST -> fromST $ do - cOrError $ unsafeIOToST $ + deriveVerKeyDSIGNM (SignKeyEd25519DSIGNM sk) = + VerKeyEd25519DSIGNM <$!> do + mlsbUseAsSizedPtr sk $ \skPtr -> do + (psb, maybeErrno) <- + psbCreateSizedResult $ \pkPtr -> + withLiftST $ \fromST -> fromST $ do + cOrError $ + unsafeIOToST $ c_crypto_sign_ed25519_sk_to_pk pkPtr skPtr - throwOnErrno "deriveVerKeyDSIGNM @Ed25519DSIGNM" "c_crypto_sign_ed25519_sk_to_pk" maybeErrno - return psb - + throwOnErrno "deriveVerKeyDSIGNM @Ed25519DSIGNM" "c_crypto_sign_ed25519_sk_to_pk" maybeErrno + return psb - signDSIGNM () a (SignKeyEd25519DSIGNM sk) = - let bs = getSignableRepresentation a - in SigEd25519DSIGNM <$!> do + signDSIGNM () a (SignKeyEd25519DSIGNM sk) = + let bs = getSignableRepresentation a + in SigEd25519DSIGNM <$!> do mlsbUseAsSizedPtr sk $ \skPtr -> do (psb, maybeErrno) <- psbCreateSizedResult $ \sigPtr -> do @@ -216,64 +223,67 @@ instance DSIGNMAlgorithm Ed25519DSIGNM where throwOnErrno "signDSIGNM @Ed25519DSIGNM" "c_crypto_sign_ed25519_detached" maybeErrno return psb - -- - -- Key generation - -- - {-# NOINLINE genKeyDSIGNMWith #-} - genKeyDSIGNMWith allocator seed = SignKeyEd25519DSIGNM <$!> do + -- + -- Key generation + -- + {-# NOINLINE genKeyDSIGNMWith #-} + genKeyDSIGNMWith allocator seed = + SignKeyEd25519DSIGNM <$!> do sk <- mlsbNewWith allocator mlsbUseAsSizedPtr sk $ \skPtr -> mlockedSeedUseAsCPtr seed $ \seedPtr -> do maybeErrno <- withLiftST $ \fromST -> fromST $ allocaSizedST $ \pkPtr -> do - cOrError $ unsafeIOToST $ - c_crypto_sign_ed25519_seed_keypair pkPtr skPtr (SizedPtr . castPtr $ seedPtr) + cOrError $ + unsafeIOToST $ + c_crypto_sign_ed25519_seed_keypair pkPtr skPtr (SizedPtr . castPtr $ seedPtr) throwOnErrno "genKeyDSIGNM @Ed25519DSIGNM" "c_crypto_sign_ed25519_seed_keypair" maybeErrno return sk - where - allocaSizedST k = - unsafeIOToST $ allocaSized $ \ptr -> stToIO $ k ptr - - cloneKeyDSIGNMWith allocator (SignKeyEd25519DSIGNM sk) = - SignKeyEd25519DSIGNM <$!> mlsbCopyWith allocator sk - - getSeedDSIGNMWith allocator _ (SignKeyEd25519DSIGNM sk) = do - seed <- mlockedSeedNewWith allocator - mlsbUseAsSizedPtr sk $ \skPtr -> - mlockedSeedUseAsSizedPtr seed $ \seedPtr -> do - maybeErrno <- withLiftST $ \fromST -> - fromST $ - cOrError $ unsafeIOToST $ + where + allocaSizedST k = + unsafeIOToST $ allocaSized $ \ptr -> stToIO $ k ptr + + cloneKeyDSIGNMWith allocator (SignKeyEd25519DSIGNM sk) = + SignKeyEd25519DSIGNM <$!> mlsbCopyWith allocator sk + + getSeedDSIGNMWith allocator _ (SignKeyEd25519DSIGNM sk) = do + seed <- mlockedSeedNewWith allocator + mlsbUseAsSizedPtr sk $ \skPtr -> + mlockedSeedUseAsSizedPtr seed $ \seedPtr -> do + maybeErrno <- withLiftST $ \fromST -> + fromST $ + cOrError $ + unsafeIOToST $ c_crypto_sign_ed25519_sk_to_seed seedPtr skPtr - throwOnErrno "genKeyDSIGNM @Ed25519DSIGNM" "c_crypto_sign_ed25519_seed_keypair" maybeErrno - return seed + throwOnErrno "genKeyDSIGNM @Ed25519DSIGNM" "c_crypto_sign_ed25519_seed_keypair" maybeErrno + return seed - -- - -- Secure forgetting - -- - forgetSignKeyDSIGNMWith _ (SignKeyEd25519DSIGNM sk) = mlsbFinalize sk + -- + -- Secure forgetting + -- + forgetSignKeyDSIGNMWith _ (SignKeyEd25519DSIGNM sk) = mlsbFinalize sk instance UnsoundDSIGNMAlgorithm Ed25519DSIGNM where - -- - -- Ser/deser (dangerous - do not use in production code) - -- - rawSerialiseSignKeyDSIGNM sk = do - seed <- getSeedDSIGNM (Proxy @Ed25519DSIGNM) sk - -- We need to copy the seed into unsafe memory and finalize the MLSB, in - -- order to avoid leaking mlocked memory. This will, however, expose the - -- secret seed to the unprotected Haskell heap (see 'mlsbToByteString'). - raw <- mlsbToByteString . mlockedSeedMLSB $ seed - mlockedSeedFinalize seed - return raw - - rawDeserialiseSignKeyDSIGNMWith allocator raw = do - mseed <- fmap MLockedSeed <$> mlsbFromByteStringCheckWith allocator raw - case mseed of - Nothing -> return Nothing - Just seed -> do - sk <- Just <$> genKeyDSIGNMWith allocator seed - mlockedSeedFinalize seed - return sk + -- + -- Ser/deser (dangerous - do not use in production code) + -- + rawSerialiseSignKeyDSIGNM sk = do + seed <- getSeedDSIGNM (Proxy @Ed25519DSIGNM) sk + -- We need to copy the seed into unsafe memory and finalize the MLSB, in + -- order to avoid leaking mlocked memory. This will, however, expose the + -- secret seed to the unprotected Haskell heap (see 'mlsbToByteString'). + raw <- mlsbToByteString . mlockedSeedMLSB $ seed + mlockedSeedFinalize seed + return raw + + rawDeserialiseSignKeyDSIGNMWith allocator raw = do + mseed <- fmap MLockedSeed <$> mlsbFromByteStringCheckWith allocator raw + case mseed of + Nothing -> return Nothing + Just seed -> do + sk <- Just <$> genKeyDSIGNMWith allocator seed + mlockedSeedFinalize seed + return sk instance ToCBOR (VerKeyDSIGNM Ed25519DSIGNM) where toCBOR = encodeVerKeyDSIGNM @@ -282,13 +292,17 @@ instance ToCBOR (VerKeyDSIGNM Ed25519DSIGNM) where instance FromCBOR (VerKeyDSIGNM Ed25519DSIGNM) where fromCBOR = decodeVerKeyDSIGNM -instance TypeError ('Text "CBOR encoding would violate mlocking guarantees") - => ToCBOR (SignKeyDSIGNM Ed25519DSIGNM) where +instance + TypeError ('Text "CBOR encoding would violate mlocking guarantees") => + ToCBOR (SignKeyDSIGNM Ed25519DSIGNM) + where toCBOR = error "unsupported" encodedSizeExpr _ = error "unsupported" -instance TypeError ('Text "CBOR decoding would violate mlocking guarantees") - => FromCBOR (SignKeyDSIGNM Ed25519DSIGNM) where +instance + TypeError ('Text "CBOR decoding would violate mlocking guarantees") => + FromCBOR (SignKeyDSIGNM Ed25519DSIGNM) + where fromCBOR = error "unsupported" instance ToCBOR (SigDSIGNM Ed25519DSIGNM) where diff --git a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed448.hs b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed448.hs index 3834e335e..29d8c3e18 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed448.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Ed448.hs @@ -7,18 +7,18 @@ {-# LANGUAGE TypeFamilies #-} -- | Ed448 digital signatures. -module Cardano.Crypto.DSIGN.Ed448 - ( Ed448DSIGN - , SigDSIGN (..) - , SignKeyDSIGN (..) - , VerKeyDSIGN (..) - ) +module Cardano.Crypto.DSIGN.Ed448 ( + Ed448DSIGN, + SigDSIGN (..), + SignKeyDSIGN (..), + VerKeyDSIGN (..), +) where import Control.DeepSeq (NFData) import Data.ByteArray as BA (ByteArrayAccess, convert) import GHC.Generics (Generic) -import NoThunks.Class (NoThunks, InspectHeap(..)) +import NoThunks.Class (InspectHeap (..), NoThunks) import Cardano.Binary (FromCBOR (..), ToCBOR (..)) @@ -27,84 +27,88 @@ import Crypto.PubKey.Ed448 as Ed448 import Cardano.Crypto.DSIGN.Class import Cardano.Crypto.Seed -import Cardano.Crypto.Util (SignableRepresentation(..)) - +import Cardano.Crypto.Util (SignableRepresentation (..)) data Ed448DSIGN instance DSIGNAlgorithm Ed448DSIGN where - type SeedSizeDSIGN Ed448DSIGN = 57 - -- | Goldilocks points are 448 bits long - type SizeVerKeyDSIGN Ed448DSIGN = 57 - type SizeSignKeyDSIGN Ed448DSIGN = 57 - type SizeSigDSIGN Ed448DSIGN = 114 - - -- - -- Key and signature types - -- - - newtype VerKeyDSIGN Ed448DSIGN = VerKeyEd448DSIGN PublicKey - deriving (Show, Eq, Generic, ByteArrayAccess) - deriving newtype NFData - deriving NoThunks via InspectHeap PublicKey - - newtype SignKeyDSIGN Ed448DSIGN = SignKeyEd448DSIGN SecretKey - deriving (Show, Eq, Generic, ByteArrayAccess) - deriving newtype NFData - deriving NoThunks via InspectHeap SecretKey - - newtype SigDSIGN Ed448DSIGN = SigEd448DSIGN Signature - deriving (Show, Eq, Generic, ByteArrayAccess) - deriving NoThunks via InspectHeap Signature - - -- - -- Metadata and basic key operations - -- - - algorithmNameDSIGN _ = "ed448" - - deriveVerKeyDSIGN (SignKeyEd448DSIGN sk) = VerKeyEd448DSIGN $ toPublic sk - - - -- - -- Core algorithm operations - -- - - type Signable Ed448DSIGN = SignableRepresentation - - signDSIGN () a (SignKeyEd448DSIGN sk) = - let vk = toPublic sk - bs = getSignableRepresentation a - in SigEd448DSIGN $ sign sk vk bs - - verifyDSIGN () (VerKeyEd448DSIGN vk) a (SigEd448DSIGN sig) = - if verify vk (getSignableRepresentation a) sig - then Right () - else Left "Verification failed" - - -- - -- Key generation - -- - - genKeyDSIGN seed = - let sk = runMonadRandomWithSeed seed Ed448.generateSecretKey - in SignKeyEd448DSIGN sk - - -- - -- raw serialise/deserialise - -- - - rawSerialiseVerKeyDSIGN = BA.convert - rawSerialiseSignKeyDSIGN = BA.convert - rawSerialiseSigDSIGN = BA.convert - - rawDeserialiseVerKeyDSIGN = fmap VerKeyEd448DSIGN - . cryptoFailableToMaybe . Ed448.publicKey - rawDeserialiseSignKeyDSIGN = fmap SignKeyEd448DSIGN - . cryptoFailableToMaybe . Ed448.secretKey - rawDeserialiseSigDSIGN = fmap SigEd448DSIGN - . cryptoFailableToMaybe . Ed448.signature - + type SeedSizeDSIGN Ed448DSIGN = 57 + + -- \| Goldilocks points are 448 bits long + type SizeVerKeyDSIGN Ed448DSIGN = 57 + type SizeSignKeyDSIGN Ed448DSIGN = 57 + type SizeSigDSIGN Ed448DSIGN = 114 + + -- + -- Key and signature types + -- + + newtype VerKeyDSIGN Ed448DSIGN = VerKeyEd448DSIGN PublicKey + deriving (Show, Eq, Generic, ByteArrayAccess) + deriving newtype (NFData) + deriving (NoThunks) via InspectHeap PublicKey + + newtype SignKeyDSIGN Ed448DSIGN = SignKeyEd448DSIGN SecretKey + deriving (Show, Eq, Generic, ByteArrayAccess) + deriving newtype (NFData) + deriving (NoThunks) via InspectHeap SecretKey + + newtype SigDSIGN Ed448DSIGN = SigEd448DSIGN Signature + deriving (Show, Eq, Generic, ByteArrayAccess) + deriving (NoThunks) via InspectHeap Signature + + -- + -- Metadata and basic key operations + -- + + algorithmNameDSIGN _ = "ed448" + + deriveVerKeyDSIGN (SignKeyEd448DSIGN sk) = VerKeyEd448DSIGN $ toPublic sk + + -- + -- Core algorithm operations + -- + + type Signable Ed448DSIGN = SignableRepresentation + + signDSIGN () a (SignKeyEd448DSIGN sk) = + let vk = toPublic sk + bs = getSignableRepresentation a + in SigEd448DSIGN $ sign sk vk bs + + verifyDSIGN () (VerKeyEd448DSIGN vk) a (SigEd448DSIGN sig) = + if verify vk (getSignableRepresentation a) sig + then Right () + else Left "Verification failed" + + -- + -- Key generation + -- + + genKeyDSIGN seed = + let sk = runMonadRandomWithSeed seed Ed448.generateSecretKey + in SignKeyEd448DSIGN sk + + -- + -- raw serialise/deserialise + -- + + rawSerialiseVerKeyDSIGN = BA.convert + rawSerialiseSignKeyDSIGN = BA.convert + rawSerialiseSigDSIGN = BA.convert + + rawDeserialiseVerKeyDSIGN = + fmap VerKeyEd448DSIGN + . cryptoFailableToMaybe + . Ed448.publicKey + rawDeserialiseSignKeyDSIGN = + fmap SignKeyEd448DSIGN + . cryptoFailableToMaybe + . Ed448.secretKey + rawDeserialiseSigDSIGN = + fmap SigEd448DSIGN + . cryptoFailableToMaybe + . Ed448.signature instance ToCBOR (VerKeyDSIGN Ed448DSIGN) where toCBOR = encodeVerKeyDSIGN @@ -127,8 +131,6 @@ instance ToCBOR (SigDSIGN Ed448DSIGN) where instance FromCBOR (SigDSIGN Ed448DSIGN) where fromCBOR = decodeSigDSIGN - cryptoFailableToMaybe :: CryptoFailable a -> Maybe a cryptoFailableToMaybe (CryptoPassed a) = Just a cryptoFailableToMaybe (CryptoFailed _) = Nothing - diff --git a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Mock.hs b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Mock.hs index a7b9f7718..cbe5f8540 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Mock.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/Mock.hs @@ -5,129 +5,125 @@ {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} -- | Mock implementation of digital signatures. -module Cardano.Crypto.DSIGN.Mock - ( MockDSIGN - , SignKeyDSIGN (..) - , VerKeyDSIGN (..) - , SigDSIGN (..) - , mockSign - ) +module Cardano.Crypto.DSIGN.Mock ( + MockDSIGN, + SignKeyDSIGN (..), + VerKeyDSIGN (..), + SigDSIGN (..), + mockSign, +) where import Control.DeepSeq (NFData) +import Data.Proxy (Proxy (..)) import Data.Word (Word64) import GHC.Generics (Generic) -import GHC.TypeLits (type (+)) -import Data.Proxy (Proxy (..)) import GHC.Stack +import GHC.TypeLits (type (+)) import NoThunks.Class (NoThunks) import Cardano.Binary (FromCBOR (..), ToCBOR (..)) import Cardano.Crypto.DSIGN.Class -import Cardano.Crypto.Seed import Cardano.Crypto.Hash +import Cardano.Crypto.Seed import Cardano.Crypto.Util - data MockDSIGN instance DSIGNAlgorithm MockDSIGN where - type SeedSizeDSIGN MockDSIGN = 8 - type SizeVerKeyDSIGN MockDSIGN = 8 -- for 64 bit int - type SizeSignKeyDSIGN MockDSIGN = 8 - type SizeSigDSIGN MockDSIGN = SizeHash ShortHash + 8 - - -- - -- Key and signature types - -- - - newtype VerKeyDSIGN MockDSIGN = VerKeyMockDSIGN Word64 - deriving stock (Show, Eq, Generic) - deriving newtype (Num, NoThunks, NFData) - - newtype SignKeyDSIGN MockDSIGN = SignKeyMockDSIGN Word64 - deriving stock (Show, Eq, Generic) - deriving newtype (Num, NoThunks, NFData) - - data SigDSIGN MockDSIGN = SigMockDSIGN !(Hash ShortHash ()) !Word64 - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NoThunks, NFData) - - - -- - -- Metadata and basic key operations - -- - - algorithmNameDSIGN _ = "mock" - - deriveVerKeyDSIGN (SignKeyMockDSIGN n) = VerKeyMockDSIGN n - - -- - -- Core algorithm operations - -- - - type Signable MockDSIGN = SignableRepresentation - - signDSIGN () a sk = mockSign a sk - - verifyDSIGN () (VerKeyMockDSIGN n) a s = - if s == mockSign a (SignKeyMockDSIGN n) - then Right () - else Left $ show $ MockVerificationFailure { - vErrVerKey = VerKeyMockDSIGN n - , vErrSignature = s - , vErrCallStack = prettyCallStack callStack - } - - -- - -- Key generation - -- - - genKeyDSIGN seed = - SignKeyMockDSIGN (runMonadRandomWithSeed seed getRandomWord64) - - - -- - -- raw serialise/deserialise - -- - - - rawSerialiseVerKeyDSIGN (VerKeyMockDSIGN k) = writeBinaryWord64 k - rawSerialiseSignKeyDSIGN (SignKeyMockDSIGN k) = writeBinaryWord64 k - rawSerialiseSigDSIGN (SigMockDSIGN h k) = hashToBytes h - <> writeBinaryWord64 k - - rawDeserialiseVerKeyDSIGN bs - | [kb] <- splitsAt [8] bs - , let k = readBinaryWord64 kb - = Just $! VerKeyMockDSIGN k - - | otherwise - = Nothing - - rawDeserialiseSignKeyDSIGN bs - | [kb] <- splitsAt [8] bs - , let k = readBinaryWord64 kb - = Just $! SignKeyMockDSIGN k - - | otherwise - = Nothing - - rawDeserialiseSigDSIGN bs - | [hb, kb] <- splitsAt [fromIntegral $ sizeHash (Proxy :: Proxy ShortHash), 8] bs - , Just h <- hashFromBytes hb - , let k = readBinaryWord64 kb - = Just $! SigMockDSIGN h k - - | otherwise - = Nothing - + type SeedSizeDSIGN MockDSIGN = 8 + type SizeVerKeyDSIGN MockDSIGN = 8 -- for 64 bit int + type SizeSignKeyDSIGN MockDSIGN = 8 + type SizeSigDSIGN MockDSIGN = SizeHash ShortHash + 8 + + -- + -- Key and signature types + -- + + newtype VerKeyDSIGN MockDSIGN = VerKeyMockDSIGN Word64 + deriving stock (Show, Eq, Generic) + deriving newtype (Num, NoThunks, NFData) + + newtype SignKeyDSIGN MockDSIGN = SignKeyMockDSIGN Word64 + deriving stock (Show, Eq, Generic) + deriving newtype (Num, NoThunks, NFData) + + data SigDSIGN MockDSIGN = SigMockDSIGN !(Hash ShortHash ()) !Word64 + deriving stock (Show, Eq, Ord, Generic) + deriving anyclass (NoThunks, NFData) + + -- + -- Metadata and basic key operations + -- + + algorithmNameDSIGN _ = "mock" + + deriveVerKeyDSIGN (SignKeyMockDSIGN n) = VerKeyMockDSIGN n + + -- + -- Core algorithm operations + -- + + type Signable MockDSIGN = SignableRepresentation + + signDSIGN () a sk = mockSign a sk + + verifyDSIGN () (VerKeyMockDSIGN n) a s = + if s == mockSign a (SignKeyMockDSIGN n) + then Right () + else + Left $ + show $ + MockVerificationFailure + { vErrVerKey = VerKeyMockDSIGN n + , vErrSignature = s + , vErrCallStack = prettyCallStack callStack + } + + -- + -- Key generation + -- + + genKeyDSIGN seed = + SignKeyMockDSIGN (runMonadRandomWithSeed seed getRandomWord64) + + -- + -- raw serialise/deserialise + -- + + rawSerialiseVerKeyDSIGN (VerKeyMockDSIGN k) = writeBinaryWord64 k + rawSerialiseSignKeyDSIGN (SignKeyMockDSIGN k) = writeBinaryWord64 k + rawSerialiseSigDSIGN (SigMockDSIGN h k) = + hashToBytes h + <> writeBinaryWord64 k + + rawDeserialiseVerKeyDSIGN bs + | [kb] <- splitsAt [8] bs + , let k = readBinaryWord64 kb = + Just $! VerKeyMockDSIGN k + | otherwise = + Nothing + + rawDeserialiseSignKeyDSIGN bs + | [kb] <- splitsAt [8] bs + , let k = readBinaryWord64 kb = + Just $! SignKeyMockDSIGN k + | otherwise = + Nothing + + rawDeserialiseSigDSIGN bs + | [hb, kb] <- splitsAt [fromIntegral $ sizeHash (Proxy :: Proxy ShortHash), 8] bs + , Just h <- hashFromBytes hb + , let k = readBinaryWord64 kb = + Just $! SigMockDSIGN h k + | otherwise = + Nothing instance ToCBOR (VerKeyDSIGN MockDSIGN) where toCBOR = encodeVerKeyDSIGN @@ -150,20 +146,20 @@ instance ToCBOR (SigDSIGN MockDSIGN) where instance FromCBOR (SigDSIGN MockDSIGN) where fromCBOR = decodeSigDSIGN - -- | Debugging: provide information about the verification failure -- -- We don't include the actual value here as that would require propagating a -- 'Show' constraint. data VerificationFailure = MockVerificationFailure - { vErrVerKey :: VerKeyDSIGN MockDSIGN - , vErrSignature :: SigDSIGN MockDSIGN - , vErrCallStack :: String - } - deriving Show - -mockSign :: SignableRepresentation a - => a -> SignKeyDSIGN MockDSIGN -> SigDSIGN MockDSIGN + { vErrVerKey :: VerKeyDSIGN MockDSIGN + , vErrSignature :: SigDSIGN MockDSIGN + , vErrCallStack :: String + } + deriving (Show) + +mockSign :: + SignableRepresentation a => + a -> SignKeyDSIGN MockDSIGN -> SigDSIGN MockDSIGN mockSign a (SignKeyMockDSIGN n) = SigMockDSIGN (castHash (hashWith getSignableRepresentation a)) n diff --git a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/NeverUsed.hs b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/NeverUsed.hs index 938ea3b20..6064eeba3 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/NeverUsed.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/NeverUsed.hs @@ -3,12 +3,13 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} -module Cardano.Crypto.DSIGN.NeverUsed - ( NeverDSIGN - , VerKeyDSIGN (..) - , SignKeyDSIGN (..) - , SigDSIGN (..) - ) + +module Cardano.Crypto.DSIGN.NeverUsed ( + NeverDSIGN, + VerKeyDSIGN (..), + SignKeyDSIGN (..), + SigDSIGN (..), +) where import GHC.Generics (Generic) @@ -17,7 +18,6 @@ import NoThunks.Class (NoThunks) import Cardano.Crypto.DSIGN.Class - -- | DSIGN never used -- -- The type of keys and signatures is isomorphic to unit, but when actually @@ -26,33 +26,32 @@ data NeverDSIGN instance DSIGNAlgorithm NeverDSIGN where type SeedSizeDSIGN NeverDSIGN = 0 - type SizeVerKeyDSIGN NeverDSIGN = 0 + type SizeVerKeyDSIGN NeverDSIGN = 0 type SizeSignKeyDSIGN NeverDSIGN = 0 - type SizeSigDSIGN NeverDSIGN = 0 + type SizeSigDSIGN NeverDSIGN = 0 - data VerKeyDSIGN NeverDSIGN = NeverUsedVerKeyDSIGN - deriving (Show, Eq, Generic, NoThunks) + data VerKeyDSIGN NeverDSIGN = NeverUsedVerKeyDSIGN + deriving (Show, Eq, Generic, NoThunks) data SignKeyDSIGN NeverDSIGN = NeverUsedSignKeyDSIGN - deriving (Show, Eq, Generic, NoThunks) + deriving (Show, Eq, Generic, NoThunks) - data SigDSIGN NeverDSIGN = NeverUsedSigDSIGN - deriving (Show, Eq, Generic, NoThunks) + data SigDSIGN NeverDSIGN = NeverUsedSigDSIGN + deriving (Show, Eq, Generic, NoThunks) algorithmNameDSIGN _ = "never" deriveVerKeyDSIGN _ = NeverUsedVerKeyDSIGN - signDSIGN = error "DSIGN not available" + signDSIGN = error "DSIGN not available" verifyDSIGN = error "DSIGN not available" - genKeyDSIGN _ = NeverUsedSignKeyDSIGN + genKeyDSIGN _ = NeverUsedSignKeyDSIGN - rawSerialiseVerKeyDSIGN _ = mempty + rawSerialiseVerKeyDSIGN _ = mempty rawSerialiseSignKeyDSIGN _ = mempty - rawSerialiseSigDSIGN _ = mempty + rawSerialiseSigDSIGN _ = mempty - rawDeserialiseVerKeyDSIGN _ = Just NeverUsedVerKeyDSIGN + rawDeserialiseVerKeyDSIGN _ = Just NeverUsedVerKeyDSIGN rawDeserialiseSignKeyDSIGN _ = Just NeverUsedSignKeyDSIGN - rawDeserialiseSigDSIGN _ = Just NeverUsedSigDSIGN - + rawDeserialiseSigDSIGN _ = Just NeverUsedSigDSIGN diff --git a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/SchnorrSecp256k1.hs b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/SchnorrSecp256k1.hs index da586bdb8..bb53e5b7f 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/DSIGN/SchnorrSecp256k1.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/DSIGN/SchnorrSecp256k1.hs @@ -1,12 +1,12 @@ {-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} -- According to the documentation for unsafePerformIO: -- -- > Make sure that the either you switch off let-floating @@ -23,80 +23,82 @@ module Cardano.Crypto.DSIGN.SchnorrSecp256k1 ( SchnorrSecp256k1DSIGN, VerKeyDSIGN, SignKeyDSIGN, - SigDSIGN - ) where + SigDSIGN, +) where -import GHC.TypeNats (natVal) -import Foreign.ForeignPtr (withForeignPtr) -import Data.Proxy (Proxy (Proxy)) -import Data.ByteString (useAsCStringLen) -import GHC.Generics (Generic) -import Control.DeepSeq (NFData) -import Data.Primitive.Ptr (copyPtr) -import Cardano.Crypto.Seed (getBytesFromSeedT) -import Cardano.Crypto.SECP256K1.Constants ( - SECP256K1_SCHNORR_PRIVKEY_BYTES, - SECP256K1_SCHNORR_SIGNATURE_BYTES, - SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL, - SECP256K1_SCHNORR_PUBKEY_BYTES, - ) -import Cardano.Crypto.SECP256K1.C ( - secpKeyPairCreate, - secpXOnlyPubkeySerialize, - secpKeyPairXOnlyPub, - secpXOnlyPubkeyParse, - secpSchnorrSigVerify, - secpSchnorrSigSignCustom, - secpCtxPtr, - ) -import Cardano.Foreign (allocaSized) -import Control.Monad (when) -import System.IO.Unsafe (unsafeDupablePerformIO) -import Cardano.Binary (FromCBOR (fromCBOR), ToCBOR (toCBOR, encodedSizeExpr)) -import Foreign.Ptr (castPtr, nullPtr) -import NoThunks.Class (NoThunks) +import Cardano.Binary (FromCBOR (fromCBOR), ToCBOR (encodedSizeExpr, toCBOR)) import Cardano.Crypto.DSIGN.Class ( - DSIGNAlgorithm (VerKeyDSIGN, - SignKeyDSIGN, - SigDSIGN, - SeedSizeDSIGN, - SizeSigDSIGN, - SizeSignKeyDSIGN, - SizeVerKeyDSIGN, - algorithmNameDSIGN, - deriveVerKeyDSIGN, - signDSIGN, - verifyDSIGN, - genKeyDSIGN, - rawSerialiseSigDSIGN, - Signable, - rawSerialiseVerKeyDSIGN, - rawSerialiseSignKeyDSIGN, - rawDeserialiseVerKeyDSIGN, - rawDeserialiseSignKeyDSIGN, - rawDeserialiseSigDSIGN), - encodeVerKeyDSIGN, - encodedVerKeyDSIGNSizeExpr, - decodeVerKeyDSIGN, - encodeSignKeyDSIGN, - encodedSignKeyDSIGNSizeExpr, + DSIGNAlgorithm ( + SeedSizeDSIGN, + SigDSIGN, + SignKeyDSIGN, + Signable, + SizeSigDSIGN, + SizeSignKeyDSIGN, + SizeVerKeyDSIGN, + VerKeyDSIGN, + algorithmNameDSIGN, + deriveVerKeyDSIGN, + genKeyDSIGN, + rawDeserialiseSigDSIGN, + rawDeserialiseSignKeyDSIGN, + rawDeserialiseVerKeyDSIGN, + rawSerialiseSigDSIGN, + rawSerialiseSignKeyDSIGN, + rawSerialiseVerKeyDSIGN, + signDSIGN, + verifyDSIGN + ), + decodeSigDSIGN, decodeSignKeyDSIGN, + decodeVerKeyDSIGN, encodeSigDSIGN, + encodeSignKeyDSIGN, + encodeVerKeyDSIGN, encodedSigDSIGNSizeExpr, - decodeSigDSIGN, - seedSizeDSIGN - ) -import Cardano.Crypto.Util (SignableRepresentation (getSignableRepresentation)) + encodedSignKeyDSIGNSizeExpr, + encodedVerKeyDSIGNSizeExpr, + seedSizeDSIGN, + ) import Cardano.Crypto.PinnedSizedBytes ( PinnedSizedBytes, - psbUseAsSizedPtr, - psbCreateSizedResult, psbCreate, psbCreateSized, - psbToByteString, + psbCreateSizedResult, psbFromByteStringCheck, - ) + psbToByteString, + psbUseAsSizedPtr, + ) +import Cardano.Crypto.SECP256K1.C ( + secpCtxPtr, + secpKeyPairCreate, + secpKeyPairXOnlyPub, + secpSchnorrSigSignCustom, + secpSchnorrSigVerify, + secpXOnlyPubkeyParse, + secpXOnlyPubkeySerialize, + ) +import Cardano.Crypto.SECP256K1.Constants ( + SECP256K1_SCHNORR_PRIVKEY_BYTES, + SECP256K1_SCHNORR_PUBKEY_BYTES, + SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL, + SECP256K1_SCHNORR_SIGNATURE_BYTES, + ) +import Cardano.Crypto.Seed (getBytesFromSeedT) +import Cardano.Crypto.Util (SignableRepresentation (getSignableRepresentation)) +import Cardano.Foreign (allocaSized) +import Control.DeepSeq (NFData) +import Control.Monad (when) +import Data.ByteString (useAsCStringLen) import Data.ByteString.Unsafe (unsafeUseAsCStringLen) +import Data.Primitive.Ptr (copyPtr) +import Data.Proxy (Proxy (Proxy)) +import Foreign.ForeignPtr (withForeignPtr) +import Foreign.Ptr (castPtr, nullPtr) +import GHC.Generics (Generic) +import GHC.TypeNats (natVal) +import NoThunks.Class (NoThunks) +import System.IO.Unsafe (unsafeDupablePerformIO) data SchnorrSecp256k1DSIGN @@ -106,18 +108,18 @@ instance DSIGNAlgorithm SchnorrSecp256k1DSIGN where type SizeSignKeyDSIGN SchnorrSecp256k1DSIGN = SECP256K1_SCHNORR_PRIVKEY_BYTES type SizeVerKeyDSIGN SchnorrSecp256k1DSIGN = SECP256K1_SCHNORR_PUBKEY_BYTES type Signable SchnorrSecp256k1DSIGN = SignableRepresentation - newtype VerKeyDSIGN SchnorrSecp256k1DSIGN = - VerKeySchnorrSecp256k1 (PinnedSizedBytes SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL) + newtype VerKeyDSIGN SchnorrSecp256k1DSIGN + = VerKeySchnorrSecp256k1 (PinnedSizedBytes SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL) deriving newtype (Eq, NFData) deriving stock (Show, Generic) deriving anyclass (NoThunks) - newtype SignKeyDSIGN SchnorrSecp256k1DSIGN = - SignKeySchnorrSecp256k1 (PinnedSizedBytes (SizeSignKeyDSIGN SchnorrSecp256k1DSIGN)) + newtype SignKeyDSIGN SchnorrSecp256k1DSIGN + = SignKeySchnorrSecp256k1 (PinnedSizedBytes (SizeSignKeyDSIGN SchnorrSecp256k1DSIGN)) deriving newtype (Eq, NFData) deriving stock (Show, Generic) deriving anyclass (NoThunks) - newtype SigDSIGN SchnorrSecp256k1DSIGN = - SigSchnorrSecp256k1 (PinnedSizedBytes (SizeSigDSIGN SchnorrSecp256k1DSIGN)) + newtype SigDSIGN SchnorrSecp256k1DSIGN + = SigSchnorrSecp256k1 (PinnedSizedBytes (SizeSigDSIGN SchnorrSecp256k1DSIGN)) deriving newtype (Eq, NFData) deriving stock (Show, Generic) deriving anyclass (NoThunks) @@ -128,12 +130,14 @@ instance DSIGNAlgorithm SchnorrSecp256k1DSIGN where allocaSized $ \kpp -> withForeignPtr secpCtxPtr $ \ctx -> do res <- secpKeyPairCreate ctx kpp skp - when (res /= 1) - (error "deriveVerKeyDSIGN: Failed to create keypair for SchnorrSecp256k1DSIGN") + when + (res /= 1) + (error "deriveVerKeyDSIGN: Failed to create keypair for SchnorrSecp256k1DSIGN") xonlyPSB <- psbCreateSized $ \xonlyp -> do - res' <- secpKeyPairXOnlyPub ctx xonlyp nullPtr kpp - when (res' /= 1) - (error "deriveVerKeyDSIGN: could not extract xonly pubkey for SchnorrSecp256k1DSIGN") + res' <- secpKeyPairXOnlyPub ctx xonlyp nullPtr kpp + when + (res' /= 1) + (error "deriveVerKeyDSIGN: could not extract xonly pubkey for SchnorrSecp256k1DSIGN") pure . VerKeySchnorrSecp256k1 $ xonlyPSB {-# NOINLINE signDSIGN #-} signDSIGN () msg (SignKeySchnorrSecp256k1 skpsb) = @@ -144,12 +148,14 @@ instance DSIGNAlgorithm SchnorrSecp256k1DSIGN where res <- secpKeyPairCreate ctx kpp skp when (res /= 1) (error "signDSIGN: Failed to create keypair for SchnorrSecp256k1DSIGN") sigPSB <- psbCreateSized $ \sigp -> useAsCStringLen bs $ \(msgp, msgLen) -> do - res' <- secpSchnorrSigSignCustom ctx - sigp - (castPtr msgp) - (fromIntegral msgLen) - kpp - nullPtr + res' <- + secpSchnorrSigSignCustom + ctx + sigp + (castPtr msgp) + (fromIntegral msgLen) + kpp + nullPtr when (res' /= 1) (error "signDSIGN: Failed to sign SchnorrSecp256k1DSIGN message") pure . SigSchnorrSecp256k1 $ sigPSB {-# NOINLINE verifyDSIGN #-} @@ -159,21 +165,25 @@ instance DSIGNAlgorithm SchnorrSecp256k1DSIGN where let bs = getSignableRepresentation msg res <- useAsCStringLen bs $ \(msgp, msgLen) -> withForeignPtr secpCtxPtr $ \ctx -> - pure $ secpSchnorrSigVerify ctx - sigp - (castPtr msgp) - (fromIntegral msgLen) - pkp - pure $ if res == 0 - then Left "SigDSIGN SchnorrSecp256k1DSIGN failed to verify." - else pure () + pure $ + secpSchnorrSigVerify + ctx + sigp + (castPtr msgp) + (fromIntegral msgLen) + pkp + pure $ + if res == 0 + then Left "SigDSIGN SchnorrSecp256k1DSIGN failed to verify." + else pure () {-# NOINLINE genKeyDSIGN #-} - genKeyDSIGN seed = SignKeySchnorrSecp256k1 $ - let (bs, _) = getBytesFromSeedT (seedSizeDSIGN (Proxy @SchnorrSecp256k1DSIGN)) seed - in unsafeDupablePerformIO $ - psbCreate $ \skp -> - useAsCStringLen bs $ \(bsp, sz) -> - copyPtr skp (castPtr bsp) sz + genKeyDSIGN seed = + SignKeySchnorrSecp256k1 $ + let (bs, _) = getBytesFromSeedT (seedSizeDSIGN (Proxy @SchnorrSecp256k1DSIGN)) seed + in unsafeDupablePerformIO $ + psbCreate $ \skp -> + useAsCStringLen bs $ \(bsp, sz) -> + copyPtr skp (castPtr bsp) sz rawSerialiseSigDSIGN (SigSchnorrSecp256k1 sigPSB) = psbToByteString sigPSB {-# NOINLINE rawSerialiseVerKeyDSIGN #-} rawSerialiseVerKeyDSIGN (VerKeySchnorrSecp256k1 vkPSB) = @@ -181,23 +191,24 @@ instance DSIGNAlgorithm SchnorrSecp256k1DSIGN where res <- psbCreateSized $ \bsPtr -> withForeignPtr secpCtxPtr $ \ctx -> do res' <- secpXOnlyPubkeySerialize ctx bsPtr pkbPtr - when (res' /= 1) - (error "rawSerialiseVerKeyDSIGN: Failed to serialise VerKeyDSIGN SchnorrSecp256k1DSIGN") + when + (res' /= 1) + (error "rawSerialiseVerKeyDSIGN: Failed to serialise VerKeyDSIGN SchnorrSecp256k1DSIGN") pure . psbToByteString $ res rawSerialiseSignKeyDSIGN (SignKeySchnorrSecp256k1 skPSB) = psbToByteString skPSB {-# NOINLINE rawDeserialiseVerKeyDSIGN #-} rawDeserialiseVerKeyDSIGN bs = unsafeDupablePerformIO . unsafeUseAsCStringLen bs $ \(ptr, len) -> if len /= (fromIntegral . natVal $ Proxy @(SizeVerKeyDSIGN SchnorrSecp256k1DSIGN)) - then pure Nothing - else do - let dataPtr = castPtr ptr - (vkPsb, res) <- psbCreateSizedResult $ \outPtr -> - withForeignPtr secpCtxPtr $ \ctx -> - secpXOnlyPubkeyParse ctx outPtr dataPtr - pure $ case res of - 1 -> pure . VerKeySchnorrSecp256k1 $ vkPsb - _ -> Nothing + then pure Nothing + else do + let dataPtr = castPtr ptr + (vkPsb, res) <- psbCreateSizedResult $ \outPtr -> + withForeignPtr secpCtxPtr $ \ctx -> + secpXOnlyPubkeyParse ctx outPtr dataPtr + pure $ case res of + 1 -> pure . VerKeySchnorrSecp256k1 $ vkPsb + _ -> Nothing rawDeserialiseSignKeyDSIGN bs = SignKeySchnorrSecp256k1 <$> psbFromByteStringCheck bs rawDeserialiseSigDSIGN bs = diff --git a/cardano-crypto-class/src/Cardano/Crypto/DirectSerialise.hs b/cardano-crypto-class/src/Cardano/Crypto/DirectSerialise.hs index a07855c6d..89f2722cf 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/DirectSerialise.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/DirectSerialise.hs @@ -16,23 +16,23 @@ module Cardano.Crypto.DirectSerialise where -import Foreign.Ptr -import Foreign.C.Types +import Cardano.Crypto.Libsodium.Memory (copyMem) +import Control.Exception import Control.Monad (when) -import Control.Monad.Class.MonadThrow (MonadThrow) import Control.Monad.Class.MonadST (MonadST, stToIO) -import Control.Exception +import Control.Monad.Class.MonadThrow (MonadThrow) import Data.STRef (newSTRef, readSTRef, writeSTRef) -import Cardano.Crypto.Libsodium.Memory (copyMem) +import Foreign.C.Types +import Foreign.Ptr -data SizeCheckException = - SizeCheckException - { expectedSize :: Int - , actualSize :: Int - } - deriving (Show) +data SizeCheckException + = SizeCheckException + { expectedSize :: Int + , actualSize :: Int + } + deriving (Show) -instance Exception SizeCheckException where +instance Exception SizeCheckException sizeCheckFailed :: Int -> Int -> m () sizeCheckFailed ex ac = @@ -62,14 +62,15 @@ class DirectSerialise a where -- | Helper function for bounds-checked serialization. -- Verifies that no more than the maximum number of bytes are written, and -- returns the actual number of bytes written. -directSerialiseTo :: forall m a. - DirectSerialise a - => MonadST m - => MonadThrow m - => (Int -> Ptr CChar -> CSize -> m ()) - -> Int - -> a - -> m Int +directSerialiseTo :: + forall m a. + DirectSerialise a => + MonadST m => + MonadThrow m => + (Int -> Ptr CChar -> CSize -> m ()) -> + Int -> + a -> + m Int directSerialiseTo writeBytes dstsize val = do posRef <- stToIO $ newSTRef 0 let pusher :: Ptr CChar -> CSize -> m () @@ -77,7 +78,7 @@ directSerialiseTo writeBytes dstsize val = do pos <- stToIO $ readSTRef posRef let pos' = pos + fromIntegral srcsize when (pos' > dstsize) $ - sizeCheckFailed (dstsize - pos) (pos' - pos) + sizeCheckFailed (dstsize - pos) (pos' - pos) writeBytes pos src (fromIntegral srcsize) stToIO $ writeSTRef posRef pos' directSerialise pusher val @@ -85,14 +86,15 @@ directSerialiseTo writeBytes dstsize val = do -- | Helper function for size-checked serialization. -- Verifies that exactly the specified number of bytes are written. -directSerialiseToChecked :: forall m a. - DirectSerialise a - => MonadST m - => MonadThrow m - => (Int -> Ptr CChar -> CSize -> m ()) - -> Int - -> a - -> m () +directSerialiseToChecked :: + forall m a. + DirectSerialise a => + MonadST m => + MonadThrow m => + (Int -> Ptr CChar -> CSize -> m ()) -> + Int -> + a -> + m () directSerialiseToChecked writeBytes dstsize val = do bytesWritten <- directSerialiseTo writeBytes dstsize val when (bytesWritten /= dstsize) $ @@ -102,27 +104,29 @@ directSerialiseToChecked writeBytes dstsize val = do -- buffer. -- Verifies that no more than the maximum number of bytes are written, and -- returns the actual number of bytes written. -directSerialiseBuf :: forall m a. - DirectSerialise a - => MonadST m - => MonadThrow m - => Ptr CChar - -> Int - -> a - -> m Int +directSerialiseBuf :: + forall m a. + DirectSerialise a => + MonadST m => + MonadThrow m => + Ptr CChar -> + Int -> + a -> + m Int directSerialiseBuf dst = directSerialiseTo (copyMem . plusPtr dst) -- | Helper function for size-checked serialization to an in-memory buffer. -- Verifies that exactly the specified number of bytes are written. -directSerialiseBufChecked :: forall m a. - DirectSerialise a - => MonadST m - => MonadThrow m - => Ptr CChar - -> Int - -> a - -> m () +directSerialiseBufChecked :: + forall m a. + DirectSerialise a => + MonadST m => + MonadThrow m => + Ptr CChar -> + Int -> + a -> + m () directSerialiseBufChecked buf dstsize val = do bytesWritten <- directSerialiseBuf buf dstsize val when (bytesWritten /= dstsize) $ @@ -131,13 +135,14 @@ directSerialiseBufChecked buf dstsize val = do -- | Helper function for size-checked deserialization. -- Verifies that no more than the maximum number of bytes are read, and returns -- the actual number of bytes read. -directDeserialiseFrom :: forall m a. - DirectDeserialise a - => MonadST m - => MonadThrow m - => (Int -> Ptr CChar -> CSize -> m ()) - -> Int - -> m (a, Int) +directDeserialiseFrom :: + forall m a. + DirectDeserialise a => + MonadST m => + MonadThrow m => + (Int -> Ptr CChar -> CSize -> m ()) -> + Int -> + m (a, Int) directDeserialiseFrom readBytes srcsize = do posRef <- stToIO $ newSTRef 0 let puller :: Ptr CChar -> CSize -> m () @@ -145,20 +150,21 @@ directDeserialiseFrom readBytes srcsize = do pos <- stToIO $ readSTRef posRef let pos' = pos + fromIntegral dstsize when (pos' > srcsize) $ - sizeCheckFailed (srcsize - pos) (pos' - pos) + sizeCheckFailed (srcsize - pos) (pos' - pos) readBytes pos dst (fromIntegral dstsize) stToIO $ writeSTRef posRef pos' (,) <$> directDeserialise puller <*> stToIO (readSTRef posRef) -- | Helper function for size-checked deserialization. -- Verifies that exactly the specified number of bytes are read. -directDeserialiseFromChecked :: forall m a. - DirectDeserialise a - => MonadST m - => MonadThrow m - => (Int -> Ptr CChar -> CSize -> m ()) - -> Int - -> m a +directDeserialiseFromChecked :: + forall m a. + DirectDeserialise a => + MonadST m => + MonadThrow m => + (Int -> Ptr CChar -> CSize -> m ()) -> + Int -> + m a directDeserialiseFromChecked readBytes srcsize = do (r, bytesRead) <- directDeserialiseFrom readBytes srcsize when (bytesRead /= srcsize) $ @@ -169,25 +175,27 @@ directDeserialiseFromChecked readBytes srcsize = do -- buffer. -- Verifies that no more than the maximum number of bytes are read, and returns -- the actual number of bytes read. -directDeserialiseBuf :: forall m a. - DirectDeserialise a - => MonadST m - => MonadThrow m - => Ptr CChar - -> Int - -> m (a, Int) +directDeserialiseBuf :: + forall m a. + DirectDeserialise a => + MonadST m => + MonadThrow m => + Ptr CChar -> + Int -> + m (a, Int) directDeserialiseBuf src = directDeserialiseFrom (\pos dst -> copyMem dst (plusPtr src pos)) -- | Helper function for size-checked deserialization from an in-memory buffer. -- Verifies that exactly the specified number of bytes are read. -directDeserialiseBufChecked :: forall m a. - DirectDeserialise a - => MonadST m - => MonadThrow m - => Ptr CChar - -> Int - -> m a +directDeserialiseBufChecked :: + forall m a. + DirectDeserialise a => + MonadST m => + MonadThrow m => + Ptr CChar -> + Int -> + m a directDeserialiseBufChecked buf srcsize = do (r, bytesRead) <- directDeserialiseBuf buf srcsize when (bytesRead /= srcsize) $ diff --git a/cardano-crypto-class/src/Cardano/Crypto/EllipticCurve/BLS12_381.hs b/cardano-crypto-class/src/Cardano/Crypto/EllipticCurve/BLS12_381.hs index 9dee9daf3..7f4e83df0 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/EllipticCurve/BLS12_381.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/EllipticCurve/BLS12_381.hs @@ -1,44 +1,45 @@ -{-#LANGUAGE ScopedTypeVariables #-} -{-#LANGUAGE FlexibleContexts #-} -module Cardano.Crypto.EllipticCurve.BLS12_381 -( +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Cardano.Crypto.EllipticCurve.BLS12_381 ( -- * Types - Point - , Point1 - , Point2 - , PT - , Curve1 - , Curve2 - , BLSTError (..) + Point, + Point1, + Point2, + PT, + Curve1, + Curve2, + BLSTError (..), -- * BLS Class - , BLS + BLS, -- * Point / Group operations + -- | These work on both curves, and take phantom parameters of type 'Curve1' -- or 'Curve2' to select one of the two provided elliptic curves. - , blsInGroup - , blsAddOrDouble - , blsMult - , blsCneg - , blsNeg - , blsCompress - , blsSerialize - , blsUncompress - , blsDeserialize - , blsHash - , blsGenerator - , blsIsInf + blsInGroup, + blsAddOrDouble, + blsMult, + blsCneg, + blsNeg, + blsCompress, + blsSerialize, + blsUncompress, + blsDeserialize, + blsHash, + blsGenerator, + blsIsInf, -- * PT operations - , ptMult - , ptFinalVerify + ptMult, + ptFinalVerify, -- * Pairings - , millerLoop + millerLoop, -- * The period (modulo) of scalars - , scalarPeriod + scalarPeriod, ) where diff --git a/cardano-crypto-class/src/Cardano/Crypto/EllipticCurve/BLS12_381/Internal.hs b/cardano-crypto-class/src/Cardano/Crypto/EllipticCurve/BLS12_381/Internal.hs index 239ee11e6..e7aacdbf0 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/EllipticCurve/BLS12_381/Internal.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/EllipticCurve/BLS12_381/Internal.hs @@ -1,179 +1,170 @@ +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ForeignFunctionInterface #-} +{-# LANGUAGE RoleAnnotations #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} -{-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE RoleAnnotations #-} -module Cardano.Crypto.EllipticCurve.BLS12_381.Internal -( +module Cardano.Crypto.EllipticCurve.BLS12_381.Internal ( -- * Unsafe Types - ScalarPtr - , PointPtr (..) - , AffinePtr - - , Point1Ptr - , Point2Ptr - , Affine1Ptr - , Affine2Ptr - - , PTPtr + ScalarPtr, + PointPtr (..), + AffinePtr, + Point1Ptr, + Point2Ptr, + Affine1Ptr, + Affine2Ptr, + PTPtr, -- * Phantom Types - , Curve1 - , Curve2 + Curve1, + Curve2, -- * Error codes - , c_blst_success - , c_blst_error_bad_encoding - , c_blst_error_point_not_on_curve - , c_blst_error_point_not_in_group - , c_blst_error_aggr_type_mismatch - , c_blst_error_verify_fail - , c_blst_error_pk_is_infinity - , c_blst_error_bad_scalar + c_blst_success, + c_blst_error_bad_encoding, + c_blst_error_point_not_on_curve, + c_blst_error_point_not_in_group, + c_blst_error_aggr_type_mismatch, + c_blst_error_verify_fail, + c_blst_error_pk_is_infinity, + c_blst_error_bad_scalar, -- * Safe types - , Affine - , Affine1 - , Affine2 - , BLSTError (..) - , Point (..) - , Point1 - , Point2 - , PT - , Scalar (..) - , Fr (..) - - , unsafePointFromPointPtr + Affine, + Affine1, + Affine2, + BLSTError (..), + Point (..), + Point1, + Point2, + PT, + Scalar (..), + Fr (..), + unsafePointFromPointPtr, -- * The period of scalars - , scalarPeriod + scalarPeriod, -- * Curve abstraction - - , BLS - ( c_blst_on_curve - , c_blst_add_or_double - , c_blst_mult - , c_blst_cneg - , c_blst_hash - , c_blst_compress - , c_blst_serialize - , c_blst_uncompress - , c_blst_deserialize - , c_blst_in_g - , c_blst_to_affine - , c_blst_from_affine - , c_blst_affine_in_g - , c_blst_generator - , c_blst_p_is_equal - , c_blst_p_is_inf - ) + BLS ( + c_blst_on_curve, + c_blst_add_or_double, + c_blst_mult, + c_blst_cneg, + c_blst_hash, + c_blst_compress, + c_blst_serialize, + c_blst_uncompress, + c_blst_deserialize, + c_blst_in_g, + c_blst_to_affine, + c_blst_from_affine, + c_blst_affine_in_g, + c_blst_generator, + c_blst_p_is_equal, + c_blst_p_is_inf + ), -- * Pairing check - - , c_blst_miller_loop + c_blst_miller_loop, -- * FP12 functions + -- - , c_blst_fp12_mul - , c_blst_fp12_is_equal - , c_blst_fp12_finalverify + c_blst_fp12_mul, + c_blst_fp12_is_equal, + c_blst_fp12_finalverify, -- * Scalar functions - - , c_blst_scalar_fr_check - - , c_blst_scalar_from_fr - , c_blst_fr_from_scalar - , c_blst_scalar_from_be_bytes - , c_blst_bendian_from_scalar + c_blst_scalar_fr_check, + c_blst_scalar_from_fr, + c_blst_fr_from_scalar, + c_blst_scalar_from_be_bytes, + c_blst_bendian_from_scalar, -- * Marshalling functions - , sizePoint - , withPoint - , withNewPoint - , withNewPoint_ - , withNewPoint' - , clonePoint - , compressedSizePoint - , serializedSizePoint - - , sizeAffine - , withAffine - , withNewAffine - , withNewAffine_ - , withNewAffine' - - , sizePT - , withPT - , withNewPT - , withNewPT_ - , withNewPT' - - , sizeScalar - , withScalar - , withNewScalar - , withNewScalar_ - , withNewScalar' - , cloneScalar - - , sizeFr - , withFr - , withNewFr - , withNewFr_ - , withNewFr' - , cloneFr + sizePoint, + withPoint, + withNewPoint, + withNewPoint_, + withNewPoint', + clonePoint, + compressedSizePoint, + serializedSizePoint, + sizeAffine, + withAffine, + withNewAffine, + withNewAffine_, + withNewAffine', + sizePT, + withPT, + withNewPT, + withNewPT_, + withNewPT', + sizeScalar, + withScalar, + withNewScalar, + withNewScalar_, + withNewScalar', + cloneScalar, + sizeFr, + withFr, + withNewFr, + withNewFr_, + withNewFr', + cloneFr, -- * Utility - , integerAsCStrL - , cstrToInteger - , integerToBS - , padBS + integerAsCStrL, + cstrToInteger, + integerToBS, + padBS, -- * Point1/G1 operations - , blsInGroup - , blsAddOrDouble - , blsMult - , blsCneg - , blsNeg - , blsCompress - , blsSerialize - , blsUncompress - , blsDeserialize - , blsHash - , blsGenerator - , blsIsInf - , blsZero - - , toAffine - , fromAffine - , affineInG + blsInGroup, + blsAddOrDouble, + blsMult, + blsCneg, + blsNeg, + blsCompress, + blsSerialize, + blsUncompress, + blsDeserialize, + blsHash, + blsGenerator, + blsIsInf, + blsZero, + toAffine, + fromAffine, + affineInG, -- * PT operations - , ptMult - , ptFinalVerify + ptMult, + ptFinalVerify, -- * Scalar / Fr operations - , scalarFromFr - , frFromScalar - , frFromCanonicalScalar - , scalarFromBS - , scalarToBS - , scalarFromInteger - , scalarToInteger - , scalarCanonical + scalarFromFr, + frFromScalar, + frFromCanonicalScalar, + scalarFromBS, + scalarToBS, + scalarFromInteger, + scalarToInteger, + scalarCanonical, -- * Pairings - , millerLoop + millerLoop, ) where import Data.Bits (shiftL, shiftR, (.|.)) import Data.ByteString (ByteString) +import qualified Data.ByteString as BS +import qualified Data.ByteString.Internal as BSI +import qualified Data.ByteString.Unsafe as BSU import Data.Proxy (Proxy (..)) import Data.Void import Foreign.C.String @@ -181,11 +172,8 @@ import Foreign.C.Types import Foreign.ForeignPtr import Foreign.Marshal.Alloc (allocaBytes) import Foreign.Marshal.Utils (copyBytes) -import Foreign.Ptr (Ptr, nullPtr, castPtr, plusPtr) +import Foreign.Ptr (Ptr, castPtr, nullPtr, plusPtr) import Foreign.Storable (peek) -import qualified Data.ByteString as BS -import qualified Data.ByteString.Unsafe as BSU -import qualified Data.ByteString.Internal as BSI import System.IO.Unsafe (unsafePerformIO) ---- Phantom Types @@ -247,37 +235,37 @@ newtype PT = PT (ForeignPtr Void) -- | Sizes of various representations of elliptic curve points. -- | Size of a curve point in memory -sizePoint :: forall curve. (BLS curve) => Proxy curve -> Int +sizePoint :: forall curve. BLS curve => Proxy curve -> Int sizePoint = fromIntegral . sizePoint_ -- | Size of a curved point when serialized in compressed form -compressedSizePoint :: forall curve. (BLS curve) => Proxy curve -> Int +compressedSizePoint :: forall curve. BLS curve => Proxy curve -> Int compressedSizePoint = fromIntegral . compressedSizePoint_ -- | Size of a curved point when serialized in uncompressed form -serializedSizePoint :: forall curve. (BLS curve) => Proxy curve -> Int +serializedSizePoint :: forall curve. BLS curve => Proxy curve -> Int serializedSizePoint = fromIntegral . serializedSizePoint_ -- | In-memory size of the affine representation of a curve point -sizeAffine :: forall curve. (BLS curve) => Proxy curve -> Int +sizeAffine :: forall curve. BLS curve => Proxy curve -> Int sizeAffine = fromIntegral . sizeAffine_ withPoint :: forall a curve. Point curve -> (PointPtr curve -> IO a) -> IO a withPoint (Point p) go = withForeignPtr p (go . PointPtr) -withNewPoint :: forall curve a. (BLS curve) => (PointPtr curve -> IO a) -> IO (a, Point curve) +withNewPoint :: forall curve a. BLS curve => (PointPtr curve -> IO a) -> IO (a, Point curve) withNewPoint go = do p <- mallocForeignPtrBytes (sizePoint (Proxy @curve)) x <- withForeignPtr p (go . PointPtr) return (x, Point p) -withNewPoint_ :: (BLS curve) => (PointPtr curve -> IO a) -> IO a +withNewPoint_ :: BLS curve => (PointPtr curve -> IO a) -> IO a withNewPoint_ = fmap fst . withNewPoint -withNewPoint' :: (BLS curve) => (PointPtr curve -> IO a) -> IO (Point curve) +withNewPoint' :: BLS curve => (PointPtr curve -> IO a) -> IO (Point curve) withNewPoint' = fmap snd . withNewPoint -clonePoint :: forall curve. (BLS curve) => Point curve -> IO (Point curve) +clonePoint :: forall curve. BLS curve => Point curve -> IO (Point curve) clonePoint (Point a) = do b <- mallocForeignPtrBytes (sizePoint (Proxy @curve)) withForeignPtr a $ \ap -> @@ -288,19 +276,18 @@ clonePoint (Point a) = do withAffine :: forall a curve. Affine curve -> (AffinePtr curve -> IO a) -> IO a withAffine (Affine p) go = withForeignPtr p (go . AffinePtr) -withNewAffine :: forall curve a. (BLS curve) => (AffinePtr curve -> IO a) -> IO (a, Affine curve) +withNewAffine :: forall curve a. BLS curve => (AffinePtr curve -> IO a) -> IO (a, Affine curve) withNewAffine go = do p <- mallocForeignPtrBytes (sizeAffine (Proxy @curve)) x <- withForeignPtr p (go . AffinePtr) return (x, Affine p) -withNewAffine_ :: (BLS curve) => (AffinePtr curve -> IO a) -> IO a +withNewAffine_ :: BLS curve => (AffinePtr curve -> IO a) -> IO a withNewAffine_ = fmap fst . withNewAffine -withNewAffine' :: (BLS curve) => (AffinePtr curve -> IO a) -> IO (Affine curve) +withNewAffine' :: BLS curve => (AffinePtr curve -> IO a) -> IO (Affine curve) withNewAffine' = fmap snd . withNewAffine - withPT :: PT -> (PTPtr -> IO a) -> IO a withPT (PT pt) go = withForeignPtr pt (go . PTPtr) @@ -319,7 +306,6 @@ withNewPT' = fmap snd . withNewPT sizePT :: Int sizePT = fromIntegral c_size_blst_fp12 - ---- Curve operations -- | BLS curve operations. Class methods are low-level; user code will want to @@ -331,7 +317,8 @@ class BLS curve where c_blst_mult :: PointPtr curve -> PointPtr curve -> ScalarPtr -> CSize -> IO () c_blst_cneg :: PointPtr curve -> Bool -> IO () - c_blst_hash :: PointPtr curve -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> IO () + c_blst_hash :: + PointPtr curve -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> IO () c_blst_compress :: Ptr CChar -> PointPtr curve -> IO () c_blst_serialize :: Ptr CChar -> PointPtr curve -> IO () c_blst_uncompress :: AffinePtr curve -> Ptr CChar -> IO CInt @@ -490,11 +477,11 @@ cstrToInteger p l = do where go :: Int -> Ptr CUChar -> IO Integer go n ptr - | n <= 0 = pure 0 - | otherwise = do - val <- peek ptr - res <- go (pred n) (plusPtr ptr 1) - return $ res .|. shiftL (fromIntegral val) (8 * pred n) + | n <= 0 = pure 0 + | otherwise = do + val <- peek ptr + res <- go (pred n) (plusPtr ptr 1) + return $ res .|. shiftL (fromIntegral val) (8 * pred n) integerToBS :: Integer -> ByteString integerToBS k @@ -506,10 +493,10 @@ integerToBS k padBS :: Int -> ByteString -> ByteString padBS i b - | i > BS.length b - = BS.replicate (i - BS.length b) 0 <> b - | otherwise - = b + | i > BS.length b = + BS.replicate (i - BS.length b) 0 <> b + | otherwise = + b integerAsCStrL :: Int -> Integer -> (Ptr CChar -> Int -> IO a) -> IO a integerAsCStrL i n f = do @@ -536,23 +523,30 @@ foreign import ccall "blst_scalar_fr_check" c_blst_scalar_fr_check :: ScalarPtr foreign import ccall "blst_scalar_from_fr" c_blst_scalar_from_fr :: ScalarPtr -> FrPtr -> IO () foreign import ccall "blst_fr_from_scalar" c_blst_fr_from_scalar :: FrPtr -> ScalarPtr -> IO () -foreign import ccall "blst_scalar_from_be_bytes" c_blst_scalar_from_be_bytes :: ScalarPtr -> Ptr CChar -> CSize -> IO Bool -foreign import ccall "blst_scalar_from_bendian" c_blst_scalar_from_bendian :: ScalarPtr -> Ptr CChar -> IO () +foreign import ccall "blst_scalar_from_be_bytes" + c_blst_scalar_from_be_bytes :: ScalarPtr -> Ptr CChar -> CSize -> IO Bool +foreign import ccall "blst_scalar_from_bendian" + c_blst_scalar_from_bendian :: ScalarPtr -> Ptr CChar -> IO () ---- Raw Point1 functions foreign import ccall "size_blst_p1" c_size_blst_p1 :: CSize foreign import ccall "blst_p1_on_curve" c_blst_p1_on_curve :: Point1Ptr -> IO Bool -foreign import ccall "blst_p1_add_or_double" c_blst_p1_add_or_double :: Point1Ptr -> Point1Ptr -> Point1Ptr -> IO () -foreign import ccall "blst_p1_mult" c_blst_p1_mult :: Point1Ptr -> Point1Ptr -> ScalarPtr -> CSize -> IO () +foreign import ccall "blst_p1_add_or_double" + c_blst_p1_add_or_double :: Point1Ptr -> Point1Ptr -> Point1Ptr -> IO () +foreign import ccall "blst_p1_mult" + c_blst_p1_mult :: Point1Ptr -> Point1Ptr -> ScalarPtr -> CSize -> IO () foreign import ccall "blst_p1_cneg" c_blst_p1_cneg :: Point1Ptr -> Bool -> IO () -foreign import ccall "blst_hash_to_g1" c_blst_hash_to_g1 :: Point1Ptr -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> IO () +foreign import ccall "blst_hash_to_g1" + c_blst_hash_to_g1 :: + Point1Ptr -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> IO () foreign import ccall "blst_p1_compress" c_blst_p1_compress :: Ptr CChar -> Point1Ptr -> IO () foreign import ccall "blst_p1_serialize" c_blst_p1_serialize :: Ptr CChar -> Point1Ptr -> IO () foreign import ccall "blst_p1_uncompress" c_blst_p1_uncompress :: Affine1Ptr -> Ptr CChar -> IO CInt -foreign import ccall "blst_p1_deserialize" c_blst_p1_deserialize :: Affine1Ptr -> Ptr CChar -> IO CInt +foreign import ccall "blst_p1_deserialize" + c_blst_p1_deserialize :: Affine1Ptr -> Ptr CChar -> IO CInt foreign import ccall "blst_p1_in_g1" c_blst_p1_in_g1 :: Point1Ptr -> IO Bool @@ -566,15 +560,20 @@ foreign import ccall "blst_p1_is_inf" c_blst_p1_is_inf :: Point1Ptr -> IO Bool foreign import ccall "size_blst_p2" c_size_blst_p2 :: CSize foreign import ccall "blst_p2_on_curve" c_blst_p2_on_curve :: Point2Ptr -> IO Bool -foreign import ccall "blst_p2_add_or_double" c_blst_p2_add_or_double :: Point2Ptr -> Point2Ptr -> Point2Ptr -> IO () -foreign import ccall "blst_p2_mult" c_blst_p2_mult :: Point2Ptr -> Point2Ptr -> ScalarPtr -> CSize -> IO () +foreign import ccall "blst_p2_add_or_double" + c_blst_p2_add_or_double :: Point2Ptr -> Point2Ptr -> Point2Ptr -> IO () +foreign import ccall "blst_p2_mult" + c_blst_p2_mult :: Point2Ptr -> Point2Ptr -> ScalarPtr -> CSize -> IO () foreign import ccall "blst_p2_cneg" c_blst_p2_cneg :: Point2Ptr -> Bool -> IO () -foreign import ccall "blst_hash_to_g2" c_blst_hash_to_g2 :: Point2Ptr -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> IO () +foreign import ccall "blst_hash_to_g2" + c_blst_hash_to_g2 :: + Point2Ptr -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> IO () foreign import ccall "blst_p2_compress" c_blst_p2_compress :: Ptr CChar -> Point2Ptr -> IO () foreign import ccall "blst_p2_serialize" c_blst_p2_serialize :: Ptr CChar -> Point2Ptr -> IO () foreign import ccall "blst_p2_uncompress" c_blst_p2_uncompress :: Affine2Ptr -> Ptr CChar -> IO CInt -foreign import ccall "blst_p2_deserialize" c_blst_p2_deserialize :: Affine2Ptr -> Ptr CChar -> IO CInt +foreign import ccall "blst_p2_deserialize" + c_blst_p2_deserialize :: Affine2Ptr -> Ptr CChar -> IO CInt foreign import ccall "blst_p2_in_g2" c_blst_p2_in_g2 :: Point2Ptr -> IO Bool @@ -588,10 +587,14 @@ foreign import ccall "blst_p2_is_inf" c_blst_p2_is_inf :: Point2Ptr -> IO Bool foreign import ccall "size_blst_affine1" c_size_blst_affine1 :: CSize foreign import ccall "size_blst_affine2" c_size_blst_affine2 :: CSize -foreign import ccall "blst_p1_to_affine" c_blst_p1_to_affine :: AffinePtr Curve1 -> PointPtr Curve1 -> IO () -foreign import ccall "blst_p2_to_affine" c_blst_p2_to_affine :: AffinePtr Curve2 -> PointPtr Curve2 -> IO () -foreign import ccall "blst_p1_from_affine" c_blst_p1_from_affine :: PointPtr Curve1 -> AffinePtr Curve1 -> IO () -foreign import ccall "blst_p2_from_affine" c_blst_p2_from_affine :: PointPtr Curve2 -> AffinePtr Curve2 -> IO () +foreign import ccall "blst_p1_to_affine" + c_blst_p1_to_affine :: AffinePtr Curve1 -> PointPtr Curve1 -> IO () +foreign import ccall "blst_p2_to_affine" + c_blst_p2_to_affine :: AffinePtr Curve2 -> PointPtr Curve2 -> IO () +foreign import ccall "blst_p1_from_affine" + c_blst_p1_from_affine :: PointPtr Curve1 -> AffinePtr Curve1 -> IO () +foreign import ccall "blst_p2_from_affine" + c_blst_p2_from_affine :: PointPtr Curve2 -> AffinePtr Curve2 -> IO () foreign import ccall "blst_p1_affine_in_g1" c_blst_p1_affine_in_g1 :: AffinePtr Curve1 -> IO Bool foreign import ccall "blst_p2_affine_in_g2" c_blst_p2_affine_in_g2 :: AffinePtr Curve2 -> IO Bool @@ -605,7 +608,8 @@ foreign import ccall "blst_fp12_finalverify" c_blst_fp12_finalverify :: PTPtr -> ---- Pairing -foreign import ccall "blst_miller_loop" c_blst_miller_loop :: PTPtr -> Affine2Ptr -> Affine1Ptr -> IO () +foreign import ccall "blst_miller_loop" + c_blst_miller_loop :: PTPtr -> Affine2Ptr -> Affine1Ptr -> IO () ---- Raw BLST error constants @@ -621,7 +625,8 @@ foreign import ccall "blst_error_bad_scalar" c_blst_error_bad_scalar :: CInt ---- Utility functions foreign import ccall "memcmp" c_memcmp :: Ptr a -> Ptr a -> CSize -> IO CSize -foreign import ccall "blst_bendian_from_scalar" c_blst_bendian_from_scalar :: Ptr CChar -> ScalarPtr -> IO () +foreign import ccall "blst_bendian_from_scalar" + c_blst_bendian_from_scalar :: Ptr CChar -> ScalarPtr -> IO () data BLSTError = BLST_SUCCESS @@ -637,24 +642,24 @@ data BLSTError mkBLSTError :: CInt -> BLSTError mkBLSTError e - | e == c_blst_success - = BLST_SUCCESS - | e == c_blst_error_bad_encoding - = BLST_BAD_ENCODING - | e == c_blst_error_point_not_on_curve - = BLST_POINT_NOT_ON_CURVE - | e == c_blst_error_point_not_in_group - = BLST_POINT_NOT_IN_GROUP - | e == c_blst_error_aggr_type_mismatch - = BLST_AGGR_TYPE_MISMATCH - | e == c_blst_error_verify_fail - = BLST_VERIFY_FAIL - | e == c_blst_error_pk_is_infinity - = BLST_PK_IS_INFINITY - | e == c_blst_error_bad_scalar - = BLST_BAD_SCALAR - | otherwise - = BLST_UNKNOWN_ERROR + | e == c_blst_success = + BLST_SUCCESS + | e == c_blst_error_bad_encoding = + BLST_BAD_ENCODING + | e == c_blst_error_point_not_on_curve = + BLST_POINT_NOT_ON_CURVE + | e == c_blst_error_point_not_in_group = + BLST_POINT_NOT_IN_GROUP + | e == c_blst_error_aggr_type_mismatch = + BLST_AGGR_TYPE_MISMATCH + | e == c_blst_error_verify_fail = + BLST_VERIFY_FAIL + | e == c_blst_error_pk_is_infinity = + BLST_PK_IS_INFINITY + | e == c_blst_error_bad_scalar = + BLST_BAD_SCALAR + | otherwise = + BLST_UNKNOWN_ERROR ---- Curve point operations @@ -668,8 +673,9 @@ instance Eq Scalar where a == b = scalarToBS a == scalarToBS b instance Eq Fr where - a == b = unsafePerformIO $ - (==) <$> scalarFromFr a <*> scalarFromFr b + a == b = + unsafePerformIO $ + (==) <$> scalarFromFr a <*> scalarFromFr b -- | Check whether a point is in the group corresponding to its elliptic curve blsInGroup :: BLS curve => Point curve -> Bool @@ -712,54 +718,60 @@ blsNeg p = blsCneg p True blsUncompress :: forall curve. BLS curve => ByteString -> Either BLSTError (Point curve) blsUncompress bs = unsafePerformIO $ do BSU.unsafeUseAsCStringLen bs $ \(bytes, numBytes) -> - if numBytes == compressedSizePoint (Proxy @curve) then do - (err, affine) <- withNewAffine $ \ap -> c_blst_uncompress ap bytes - let p = fromAffine affine - if err /= 0 then - return $ Left $ mkBLSTError err - else - if blsInGroup p then - return $ Right p - else - return $ Left BLST_POINT_NOT_IN_GROUP - else do - return $ Left BLST_BAD_ENCODING + if numBytes == compressedSizePoint (Proxy @curve) + then do + (err, affine) <- withNewAffine $ \ap -> c_blst_uncompress ap bytes + let p = fromAffine affine + if err /= 0 + then + return $ Left $ mkBLSTError err + else + if blsInGroup p + then + return $ Right p + else + return $ Left BLST_POINT_NOT_IN_GROUP + else do + return $ Left BLST_BAD_ENCODING blsDeserialize :: forall curve. BLS curve => ByteString -> Either BLSTError (Point curve) blsDeserialize bs = unsafePerformIO $ do BSU.unsafeUseAsCStringLen bs $ \(bytes, numBytes) -> - if numBytes == serializedSizePoint (Proxy @curve) then do - (err, affine) <- withNewAffine $ \ap -> c_blst_deserialize ap bytes - let p = fromAffine affine - if err /= 0 then - return $ Left $ mkBLSTError err - else - if blsInGroup p then - return $ Right p - else - return $ Left BLST_POINT_NOT_IN_GROUP - else do - return $ Left BLST_BAD_ENCODING + if numBytes == serializedSizePoint (Proxy @curve) + then do + (err, affine) <- withNewAffine $ \ap -> c_blst_deserialize ap bytes + let p = fromAffine affine + if err /= 0 + then + return $ Left $ mkBLSTError err + else + if blsInGroup p + then + return $ Right p + else + return $ Left BLST_POINT_NOT_IN_GROUP + else do + return $ Left BLST_BAD_ENCODING blsCompress :: forall curve. BLS curve => Point curve -> ByteString blsCompress p = BSI.fromForeignPtr (castForeignPtr ptr) 0 (compressedSizePoint (Proxy @curve)) - where - ptr = unsafePerformIO $ do - cstr <- mallocForeignPtrBytes (compressedSizePoint (Proxy @curve)) - withForeignPtr cstr $ \cstrp -> do - withPoint p $ \pp -> do - c_blst_compress cstrp pp - return cstr + where + ptr = unsafePerformIO $ do + cstr <- mallocForeignPtrBytes (compressedSizePoint (Proxy @curve)) + withForeignPtr cstr $ \cstrp -> do + withPoint p $ \pp -> do + c_blst_compress cstrp pp + return cstr blsSerialize :: forall curve. BLS curve => Point curve -> ByteString blsSerialize p = BSI.fromForeignPtr (castForeignPtr ptr) 0 (serializedSizePoint (Proxy @curve)) - where - ptr = unsafePerformIO $ do - cstr <- mallocForeignPtrBytes (serializedSizePoint (Proxy @curve)) - withForeignPtr cstr $ \cstrp -> do - withPoint p $ \pp -> do - c_blst_serialize cstrp pp - return cstr + where + ptr = unsafePerformIO $ do + cstr <- mallocForeignPtrBytes (serializedSizePoint (Proxy @curve)) + withForeignPtr cstr $ \cstrp -> do + withPoint p $ \pp -> do + c_blst_serialize cstrp pp + return cstr -- | @blsHash msg mDST mAug@ generates the elliptic curve blsHash for the given -- message @msg@; @mDST@ and @mAug@ are the optional @aug@ and @dst@ @@ -770,7 +782,14 @@ blsHash msg mDST mAug = unsafePerformIO $ withMaybeCStringLen mDST $ \(dstPtr, dstLen) -> withMaybeCStringLen mAug $ \(augPtr, augLen) -> withNewPoint' $ \pPtr -> - c_blst_hash pPtr msgPtr (fromIntegral msgLen) dstPtr (fromIntegral dstLen) augPtr (fromIntegral augLen) + c_blst_hash + pPtr + msgPtr + (fromIntegral msgLen) + dstPtr + (fromIntegral dstLen) + augPtr + (fromIntegral augLen) toAffine :: BLS curve => Point curve -> Affine curve toAffine p = unsafePerformIO $ @@ -789,8 +808,9 @@ blsIsInf :: BLS curve => Point curve -> Bool blsIsInf p = unsafePerformIO $ withPoint p c_blst_p_is_inf affineInG :: BLS curve => Affine curve -> Bool -affineInG affine = unsafePerformIO $ - withAffine affine c_blst_affine_in_g +affineInG affine = + unsafePerformIO $ + withAffine affine c_blst_affine_in_g blsGenerator :: BLS curve => Point curve blsGenerator = unsafePointFromPointPtr c_blst_generator @@ -800,11 +820,11 @@ blsZero = -- Compressed serialised G1 points are bytestrings of length 48: see CIP-0381. let b = BS.pack (0xc0 : replicate (compressedSizePoint (Proxy @curve) - 1) 0x00) in case blsUncompress b of - Left err -> + Left err -> error $ "Unexpected failure deserialising point at infinity on BLS12_381.G1: " ++ show err Right infinity -> - infinity -- The zero point on this curve is chosen to be the point at infinity. ----- Scalar / Fr operations + infinity -- The zero point on this curve is chosen to be the point at infinity. + ---- Scalar / Fr operations scalarFromFr :: Fr -> IO Scalar scalarFromFr fr = @@ -814,43 +834,46 @@ scalarFromFr fr = frFromScalar :: Scalar -> IO Fr frFromScalar scalar = - withNewFr' $ \frPtr -> - withScalar scalar $ \scalarPtr -> - c_blst_fr_from_scalar frPtr scalarPtr + withNewFr' $ \frPtr -> + withScalar scalar $ \scalarPtr -> + c_blst_fr_from_scalar frPtr scalarPtr frFromCanonicalScalar :: Scalar -> IO (Maybe Fr) frFromCanonicalScalar scalar - | scalarCanonical scalar - = Just <$> frFromScalar scalar - | otherwise - = return Nothing + | scalarCanonical scalar = + Just <$> frFromScalar scalar + | otherwise = + return Nothing scalarFromBS :: ByteString -> Either BLSTError Scalar scalarFromBS bs = unsafePerformIO $ do BSU.unsafeUseAsCStringLen bs $ \(cstr, l) -> - if l == sizeScalar then do - (success, scalar) <- withNewScalar $ \scalarPtr -> - c_blst_scalar_from_be_bytes scalarPtr cstr (fromIntegral l) - if success then - return $ Right scalar + if l == sizeScalar + then do + (success, scalar) <- withNewScalar $ \scalarPtr -> + c_blst_scalar_from_be_bytes scalarPtr cstr (fromIntegral l) + if success + then + return $ Right scalar + else + return $ Left BLST_BAD_SCALAR else return $ Left BLST_BAD_SCALAR - else - return $ Left BLST_BAD_SCALAR scalarToBS :: Scalar -> ByteString scalarToBS scalar = BSI.fromForeignPtr (castForeignPtr ptr) 0 sizeScalar - where - ptr = unsafePerformIO $ do - cstr <- mallocForeignPtrBytes sizeScalar - withForeignPtr cstr $ \cstrp -> do - withScalar scalar $ \scalarPtr -> do - c_blst_bendian_from_scalar cstrp scalarPtr - return cstr + where + ptr = unsafePerformIO $ do + cstr <- mallocForeignPtrBytes sizeScalar + withForeignPtr cstr $ \cstrp -> do + withScalar scalar $ \scalarPtr -> do + c_blst_bendian_from_scalar cstrp scalarPtr + return cstr scalarCanonical :: Scalar -> Bool -scalarCanonical scalar = unsafePerformIO $ - withScalar scalar c_blst_scalar_fr_check +scalarCanonical scalar = + unsafePerformIO $ + withScalar scalar c_blst_scalar_fr_check ---- PT operations diff --git a/cardano-crypto-class/src/Cardano/Crypto/Hash.hs b/cardano-crypto-class/src/Cardano/Crypto/Hash.hs index 32aed09b9..7e7e88da4 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Hash.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Hash.hs @@ -1,13 +1,13 @@ -- | Hashing functionality. -module Cardano.Crypto.Hash - ( module X - ) +module Cardano.Crypto.Hash ( + module X, +) where import Cardano.Crypto.Hash.Blake2b as X import Cardano.Crypto.Hash.Class as X +import Cardano.Crypto.Hash.Keccak256 as X import Cardano.Crypto.Hash.NeverUsed as X import Cardano.Crypto.Hash.SHA256 as X import Cardano.Crypto.Hash.SHA3_256 as X import Cardano.Crypto.Hash.Short as X -import Cardano.Crypto.Hash.Keccak256 as X diff --git a/cardano-crypto-class/src/Cardano/Crypto/Hash/Blake2b.hs b/cardano-crypto-class/src/Cardano/Crypto/Hash/Blake2b.hs index 81facd034..7f1a326fc 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Hash/Blake2b.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Hash/Blake2b.hs @@ -2,19 +2,19 @@ {-# LANGUAGE TypeFamilies #-} -- | Implementation of the Blake2b hashing algorithm, with various sizes. -module Cardano.Crypto.Hash.Blake2b - ( Blake2b_224 - , Blake2b_256 - , blake2b_libsodium -- Used for Hash.Short - ) +module Cardano.Crypto.Hash.Blake2b ( + Blake2b_224, + Blake2b_256, + blake2b_libsodium, -- Used for Hash.Short +) where -import Control.Monad (unless) import Cardano.Crypto.Libsodium.C (c_crypto_generichash_blake2b) +import Control.Monad (unless) -import Cardano.Crypto.Hash.Class (HashAlgorithm (..), SizeHash, hashAlgorithmName, digest) -import Foreign.Ptr (castPtr, nullPtr) +import Cardano.Crypto.Hash.Class (HashAlgorithm (..), SizeHash, digest, hashAlgorithmName) import Foreign.C.Error (errnoToIOError, getErrno) +import Foreign.Ptr (castPtr, nullPtr) import GHC.IO.Exception (ioException) import qualified Data.ByteString as B @@ -37,7 +37,14 @@ blake2b_libsodium :: Int -> B.ByteString -> B.ByteString blake2b_libsodium size input = BI.unsafeCreate size $ \outptr -> B.useAsCStringLen input $ \(inptr, inputlen) -> do - res <- c_crypto_generichash_blake2b (castPtr outptr) (fromIntegral size) (castPtr inptr) (fromIntegral inputlen) nullPtr 0 -- we used unkeyed hash + res <- + c_crypto_generichash_blake2b + (castPtr outptr) + (fromIntegral size) + (castPtr inptr) + (fromIntegral inputlen) + nullPtr + 0 -- we used unkeyed hash unless (res == 0) $ do errno <- getErrno ioException $ errnoToIOError "digest @Blake2b: crypto_generichash_blake2b" errno Nothing Nothing diff --git a/cardano-crypto-class/src/Cardano/Crypto/Hash/Class.hs b/cardano-crypto-class/src/Cardano/Crypto/Hash/Class.hs index 51296e2be..e3e5d6d09 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Hash/Class.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Hash/Class.hs @@ -14,50 +14,50 @@ {-# LANGUAGE ViewPatterns #-} -- | Abstract hashing functionality. -module Cardano.Crypto.Hash.Class - ( HashAlgorithm (..) - , sizeHash - , ByteString - , Hash(UnsafeHash) - , PackedBytes(PackedBytes8, PackedBytes28, PackedBytes32) - - -- * Core operations - , hashWith - , hashWithSerialiser - - -- * Conversions - , castHash - , hashToBytes - , hashFromBytes - , hashToBytesShort - , hashFromBytesShort - , hashFromOffsetBytesShort - , hashToPackedBytes - , hashFromPackedBytes - - -- * Rendering and parsing - , hashToBytesAsHex - , hashFromBytesAsHex - , hashToTextAsHex - , hashFromTextAsHex - , hashToStringAsHex - , hashFromStringAsHex - - -- * Other operations - , xor - - -- * Deprecated - , hash - , fromHash - , hashRaw - , getHash - , getHashBytesAsHex - ) +module Cardano.Crypto.Hash.Class ( + HashAlgorithm (..), + sizeHash, + ByteString, + Hash (UnsafeHash), + PackedBytes (PackedBytes8, PackedBytes28, PackedBytes32), + + -- * Core operations + hashWith, + hashWithSerialiser, + + -- * Conversions + castHash, + hashToBytes, + hashFromBytes, + hashToBytesShort, + hashFromBytesShort, + hashFromOffsetBytesShort, + hashToPackedBytes, + hashFromPackedBytes, + + -- * Rendering and parsing + hashToBytesAsHex, + hashFromBytesAsHex, + hashToTextAsHex, + hashFromTextAsHex, + hashToStringAsHex, + hashFromStringAsHex, + + -- * Other operations + xor, + + -- * Deprecated + hash, + fromHash, + hashRaw, + getHash, + getHashBytesAsHex, +) where import qualified Data.Foldable as F (foldl') import Data.Maybe (maybeToList) -import Data.Proxy (Proxy(..)) +import Data.Proxy (Proxy (..)) import Data.Typeable (Typeable) import GHC.Generics (Generic) import GHC.TypeLits (KnownNat, Nat, natVal) @@ -68,18 +68,18 @@ import qualified Data.ByteString.Base16 as Base16 import qualified Data.ByteString.Char8 as BSC import Data.ByteString.Short (ShortByteString) import qualified Data.ByteString.Short as SBS -import Data.MemPack (StateT(StateT), FailT(FailT), MemPack, Unpack(Unpack)) +import Data.MemPack (FailT (FailT), MemPack, StateT (StateT), Unpack (Unpack)) import Data.Word (Word8) import Numeric.Natural (Natural) -import Data.String (IsString(..)) +import Data.String (IsString (..)) import Data.Text (Text) import qualified Data.Text as Text import qualified Data.Text.Encoding as Text -import Language.Haskell.TH.Syntax (Q, TExp(..)) +import Language.Haskell.TH.Syntax (Q, TExp (..)) import Language.Haskell.TH.Syntax.Compat (Code (Code), examineSplice) -import Data.Aeson (FromJSON(..), FromJSONKey(..), ToJSON(..), ToJSONKey(..)) +import Data.Aeson (FromJSON (..), FromJSONKey (..), ToJSON (..), ToJSONKey (..)) import qualified Data.Aeson as Aeson import qualified Data.Aeson.Types as Aeson @@ -87,7 +87,7 @@ import Control.DeepSeq (NFData) import NoThunks.Class (NoThunks) -import Cardano.Binary (Encoding, FromCBOR(..), Size, ToCBOR(..), serialize') +import Cardano.Binary (Encoding, FromCBOR (..), Size, ToCBOR (..), serialize') import Cardano.Crypto.PackedBytes import Cardano.Crypto.Util (decodeHexString) import Cardano.HeapWords (HeapWords (..)) @@ -95,7 +95,7 @@ import Cardano.HeapWords (HeapWords (..)) import qualified Data.ByteString.Short.Internal as SBSI class (KnownNat (SizeHash h), Typeable h) => HashAlgorithm h where - --TODO: eliminate this Typeable constraint needed only for the ToCBOR + -- TODO: eliminate this Typeable constraint needed only for the ToCBOR -- the ToCBOR should not need it either -- | Size of hash digest @@ -144,7 +144,7 @@ instance HashAlgorithm h => IsString (Q (TExp (Hash h a))) where let n = fromInteger $ natVal (Proxy @(SizeHash h)) case decodeHexString hexStr n of Left err -> fail $ ": " ++ err - Right _ -> examineSplice [|| either error (UnsafeHashRep . packPinnedBytes) (decodeHexString hexStr n) ||] + Right _ -> examineSplice [||either error (UnsafeHashRep . packPinnedBytes) (decodeHexString hexStr n)||] instance HashAlgorithm h => IsString (Code Q (Hash h a)) where fromString = Code . fromString @@ -152,11 +152,11 @@ instance HashAlgorithm h => IsString (Code Q (Hash h a)) where pattern UnsafeHash :: forall h a. HashAlgorithm h => ShortByteString -> Hash h a pattern UnsafeHash bytes <- UnsafeHashRep (unpackBytes -> bytes) where - UnsafeHash bytes = - case hashFromBytesShort bytes of - Nothing -> - error "UnsafeHash: mismatched size of the supplied ShortByteString and the expected digest" - Just h -> h + UnsafeHash bytes = + case hashFromBytesShort bytes of + Nothing -> + error "UnsafeHash: mismatched size of the supplied ShortByteString and the expected digest" + Just h -> h {-# COMPLETE UnsafeHash #-} -- @@ -164,21 +164,17 @@ pattern UnsafeHash bytes <- UnsafeHashRep (unpackBytes -> bytes) -- -- | Hash the given value, using a serialisation function to turn it into bytes. --- hashWith :: forall h a. HashAlgorithm h => (a -> ByteString) -> a -> Hash h a hashWith serialise = - UnsafeHashRep - . packPinnedBytes - . digest (Proxy :: Proxy h) - . serialise - + UnsafeHashRep + . packPinnedBytes + . digest (Proxy :: Proxy h) + . serialise -- | A variation on 'hashWith', but specially for CBOR encodings. --- hashWithSerialiser :: forall h a. HashAlgorithm h => (a -> Encoding) -> a -> Hash h a hashWithSerialiser toEnc = hashWith (serialize' . toEnc) - -- -- Conversions -- @@ -188,64 +184,55 @@ hashWithSerialiser toEnc = hashWith (serialize' . toEnc) -- The 'Hash' type has a phantom type parameter to indicate what type the -- hash is of. It is sometimes necessary to fake this and hash a value of one -- type and use it where as hash of a different type is expected. --- castHash :: Hash h a -> Hash h b castHash (UnsafeHashRep h) = UnsafeHashRep h - -- | The representation of the hash as bytes. --- hashToBytes :: Hash h a -> ByteString hashToBytes (UnsafeHashRep h) = unpackPinnedBytes h - -- | Make a hash from it bytes representation. --- hashFromBytes :: - forall h a. HashAlgorithm h - => ByteString - -- ^ It must have an exact length, as given by 'sizeHash'. - -> Maybe (Hash h a) + forall h a. + HashAlgorithm h => + -- | It must have an exact length, as given by 'sizeHash'. + ByteString -> + Maybe (Hash h a) hashFromBytes bytes - | BS.length bytes == fromIntegral (sizeHash (Proxy :: Proxy h)) - = Just $ UnsafeHashRep (packPinnedBytes bytes) - - | otherwise - = Nothing + | BS.length bytes == fromIntegral (sizeHash (Proxy :: Proxy h)) = + Just $ UnsafeHashRep (packPinnedBytes bytes) + | otherwise = + Nothing -- | Make a hash from it bytes representation, as a 'ShortByteString'. --- hashFromBytesShort :: - forall h a. HashAlgorithm h - => ShortByteString - -- ^ It must be a buffer of exact length, as given by 'sizeHash'. - -> Maybe (Hash h a) + forall h a. + HashAlgorithm h => + -- | It must be a buffer of exact length, as given by 'sizeHash'. + ShortByteString -> + Maybe (Hash h a) hashFromBytesShort bytes = UnsafeHashRep <$> packBytesMaybe bytes 0 -- | Just like `hashFromBytesShort`, but allows using a region of a 'ShortByteString'. --- hashFromOffsetBytesShort :: - forall h a. HashAlgorithm h - => ShortByteString - -- ^ It must be a buffer that contains at least 'sizeHash' many bytes staring at an offset. - -> Int - -- ^ Offset in number of bytes - -> Maybe (Hash h a) + forall h a. + HashAlgorithm h => + -- | It must be a buffer that contains at least 'sizeHash' many bytes staring at an offset. + ShortByteString -> + -- | Offset in number of bytes + Int -> + Maybe (Hash h a) hashFromOffsetBytesShort bytes offset = UnsafeHashRep <$> packBytesMaybe bytes offset - -- | The representation of the hash as bytes, as a 'ShortByteString'. --- hashToBytesShort :: Hash h a -> ShortByteString hashToBytesShort (UnsafeHashRep h) = unpackBytes h -- | /O(1)/ - Get the underlying hash representation --- hashToPackedBytes :: Hash h a -> PackedBytes (SizeHash h) hashToPackedBytes (UnsafeHashRep pb) = pb -- | /O(1)/ - Construct hash from the underlying representation --- hashFromPackedBytes :: PackedBytes (SizeHash h) -> Hash h a hashFromPackedBytes = UnsafeHashRep @@ -261,12 +248,10 @@ hashToStringAsHex = Text.unpack . hashToTextAsHex -- -- This can fail for the same reason as 'hashFromBytes', or because the input -- is invalid hex. The whole byte string must be valid hex, not just a prefix. --- hashFromStringAsHex :: HashAlgorithm h => String -> Maybe (Hash h a) hashFromStringAsHex = hashFromTextAsHex . Text.pack -- | Convert the hash to hex encoding, as 'Text'. --- hashToTextAsHex :: Hash h a -> Text hashToTextAsHex = Text.decodeLatin1 . hashToBytesAsHex @@ -274,12 +259,10 @@ hashToTextAsHex = Text.decodeLatin1 . hashToBytesAsHex -- -- This can fail for the same reason as 'hashFromBytes', or because the input -- is invalid hex. The whole byte string must be valid hex, not just a prefix. --- hashFromTextAsHex :: HashAlgorithm h => Text -> Maybe (Hash h a) hashFromTextAsHex = hashFromBytesAsHex . Text.encodeUtf8 -- | Convert the hash to hex encoding, as 'ByteString'. --- hashToBytesAsHex :: Hash h a -> ByteString hashToBytesAsHex = Base16.encode . hashToBytes @@ -287,7 +270,6 @@ hashToBytesAsHex = Base16.encode . hashToBytes -- -- This can fail for the same reason as 'hashFromBytes', or because the input -- is invalid hex. The whole byte string must be valid hex, not just a prefix. --- hashFromBytesAsHex :: HashAlgorithm h => ByteString -> Maybe (Hash h a) hashFromBytesAsHex bsHex = do Right bs <- Just $ Base16.decode bsHex @@ -297,12 +279,12 @@ instance Show (Hash h a) where show = show . hashToStringAsHex instance HashAlgorithm h => Read (Hash h a) where - readsPrec p str = [ (h, y) | (x, y) <- readsPrec p str, h <- maybeToList (hashFromStringAsHex x) ] + readsPrec p str = [(h, y) | (x, y) <- readsPrec p str, h <- maybeToList (hashFromStringAsHex x)] instance HashAlgorithm h => IsString (Hash h a) where fromString str = case hashFromBytesAsHex (BSC.pack str) of - Just x -> x + Just x -> x Nothing -> error ("fromString: cannot decode hash " ++ show str) instance HashAlgorithm h => ToJSONKey (Hash h a) where @@ -326,9 +308,9 @@ instance HeapWords (Hash h a) where parseHash :: HashAlgorithm crypto => Text -> Aeson.Parser (Hash crypto a) parseHash t = - case Base16.decode (Text.encodeUtf8 t) of - Right bytes -> maybe badSize return (hashFromBytes bytes) - Left _ -> badHex + case Base16.decode (Text.encodeUtf8 t) of + Right bytes -> maybe badSize return (hashFromBytes bytes) + Left _ -> badHex where badHex :: Aeson.Parser b badHex = fail "Hashes are expected in hex encoding" @@ -343,14 +325,13 @@ parseHash t = instance (HashAlgorithm h, Typeable a) => ToCBOR (Hash h a) where toCBOR (UnsafeHash h) = toCBOR h - -- | 'Size' expression for @Hash h a@, which is expressed using the 'ToCBOR' + -- \| 'Size' expression for @Hash h a@, which is expressed using the 'ToCBOR' -- instance for 'ByteString' (as is the above 'toCBOR' method). 'Size' -- computation of length of the bytestring is passed as the first argument to -- 'encodedSizeExpr'. The 'ByteString' instance will use it to calculate -- @'size' ('Proxy' @('LengthOf' 'ByteString'))@. - -- encodedSizeExpr _size proxy = - encodedSizeExpr (const hashSize) (hashToBytes <$> proxy) + encodedSizeExpr (const hashSize) (hashToBytes <$> proxy) where hashSize :: Size hashSize = fromIntegral (sizeHash (Proxy :: Proxy h)) @@ -359,12 +340,16 @@ instance (HashAlgorithm h, Typeable a) => FromCBOR (Hash h a) where fromCBOR = do sbs <- fromCBOR case hashFromBytesShort sbs of - Just x -> return x - Nothing -> fail $ "hash bytes wrong size, expected " ++ show expected - ++ " but got " ++ show actual + Just x -> return x + Nothing -> + fail $ + "hash bytes wrong size, expected " + ++ show expected + ++ " but got " + ++ show actual where expected = sizeHash (Proxy :: Proxy h) - actual = SBS.length sbs + actual = SBS.length sbs -- -- Deprecated diff --git a/cardano-crypto-class/src/Cardano/Crypto/Hash/Keccak256.hs b/cardano-crypto-class/src/Cardano/Crypto/Hash/Keccak256.hs index ca6b3fc5b..e6a47a557 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Hash/Keccak256.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Hash/Keccak256.hs @@ -3,14 +3,14 @@ {-# LANGUAGE TypeFamilies #-} -- | Implementation of the Keccak256 hashing algorithm. -module Cardano.Crypto.Hash.Keccak256 - ( Keccak256 - ) +module Cardano.Crypto.Hash.Keccak256 ( + Keccak256, +) where import Cardano.Crypto.Hash.Class -import qualified "crypton" Crypto.Hash as H import qualified Data.ByteArray as BA +import qualified "crypton" Crypto.Hash as H data Keccak256 diff --git a/cardano-crypto-class/src/Cardano/Crypto/Hash/NeverUsed.hs b/cardano-crypto-class/src/Cardano/Crypto/Hash/NeverUsed.hs index 1e7faf857..6ff12a59b 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Hash/NeverUsed.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Hash/NeverUsed.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeFamilies #-} + module Cardano.Crypto.Hash.NeverUsed (NeverHash) where import Cardano.Crypto.Hash.Class diff --git a/cardano-crypto-class/src/Cardano/Crypto/Hash/RIPEMD160.hs b/cardano-crypto-class/src/Cardano/Crypto/Hash/RIPEMD160.hs index c9e91ad0a..44fc6e46b 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Hash/RIPEMD160.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Hash/RIPEMD160.hs @@ -3,14 +3,14 @@ {-# LANGUAGE TypeFamilies #-} -- | Implementation of the RIPEMD-160 hashing algorithm. -module Cardano.Crypto.Hash.RIPEMD160 - ( RIPEMD160 - ) - where +module Cardano.Crypto.Hash.RIPEMD160 ( + RIPEMD160, +) +where import Cardano.Crypto.Hash.Class -import qualified "crypton" Crypto.Hash as H import qualified Data.ByteArray as BA +import qualified "crypton" Crypto.Hash as H data RIPEMD160 diff --git a/cardano-crypto-class/src/Cardano/Crypto/Hash/SHA256.hs b/cardano-crypto-class/src/Cardano/Crypto/Hash/SHA256.hs index 67b0212a9..2f73f4782 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Hash/SHA256.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Hash/SHA256.hs @@ -2,26 +2,25 @@ {-# LANGUAGE TypeFamilies #-} -- | Implementation of the SHA256 hashing algorithm. -module Cardano.Crypto.Hash.SHA256 - ( SHA256 - ) +module Cardano.Crypto.Hash.SHA256 ( + SHA256, +) where -import Control.Monad (unless) +import Cardano.Crypto.Hash.Class (HashAlgorithm, SizeHash, digest, hashAlgorithmName) import Cardano.Crypto.Libsodium.C (c_crypto_hash_sha256) -import Cardano.Foreign (SizedPtr(SizedPtr)) -import Cardano.Crypto.Hash.Class (HashAlgorithm, SizeHash, hashAlgorithmName, digest) +import Cardano.Foreign (SizedPtr (SizedPtr)) +import Control.Monad (unless) -import Foreign.Ptr (castPtr) +import Data.Proxy (Proxy (..)) import Foreign.C.Error (errnoToIOError, getErrno) -import Data.Proxy (Proxy(..)) -import GHC.TypeLits (natVal) +import Foreign.Ptr (castPtr) import GHC.IO.Exception (ioException) +import GHC.TypeLits (natVal) import qualified Data.ByteString as B import qualified Data.ByteString.Internal as BI - data SHA256 instance HashAlgorithm SHA256 where @@ -35,8 +34,7 @@ sha256_libsodium input = B.useAsCStringLen input $ \(inptr, inputlen) -> do res <- c_crypto_hash_sha256 (SizedPtr (castPtr outptr)) (castPtr inptr) (fromIntegral inputlen) unless (res == 0) $ do - errno <- getErrno - ioException $ errnoToIOError "digest @SHA256: c_crypto_hash_sha256" errno Nothing Nothing - + errno <- getErrno + ioException $ errnoToIOError "digest @SHA256: c_crypto_hash_sha256" errno Nothing Nothing where - expected_size = fromIntegral (natVal (Proxy::Proxy (SizeHash SHA256))) + expected_size = fromIntegral (natVal (Proxy :: Proxy (SizeHash SHA256))) diff --git a/cardano-crypto-class/src/Cardano/Crypto/Hash/SHA3_256.hs b/cardano-crypto-class/src/Cardano/Crypto/Hash/SHA3_256.hs index 0a0b17642..5ba2825b7 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Hash/SHA3_256.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Hash/SHA3_256.hs @@ -3,14 +3,14 @@ {-# LANGUAGE TypeFamilies #-} -- | Implementation of the SHA3_256 hashing algorithm. -module Cardano.Crypto.Hash.SHA3_256 - ( SHA3_256 - ) +module Cardano.Crypto.Hash.SHA3_256 ( + SHA3_256, +) where import Cardano.Crypto.Hash.Class -import qualified "crypton" Crypto.Hash as H import qualified Data.ByteArray as BA +import qualified "crypton" Crypto.Hash as H data SHA3_256 diff --git a/cardano-crypto-class/src/Cardano/Crypto/Hash/Short.hs b/cardano-crypto-class/src/Cardano/Crypto/Hash/Short.hs index 6efeadb55..f17452745 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Hash/Short.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Hash/Short.hs @@ -5,17 +5,17 @@ {-# LANGUAGE TypeOperators #-} -- | Implementation of short hashing algorithm, suitable for testing. -module Cardano.Crypto.Hash.Short - ( ShortHash - , Blake2bPrefix - ) +module Cardano.Crypto.Hash.Short ( + ShortHash, + Blake2bPrefix, +) where -import Cardano.Crypto.Hash.Class import Cardano.Crypto.Hash.Blake2b (blake2b_libsodium) +import Cardano.Crypto.Hash.Class -import GHC.TypeLits (Nat, KnownNat, CmpNat, natVal) import Data.Proxy (Proxy (..)) +import GHC.TypeLits (CmpNat, KnownNat, Nat, natVal) type ShortHash = Blake2bPrefix 8 diff --git a/cardano-crypto-class/src/Cardano/Crypto/Init.hs b/cardano-crypto-class/src/Cardano/Crypto/Init.hs index 70d2028ea..d6f5f0d4d 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Init.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Init.hs @@ -2,8 +2,8 @@ -- | Initialization for the library's functionality module Cardano.Crypto.Init ( - cryptoInit - ) where + cryptoInit, +) where import Cardano.Crypto.Libsodium.Init (sodiumInit) #if defined(SECP256K1_ENABLED) diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES.hs b/cardano-crypto-class/src/Cardano/Crypto/KES.hs index 13f109463..0d7e96cf1 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES.hs @@ -1,14 +1,14 @@ -- | Key evolving signatures. -module Cardano.Crypto.KES - ( module X - ) +module Cardano.Crypto.KES ( + module X, +) where import Cardano.Crypto.KES.Class as X +import Cardano.Crypto.KES.CompactSingle as X +import Cardano.Crypto.KES.CompactSum as X import Cardano.Crypto.KES.Mock as X import Cardano.Crypto.KES.NeverUsed as X import Cardano.Crypto.KES.Simple as X import Cardano.Crypto.KES.Single as X import Cardano.Crypto.KES.Sum as X -import Cardano.Crypto.KES.CompactSingle as X -import Cardano.Crypto.KES.CompactSum as X diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES/Class.hs b/cardano-crypto-class/src/Cardano/Crypto/KES/Class.hs index 9c7f3f5c0..651a26519 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES/Class.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES/Class.hs @@ -2,129 +2,127 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE RankNTypes #-} -- | Abstract key evolving signatures. -module Cardano.Crypto.KES.Class - ( - -- * KES algorithm class - KESAlgorithm (..) - , genKeyKES - , updateKES - , forgetSignKeyKES - , Period - - , OptimizedKESAlgorithm (..) - , verifyOptimizedKES - - -- * 'SignKeyWithPeriodKES' wrapper - , SignKeyWithPeriodKES (..) - , updateKESWithPeriod - - -- * 'SignedKES' wrapper - , SignedKES (..) - , signedKES - , verifySignedKES - - -- * CBOR encoding and decoding - , encodeVerKeyKES - , decodeVerKeyKES - , encodeSigKES - , decodeSigKES - , encodeSignedKES - , decodeSignedKES - - -- * Encoded 'Size' expressions - , encodedVerKeyKESSizeExpr - , encodedSignKeyKESSizeExpr - , encodedSigKESSizeExpr - - -- * Raw sizes - , sizeVerKeyKES - , sizeSigKES - , sizeSignKeyKES - , seedSizeKES - - -- * Unsound APIs - - , UnsoundKESAlgorithm (..) - , encodeSignKeyKES - , decodeSignKeyKES - , rawDeserialiseSignKeyKES - - , UnsoundPureKESAlgorithm (..) - , unsoundPureSignedKES - , encodeUnsoundPureSignKeyKES - , decodeUnsoundPureSignKeyKES - - -- * Utility functions - -- These are used between multiple KES implementations. User code will - -- most likely not need these, but they are required for recursive - -- definitions of the SumKES algorithms, and can be expressed entirely in - -- terms of the KES, DSIGN and Hash typeclasses, so we keep them here for - -- convenience. - , hashPairOfVKeys - , mungeName - , unsoundPureSignKeyKESToSoundSignKeyKESViaSer - ) +module Cardano.Crypto.KES.Class ( + -- * KES algorithm class + KESAlgorithm (..), + genKeyKES, + updateKES, + forgetSignKeyKES, + Period, + OptimizedKESAlgorithm (..), + verifyOptimizedKES, + + -- * 'SignKeyWithPeriodKES' wrapper + SignKeyWithPeriodKES (..), + updateKESWithPeriod, + + -- * 'SignedKES' wrapper + SignedKES (..), + signedKES, + verifySignedKES, + + -- * CBOR encoding and decoding + encodeVerKeyKES, + decodeVerKeyKES, + encodeSigKES, + decodeSigKES, + encodeSignedKES, + decodeSignedKES, + + -- * Encoded 'Size' expressions + encodedVerKeyKESSizeExpr, + encodedSignKeyKESSizeExpr, + encodedSigKESSizeExpr, + + -- * Raw sizes + sizeVerKeyKES, + sizeSigKES, + sizeSignKeyKES, + seedSizeKES, + + -- * Unsound APIs + UnsoundKESAlgorithm (..), + encodeSignKeyKES, + decodeSignKeyKES, + rawDeserialiseSignKeyKES, + UnsoundPureKESAlgorithm (..), + unsoundPureSignedKES, + encodeUnsoundPureSignKeyKES, + decodeUnsoundPureSignKeyKES, + + -- * Utility functions + + -- These are used between multiple KES implementations. User code will + -- most likely not need these, but they are required for recursive + -- definitions of the SumKES algorithms, and can be expressed entirely in + -- terms of the KES, DSIGN and Hash typeclasses, so we keep them here for + -- convenience. + hashPairOfVKeys, + mungeName, + unsoundPureSignKeyKESToSoundSignKeyKESViaSer, +) where +import Control.Monad.Class.MonadST (MonadST) +import Control.Monad.Class.MonadThrow (MonadThrow) +import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT) import Data.ByteString (ByteString) import qualified Data.ByteString as BS import Data.Kind (Type) -import Data.Proxy (Proxy(..)) +import Data.Proxy (Proxy (..)) import Data.Typeable (Typeable) import GHC.Exts (Constraint) import GHC.Generics (Generic) import GHC.Stack -import GHC.TypeLits (Nat, KnownNat, natVal, TypeError, ErrorMessage (..)) +import GHC.TypeLits (ErrorMessage (..), KnownNat, Nat, TypeError, natVal) import NoThunks.Class (NoThunks) -import Control.Monad.Class.MonadST (MonadST) -import Control.Monad.Class.MonadThrow (MonadThrow) -import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT) -import Cardano.Binary (Decoder, decodeBytes, Encoding, encodeBytes, Size, withWordSize) +import Cardano.Binary (Decoder, Encoding, Size, decodeBytes, encodeBytes, withWordSize) -import Cardano.Crypto.Util (Empty) -import Cardano.Crypto.Libsodium.MLockedSeed -import Cardano.Crypto.Libsodium (MLockedAllocator, mlockedMalloc) -import Cardano.Crypto.Hash.Class (HashAlgorithm, Hash, hashWith) import Cardano.Crypto.DSIGN.Class (failSizeCheck) +import Cardano.Crypto.Hash.Class (Hash, HashAlgorithm, hashWith) +import Cardano.Crypto.Libsodium (MLockedAllocator, mlockedMalloc) +import Cardano.Crypto.Libsodium.MLockedSeed import Cardano.Crypto.Seed +import Cardano.Crypto.Util (Empty) -class ( Typeable v - , Show (VerKeyKES v) - , Eq (VerKeyKES v) - , Show (SigKES v) - , Eq (SigKES v) - , NoThunks (SigKES v) - , NoThunks (SignKeyKES v) - , NoThunks (VerKeyKES v) - , KnownNat (SeedSizeKES v) - , KnownNat (SizeVerKeyKES v) - , KnownNat (SizeSignKeyKES v) - , KnownNat (SizeSigKES v) - ) - => KESAlgorithm v where +class + ( Typeable v + , Show (VerKeyKES v) + , Eq (VerKeyKES v) + , Show (SigKES v) + , Eq (SigKES v) + , NoThunks (SigKES v) + , NoThunks (SignKeyKES v) + , NoThunks (VerKeyKES v) + , KnownNat (SeedSizeKES v) + , KnownNat (SizeVerKeyKES v) + , KnownNat (SizeSignKeyKES v) + , KnownNat (SizeSigKES v) + ) => + KESAlgorithm v + where -- -- Key and signature types -- - data VerKeyKES v :: Type - data SigKES v :: Type + data VerKeyKES v :: Type + data SigKES v :: Type data SignKeyKES v :: Type - - type SeedSizeKES v :: Nat - type SizeVerKeyKES v :: Nat + type SeedSizeKES v :: Nat + type SizeVerKeyKES v :: Nat type SizeSignKeyKES v :: Nat - type SizeSigKES v :: Nat + type SizeSigKES v :: Nat -- -- Metadata and basic key operations @@ -138,6 +136,7 @@ class ( Typeable v -- -- Unit by default (no context required) type ContextKES v :: Type + type ContextKES v = () type Signable v :: Type -> Constraint @@ -150,14 +149,15 @@ class ( Typeable v -- | Full KES verification. This method checks that the signature itself -- checks out (as per 'verifySigKES'), and also makes sure that it matches -- the provided VerKey. - verifyKES - :: (Signable v a, HasCallStack) - => ContextKES v - -> VerKeyKES v - -> Period -- ^ The /current/ period for the key - -> a - -> SigKES v - -> Either String () + verifyKES :: + (Signable v a, HasCallStack) => + ContextKES v -> + VerKeyKES v -> + -- | The /current/ period for the key + Period -> + a -> + SigKES v -> + Either String () -- | Return the total number of KES periods supported by this algorithm. The -- KES algorithm is assumed to support a fixed maximum number of periods, not @@ -166,19 +166,18 @@ class ( Typeable v -- Do note that this is the total number of /periods/ not the total number of -- evolutions. The difference is off-by-one. For example if there are 2 -- periods (period 0 and 1) then there is only one evolution. - -- - totalPeriodsKES - :: proxy v -> Word + totalPeriodsKES :: + proxy v -> Word -- -- Serialisation/(de)serialisation in fixed-size raw format -- - rawSerialiseVerKeyKES :: VerKeyKES v -> ByteString - rawSerialiseSigKES :: SigKES v -> ByteString + rawSerialiseVerKeyKES :: VerKeyKES v -> ByteString + rawSerialiseSigKES :: SigKES v -> ByteString - rawDeserialiseVerKeyKES :: ByteString -> Maybe (VerKeyKES v) - rawDeserialiseSigKES :: ByteString -> Maybe (SigKES v) + rawDeserialiseVerKeyKES :: ByteString -> Maybe (VerKeyKES v) + rawDeserialiseSigKES :: ByteString -> Maybe (SigKES v) deriveVerKeyKES :: (MonadST m, MonadThrow m) => SignKeyKES v -> m (VerKeyKES v) @@ -186,28 +185,30 @@ class ( Typeable v -- Core algorithm operations -- - signKES - :: forall a m. (Signable v a, MonadST m, MonadThrow m) - => ContextKES v - -> Period -- ^ The /current/ period for the key - -> a - -> SignKeyKES v - -> m (SigKES v) - - updateKESWith - :: (MonadST m, MonadThrow m) - => MLockedAllocator m - -> ContextKES v - -> SignKeyKES v - -> Period -- ^ The /current/ period for the key, not the target period. - -> m (Maybe (SignKeyKES v)) - - genKeyKESWith - :: (MonadST m, MonadThrow m) - => MLockedAllocator m - -> MLockedSeed (SeedSizeKES v) - -> m (SignKeyKES v) - + signKES :: + forall a m. + (Signable v a, MonadST m, MonadThrow m) => + ContextKES v -> + -- | The /current/ period for the key + Period -> + a -> + SignKeyKES v -> + m (SigKES v) + + updateKESWith :: + (MonadST m, MonadThrow m) => + MLockedAllocator m -> + ContextKES v -> + SignKeyKES v -> + -- | The /current/ period for the key, not the target period. + Period -> + m (Maybe (SignKeyKES v)) + + genKeyKESWith :: + (MonadST m, MonadThrow m) => + MLockedAllocator m -> + MLockedSeed (SeedSizeKES v) -> + m (SignKeyKES v) -- -- Secure forgetting @@ -218,17 +219,16 @@ class ( Typeable v -- longer in memory. -- -- The precondition is that this key value will not be used again. - -- - forgetSignKeyKESWith - :: (MonadST m, MonadThrow m) - => MLockedAllocator m - -> SignKeyKES v - -> m () + forgetSignKeyKESWith :: + (MonadST m, MonadThrow m) => + MLockedAllocator m -> + SignKeyKES v -> + m () -sizeVerKeyKES :: forall v proxy. KESAlgorithm v => proxy v -> Word +sizeVerKeyKES :: forall v proxy. KESAlgorithm v => proxy v -> Word sizeVerKeyKES _ = fromInteger (natVal (Proxy @(SizeVerKeyKES v))) -sizeSigKES :: forall v proxy. KESAlgorithm v => proxy v -> Word +sizeSigKES :: forall v proxy. KESAlgorithm v => proxy v -> Word sizeSigKES _ = fromInteger (natVal (Proxy @(SizeSigKES v))) sizeSignKeyKES :: forall v proxy. KESAlgorithm v => proxy v -> Word @@ -238,28 +238,25 @@ sizeSignKeyKES _ = fromInteger (natVal (Proxy @(SizeSignKeyKES v))) seedSizeKES :: forall v proxy. KESAlgorithm v => proxy v -> Word seedSizeKES _ = fromInteger (natVal (Proxy @(SeedSizeKES v))) - -- | Forget a signing key synchronously, rather than waiting for GC. In some -- non-mock instances this provides a guarantee that the signing key is no -- longer in memory. -- -- The precondition is that this key value will not be used again. --- -forgetSignKeyKES - :: (KESAlgorithm v, MonadST m, MonadThrow m) - => SignKeyKES v - -> m () +forgetSignKeyKES :: + (KESAlgorithm v, MonadST m, MonadThrow m) => + SignKeyKES v -> + m () forgetSignKeyKES = forgetSignKeyKESWith mlockedMalloc -- | Key generation --- -genKeyKES - :: forall v m. (KESAlgorithm v, MonadST m, MonadThrow m) - => MLockedSeed (SeedSizeKES v) - -> m (SignKeyKES v) +genKeyKES :: + forall v m. + (KESAlgorithm v, MonadST m, MonadThrow m) => + MLockedSeed (SeedSizeKES v) -> + m (SignKeyKES v) genKeyKES = genKeyKESWith mlockedMalloc - -- | Update the KES signature key to the /next/ period, given the /current/ -- period. -- @@ -275,16 +272,16 @@ genKeyKES = genKeyKESWith mlockedMalloc -- Note that you must track the current period separately, and to skip to a -- later period requires repeated use of this function, since it only -- increments one period at once. --- -updateKES - :: forall v m. (KESAlgorithm v, MonadST m, MonadThrow m) - => ContextKES v - -> SignKeyKES v - -> Period -- ^ The /current/ period for the key, not the target period. - -> m (Maybe (SignKeyKES v)) +updateKES :: + forall v m. + (KESAlgorithm v, MonadST m, MonadThrow m) => + ContextKES v -> + SignKeyKES v -> + -- | The /current/ period for the key, not the target period. + Period -> + m (Maybe (SignKeyKES v)) updateKES = updateKESWith mlockedMalloc - -- | Pure implementations of the core KES operations. These are unsound, because -- proper handling of KES secrets (seeds, sign keys) requires mlocking and -- deterministic erasure (\"secure forgetting\"), which is not possible in pure @@ -294,66 +291,68 @@ updateKES = updateKESWith mlockedMalloc class KESAlgorithm v => UnsoundPureKESAlgorithm v where data UnsoundPureSignKeyKES v :: Type - unsoundPureSignKES - :: forall a. (Signable v a) - => ContextKES v - -> Period -- ^ The /current/ period for the key - -> a - -> UnsoundPureSignKeyKES v - -> SigKES v - - unsoundPureUpdateKES - :: ContextKES v - -> UnsoundPureSignKeyKES v - -> Period -- ^ The /current/ period for the key, not the target period. - -> Maybe (UnsoundPureSignKeyKES v) - - unsoundPureGenKeyKES - :: Seed - -> UnsoundPureSignKeyKES v - - unsoundPureDeriveVerKeyKES - :: UnsoundPureSignKeyKES v - -> VerKeyKES v - - unsoundPureSignKeyKESToSoundSignKeyKES - :: (MonadST m, MonadThrow m) - => UnsoundPureSignKeyKES v - -> m (SignKeyKES v) - - rawSerialiseUnsoundPureSignKeyKES :: UnsoundPureSignKeyKES v -> ByteString - rawDeserialiseUnsoundPureSignKeyKES :: ByteString -> Maybe (UnsoundPureSignKeyKES v) - + unsoundPureSignKES :: + forall a. + Signable v a => + ContextKES v -> + -- | The /current/ period for the key + Period -> + a -> + UnsoundPureSignKeyKES v -> + SigKES v + + unsoundPureUpdateKES :: + ContextKES v -> + UnsoundPureSignKeyKES v -> + -- | The /current/ period for the key, not the target period. + Period -> + Maybe (UnsoundPureSignKeyKES v) + + unsoundPureGenKeyKES :: + Seed -> + UnsoundPureSignKeyKES v + + unsoundPureDeriveVerKeyKES :: + UnsoundPureSignKeyKES v -> + VerKeyKES v + + unsoundPureSignKeyKESToSoundSignKeyKES :: + (MonadST m, MonadThrow m) => + UnsoundPureSignKeyKES v -> + m (SignKeyKES v) + + rawSerialiseUnsoundPureSignKeyKES :: UnsoundPureSignKeyKES v -> ByteString + rawDeserialiseUnsoundPureSignKeyKES :: ByteString -> Maybe (UnsoundPureSignKeyKES v) -- | Unsound operations on KES sign keys. These operations violate secure -- forgetting constraints by leaking secrets to unprotected memory. Consider -- using the 'DirectSerialise' / 'DirectDeserialise' APIs instead. class KESAlgorithm v => UnsoundKESAlgorithm v where - rawDeserialiseSignKeyKESWith :: (MonadST m, MonadThrow m) - => MLockedAllocator m - -> ByteString - -> m (Maybe (SignKeyKES v)) + rawDeserialiseSignKeyKESWith :: + (MonadST m, MonadThrow m) => + MLockedAllocator m -> + ByteString -> + m (Maybe (SignKeyKES v)) rawSerialiseSignKeyKES :: (MonadST m, MonadThrow m) => SignKeyKES v -> m ByteString rawDeserialiseSignKeyKES :: - (UnsoundKESAlgorithm v, MonadST m, MonadThrow m) - => ByteString - -> m (Maybe (SignKeyKES v)) + (UnsoundKESAlgorithm v, MonadST m, MonadThrow m) => + ByteString -> + m (Maybe (SignKeyKES v)) rawDeserialiseSignKeyKES = rawDeserialiseSignKeyKESWith mlockedMalloc -- | Helper function for implementing 'unsoundPureSignKeyKESToSoundSignKeyKES' -- for KES algorithms that support both 'UnsoundKESAlgorithm' and -- 'UnsoundPureKESAlgorithm'. For such KES algorithms, unsound sign keys can be -- marshalled to sound sign keys by serializing and then deserializing them. -unsoundPureSignKeyKESToSoundSignKeyKESViaSer - :: (MonadST m, MonadThrow m, UnsoundKESAlgorithm k, UnsoundPureKESAlgorithm k) - => UnsoundPureSignKeyKES k - -> m (SignKeyKES k) +unsoundPureSignKeyKESToSoundSignKeyKESViaSer :: + (MonadST m, MonadThrow m, UnsoundKESAlgorithm k, UnsoundPureKESAlgorithm k) => + UnsoundPureSignKeyKES k -> + m (SignKeyKES k) unsoundPureSignKeyKESToSoundSignKeyKESViaSer sk = - maybe (error "unsoundPureSignKeyKESToSoundSignKeyKES: deserialisation failure") return =<< - (rawDeserialiseSignKeyKES . rawSerialiseUnsoundPureSignKeyKES $ sk) - + maybe (error "unsoundPureSignKeyKESToSoundSignKeyKES: deserialisation failure") return + =<< (rawDeserialiseSignKeyKES . rawSerialiseUnsoundPureSignKeyKES $ sk) -- | Subclass for KES algorithms that embed a copy of the VerKey into the -- signature itself, rather than relying on the externally supplied VerKey @@ -364,54 +363,62 @@ class KESAlgorithm v => OptimizedKESAlgorithm v where -- | Partial verification: this method only verifies the signature itself, -- but it does not check it against any externally-provided VerKey. Use -- 'verifyKES' for full KES verification. - verifySigKES - :: (Signable v a, HasCallStack) - => ContextKES v - -> Period -- ^ The /current/ period for the key - -> a - -> SigKES v - -> Either String () + verifySigKES :: + (Signable v a, HasCallStack) => + ContextKES v -> + -- | The /current/ period for the key + Period -> + a -> + SigKES v -> + Either String () -- | Extract a VerKey from a SigKES. Note that a VerKey embedded in or -- derived from a SigKES is effectively user-supplied, so it is not enough -- to validate a SigKES against this VerKey (like 'verifySigKES' does); you -- must also compare the VerKey against an externally-provided key that you -- want to verify against (see 'verifyKES'). - verKeyFromSigKES - :: ContextKES v - -> Period - -> SigKES v - -> VerKeyKES v - -verifyOptimizedKES :: (OptimizedKESAlgorithm v, Signable v a, HasCallStack) - => ContextKES v - -> VerKeyKES v - -> Period - -> a - -> SigKES v - -> Either String () + verKeyFromSigKES :: + ContextKES v -> + Period -> + SigKES v -> + VerKeyKES v + +verifyOptimizedKES :: + (OptimizedKESAlgorithm v, Signable v a, HasCallStack) => + ContextKES v -> + VerKeyKES v -> + Period -> + a -> + SigKES v -> + Either String () verifyOptimizedKES ctx vk t a sig = do verifySigKES ctx t a sig let vk' = verKeyFromSigKES ctx t sig - if vk' == vk then - return () - else - Left "KES verification failed" + if vk' == vk + then + return () + else + Left "KES verification failed" + -- -- Do not provide Ord instances for keys, see #38 -- -instance ( TypeError ('Text "Ord not supported for signing keys, use the hash instead") - , Eq (SignKeyKES v) - ) - => Ord (SignKeyKES v) where - compare = error "unsupported" - -instance ( TypeError ('Text "Ord not supported for verification keys, use the hash instead") - , KESAlgorithm v - ) - => Ord (VerKeyKES v) where - compare = error "unsupported" +instance + ( TypeError ('Text "Ord not supported for signing keys, use the hash instead") + , Eq (SignKeyKES v) + ) => + Ord (SignKeyKES v) + where + compare = error "unsupported" + +instance + ( TypeError ('Text "Ord not supported for verification keys, use the hash instead") + , KESAlgorithm v + ) => + Ord (VerKeyKES v) + where + compare = error "unsupported" -- -- Convenient CBOR encoding/decoding @@ -429,9 +436,10 @@ encodeSigKES :: KESAlgorithm v => SigKES v -> Encoding encodeSigKES = encodeBytes . rawSerialiseSigKES encodeSignKeyKES :: - forall v m. (UnsoundKESAlgorithm v, MonadST m, MonadThrow m) - => SignKeyKES v - -> m Encoding + forall v m. + (UnsoundKESAlgorithm v, MonadST m, MonadThrow m) => + SignKeyKES v -> + m Encoding encodeSignKeyKES = fmap encodeBytes . rawSerialiseSignKeyKES decodeVerKeyKES :: forall v s. KESAlgorithm v => Decoder s (VerKeyKES v) @@ -442,7 +450,8 @@ decodeVerKeyKES = do Nothing -> failSizeCheck "decodeVerKeyKES" "key" bs (sizeVerKeyKES (Proxy :: Proxy v)) {-# INLINE decodeVerKeyKES #-} -decodeUnsoundPureSignKeyKES :: forall v s. UnsoundPureKESAlgorithm v => Decoder s (UnsoundPureSignKeyKES v) +decodeUnsoundPureSignKeyKES :: + forall v s. UnsoundPureKESAlgorithm v => Decoder s (UnsoundPureSignKeyKES v) decodeUnsoundPureSignKeyKES = do bs <- decodeBytes case rawDeserialiseUnsoundPureSignKeyKES bs of @@ -459,15 +468,21 @@ decodeSigKES = do {-# INLINE decodeSigKES #-} decodeSignKeyKES :: - forall v s m. (UnsoundKESAlgorithm v, MonadST m, MonadThrow m) - => Decoder s (m (Maybe (SignKeyKES v))) + forall v s m. + (UnsoundKESAlgorithm v, MonadST m, MonadThrow m) => + Decoder s (m (Maybe (SignKeyKES v))) decodeSignKeyKES = do - bs <- decodeBytes - let expected = fromIntegral (sizeSignKeyKES (Proxy @v)) - actual = BS.length bs - if actual /= expected then - fail ("decodeSignKeyKES: wrong length, expected " ++ - show expected ++ " bytes but got " ++ show actual) + bs <- decodeBytes + let expected = fromIntegral (sizeSignKeyKES (Proxy @v)) + actual = BS.length bs + if actual /= expected + then + fail + ( "decodeSignKeyKES: wrong length, expected " + ++ show expected + ++ " bytes but got " + ++ show actual + ) else return $ rawDeserialiseSignKeyKES bs @@ -475,47 +490,46 @@ decodeSignKeyKES = do -- -- Be careful of fencepost errors: if there are 2 periods (period 0 and 1) -- then there is only one key evolution. --- type Period = Word newtype SignedKES v a = SignedKES {getSig :: SigKES v} - deriving Generic + deriving (Generic) deriving instance KESAlgorithm v => Show (SignedKES v a) -deriving instance KESAlgorithm v => Eq (SignedKES v a) +deriving instance KESAlgorithm v => Eq (SignedKES v a) instance KESAlgorithm v => NoThunks (SignedKES v a) - -- use generic instance - -signedKES - :: (KESAlgorithm v, Signable v a, MonadST m, MonadThrow m) - => ContextKES v - -> Period - -> a - -> SignKeyKES v - -> m (SignedKES v a) + +-- use generic instance + +signedKES :: + (KESAlgorithm v, Signable v a, MonadST m, MonadThrow m) => + ContextKES v -> + Period -> + a -> + SignKeyKES v -> + m (SignedKES v a) signedKES ctxt time a key = SignedKES <$> signKES ctxt time a key -verifySignedKES - :: (KESAlgorithm v, Signable v a) - => ContextKES v - -> VerKeyKES v - -> Period - -> a - -> SignedKES v a - -> Either String () +verifySignedKES :: + (KESAlgorithm v, Signable v a) => + ContextKES v -> + VerKeyKES v -> + Period -> + a -> + SignedKES v a -> + Either String () verifySignedKES ctxt vk j a (SignedKES sig) = verifyKES ctxt vk j a sig -unsoundPureSignedKES - :: (UnsoundPureKESAlgorithm v, Signable v a) - => ContextKES v - -> Period - -> a - -> UnsoundPureSignKeyKES v - -> SignedKES v a +unsoundPureSignedKES :: + (UnsoundPureKESAlgorithm v, Signable v a) => + ContextKES v -> + Period -> + a -> + UnsoundPureSignKeyKES v -> + SignedKES v a unsoundPureSignedKES ctxt time a key = SignedKES $ unsoundPureSignKES ctxt time a key - encodeSignedKES :: KESAlgorithm v => SignedKES v a -> Encoding encodeSignedKES (SignedKES s) = encodeSigKES s @@ -524,25 +538,26 @@ decodeSignedKES = SignedKES <$> decodeSigKES {-# INLINE decodeSignedKES #-} -- | A sign key bundled with its associated period. -data SignKeyWithPeriodKES v = - SignKeyWithPeriodKES - { skWithoutPeriodKES :: !(SignKeyKES v) - , periodKES :: !Period - } - deriving (Generic) +data SignKeyWithPeriodKES v + = SignKeyWithPeriodKES + { skWithoutPeriodKES :: !(SignKeyKES v) + , periodKES :: !Period + } + deriving (Generic) deriving instance (KESAlgorithm v, Eq (SignKeyKES v)) => Eq (SignKeyWithPeriodKES v) deriving instance (KESAlgorithm v, Show (SignKeyKES v)) => Show (SignKeyWithPeriodKES v) instance KESAlgorithm v => NoThunks (SignKeyWithPeriodKES v) - -- use generic instance -updateKESWithPeriod - :: (KESAlgorithm v, MonadST m, MonadThrow m) - => ContextKES v - -> SignKeyWithPeriodKES v - -> m (Maybe (SignKeyWithPeriodKES v)) +-- use generic instance + +updateKESWithPeriod :: + (KESAlgorithm v, MonadST m, MonadThrow m) => + ContextKES v -> + SignKeyWithPeriodKES v -> + m (Maybe (SignKeyWithPeriodKES v)) updateKESWithPeriod c (SignKeyWithPeriodKES sk t) = runMaybeT $ do sk' <- MaybeT $ updateKES c sk t return $ SignKeyWithPeriodKES sk' (succ t) @@ -553,46 +568,43 @@ updateKESWithPeriod c (SignKeyWithPeriodKES sk t) = runMaybeT $ do -- | 'Size' expression for 'VerKeyKES' which is using 'sizeVerKeyKES' encoded -- as 'Size'. --- encodedVerKeyKESSizeExpr :: forall v. KESAlgorithm v => Proxy (VerKeyKES v) -> Size encodedVerKeyKESSizeExpr _proxy = - -- 'encodeBytes' envelope - fromIntegral ((withWordSize :: Word -> Integer) (sizeVerKeyKES (Proxy :: Proxy v))) - -- payload + -- 'encodeBytes' envelope + fromIntegral ((withWordSize :: Word -> Integer) (sizeVerKeyKES (Proxy :: Proxy v))) + -- payload + fromIntegral (sizeVerKeyKES (Proxy :: Proxy v)) -- | 'Size' expression for 'SignKeyKES' which is using 'sizeSignKeyKES' encoded -- as 'Size'. --- encodedSignKeyKESSizeExpr :: forall v. KESAlgorithm v => Proxy (SignKeyKES v) -> Size encodedSignKeyKESSizeExpr _proxy = - -- 'encodeBytes' envelope - fromIntegral ((withWordSize :: Word -> Integer) (sizeSignKeyKES (Proxy @v))) - -- payload + -- 'encodeBytes' envelope + fromIntegral ((withWordSize :: Word -> Integer) (sizeSignKeyKES (Proxy @v))) + -- payload + fromIntegral (sizeSignKeyKES (Proxy :: Proxy v)) -- | 'Size' expression for 'SigKES' which is using 'sizeSigKES' encoded as -- 'Size'. --- encodedSigKESSizeExpr :: forall v. KESAlgorithm v => Proxy (SigKES v) -> Size encodedSigKESSizeExpr _proxy = - -- 'encodeBytes' envelope - fromIntegral ((withWordSize :: Word -> Integer) (sizeSigKES (Proxy :: Proxy v))) - -- payload + -- 'encodeBytes' envelope + fromIntegral ((withWordSize :: Word -> Integer) (sizeSigKES (Proxy :: Proxy v))) + -- payload + fromIntegral (sizeSigKES (Proxy :: Proxy v)) -hashPairOfVKeys :: (KESAlgorithm d, HashAlgorithm h) - => (VerKeyKES d, VerKeyKES d) - -> Hash h (VerKeyKES d, VerKeyKES d) +hashPairOfVKeys :: + (KESAlgorithm d, HashAlgorithm h) => + (VerKeyKES d, VerKeyKES d) -> + Hash h (VerKeyKES d, VerKeyKES d) hashPairOfVKeys = - hashWith $ \(a,b) -> - rawSerialiseVerKeyKES a <> rawSerialiseVerKeyKES b + hashWith $ \(a, b) -> + rawSerialiseVerKeyKES a <> rawSerialiseVerKeyKES b mungeName :: String -> String mungeName basename - | (name, '^':nstr) <- span (/= '^') basename - , [(n, "")] <- reads nstr - = name ++ '^' : show (n+1 :: Word) - - | otherwise - = basename ++ "_2^1" + | (name, '^' : nstr) <- span (/= '^') basename + , [(n, "")] <- reads nstr = + name ++ '^' : show (n + 1 :: Word) + | otherwise = + basename ++ "_2^1" diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES/CompactSingle.hs b/cardano-crypto-class/src/Cardano/Crypto/KES/CompactSingle.hs index e940c4775..e4551b394 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES/CompactSingle.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES/CompactSingle.hs @@ -1,6 +1,6 @@ {-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} @@ -39,255 +39,280 @@ -- like 'Cardano.Crypto.KES.Sum' does. See 'Cardano.Crypto.KES.CompactSum' for -- more details. module Cardano.Crypto.KES.CompactSingle ( - CompactSingleKES - , VerKeyKES (..) - , SignKeyKES (..) - , SigKES (..) - ) where + CompactSingleKES, + VerKeyKES (..), + SignKeyKES (..), + SigKES (..), +) where -import Data.Proxy (Proxy(..)) +import Control.Monad (guard, (<$!>)) +import qualified Data.ByteString as BS +import Data.Proxy (Proxy (..)) import GHC.Generics (Generic) import GHC.TypeLits (KnownNat, type (+)) import NoThunks.Class (NoThunks) -import qualified Data.ByteString as BS -import Control.Monad (guard, (<$!>)) -import Control.Exception (assert) import Control.DeepSeq (NFData) +import Control.Exception (assert) import Cardano.Binary (FromCBOR (..), ToCBOR (..)) -import Cardano.Crypto.Hash.Class import Cardano.Crypto.DSIGN.Class as DSIGN -import Cardano.Crypto.KES.Class import Cardano.Crypto.DirectSerialise +import Cardano.Crypto.Hash.Class +import Cardano.Crypto.KES.Class -- | A standard signature scheme is a forward-secure signature scheme with a -- single time period. --- data CompactSingleKES d deriving newtype instance NFData (VerKeyDSIGN d) => NFData (VerKeyKES (CompactSingleKES d)) deriving newtype instance NFData (SignKeyDSIGNM d) => NFData (SignKeyKES (CompactSingleKES d)) -deriving instance (NFData (SigDSIGN d), NFData (VerKeyDSIGN d)) => NFData (SigKES (CompactSingleKES d)) - +deriving instance + (NFData (SigDSIGN d), NFData (VerKeyDSIGN d)) => NFData (SigKES (CompactSingleKES d)) +instance + ( DSIGNMAlgorithm d + , KnownNat (SizeSigDSIGN d + SizeVerKeyDSIGN d) + ) => + KESAlgorithm (CompactSingleKES d) + where + type SeedSizeKES (CompactSingleKES d) = SeedSizeDSIGN d -instance ( DSIGNMAlgorithm d - , KnownNat (SizeSigDSIGN d + SizeVerKeyDSIGN d) - ) - => KESAlgorithm (CompactSingleKES d) where - type SeedSizeKES (CompactSingleKES d) = SeedSizeDSIGN d + -- + -- Key and signature types + -- + newtype VerKeyKES (CompactSingleKES d) = VerKeyCompactSingleKES (VerKeyDSIGN d) + deriving (Generic) - -- - -- Key and signature types - -- + data SigKES (CompactSingleKES d) = SigCompactSingleKES !(SigDSIGN d) !(VerKeyDSIGN d) + deriving (Generic) - newtype VerKeyKES (CompactSingleKES d) = VerKeyCompactSingleKES (VerKeyDSIGN d) - deriving Generic + newtype SignKeyKES (CompactSingleKES d) = SignKeyCompactSingleKES (SignKeyDSIGNM d) - data SigKES (CompactSingleKES d) = SigCompactSingleKES !(SigDSIGN d) !(VerKeyDSIGN d) - deriving Generic + type ContextKES (CompactSingleKES d) = ContextDSIGN d + type Signable (CompactSingleKES d) = DSIGN.Signable d - newtype SignKeyKES (CompactSingleKES d) = SignKeyCompactSingleKES (SignKeyDSIGNM d) + -- + -- Metadata and basic key operations + -- - type ContextKES (CompactSingleKES d) = ContextDSIGN d - type Signable (CompactSingleKES d) = DSIGN.Signable d + algorithmNameKES _ = algorithmNameDSIGN (Proxy :: Proxy d) ++ "_kes_2^0" + totalPeriodsKES _ = 1 - -- - -- Metadata and basic key operations - -- + -- + -- Core algorithm operations + -- - algorithmNameKES _ = algorithmNameDSIGN (Proxy :: Proxy d) ++ "_kes_2^0" + verifyKES = verifyOptimizedKES - totalPeriodsKES _ = 1 + -- + -- raw serialise/deserialise + -- - -- - -- Core algorithm operations - -- + type SizeVerKeyKES (CompactSingleKES d) = SizeVerKeyDSIGN d + type SizeSignKeyKES (CompactSingleKES d) = SizeSignKeyDSIGN d + type SizeSigKES (CompactSingleKES d) = SizeSigDSIGN d + SizeVerKeyDSIGN d - verifyKES = verifyOptimizedKES + hashVerKeyKES (VerKeyCompactSingleKES vk) = + castHash (hashVerKeyDSIGN vk) - -- - -- raw serialise/deserialise - -- + rawSerialiseVerKeyKES (VerKeyCompactSingleKES vk) = rawSerialiseVerKeyDSIGN vk + rawSerialiseSigKES (SigCompactSingleKES sig vk) = + rawSerialiseSigDSIGN sig <> rawSerialiseVerKeyDSIGN vk - type SizeVerKeyKES (CompactSingleKES d) = SizeVerKeyDSIGN d - type SizeSignKeyKES (CompactSingleKES d) = SizeSignKeyDSIGN d - type SizeSigKES (CompactSingleKES d) = SizeSigDSIGN d + SizeVerKeyDSIGN d + rawDeserialiseVerKeyKES = fmap VerKeyCompactSingleKES . rawDeserialiseVerKeyDSIGN + rawDeserialiseSigKES b = do + guard (BS.length b == fromIntegral size_total) + sigma <- rawDeserialiseSigDSIGN b_sig + vk <- rawDeserialiseVerKeyDSIGN b_vk + return (SigCompactSingleKES sigma vk) + where + b_sig = slice off_sig size_sig b + b_vk = slice off_vk size_vk b - hashVerKeyKES (VerKeyCompactSingleKES vk) = - castHash (hashVerKeyDSIGN vk) + size_sig = sizeSigDSIGN (Proxy :: Proxy d) + size_vk = sizeVerKeyDSIGN (Proxy :: Proxy d) + size_total = sizeSigKES (Proxy :: Proxy (CompactSingleKES d)) + off_sig = 0 :: Word + off_vk = size_sig - rawSerialiseVerKeyKES (VerKeyCompactSingleKES vk) = rawSerialiseVerKeyDSIGN vk - rawSerialiseSigKES (SigCompactSingleKES sig vk) = - rawSerialiseSigDSIGN sig <> rawSerialiseVerKeyDSIGN vk + deriveVerKeyKES (SignKeyCompactSingleKES v) = + VerKeyCompactSingleKES <$!> deriveVerKeyDSIGNM v - rawDeserialiseVerKeyKES = fmap VerKeyCompactSingleKES . rawDeserialiseVerKeyDSIGN - rawDeserialiseSigKES b = do - guard (BS.length b == fromIntegral size_total) - sigma <- rawDeserialiseSigDSIGN b_sig - vk <- rawDeserialiseVerKeyDSIGN b_vk - return (SigCompactSingleKES sigma vk) - where - b_sig = slice off_sig size_sig b - b_vk = slice off_vk size_vk b + -- + -- Core algorithm operations + -- + signKES ctxt t a (SignKeyCompactSingleKES sk) = + assert (t == 0) $ + SigCompactSingleKES <$!> signDSIGNM ctxt a sk <*> deriveVerKeyDSIGNM sk - size_sig = sizeSigDSIGN (Proxy :: Proxy d) - size_vk = sizeVerKeyDSIGN (Proxy :: Proxy d) - size_total = sizeSigKES (Proxy :: Proxy (CompactSingleKES d)) + updateKESWith _allocator _ctx (SignKeyCompactSingleKES _sk) _to = return Nothing - off_sig = 0 :: Word - off_vk = size_sig + -- + -- Key generation + -- - deriveVerKeyKES (SignKeyCompactSingleKES v) = - VerKeyCompactSingleKES <$!> deriveVerKeyDSIGNM v + genKeyKESWith allocator seed = SignKeyCompactSingleKES <$!> genKeyDSIGNMWith allocator seed - -- - -- Core algorithm operations - -- - signKES ctxt t a (SignKeyCompactSingleKES sk) = - assert (t == 0) $ - SigCompactSingleKES <$!> signDSIGNM ctxt a sk <*> deriveVerKeyDSIGNM sk + -- + -- forgetting + -- + forgetSignKeyKESWith allocator (SignKeyCompactSingleKES v) = + forgetSignKeyDSIGNMWith allocator v - updateKESWith _allocator _ctx (SignKeyCompactSingleKES _sk) _to = return Nothing +instance + ( KESAlgorithm (CompactSingleKES d) + , UnsoundDSIGNMAlgorithm d + ) => + UnsoundPureKESAlgorithm (CompactSingleKES d) + where + data UnsoundPureSignKeyKES (CompactSingleKES d) + = UnsoundPureSignKeyCompactSingleKES (SignKeyDSIGN d) + deriving (Generic) + + unsoundPureSignKES ctxt t a (UnsoundPureSignKeyCompactSingleKES sk) = + assert (t == 0) $! + SigCompactSingleKES (signDSIGN ctxt a sk) (deriveVerKeyDSIGN sk) - -- - -- Key generation - -- + unsoundPureUpdateKES _ctx _sk _to = Nothing - genKeyKESWith allocator seed = SignKeyCompactSingleKES <$!> genKeyDSIGNMWith allocator seed + -- + -- Key generation + -- - -- - -- forgetting - -- - forgetSignKeyKESWith allocator (SignKeyCompactSingleKES v) = - forgetSignKeyDSIGNMWith allocator v - -instance ( KESAlgorithm (CompactSingleKES d) - , UnsoundDSIGNMAlgorithm d - ) - => UnsoundPureKESAlgorithm (CompactSingleKES d) where - data UnsoundPureSignKeyKES (CompactSingleKES d) = - UnsoundPureSignKeyCompactSingleKES (SignKeyDSIGN d) - deriving (Generic) - - unsoundPureSignKES ctxt t a (UnsoundPureSignKeyCompactSingleKES sk) = - assert (t == 0) $! - SigCompactSingleKES (signDSIGN ctxt a sk) (deriveVerKeyDSIGN sk) - - unsoundPureUpdateKES _ctx _sk _to = Nothing - - -- - -- Key generation - -- - - unsoundPureGenKeyKES seed = - UnsoundPureSignKeyCompactSingleKES $! genKeyDSIGN seed - - unsoundPureDeriveVerKeyKES (UnsoundPureSignKeyCompactSingleKES v) = - VerKeyCompactSingleKES $! deriveVerKeyDSIGN v - - unsoundPureSignKeyKESToSoundSignKeyKES = - unsoundPureSignKeyKESToSoundSignKeyKESViaSer - - rawSerialiseUnsoundPureSignKeyKES (UnsoundPureSignKeyCompactSingleKES sk) = - rawSerialiseSignKeyDSIGN sk - rawDeserialiseUnsoundPureSignKeyKES b = - UnsoundPureSignKeyCompactSingleKES <$> rawDeserialiseSignKeyDSIGN b - -instance ( KESAlgorithm (CompactSingleKES d) - , DSIGNMAlgorithm d - ) => OptimizedKESAlgorithm (CompactSingleKES d) where - verifySigKES ctxt t a (SigCompactSingleKES sig vk) = - assert (t == 0) $ + unsoundPureGenKeyKES seed = + UnsoundPureSignKeyCompactSingleKES $! genKeyDSIGN seed + + unsoundPureDeriveVerKeyKES (UnsoundPureSignKeyCompactSingleKES v) = + VerKeyCompactSingleKES $! deriveVerKeyDSIGN v + + unsoundPureSignKeyKESToSoundSignKeyKES = + unsoundPureSignKeyKESToSoundSignKeyKESViaSer + + rawSerialiseUnsoundPureSignKeyKES (UnsoundPureSignKeyCompactSingleKES sk) = + rawSerialiseSignKeyDSIGN sk + rawDeserialiseUnsoundPureSignKeyKES b = + UnsoundPureSignKeyCompactSingleKES <$> rawDeserialiseSignKeyDSIGN b + +instance + ( KESAlgorithm (CompactSingleKES d) + , DSIGNMAlgorithm d + ) => + OptimizedKESAlgorithm (CompactSingleKES d) + where + verifySigKES ctxt t a (SigCompactSingleKES sig vk) = + assert (t == 0) $ verifyDSIGN ctxt vk a sig - verKeyFromSigKES _ctxt t (SigCompactSingleKES _ vk) = - assert (t == 0) $ + verKeyFromSigKES _ctxt t (SigCompactSingleKES _ vk) = + assert (t == 0) $ VerKeyCompactSingleKES vk -instance (KESAlgorithm (CompactSingleKES d), UnsoundDSIGNMAlgorithm d) - => UnsoundKESAlgorithm (CompactSingleKES d) where - rawSerialiseSignKeyKES (SignKeyCompactSingleKES sk) = rawSerialiseSignKeyDSIGNM sk - rawDeserialiseSignKeyKESWith allocator bs = fmap SignKeyCompactSingleKES <$> rawDeserialiseSignKeyDSIGNMWith allocator bs - +instance + (KESAlgorithm (CompactSingleKES d), UnsoundDSIGNMAlgorithm d) => + UnsoundKESAlgorithm (CompactSingleKES d) + where + rawSerialiseSignKeyKES (SignKeyCompactSingleKES sk) = rawSerialiseSignKeyDSIGNM sk + rawDeserialiseSignKeyKESWith allocator bs = fmap SignKeyCompactSingleKES <$> rawDeserialiseSignKeyDSIGNMWith allocator bs -- -- VerKey instances -- deriving instance DSIGNMAlgorithm d => Show (VerKeyKES (CompactSingleKES d)) -deriving instance DSIGNMAlgorithm d => Eq (VerKeyKES (CompactSingleKES d)) +deriving instance DSIGNMAlgorithm d => Eq (VerKeyKES (CompactSingleKES d)) -instance (DSIGNMAlgorithm d, KnownNat (SizeSigDSIGN d + SizeVerKeyDSIGN d)) => ToCBOR (VerKeyKES (CompactSingleKES d)) where +instance + (DSIGNMAlgorithm d, KnownNat (SizeSigDSIGN d + SizeVerKeyDSIGN d)) => + ToCBOR (VerKeyKES (CompactSingleKES d)) + where toCBOR = encodeVerKeyKES encodedSizeExpr _size = encodedVerKeyKESSizeExpr -instance (DSIGNMAlgorithm d, KnownNat (SizeSigDSIGN d + SizeVerKeyDSIGN d)) => FromCBOR (VerKeyKES (CompactSingleKES d)) where +instance + (DSIGNMAlgorithm d, KnownNat (SizeSigDSIGN d + SizeVerKeyDSIGN d)) => + FromCBOR (VerKeyKES (CompactSingleKES d)) + where fromCBOR = decodeVerKeyKES -instance DSIGNMAlgorithm d => NoThunks (VerKeyKES (CompactSingleKES d)) - +instance DSIGNMAlgorithm d => NoThunks (VerKeyKES (CompactSingleKES d)) -- -- SignKey instances -- -deriving via (SignKeyDSIGNM d) instance DSIGNMAlgorithm d => NoThunks (SignKeyKES (CompactSingleKES d)) +deriving via + (SignKeyDSIGNM d) + instance + DSIGNMAlgorithm d => NoThunks (SignKeyKES (CompactSingleKES d)) -- -- Sig instances -- deriving instance DSIGNMAlgorithm d => Show (SigKES (CompactSingleKES d)) -deriving instance DSIGNMAlgorithm d => Eq (SigKES (CompactSingleKES d)) +deriving instance DSIGNMAlgorithm d => Eq (SigKES (CompactSingleKES d)) instance DSIGNMAlgorithm d => NoThunks (SigKES (CompactSingleKES d)) -instance (DSIGNMAlgorithm d, KnownNat (SizeSigKES (CompactSingleKES d))) => ToCBOR (SigKES (CompactSingleKES d)) where +instance + (DSIGNMAlgorithm d, KnownNat (SizeSigKES (CompactSingleKES d))) => + ToCBOR (SigKES (CompactSingleKES d)) + where toCBOR = encodeSigKES encodedSizeExpr _size = encodedSigKESSizeExpr -instance (DSIGNMAlgorithm d, KnownNat (SizeSigKES (CompactSingleKES d))) => FromCBOR (SigKES (CompactSingleKES d)) where +instance + (DSIGNMAlgorithm d, KnownNat (SizeSigKES (CompactSingleKES d))) => + FromCBOR (SigKES (CompactSingleKES d)) + where fromCBOR = decodeSigKES slice :: Word -> Word -> ByteString -> ByteString -slice offset size = BS.take (fromIntegral size) - . BS.drop (fromIntegral offset) +slice offset size = + BS.take (fromIntegral size) + . BS.drop (fromIntegral offset) -- -- UnsoundPureSignKey instances -- deriving instance DSIGNAlgorithm d => Show (UnsoundPureSignKeyKES (CompactSingleKES d)) -deriving instance (DSIGNAlgorithm d, Eq (SignKeyDSIGN d)) => Eq (UnsoundPureSignKeyKES (CompactSingleKES d)) +deriving instance + (DSIGNAlgorithm d, Eq (SignKeyDSIGN d)) => Eq (UnsoundPureSignKeyKES (CompactSingleKES d)) -instance (UnsoundDSIGNMAlgorithm d, KnownNat (SizeSigDSIGN d + SizeVerKeyDSIGN d)) => ToCBOR (UnsoundPureSignKeyKES (CompactSingleKES d)) where +instance + (UnsoundDSIGNMAlgorithm d, KnownNat (SizeSigDSIGN d + SizeVerKeyDSIGN d)) => + ToCBOR (UnsoundPureSignKeyKES (CompactSingleKES d)) + where toCBOR = encodeUnsoundPureSignKeyKES encodedSizeExpr _size _skProxy = encodedSignKeyKESSizeExpr (Proxy :: Proxy (SignKeyKES (CompactSingleKES d))) -instance (UnsoundDSIGNMAlgorithm d, KnownNat (SizeSigDSIGN d + SizeVerKeyDSIGN d)) => FromCBOR (UnsoundPureSignKeyKES (CompactSingleKES d)) where +instance + (UnsoundDSIGNMAlgorithm d, KnownNat (SizeSigDSIGN d + SizeVerKeyDSIGN d)) => + FromCBOR (UnsoundPureSignKeyKES (CompactSingleKES d)) + where fromCBOR = decodeUnsoundPureSignKeyKES -instance DSIGNAlgorithm d => NoThunks (UnsoundPureSignKeyKES (CompactSingleKES d)) +instance DSIGNAlgorithm d => NoThunks (UnsoundPureSignKeyKES (CompactSingleKES d)) -- -- Direct ser/deser -- -instance (DirectSerialise (SignKeyDSIGNM d)) => DirectSerialise (SignKeyKES (CompactSingleKES d)) where +instance DirectSerialise (SignKeyDSIGNM d) => DirectSerialise (SignKeyKES (CompactSingleKES d)) where directSerialise push (SignKeyCompactSingleKES sk) = directSerialise push sk -instance (DirectDeserialise (SignKeyDSIGNM d)) => DirectDeserialise (SignKeyKES (CompactSingleKES d)) where +instance DirectDeserialise (SignKeyDSIGNM d) => DirectDeserialise (SignKeyKES (CompactSingleKES d)) where directDeserialise pull = SignKeyCompactSingleKES <$!> directDeserialise pull -instance (DirectSerialise (VerKeyDSIGN d)) => DirectSerialise (VerKeyKES (CompactSingleKES d)) where +instance DirectSerialise (VerKeyDSIGN d) => DirectSerialise (VerKeyKES (CompactSingleKES d)) where directSerialise push (VerKeyCompactSingleKES sk) = directSerialise push sk -instance (DirectDeserialise (VerKeyDSIGN d)) => DirectDeserialise (VerKeyKES (CompactSingleKES d)) where +instance DirectDeserialise (VerKeyDSIGN d) => DirectDeserialise (VerKeyKES (CompactSingleKES d)) where directDeserialise pull = VerKeyCompactSingleKES <$!> directDeserialise pull diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES/CompactSum.hs b/cardano-crypto-class/src/Cardano/Crypto/KES/CompactSum.hs index 650267641..dc15246ef 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES/CompactSum.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES/CompactSum.hs @@ -4,13 +4,13 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoStarIsType #-} -- | A key evolving signatures implementation. @@ -68,49 +68,49 @@ -- compilation times. Worse yet, this error will only appear when compiling -- code that depends on this module, not when compiling the module itself. module Cardano.Crypto.KES.CompactSum ( - CompactSumKES - , VerKeyKES (..) - , SignKeyKES (..) - , SigKES (..) - - -- * Type aliases for powers of binary sums - , CompactSum0KES - , CompactSum1KES - , CompactSum2KES - , CompactSum3KES - , CompactSum4KES - , CompactSum5KES - , CompactSum6KES - , CompactSum7KES - ) where - -import Data.Proxy (Proxy(..)) -import GHC.Generics (Generic) + CompactSumKES, + VerKeyKES (..), + SignKeyKES (..), + SigKES (..), + + -- * Type aliases for powers of binary sums + CompactSum0KES, + CompactSum1KES, + CompactSum2KES, + CompactSum3KES, + CompactSum4KES, + CompactSum5KES, + CompactSum6KES, + CompactSum7KES, +) where + +import Control.Monad (guard, (<$!>)) import qualified Data.ByteString as BS import qualified Data.ByteString.Internal as BS -import Control.Monad (guard, (<$!>)) -import NoThunks.Class (NoThunks, OnlyCheckWhnfNamed (..)) - -import Cardano.Binary (FromCBOR (..), ToCBOR (..)) - -import Cardano.Crypto.Hash.Class -import Cardano.Crypto.KES.Class -import Cardano.Crypto.KES.CompactSingle (CompactSingleKES) -import Cardano.Crypto.Util -import Cardano.Crypto.Seed -import Cardano.Crypto.Libsodium.MLockedSeed -import Cardano.Crypto.Libsodium -import Cardano.Crypto.Libsodium.Memory -import Cardano.Crypto.DirectSerialise - -import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT) -import Control.Monad.Trans (lift) -import Control.DeepSeq (NFData (..)) -import GHC.TypeLits (KnownNat, type (+), type (*)) -import Foreign.Ptr (castPtr) +import Data.Proxy (Proxy (..)) +import GHC.Generics (Generic) +import NoThunks.Class (NoThunks, OnlyCheckWhnfNamed (..)) + +import Cardano.Binary (FromCBOR (..), ToCBOR (..)) + +import Cardano.Crypto.DirectSerialise +import Cardano.Crypto.Hash.Class +import Cardano.Crypto.KES.Class +import Cardano.Crypto.KES.CompactSingle (CompactSingleKES) +import Cardano.Crypto.Libsodium +import Cardano.Crypto.Libsodium.MLockedSeed +import Cardano.Crypto.Libsodium.Memory +import Cardano.Crypto.Seed +import Cardano.Crypto.Util + +import Control.DeepSeq (NFData (..)) +import Control.Monad.Trans (lift) +import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT) +import Foreign.Ptr (castPtr) +import GHC.TypeLits (KnownNat, type (*), type (+)) -- | A 2^0 period KES -type CompactSum0KES d = CompactSingleKES d +type CompactSum0KES d = CompactSingleKES d -- | A 2^1 period KES type CompactSum1KES d h = CompactSumKES h (CompactSum0KES d) @@ -133,7 +133,6 @@ type CompactSum6KES d h = CompactSumKES h (CompactSum5KES d h) -- | A 2^7 period KES type CompactSum7KES d h = CompactSumKES h (CompactSum6KES d h) - -- | A composition of two KES schemes to give a KES scheme with the sum of -- the time periods. -- @@ -141,280 +140,295 @@ type CompactSum7KES d h = CompactSumKES h (CompactSum6KES d h) -- we only need it for two instances of the same scheme, and we save -- substantially on the size of the type and runtime dictionaries if we do it -- this way, especially when we start applying it recursively. --- data CompactSumKES h d -instance (NFData (SigKES d), NFData (VerKeyKES d)) => - NFData (SigKES (CompactSumKES h d)) where - -instance (NFData (SignKeyKES d), NFData (VerKeyKES d)) => - NFData (SignKeyKES (CompactSumKES h d)) where - rnf (SignKeyCompactSumKES sk r vk1 vk2) = - rnf (sk, r, vk1, vk2) - -instance ( OptimizedKESAlgorithm d - , SodiumHashAlgorithm h -- needed for secure forgetting - , SizeHash h ~ SeedSizeKES d -- can be relaxed - , NoThunks (VerKeyKES (CompactSumKES h d)) - , KnownNat (SizeVerKeyKES (CompactSumKES h d)) - , KnownNat (SizeSignKeyKES (CompactSumKES h d)) - , KnownNat (SizeSigKES (CompactSumKES h d)) - ) - => KESAlgorithm (CompactSumKES h d) where - - type SeedSizeKES (CompactSumKES h d) = SeedSizeKES d - - -- - -- Key and signature types - -- - - -- | From Section 3,1: - -- - -- The verification key @vk@ for the sum scheme is the hash of the - -- verification keys @vk_0, vk_1@ of the two constituent schemes. - -- - newtype VerKeyKES (CompactSumKES h d) = - VerKeyCompactSumKES (Hash h (VerKeyKES d, VerKeyKES d)) - deriving Generic - deriving newtype NFData - - -- | Figure 3 gives: @(sigma, vk_0, vk_1)@ - however, we store only the - -- \"off-side\" VK in the branch, and calculate the \"on-side\" one from - -- the leaf VK (stored in the leaf node, see 'CompactSingleKES') and the - -- \"off-side\" VK's along the Merkle path. - -- - data SigKES (CompactSumKES h d) = - SigCompactSumKES !(SigKES d) -- includes VerKeys for the Merkle subpath - !(VerKeyKES d) - deriving Generic - - -- | From Figure 3: @(sk_0, r_1, vk_0, vk_1)@ - -- - data SignKeyKES (CompactSumKES h d) = - SignKeyCompactSumKES !(SignKeyKES d) - !(MLockedSeed (SeedSizeKES d)) - !(VerKeyKES d) - !(VerKeyKES d) - - - - - -- - -- Metadata and basic key operations - -- - - algorithmNameKES _ = mungeName (algorithmNameKES (Proxy :: Proxy d)) - - -- The verification key in this scheme is actually a hash already - -- however the type of hashVerKeyKES says the caller gets to choose - -- the hash, not the implementation. So that's why we have to hash - -- the hash here. We could alternatively provide a "key identifier" - -- function and let the implementation choose what that is. - hashVerKeyKES (VerKeyCompactSumKES vk) = castHash (hashWith hashToBytes vk) - - - -- - -- Core algorithm operations - -- - - type Signable (CompactSumKES h d) = Signable d - type ContextKES (CompactSumKES h d) = ContextKES d - - verifyKES = verifyOptimizedKES - - totalPeriodsKES _ = 2 * totalPeriodsKES (Proxy :: Proxy d) - - -- - -- raw serialise/deserialise - -- - - type SizeVerKeyKES (CompactSumKES h d) = SizeHash h - type SizeSignKeyKES (CompactSumKES h d) = SizeSignKeyKES d - + SeedSizeKES d - + SizeVerKeyKES d * 2 - type SizeSigKES (CompactSumKES h d) = SizeSigKES d - + SizeVerKeyKES d - - rawSerialiseVerKeyKES (VerKeyCompactSumKES vk) = hashToBytes vk - - rawSerialiseSigKES (SigCompactSumKES sigma vk_other) = +instance + (NFData (SigKES d), NFData (VerKeyKES d)) => + NFData (SigKES (CompactSumKES h d)) + +instance + (NFData (SignKeyKES d), NFData (VerKeyKES d)) => + NFData (SignKeyKES (CompactSumKES h d)) + where + rnf (SignKeyCompactSumKES sk r vk1 vk2) = + rnf (sk, r, vk1, vk2) + +instance + ( OptimizedKESAlgorithm d + , SodiumHashAlgorithm h -- needed for secure forgetting + , SizeHash h ~ SeedSizeKES d -- can be relaxed + , NoThunks (VerKeyKES (CompactSumKES h d)) + , KnownNat (SizeVerKeyKES (CompactSumKES h d)) + , KnownNat (SizeSignKeyKES (CompactSumKES h d)) + , KnownNat (SizeSigKES (CompactSumKES h d)) + ) => + KESAlgorithm (CompactSumKES h d) + where + type SeedSizeKES (CompactSumKES h d) = SeedSizeKES d + + -- + -- Key and signature types + -- + + -- \| From Section 3,1: + -- + -- The verification key @vk@ for the sum scheme is the hash of the + -- verification keys @vk_0, vk_1@ of the two constituent schemes. + newtype VerKeyKES (CompactSumKES h d) + = VerKeyCompactSumKES (Hash h (VerKeyKES d, VerKeyKES d)) + deriving (Generic) + deriving newtype (NFData) + + -- \| Figure 3 gives: @(sigma, vk_0, vk_1)@ - however, we store only the + -- \"off-side\" VK in the branch, and calculate the \"on-side\" one from + -- the leaf VK (stored in the leaf node, see 'CompactSingleKES') and the + -- \"off-side\" VK's along the Merkle path. + data SigKES (CompactSumKES h d) + = SigCompactSumKES + !(SigKES d) -- includes VerKeys for the Merkle subpath + !(VerKeyKES d) + deriving (Generic) + + -- \| From Figure 3: @(sk_0, r_1, vk_0, vk_1)@ + data SignKeyKES (CompactSumKES h d) + = SignKeyCompactSumKES + !(SignKeyKES d) + !(MLockedSeed (SeedSizeKES d)) + !(VerKeyKES d) + !(VerKeyKES d) + + -- + -- Metadata and basic key operations + -- + + algorithmNameKES _ = mungeName (algorithmNameKES (Proxy :: Proxy d)) + + -- The verification key in this scheme is actually a hash already + -- however the type of hashVerKeyKES says the caller gets to choose + -- the hash, not the implementation. So that's why we have to hash + -- the hash here. We could alternatively provide a "key identifier" + -- function and let the implementation choose what that is. + hashVerKeyKES (VerKeyCompactSumKES vk) = castHash (hashWith hashToBytes vk) + + -- + -- Core algorithm operations + -- + + type Signable (CompactSumKES h d) = Signable d + type ContextKES (CompactSumKES h d) = ContextKES d + + verifyKES = verifyOptimizedKES + + totalPeriodsKES _ = 2 * totalPeriodsKES (Proxy :: Proxy d) + + -- + -- raw serialise/deserialise + -- + + type SizeVerKeyKES (CompactSumKES h d) = SizeHash h + type + SizeSignKeyKES (CompactSumKES h d) = + SizeSignKeyKES d + + SeedSizeKES d + + SizeVerKeyKES d * 2 + type + SizeSigKES (CompactSumKES h d) = + SizeSigKES d + + SizeVerKeyKES d + + rawSerialiseVerKeyKES (VerKeyCompactSumKES vk) = hashToBytes vk + + rawSerialiseSigKES (SigCompactSumKES sigma vk_other) = + mconcat + [ rawSerialiseSigKES sigma + , rawSerialiseVerKeyKES vk_other + ] + + rawDeserialiseVerKeyKES = fmap VerKeyCompactSumKES . hashFromBytes + + rawDeserialiseSigKES b = do + guard (BS.length b == fromIntegral size_total) + sigma <- rawDeserialiseSigKES b_sig + vk <- rawDeserialiseVerKeyKES b_vk + return (SigCompactSumKES sigma vk) + where + b_sig = slice off_sig size_sig b + b_vk = slice off_vk size_vk b + + size_sig = sizeSigKES (Proxy :: Proxy d) + size_vk = sizeVerKeyKES (Proxy :: Proxy d) + size_total = sizeSigKES (Proxy :: Proxy (CompactSumKES h d)) + + off_sig = 0 :: Word + off_vk = size_sig + + deriveVerKeyKES (SignKeyCompactSumKES _ _ vk_0 vk_1) = + return $! VerKeyCompactSumKES (hashPairOfVKeys (vk_0, vk_1)) + + {-# NOINLINE signKES #-} + signKES ctxt t a (SignKeyCompactSumKES sk _r_1 vk_0 vk_1) = do + sigma <- getSigma + return $! SigCompactSumKES sigma vk_other + where + (getSigma, vk_other) + | t < _T = (signKES ctxt t a sk, vk_1) + | otherwise = (signKES ctxt (t - _T) a sk, vk_0) + + _T = totalPeriodsKES (Proxy :: Proxy d) + + {-# NOINLINE updateKESWith #-} + updateKESWith allocator ctx (SignKeyCompactSumKES sk r_1 vk_0 vk_1) t + | t + 1 < _T = + runMaybeT $! + do + sk' <- MaybeT $! updateKESWith allocator ctx sk t + r_1' <- lift $! mlockedSeedCopyWith allocator r_1 + return $! SignKeyCompactSumKES sk' r_1' vk_0 vk_1 + | t + 1 == _T = do + sk' <- genKeyKESWith allocator r_1 + zero <- mlockedSeedNewZeroWith allocator + return $! Just $! SignKeyCompactSumKES sk' zero vk_0 vk_1 + | otherwise = + runMaybeT $! + do + sk' <- MaybeT $! updateKESWith allocator ctx sk (t - _T) + r_1' <- lift $! mlockedSeedCopyWith allocator r_1 + return $! SignKeyCompactSumKES sk' r_1' vk_0 vk_1 + where + _T = totalPeriodsKES (Proxy :: Proxy d) + + -- + -- Key generation + -- + + {-# NOINLINE genKeyKESWith #-} + genKeyKESWith allocator r = do + (r0raw, r1raw) <- expandHashWith allocator (Proxy :: Proxy h) (mlockedSeedMLSB r) + let r0 = MLockedSeed r0raw + r1 = MLockedSeed r1raw + sk_0 <- genKeyKESWith allocator r0 + vk_0 <- deriveVerKeyKES sk_0 + sk_1 <- genKeyKESWith allocator r1 + vk_1 <- deriveVerKeyKES sk_1 + forgetSignKeyKES sk_1 + mlockedSeedFinalize r0 + return $! SignKeyCompactSumKES sk_0 r1 vk_0 vk_1 + + -- + -- forgetting + -- + forgetSignKeyKESWith allocator (SignKeyCompactSumKES sk_0 r1 _ _) = do + forgetSignKeyKESWith allocator sk_0 + mlockedSeedFinalize r1 + +instance + ( KESAlgorithm (CompactSumKES h d) + , UnsoundKESAlgorithm d + ) => + UnsoundKESAlgorithm (CompactSumKES h d) + where + -- + -- Raw serialise/deserialise - dangerous, do not use in production code. + -- + + {-# NOINLINE rawSerialiseSignKeyKES #-} + rawSerialiseSignKeyKES (SignKeyCompactSumKES sk r_1 vk_0 vk_1) = do + ssk <- rawSerialiseSignKeyKES sk + sr1 <- mlsbToByteString . mlockedSeedMLSB $ r_1 + return $ mconcat - [ rawSerialiseSigKES sigma - , rawSerialiseVerKeyKES vk_other + [ ssk + , sr1 + , rawSerialiseVerKeyKES vk_0 + , rawSerialiseVerKeyKES vk_1 ] - rawDeserialiseVerKeyKES = fmap VerKeyCompactSumKES . hashFromBytes - - rawDeserialiseSigKES b = do - guard (BS.length b == fromIntegral size_total) - sigma <- rawDeserialiseSigKES b_sig - vk <- rawDeserialiseVerKeyKES b_vk - return (SigCompactSumKES sigma vk) - where - b_sig = slice off_sig size_sig b - b_vk = slice off_vk size_vk b - - size_sig = sizeSigKES (Proxy :: Proxy d) - size_vk = sizeVerKeyKES (Proxy :: Proxy d) - size_total = sizeSigKES (Proxy :: Proxy (CompactSumKES h d)) - - off_sig = 0 :: Word - off_vk = size_sig - - deriveVerKeyKES (SignKeyCompactSumKES _ _ vk_0 vk_1) = - return $! VerKeyCompactSumKES (hashPairOfVKeys (vk_0, vk_1)) - - {-# NOINLINE signKES #-} - signKES ctxt t a (SignKeyCompactSumKES sk _r_1 vk_0 vk_1) = do - sigma <- getSigma - return $! SigCompactSumKES sigma vk_other - where - (getSigma, vk_other) - | t < _T = (signKES ctxt t a sk, vk_1) - | otherwise = (signKES ctxt (t - _T) a sk, vk_0) - - _T = totalPeriodsKES (Proxy :: Proxy d) - - {-# NOINLINE updateKESWith #-} - updateKESWith allocator ctx (SignKeyCompactSumKES sk r_1 vk_0 vk_1) t - | t+1 < _T = runMaybeT $! - do - sk' <- MaybeT $! updateKESWith allocator ctx sk t - r_1' <- lift $! mlockedSeedCopyWith allocator r_1 - return $! SignKeyCompactSumKES sk' r_1' vk_0 vk_1 - - | t+1 == _T = do - sk' <- genKeyKESWith allocator r_1 - zero <- mlockedSeedNewZeroWith allocator - return $! Just $! SignKeyCompactSumKES sk' zero vk_0 vk_1 - | otherwise = runMaybeT $! - do - sk' <- MaybeT $! updateKESWith allocator ctx sk (t - _T) - r_1' <- lift $! mlockedSeedCopyWith allocator r_1 - return $! SignKeyCompactSumKES sk' r_1' vk_0 vk_1 - where - _T = totalPeriodsKES (Proxy :: Proxy d) - - -- - -- Key generation - -- - - {-# NOINLINE genKeyKESWith #-} - genKeyKESWith allocator r = do - (r0raw, r1raw) <- expandHashWith allocator (Proxy :: Proxy h) (mlockedSeedMLSB r) - let r0 = MLockedSeed r0raw - r1 = MLockedSeed r1raw - sk_0 <- genKeyKESWith allocator r0 - vk_0 <- deriveVerKeyKES sk_0 - sk_1 <- genKeyKESWith allocator r1 - vk_1 <- deriveVerKeyKES sk_1 - forgetSignKeyKES sk_1 - mlockedSeedFinalize r0 - return $! SignKeyCompactSumKES sk_0 r1 vk_0 vk_1 - - -- - -- forgetting - -- - forgetSignKeyKESWith allocator (SignKeyCompactSumKES sk_0 r1 _ _) = do - forgetSignKeyKESWith allocator sk_0 - mlockedSeedFinalize r1 - -instance ( KESAlgorithm (CompactSumKES h d) - , UnsoundKESAlgorithm d - ) => UnsoundKESAlgorithm (CompactSumKES h d) where - -- - -- Raw serialise/deserialise - dangerous, do not use in production code. - -- - - {-# NOINLINE rawSerialiseSignKeyKES #-} - rawSerialiseSignKeyKES (SignKeyCompactSumKES sk r_1 vk_0 vk_1) = do - ssk <- rawSerialiseSignKeyKES sk - sr1 <- mlsbToByteString . mlockedSeedMLSB $ r_1 - return $ mconcat - [ ssk - , sr1 - , rawSerialiseVerKeyKES vk_0 - , rawSerialiseVerKeyKES vk_1 - ] - - {-# NOINLINE rawDeserialiseSignKeyKESWith #-} - rawDeserialiseSignKeyKESWith allocator b = runMaybeT $ do - guard (BS.length b == fromIntegral size_total) - sk <- MaybeT $ rawDeserialiseSignKeyKESWith allocator b_sk - r <- MaybeT $ mlsbFromByteStringCheckWith allocator b_r - vk_0 <- MaybeT . return $ rawDeserialiseVerKeyKES b_vk0 - vk_1 <- MaybeT . return $ rawDeserialiseVerKeyKES b_vk1 - return (SignKeyCompactSumKES sk (MLockedSeed r) vk_0 vk_1) - where - b_sk = slice off_sk size_sk b - b_r = slice off_r size_r b - b_vk0 = slice off_vk0 size_vk b - b_vk1 = slice off_vk1 size_vk b - - size_sk = sizeSignKeyKES (Proxy :: Proxy d) - size_r = seedSizeKES (Proxy :: Proxy d) - size_vk = sizeVerKeyKES (Proxy :: Proxy d) - size_total = sizeSignKeyKES (Proxy :: Proxy (CompactSumKES h d)) - - off_sk = 0 :: Word - off_r = size_sk - off_vk0 = off_r + size_r - off_vk1 = off_vk0 + size_vk - - - -instance (KESAlgorithm (CompactSumKES h d), OptimizedKESAlgorithm d, HashAlgorithm h) => - OptimizedKESAlgorithm (CompactSumKES h d) where - - verifySigKES ctxt t a (SigCompactSumKES sigma _) = - verifySigKES ctxt t' a sigma - where - _T = totalPeriodsKES (Proxy :: Proxy d) - t' | t < _T = t - | otherwise = t - _T - - verKeyFromSigKES ctxt t (SigCompactSumKES sigma vk_other) = - VerKeyCompactSumKES $ hashPairOfVKeys (vk_0, vk_1) - where - _T = totalPeriodsKES (Proxy :: Proxy d) - t' | t < _T = t - | otherwise = t - _T - (vk_0, vk_1) | t < _T = (verKeyFromSigKES ctxt t' sigma, vk_other) - | otherwise = (vk_other, verKeyFromSigKES ctxt t' sigma) + {-# NOINLINE rawDeserialiseSignKeyKESWith #-} + rawDeserialiseSignKeyKESWith allocator b = runMaybeT $ do + guard (BS.length b == fromIntegral size_total) + sk <- MaybeT $ rawDeserialiseSignKeyKESWith allocator b_sk + r <- MaybeT $ mlsbFromByteStringCheckWith allocator b_r + vk_0 <- MaybeT . return $ rawDeserialiseVerKeyKES b_vk0 + vk_1 <- MaybeT . return $ rawDeserialiseVerKeyKES b_vk1 + return (SignKeyCompactSumKES sk (MLockedSeed r) vk_0 vk_1) + where + b_sk = slice off_sk size_sk b + b_r = slice off_r size_r b + b_vk0 = slice off_vk0 size_vk b + b_vk1 = slice off_vk1 size_vk b + + size_sk = sizeSignKeyKES (Proxy :: Proxy d) + size_r = seedSizeKES (Proxy :: Proxy d) + size_vk = sizeVerKeyKES (Proxy :: Proxy d) + size_total = sizeSignKeyKES (Proxy :: Proxy (CompactSumKES h d)) + + off_sk = 0 :: Word + off_r = size_sk + off_vk0 = off_r + size_r + off_vk1 = off_vk0 + size_vk + +instance + (KESAlgorithm (CompactSumKES h d), OptimizedKESAlgorithm d, HashAlgorithm h) => + OptimizedKESAlgorithm (CompactSumKES h d) + where + verifySigKES ctxt t a (SigCompactSumKES sigma _) = + verifySigKES ctxt t' a sigma + where + _T = totalPeriodsKES (Proxy :: Proxy d) + t' + | t < _T = t + | otherwise = t - _T + + verKeyFromSigKES ctxt t (SigCompactSumKES sigma vk_other) = + VerKeyCompactSumKES $ hashPairOfVKeys (vk_0, vk_1) + where + _T = totalPeriodsKES (Proxy :: Proxy d) + t' + | t < _T = t + | otherwise = t - _T + (vk_0, vk_1) + | t < _T = (verKeyFromSigKES ctxt t' sigma, vk_other) + | otherwise = (vk_other, verKeyFromSigKES ctxt t' sigma) -- -- VerKey instances -- deriving instance HashAlgorithm h => Show (VerKeyKES (CompactSumKES h d)) -deriving instance Eq (VerKeyKES (CompactSumKES h d)) - -deriving via OnlyCheckWhnfNamed "SignKeyKES (CompactSumKES h d)" (SignKeyKES (CompactSumKES h d)) - instance NoThunks (SignKeyKES (CompactSumKES h d)) - -instance (KESAlgorithm d) => NoThunks (VerKeyKES (CompactSumKES h d)) - -instance ( OptimizedKESAlgorithm d - , SodiumHashAlgorithm h - , SizeHash h ~ SeedSizeKES d - , NoThunks (VerKeyKES (CompactSumKES h d)) - , KnownNat (SizeVerKeyKES (CompactSumKES h d)) - , KnownNat (SizeSignKeyKES (CompactSumKES h d)) - , KnownNat (SizeSigKES (CompactSumKES h d)) - ) - => ToCBOR (VerKeyKES (CompactSumKES h d)) where +deriving instance Eq (VerKeyKES (CompactSumKES h d)) + +deriving via + OnlyCheckWhnfNamed "SignKeyKES (CompactSumKES h d)" (SignKeyKES (CompactSumKES h d)) + instance + NoThunks (SignKeyKES (CompactSumKES h d)) + +instance KESAlgorithm d => NoThunks (VerKeyKES (CompactSumKES h d)) + +instance + ( OptimizedKESAlgorithm d + , SodiumHashAlgorithm h + , SizeHash h ~ SeedSizeKES d + , NoThunks (VerKeyKES (CompactSumKES h d)) + , KnownNat (SizeVerKeyKES (CompactSumKES h d)) + , KnownNat (SizeSignKeyKES (CompactSumKES h d)) + , KnownNat (SizeSigKES (CompactSumKES h d)) + ) => + ToCBOR (VerKeyKES (CompactSumKES h d)) + where toCBOR = encodeVerKeyKES encodedSizeExpr _size = encodedVerKeyKESSizeExpr -instance ( OptimizedKESAlgorithm d - , SodiumHashAlgorithm h - , SizeHash h ~ SeedSizeKES d - , NoThunks (VerKeyKES (CompactSumKES h d)) - , KnownNat (SizeVerKeyKES (CompactSumKES h d)) - , KnownNat (SizeSignKeyKES (CompactSumKES h d)) - , KnownNat (SizeSigKES (CompactSumKES h d)) - ) - => FromCBOR (VerKeyKES (CompactSumKES h d)) where +instance + ( OptimizedKESAlgorithm d + , SodiumHashAlgorithm h + , SizeHash h ~ SeedSizeKES d + , NoThunks (VerKeyKES (CompactSumKES h d)) + , KnownNat (SizeVerKeyKES (CompactSumKES h d)) + , KnownNat (SizeSignKeyKES (CompactSumKES h d)) + , KnownNat (SizeSigKES (CompactSumKES h d)) + ) => + FromCBOR (VerKeyKES (CompactSumKES h d)) + where fromCBOR = decodeVerKeyKES -- @@ -442,179 +456,200 @@ instance ( OptimizedKESAlgorithm d -- deriving instance KESAlgorithm d => Show (SigKES (CompactSumKES h d)) -deriving instance KESAlgorithm d => Eq (SigKES (CompactSumKES h d)) +deriving instance KESAlgorithm d => Eq (SigKES (CompactSumKES h d)) instance KESAlgorithm d => NoThunks (SigKES (CompactSumKES h d)) -instance ( OptimizedKESAlgorithm d - , SodiumHashAlgorithm h - , SizeHash h ~ SeedSizeKES d - , NoThunks (VerKeyKES (CompactSumKES h d)) - , KnownNat (SizeVerKeyKES (CompactSumKES h d)) - , KnownNat (SizeSignKeyKES (CompactSumKES h d)) - , KnownNat (SizeSigKES (CompactSumKES h d)) - ) - => ToCBOR (SigKES (CompactSumKES h d)) where +instance + ( OptimizedKESAlgorithm d + , SodiumHashAlgorithm h + , SizeHash h ~ SeedSizeKES d + , NoThunks (VerKeyKES (CompactSumKES h d)) + , KnownNat (SizeVerKeyKES (CompactSumKES h d)) + , KnownNat (SizeSignKeyKES (CompactSumKES h d)) + , KnownNat (SizeSigKES (CompactSumKES h d)) + ) => + ToCBOR (SigKES (CompactSumKES h d)) + where toCBOR = encodeSigKES encodedSizeExpr _size = encodedSigKESSizeExpr -instance ( OptimizedKESAlgorithm d - , SodiumHashAlgorithm h - , SizeHash h ~ SeedSizeKES d - , NoThunks (VerKeyKES (CompactSumKES h d)) - , KnownNat (SizeVerKeyKES (CompactSumKES h d)) - , KnownNat (SizeSignKeyKES (CompactSumKES h d)) - , KnownNat (SizeSigKES (CompactSumKES h d)) - ) - => FromCBOR (SigKES (CompactSumKES h d)) where +instance + ( OptimizedKESAlgorithm d + , SodiumHashAlgorithm h + , SizeHash h ~ SeedSizeKES d + , NoThunks (VerKeyKES (CompactSumKES h d)) + , KnownNat (SizeVerKeyKES (CompactSumKES h d)) + , KnownNat (SizeSignKeyKES (CompactSumKES h d)) + , KnownNat (SizeSigKES (CompactSumKES h d)) + ) => + FromCBOR (SigKES (CompactSumKES h d)) + where fromCBOR = decodeSigKES - -- -- Unsound pure KES API -- -instance ( KESAlgorithm (CompactSumKES h d) - , HashAlgorithm h - , UnsoundPureKESAlgorithm d - ) - => UnsoundPureKESAlgorithm (CompactSumKES h d) where - data UnsoundPureSignKeyKES (CompactSumKES h d) = - UnsoundPureSignKeyCompactSumKES !(UnsoundPureSignKeyKES d) - !Seed - !(VerKeyKES d) - !(VerKeyKES d) - deriving (Generic) - - unsoundPureSignKES ctxt t a (UnsoundPureSignKeyCompactSumKES sk _r_1 vk_0 vk_1) = - SigCompactSumKES sigma vk_other - where - (sigma, vk_other) - | t < _T = (unsoundPureSignKES ctxt t a sk, vk_1) - | otherwise = (unsoundPureSignKES ctxt (t - _T) a sk, vk_0) - - _T = totalPeriodsKES (Proxy :: Proxy d) - - unsoundPureUpdateKES ctx (UnsoundPureSignKeyCompactSumKES sk r_1 vk_0 vk_1) t - | t+1 < _T = do - sk' <- unsoundPureUpdateKES ctx sk t - let r_1' = r_1 - return $! UnsoundPureSignKeyCompactSumKES sk' r_1' vk_0 vk_1 - | t+1 == _T = do - let sk' = unsoundPureGenKeyKES r_1 - let r_1' = mkSeedFromBytes (BS.replicate (fromIntegral (seedSizeKES (Proxy @d))) 0) - return $! UnsoundPureSignKeyCompactSumKES sk' r_1' vk_0 vk_1 - | otherwise = do - sk' <- unsoundPureUpdateKES ctx sk (t - _T) - let r_1' = r_1 - return $! UnsoundPureSignKeyCompactSumKES sk' r_1' vk_0 vk_1 - where - _T = totalPeriodsKES (Proxy :: Proxy d) - - -- - -- Key generation - -- - - unsoundPureGenKeyKES r = - let r0 = mkSeedFromBytes $ digest (Proxy @h) (BS.cons 1 $ getSeedBytes r) - r1 = mkSeedFromBytes $ digest (Proxy @h) (BS.cons 2 $ getSeedBytes r) - sk_0 = unsoundPureGenKeyKES r0 - vk_0 = unsoundPureDeriveVerKeyKES sk_0 - sk_1 = unsoundPureGenKeyKES r1 - vk_1 = unsoundPureDeriveVerKeyKES sk_1 - in UnsoundPureSignKeyCompactSumKES sk_0 r1 vk_0 vk_1 - - unsoundPureDeriveVerKeyKES (UnsoundPureSignKeyCompactSumKES _ _ vk_0 vk_1) = - VerKeyCompactSumKES (hashPairOfVKeys (vk_0, vk_1)) - - unsoundPureSignKeyKESToSoundSignKeyKES (UnsoundPureSignKeyCompactSumKES sk r_1 vk_0 vk_1) = - SignKeyCompactSumKES - <$> unsoundPureSignKeyKESToSoundSignKeyKES sk - <*> (fmap MLockedSeed . mlsbFromByteString . getSeedBytes $ r_1) - <*> pure vk_0 - <*> pure vk_1 - - rawSerialiseUnsoundPureSignKeyKES (UnsoundPureSignKeyCompactSumKES sk r_1 vk_0 vk_1) = - let ssk = rawSerialiseUnsoundPureSignKeyKES sk - sr1 = getSeedBytes r_1 - in mconcat +instance + ( KESAlgorithm (CompactSumKES h d) + , HashAlgorithm h + , UnsoundPureKESAlgorithm d + ) => + UnsoundPureKESAlgorithm (CompactSumKES h d) + where + data UnsoundPureSignKeyKES (CompactSumKES h d) + = UnsoundPureSignKeyCompactSumKES + !(UnsoundPureSignKeyKES d) + !Seed + !(VerKeyKES d) + !(VerKeyKES d) + deriving (Generic) + + unsoundPureSignKES ctxt t a (UnsoundPureSignKeyCompactSumKES sk _r_1 vk_0 vk_1) = + SigCompactSumKES sigma vk_other + where + (sigma, vk_other) + | t < _T = (unsoundPureSignKES ctxt t a sk, vk_1) + | otherwise = (unsoundPureSignKES ctxt (t - _T) a sk, vk_0) + + _T = totalPeriodsKES (Proxy :: Proxy d) + + unsoundPureUpdateKES ctx (UnsoundPureSignKeyCompactSumKES sk r_1 vk_0 vk_1) t + | t + 1 < _T = do + sk' <- unsoundPureUpdateKES ctx sk t + let r_1' = r_1 + return $! UnsoundPureSignKeyCompactSumKES sk' r_1' vk_0 vk_1 + | t + 1 == _T = do + let sk' = unsoundPureGenKeyKES r_1 + let r_1' = mkSeedFromBytes (BS.replicate (fromIntegral (seedSizeKES (Proxy @d))) 0) + return $! UnsoundPureSignKeyCompactSumKES sk' r_1' vk_0 vk_1 + | otherwise = do + sk' <- unsoundPureUpdateKES ctx sk (t - _T) + let r_1' = r_1 + return $! UnsoundPureSignKeyCompactSumKES sk' r_1' vk_0 vk_1 + where + _T = totalPeriodsKES (Proxy :: Proxy d) + + -- + -- Key generation + -- + + unsoundPureGenKeyKES r = + let r0 = mkSeedFromBytes $ digest (Proxy @h) (BS.cons 1 $ getSeedBytes r) + r1 = mkSeedFromBytes $ digest (Proxy @h) (BS.cons 2 $ getSeedBytes r) + sk_0 = unsoundPureGenKeyKES r0 + vk_0 = unsoundPureDeriveVerKeyKES sk_0 + sk_1 = unsoundPureGenKeyKES r1 + vk_1 = unsoundPureDeriveVerKeyKES sk_1 + in UnsoundPureSignKeyCompactSumKES sk_0 r1 vk_0 vk_1 + + unsoundPureDeriveVerKeyKES (UnsoundPureSignKeyCompactSumKES _ _ vk_0 vk_1) = + VerKeyCompactSumKES (hashPairOfVKeys (vk_0, vk_1)) + + unsoundPureSignKeyKESToSoundSignKeyKES (UnsoundPureSignKeyCompactSumKES sk r_1 vk_0 vk_1) = + SignKeyCompactSumKES + <$> unsoundPureSignKeyKESToSoundSignKeyKES sk + <*> (fmap MLockedSeed . mlsbFromByteString . getSeedBytes $ r_1) + <*> pure vk_0 + <*> pure vk_1 + + rawSerialiseUnsoundPureSignKeyKES (UnsoundPureSignKeyCompactSumKES sk r_1 vk_0 vk_1) = + let ssk = rawSerialiseUnsoundPureSignKeyKES sk + sr1 = getSeedBytes r_1 + in mconcat [ ssk , sr1 , rawSerialiseVerKeyKES vk_0 , rawSerialiseVerKeyKES vk_1 ] - rawDeserialiseUnsoundPureSignKeyKES b = do - guard (BS.length b == fromIntegral size_total) - sk <- rawDeserialiseUnsoundPureSignKeyKES b_sk - let r = mkSeedFromBytes b_r - vk_0 <- rawDeserialiseVerKeyKES b_vk0 - vk_1 <- rawDeserialiseVerKeyKES b_vk1 - return (UnsoundPureSignKeyCompactSumKES sk r vk_0 vk_1) - where - b_sk = slice off_sk size_sk b - b_r = slice off_r size_r b - b_vk0 = slice off_vk0 size_vk b - b_vk1 = slice off_vk1 size_vk b - - size_sk = sizeSignKeyKES (Proxy :: Proxy d) - size_r = seedSizeKES (Proxy :: Proxy d) - size_vk = sizeVerKeyKES (Proxy :: Proxy d) - size_total = sizeSignKeyKES (Proxy :: Proxy (CompactSumKES h d)) - - off_sk = 0 :: Word - off_r = size_sk - off_vk0 = off_r + size_r - off_vk1 = off_vk0 + size_vk + rawDeserialiseUnsoundPureSignKeyKES b = do + guard (BS.length b == fromIntegral size_total) + sk <- rawDeserialiseUnsoundPureSignKeyKES b_sk + let r = mkSeedFromBytes b_r + vk_0 <- rawDeserialiseVerKeyKES b_vk0 + vk_1 <- rawDeserialiseVerKeyKES b_vk1 + return (UnsoundPureSignKeyCompactSumKES sk r vk_0 vk_1) + where + b_sk = slice off_sk size_sk b + b_r = slice off_r size_r b + b_vk0 = slice off_vk0 size_vk b + b_vk1 = slice off_vk1 size_vk b + + size_sk = sizeSignKeyKES (Proxy :: Proxy d) + size_r = seedSizeKES (Proxy :: Proxy d) + size_vk = sizeVerKeyKES (Proxy :: Proxy d) + size_total = sizeSignKeyKES (Proxy :: Proxy (CompactSumKES h d)) + + off_sk = 0 :: Word + off_r = size_sk + off_vk0 = off_r + size_r + off_vk1 = off_vk0 + size_vk -- -- UnsoundPureSignKey instances -- -deriving instance (KESAlgorithm d, Show (UnsoundPureSignKeyKES d)) => Show (UnsoundPureSignKeyKES (CompactSumKES h d)) -deriving instance (KESAlgorithm d, Eq (UnsoundPureSignKeyKES d)) => Eq (UnsoundPureSignKeyKES (CompactSumKES h d)) - -instance ( SizeHash h ~ SeedSizeKES d - , OptimizedKESAlgorithm d - , UnsoundPureKESAlgorithm d - , SodiumHashAlgorithm h - , KnownNat (SizeVerKeyKES (CompactSumKES h d)) - , KnownNat (SizeSignKeyKES (CompactSumKES h d)) - , KnownNat (SizeSigKES (CompactSumKES h d)) - ) => ToCBOR (UnsoundPureSignKeyKES (CompactSumKES h d)) where +deriving instance + (KESAlgorithm d, Show (UnsoundPureSignKeyKES d)) => Show (UnsoundPureSignKeyKES (CompactSumKES h d)) +deriving instance + (KESAlgorithm d, Eq (UnsoundPureSignKeyKES d)) => Eq (UnsoundPureSignKeyKES (CompactSumKES h d)) + +instance + ( SizeHash h ~ SeedSizeKES d + , OptimizedKESAlgorithm d + , UnsoundPureKESAlgorithm d + , SodiumHashAlgorithm h + , KnownNat (SizeVerKeyKES (CompactSumKES h d)) + , KnownNat (SizeSignKeyKES (CompactSumKES h d)) + , KnownNat (SizeSigKES (CompactSumKES h d)) + ) => + ToCBOR (UnsoundPureSignKeyKES (CompactSumKES h d)) + where toCBOR = encodeUnsoundPureSignKeyKES encodedSizeExpr _size _skProxy = encodedSignKeyKESSizeExpr (Proxy :: Proxy (SignKeyKES (CompactSumKES h d))) -instance ( SizeHash h ~ SeedSizeKES d - , OptimizedKESAlgorithm d - , UnsoundPureKESAlgorithm d - , SodiumHashAlgorithm h - , KnownNat (SizeVerKeyKES (CompactSumKES h d)) - , KnownNat (SizeSignKeyKES (CompactSumKES h d)) - , KnownNat (SizeSigKES (CompactSumKES h d)) - ) => FromCBOR (UnsoundPureSignKeyKES (CompactSumKES h d)) where +instance + ( SizeHash h ~ SeedSizeKES d + , OptimizedKESAlgorithm d + , UnsoundPureKESAlgorithm d + , SodiumHashAlgorithm h + , KnownNat (SizeVerKeyKES (CompactSumKES h d)) + , KnownNat (SizeSignKeyKES (CompactSumKES h d)) + , KnownNat (SizeSigKES (CompactSumKES h d)) + ) => + FromCBOR (UnsoundPureSignKeyKES (CompactSumKES h d)) + where fromCBOR = decodeUnsoundPureSignKeyKES -instance (NoThunks (UnsoundPureSignKeyKES d), KESAlgorithm d) => NoThunks (UnsoundPureSignKeyKES (CompactSumKES h d)) - +instance + (NoThunks (UnsoundPureSignKeyKES d), KESAlgorithm d) => + NoThunks (UnsoundPureSignKeyKES (CompactSumKES h d)) -- -- Direct ser/deser -- -instance ( DirectSerialise (SignKeyKES d) - , DirectSerialise (VerKeyKES d) - , KESAlgorithm d - ) => DirectSerialise (SignKeyKES (CompactSumKES h d)) where +instance + ( DirectSerialise (SignKeyKES d) + , DirectSerialise (VerKeyKES d) + , KESAlgorithm d + ) => + DirectSerialise (SignKeyKES (CompactSumKES h d)) + where directSerialise push (SignKeyCompactSumKES sk r vk0 vk1) = do directSerialise push sk directSerialise push r directSerialise push vk0 directSerialise push vk1 -instance ( DirectDeserialise (SignKeyKES d) - , DirectDeserialise (VerKeyKES d) - , KESAlgorithm d - ) => DirectDeserialise (SignKeyKES (CompactSumKES h d)) where +instance + ( DirectDeserialise (SignKeyKES d) + , DirectDeserialise (VerKeyKES d) + , KESAlgorithm d + ) => + DirectDeserialise (SignKeyKES (CompactSumKES h d)) + where directDeserialise pull = do sk <- directDeserialise pull r <- directDeserialise pull @@ -623,14 +658,15 @@ instance ( DirectDeserialise (SignKeyKES d) return $! SignKeyCompactSumKES sk r vk0 vk1 - instance DirectSerialise (VerKeyKES (CompactSumKES h d)) where directSerialise push (VerKeyCompactSumKES h) = unpackByteStringCStringLen (hashToBytes h) $ \(ptr, len) -> push (castPtr ptr) (fromIntegral len) -instance (HashAlgorithm h) - => DirectDeserialise (VerKeyKES (CompactSumKES h d)) where +instance + HashAlgorithm h => + DirectDeserialise (VerKeyKES (CompactSumKES h d)) + where directDeserialise pull = do let len :: Num a => a len = fromIntegral $ sizeHash (Proxy @h) diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES/Mock.hs b/cardano-crypto-class/src/Cardano/Crypto/KES/Mock.hs index 26bd61937..66efe1f15 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES/Mock.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES/Mock.hs @@ -2,51 +2,51 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE MultiParamTypeClasses #-} -- | Mock key evolving signatures. -module Cardano.Crypto.KES.Mock - ( MockKES - , VerKeyKES (..) - , SignKeyKES (..) - , UnsoundPureSignKeyKES (..) - , SigKES (..) - ) +module Cardano.Crypto.KES.Mock ( + MockKES, + VerKeyKES (..), + SignKeyKES (..), + UnsoundPureSignKeyKES (..), + SigKES (..), +) where +import qualified Data.ByteString.Internal as BS +import Data.Proxy (Proxy (..)) import Data.Word (Word64) -import Data.Proxy (Proxy(..)) +import Foreign.Ptr (castPtr) import GHC.Generics (Generic) -import GHC.TypeNats (Nat, KnownNat, natVal) +import GHC.TypeNats (KnownNat, Nat, natVal) import NoThunks.Class (NoThunks) -import qualified Data.ByteString.Internal as BS -import Foreign.Ptr (castPtr) import Control.Exception (assert) import Cardano.Binary (FromCBOR (..), ToCBOR (..)) +import Cardano.Crypto.DirectSerialise import Cardano.Crypto.Hash -import Cardano.Crypto.Seed import Cardano.Crypto.KES.Class -import Cardano.Crypto.Util +import Cardano.Crypto.Libsodium ( + mlsbToByteString, + ) import Cardano.Crypto.Libsodium.MLockedSeed -import Cardano.Crypto.Libsodium - ( mlsbToByteString - ) -import Cardano.Crypto.Libsodium.Memory - ( unpackByteStringCStringLen - , ForeignPtr (..) - , mallocForeignPtrBytes - , withForeignPtr - ) -import Cardano.Crypto.DirectSerialise +import Cardano.Crypto.Libsodium.Memory ( + ForeignPtr (..), + mallocForeignPtrBytes, + unpackByteStringCStringLen, + withForeignPtr, + ) +import Cardano.Crypto.Seed +import Cardano.Crypto.Util data MockKES (t :: Nat) @@ -62,179 +62,177 @@ data MockKES (t :: Nat) -- keys. Mock KES is more suitable for a basic testnet, since it doesn't suffer -- from the performance implications of shuffling a giant list of keys around instance KnownNat t => KESAlgorithm (MockKES t) where - type SeedSizeKES (MockKES t) = 8 - - -- - -- Key and signature types - -- - - newtype VerKeyKES (MockKES t) = VerKeyMockKES Word64 - deriving stock (Show, Eq, Generic) - deriving newtype (NoThunks) - - data SigKES (MockKES t) = - SigMockKES !(Hash ShortHash ()) !(SignKeyKES (MockKES t)) - deriving stock (Show, Eq, Generic) - deriving anyclass (NoThunks) - - data SignKeyKES (MockKES t) = - SignKeyMockKES !(VerKeyKES (MockKES t)) !Period - deriving stock (Show, Eq, Generic) - deriving anyclass (NoThunks) - - - -- - -- Metadata and basic key operations - -- - - algorithmNameKES proxy = "mock_" ++ show (totalPeriodsKES proxy) - - type SizeVerKeyKES (MockKES t) = 8 - type SizeSignKeyKES (MockKES t) = 16 - type SizeSigKES (MockKES t) = 24 - - - -- - -- Core algorithm operations - -- - - type Signable (MockKES t) = SignableRepresentation - - verifyKES () vk t a (SigMockKES h (SignKeyMockKES vk' t')) - | vk /= vk' - = Left "KES verification failed" - - | t' == t - , castHash (hashWith getSignableRepresentation a) == h - = Right () - - | otherwise - = Left "KES verification failed" - - totalPeriodsKES _ = fromIntegral (natVal (Proxy @t)) - - -- - -- raw serialise/deserialise - -- - - rawSerialiseVerKeyKES (VerKeyMockKES vk) = - writeBinaryWord64 vk - - rawSerialiseSigKES (SigMockKES h sk) = - hashToBytes h - <> rawSerialiseSignKeyMockKES sk - - rawDeserialiseVerKeyKES bs - | [vkb] <- splitsAt [8] bs - , let vk = readBinaryWord64 vkb - = Just $! VerKeyMockKES vk - - | otherwise - = Nothing - - rawDeserialiseSigKES bs - | [hb, skb] <- splitsAt [8, 16] bs - , Just h <- hashFromBytes hb - , Just sk <- rawDeserialiseSignKeyMockKES skb - = Just $! SigMockKES h sk - | otherwise - = Nothing - - deriveVerKeyKES (SignKeyMockKES vk _) = return $! vk - - updateKESWith _allocator () (SignKeyMockKES vk t') t = - assert (t == t') $! - if t+1 < totalPeriodsKES (Proxy @(MockKES t)) - then return $! Just $! SignKeyMockKES vk (t+1) - else return Nothing - - -- | Produce valid signature only with correct key, i.e., same iteration and - -- allowed KES period. - signKES () t a (SignKeyMockKES vk t') = - assert (t == t') $! - return $! - SigMockKES (castHash (hashWith getSignableRepresentation a)) - (SignKeyMockKES vk t) - - -- - -- Key generation - -- - - genKeyKESWith _allocator seed = do - seedBS <- mlsbToByteString $ mlockedSeedMLSB seed - let vk = VerKeyMockKES (runMonadRandomWithSeed (mkSeedFromBytes seedBS) getRandomWord64) - return $! SignKeyMockKES vk 0 - - forgetSignKeyKESWith _ = const $ return () + type SeedSizeKES (MockKES t) = 8 + + -- + -- Key and signature types + -- + + newtype VerKeyKES (MockKES t) = VerKeyMockKES Word64 + deriving stock (Show, Eq, Generic) + deriving newtype (NoThunks) + + data SigKES (MockKES t) + = SigMockKES !(Hash ShortHash ()) !(SignKeyKES (MockKES t)) + deriving stock (Show, Eq, Generic) + deriving anyclass (NoThunks) + + data SignKeyKES (MockKES t) + = SignKeyMockKES !(VerKeyKES (MockKES t)) !Period + deriving stock (Show, Eq, Generic) + deriving anyclass (NoThunks) + + -- + -- Metadata and basic key operations + -- + + algorithmNameKES proxy = "mock_" ++ show (totalPeriodsKES proxy) + + type SizeVerKeyKES (MockKES t) = 8 + type SizeSignKeyKES (MockKES t) = 16 + type SizeSigKES (MockKES t) = 24 + + -- + -- Core algorithm operations + -- + + type Signable (MockKES t) = SignableRepresentation + + verifyKES () vk t a (SigMockKES h (SignKeyMockKES vk' t')) + | vk /= vk' = + Left "KES verification failed" + | t' == t + , castHash (hashWith getSignableRepresentation a) == h = + Right () + | otherwise = + Left "KES verification failed" + + totalPeriodsKES _ = fromIntegral (natVal (Proxy @t)) + + -- + -- raw serialise/deserialise + -- + + rawSerialiseVerKeyKES (VerKeyMockKES vk) = + writeBinaryWord64 vk + + rawSerialiseSigKES (SigMockKES h sk) = + hashToBytes h + <> rawSerialiseSignKeyMockKES sk + + rawDeserialiseVerKeyKES bs + | [vkb] <- splitsAt [8] bs + , let vk = readBinaryWord64 vkb = + Just $! VerKeyMockKES vk + | otherwise = + Nothing + + rawDeserialiseSigKES bs + | [hb, skb] <- splitsAt [8, 16] bs + , Just h <- hashFromBytes hb + , Just sk <- rawDeserialiseSignKeyMockKES skb = + Just $! SigMockKES h sk + | otherwise = + Nothing + + deriveVerKeyKES (SignKeyMockKES vk _) = return $! vk + + updateKESWith _allocator () (SignKeyMockKES vk t') t = + assert (t == t') $! + if t + 1 < totalPeriodsKES (Proxy @(MockKES t)) + then return $! Just $! SignKeyMockKES vk (t + 1) + else return Nothing + + -- \| Produce valid signature only with correct key, i.e., same iteration and + -- allowed KES period. + signKES () t a (SignKeyMockKES vk t') = + assert (t == t') $! + return $! + SigMockKES + (castHash (hashWith getSignableRepresentation a)) + (SignKeyMockKES vk t) + + -- + -- Key generation + -- + + genKeyKESWith _allocator seed = do + seedBS <- mlsbToByteString $ mlockedSeedMLSB seed + let vk = VerKeyMockKES (runMonadRandomWithSeed (mkSeedFromBytes seedBS) getRandomWord64) + return $! SignKeyMockKES vk 0 + + forgetSignKeyKESWith _ = const $ return () instance KnownNat t => UnsoundPureKESAlgorithm (MockKES t) where - -- - -- Key and signature types - -- - - data UnsoundPureSignKeyKES (MockKES t) = - UnsoundPureSignKeyMockKES !(VerKeyKES (MockKES t)) !Period - deriving stock (Show, Eq, Generic) - deriving anyclass (NoThunks) + -- + -- Key and signature types + -- + data UnsoundPureSignKeyKES (MockKES t) + = UnsoundPureSignKeyMockKES !(VerKeyKES (MockKES t)) !Period + deriving stock (Show, Eq, Generic) + deriving anyclass (NoThunks) - unsoundPureDeriveVerKeyKES (UnsoundPureSignKeyMockKES vk _) = vk + unsoundPureDeriveVerKeyKES (UnsoundPureSignKeyMockKES vk _) = vk - unsoundPureUpdateKES () (UnsoundPureSignKeyMockKES vk t') t = - assert (t == t') $! - if t+1 < totalPeriodsKES (Proxy @(MockKES t)) - then Just $! UnsoundPureSignKeyMockKES vk (t+1) - else Nothing + unsoundPureUpdateKES () (UnsoundPureSignKeyMockKES vk t') t = + assert (t == t') $! + if t + 1 < totalPeriodsKES (Proxy @(MockKES t)) + then Just $! UnsoundPureSignKeyMockKES vk (t + 1) + else Nothing - -- | Produce valid signature only with correct key, i.e., same iteration and - -- allowed KES period. - unsoundPureSignKES () t a (UnsoundPureSignKeyMockKES vk t') = - assert (t == t') $! - SigMockKES (castHash (hashWith getSignableRepresentation a)) - (SignKeyMockKES vk t) + -- \| Produce valid signature only with correct key, i.e., same iteration and + -- allowed KES period. + unsoundPureSignKES () t a (UnsoundPureSignKeyMockKES vk t') = + assert (t == t') $! + SigMockKES + (castHash (hashWith getSignableRepresentation a)) + (SignKeyMockKES vk t) - -- - -- Key generation - -- + -- + -- Key generation + -- - unsoundPureGenKeyKES seed = - let vk = VerKeyMockKES (runMonadRandomWithSeed seed getRandomWord64) - in UnsoundPureSignKeyMockKES vk 0 + unsoundPureGenKeyKES seed = + let vk = VerKeyMockKES (runMonadRandomWithSeed seed getRandomWord64) + in UnsoundPureSignKeyMockKES vk 0 - unsoundPureSignKeyKESToSoundSignKeyKES (UnsoundPureSignKeyMockKES vk t) = - return $ SignKeyMockKES vk t + unsoundPureSignKeyKESToSoundSignKeyKES (UnsoundPureSignKeyMockKES vk t) = + return $ SignKeyMockKES vk t - rawSerialiseUnsoundPureSignKeyKES (UnsoundPureSignKeyMockKES vk t) = - rawSerialiseSignKeyMockKES (SignKeyMockKES vk t) + rawSerialiseUnsoundPureSignKeyKES (UnsoundPureSignKeyMockKES vk t) = + rawSerialiseSignKeyMockKES (SignKeyMockKES vk t) - rawDeserialiseUnsoundPureSignKeyKES bs = do - SignKeyMockKES vt t <- rawDeserialiseSignKeyMockKES bs - return $ UnsoundPureSignKeyMockKES vt t + rawDeserialiseUnsoundPureSignKeyKES bs = do + SignKeyMockKES vt t <- rawDeserialiseSignKeyMockKES bs + return $ UnsoundPureSignKeyMockKES vt t instance KnownNat t => UnsoundKESAlgorithm (MockKES t) where - rawSerialiseSignKeyKES sk = - return $ rawSerialiseSignKeyMockKES sk + rawSerialiseSignKeyKES sk = + return $ rawSerialiseSignKeyMockKES sk - rawDeserialiseSignKeyKESWith _alloc bs = - return $ rawDeserialiseSignKeyMockKES bs + rawDeserialiseSignKeyKESWith _alloc bs = + return $ rawDeserialiseSignKeyMockKES bs -rawDeserialiseSignKeyMockKES :: KnownNat t - => ByteString - -> Maybe (SignKeyKES (MockKES t)) +rawDeserialiseSignKeyMockKES :: + KnownNat t => + ByteString -> + Maybe (SignKeyKES (MockKES t)) rawDeserialiseSignKeyMockKES bs - | [vkb, tb] <- splitsAt [8, 8] bs - , Just vk <- rawDeserialiseVerKeyKES vkb - , let t = fromIntegral (readBinaryWord64 tb) - = Just $! SignKeyMockKES vk t - | otherwise - = Nothing - -rawSerialiseSignKeyMockKES :: KnownNat t - => SignKeyKES (MockKES t) - -> ByteString + | [vkb, tb] <- splitsAt [8, 8] bs + , Just vk <- rawDeserialiseVerKeyKES vkb + , let t = fromIntegral (readBinaryWord64 tb) = + Just $! SignKeyMockKES vk t + | otherwise = + Nothing + +rawSerialiseSignKeyMockKES :: + KnownNat t => + SignKeyKES (MockKES t) -> + ByteString rawSerialiseSignKeyMockKES (SignKeyMockKES vk t) = - rawSerialiseVerKeyKES vk - <> writeBinaryWord64 (fromIntegral t) + rawSerialiseVerKeyKES vk + <> writeBinaryWord64 (fromIntegral t) instance KnownNat t => ToCBOR (VerKeyKES (MockKES t)) where toCBOR = encodeVerKeyKES @@ -257,32 +255,32 @@ instance KnownNat t => ToCBOR (UnsoundPureSignKeyKES (MockKES t)) where instance KnownNat t => FromCBOR (UnsoundPureSignKeyKES (MockKES t)) where fromCBOR = decodeUnsoundPureSignKeyKES -instance (KnownNat t) => DirectSerialise (SignKeyKES (MockKES t)) where +instance KnownNat t => DirectSerialise (SignKeyKES (MockKES t)) where directSerialise put sk = do let bs = rawSerialiseSignKeyMockKES sk unpackByteStringCStringLen bs $ \(cstr, len) -> put cstr (fromIntegral len) -instance (KnownNat t) => DirectDeserialise (SignKeyKES (MockKES t)) where +instance KnownNat t => DirectDeserialise (SignKeyKES (MockKES t)) where directDeserialise pull = do let len = fromIntegral $ sizeSignKeyKES (Proxy @(MockKES t)) fptr <- mallocForeignPtrBytes len withForeignPtr fptr $ \ptr -> - pull (castPtr ptr) (fromIntegral len) + pull (castPtr ptr) (fromIntegral len) let bs = BS.fromForeignPtr (unsafeRawForeignPtr fptr) 0 len maybe (error "directDeserialise @(SignKeyKES (MockKES t))") return $ - rawDeserialiseSignKeyMockKES bs + rawDeserialiseSignKeyMockKES bs -instance (KnownNat t) => DirectSerialise (VerKeyKES (MockKES t)) where +instance KnownNat t => DirectSerialise (VerKeyKES (MockKES t)) where directSerialise push sk = do let bs = rawSerialiseVerKeyKES sk unpackByteStringCStringLen bs $ \(cstr, len) -> push cstr (fromIntegral len) -instance (KnownNat t) => DirectDeserialise (VerKeyKES (MockKES t)) where +instance KnownNat t => DirectDeserialise (VerKeyKES (MockKES t)) where directDeserialise pull = do let len = fromIntegral $ sizeVerKeyKES (Proxy @(MockKES t)) fptr <- mallocForeignPtrBytes len withForeignPtr fptr $ \ptr -> - pull (castPtr ptr) (fromIntegral len) + pull (castPtr ptr) (fromIntegral len) let bs = BS.fromForeignPtr (unsafeRawForeignPtr fptr) 0 len maybe (error "directDeserialise @(VerKeyKES (MockKES t))") return $ - rawDeserialiseVerKeyKES bs + rawDeserialiseVerKeyKES bs diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES/NeverUsed.hs b/cardano-crypto-class/src/Cardano/Crypto/KES/NeverUsed.hs index 43ab9561e..1762bafe8 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES/NeverUsed.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES/NeverUsed.hs @@ -1,15 +1,16 @@ {-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE MultiParamTypeClasses #-} -module Cardano.Crypto.KES.NeverUsed - ( NeverKES - , VerKeyKES (..) - , SignKeyKES (..) - , SigKES (..) - ) +{-# LANGUAGE TypeFamilies #-} + +module Cardano.Crypto.KES.NeverUsed ( + NeverKES, + VerKeyKES (..), + SignKeyKES (..), + SigKES (..), +) where import GHC.Generics (Generic) @@ -17,7 +18,6 @@ import NoThunks.Class (NoThunks) import Cardano.Crypto.KES.Class - -- | KES never used -- -- The type of keys and signatures is isomorphic to unit, but when actually @@ -27,14 +27,14 @@ data NeverKES instance KESAlgorithm NeverKES where type SeedSizeKES NeverKES = 0 - data VerKeyKES NeverKES = NeverUsedVerKeyKES - deriving (Show, Eq, Generic, NoThunks) + data VerKeyKES NeverKES = NeverUsedVerKeyKES + deriving (Show, Eq, Generic, NoThunks) - data SigKES NeverKES = NeverUsedSigKES - deriving (Show, Eq, Generic, NoThunks) + data SigKES NeverKES = NeverUsedSigKES + deriving (Show, Eq, Generic, NoThunks) data SignKeyKES NeverKES = NeverUsedSignKeyKES - deriving (Show, Eq, Generic, NoThunks) + deriving (Show, Eq, Generic, NoThunks) algorithmNameKES _ = "never" @@ -42,33 +42,32 @@ instance KESAlgorithm NeverKES where totalPeriodsKES _ = 0 - type SizeVerKeyKES NeverKES = 0 + type SizeVerKeyKES NeverKES = 0 type SizeSignKeyKES NeverKES = 0 - type SizeSigKES NeverKES = 0 + type SizeSigKES NeverKES = 0 - rawSerialiseVerKeyKES _ = mempty - rawSerialiseSigKES _ = mempty + rawSerialiseVerKeyKES _ = mempty + rawSerialiseSigKES _ = mempty - rawDeserialiseVerKeyKES _ = Just NeverUsedVerKeyKES - rawDeserialiseSigKES _ = Just NeverUsedSigKES + rawDeserialiseVerKeyKES _ = Just NeverUsedVerKeyKES + rawDeserialiseSigKES _ = Just NeverUsedSigKES deriveVerKeyKES _ = return NeverUsedVerKeyKES - signKES = error "KES not available" + signKES = error "KES not available" updateKESWith _ = error "KES not available" genKeyKESWith _ _ = return NeverUsedSignKeyKES forgetSignKeyKESWith _ = const $ return () - instance UnsoundKESAlgorithm NeverKES where rawSerialiseSignKeyKES _ = return mempty rawDeserialiseSignKeyKESWith _ _ = return $ Just NeverUsedSignKeyKES instance UnsoundPureKESAlgorithm NeverKES where data UnsoundPureSignKeyKES NeverKES = NeverUsedUnsoundPureSignKeyKES - deriving (Show, Eq, Generic, NoThunks) + deriving (Show, Eq, Generic, NoThunks) unsoundPureSignKES = error "KES not available" unsoundPureGenKeyKES _ = NeverUsedUnsoundPureSignKeyKES diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES/Simple.hs b/cardano-crypto-class/src/Cardano/Crypto/KES/Simple.hs index 88686febf..83673bb98 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES/Simple.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES/Simple.hs @@ -2,52 +2,51 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE NoStarIsType #-} -{-# LANGUAGE MultiParamTypeClasses #-} - -- Needed for ghc-9.6 to avoid a redunant constraint warning on the -- `KESSignAlgorithm m (SimpleKES d t)` instance. Removing the constraint leaves another type -- error which is rather opaque. {-# OPTIONS_GHC -Wno-redundant-constraints #-} -- | Mock key evolving signatures. -module Cardano.Crypto.KES.Simple - ( SimpleKES - , SigKES (..) - , SignKeyKES (SignKeySimpleKES, ThunkySignKeySimpleKES) - , UnsoundPureSignKeyKES (UnsoundPureSignKeySimpleKES, UnsoundPureThunkySignKeySimpleKES) - ) +module Cardano.Crypto.KES.Simple ( + SimpleKES, + SigKES (..), + SignKeyKES (SignKeySimpleKES, ThunkySignKeySimpleKES), + UnsoundPureSignKeyKES (UnsoundPureSignKeySimpleKES, UnsoundPureThunkySignKeySimpleKES), +) where -import Data.Proxy (Proxy (..)) +import Control.Monad ((<$!>)) +import Control.Monad.Trans.Maybe import qualified Data.ByteString as BS -import Data.Vector ((!?), Vector) +import Data.Proxy (Proxy (..)) +import Data.Vector (Vector, (!?)) import qualified Data.Vector as Vec -import GHC.Generics (Generic) -import GHC.TypeNats (Nat, KnownNat, natVal, type (*)) -import NoThunks.Class (NoThunks) -import Control.Monad.Trans.Maybe -import Control.Monad ( (<$!>) ) +import GHC.Generics (Generic) +import GHC.TypeNats (KnownNat, Nat, natVal, type (*)) +import NoThunks.Class (NoThunks) -import Cardano.Binary (FromCBOR (..), ToCBOR (..)) +import Cardano.Binary (FromCBOR (..), ToCBOR (..)) -import Cardano.Crypto.DSIGN +import Cardano.Crypto.DSIGN import qualified Cardano.Crypto.DSIGN.Class as DSIGN -import Cardano.Crypto.KES.Class -import Cardano.Crypto.Libsodium.MLockedSeed -import Cardano.Crypto.Libsodium.MLockedBytes -import Cardano.Crypto.Util -import Cardano.Crypto.Seed -import Cardano.Crypto.DirectSerialise -import Data.Unit.Strict (forceElemsToWHNF) -import Data.Maybe (fromMaybe) +import Cardano.Crypto.DirectSerialise +import Cardano.Crypto.KES.Class +import Cardano.Crypto.Libsodium.MLockedBytes +import Cardano.Crypto.Libsodium.MLockedSeed +import Cardano.Crypto.Seed +import Cardano.Crypto.Util +import Data.Maybe (fromMaybe) +import Data.Unit.Strict (forceElemsToWHNF) data SimpleKES d (t :: Nat) @@ -73,255 +72,260 @@ pattern SignKeySimpleKES v <- ThunkySignKeySimpleKES v {-# COMPLETE SignKeySimpleKES #-} -- | See 'VerKeySimpleKES'. -pattern UnsoundPureSignKeySimpleKES :: Vector (SignKeyDSIGN d) -> UnsoundPureSignKeyKES (SimpleKES d t) +pattern UnsoundPureSignKeySimpleKES :: + Vector (SignKeyDSIGN d) -> UnsoundPureSignKeyKES (SimpleKES d t) pattern UnsoundPureSignKeySimpleKES v <- UnsoundPureThunkySignKeySimpleKES v where UnsoundPureSignKeySimpleKES v = UnsoundPureThunkySignKeySimpleKES (forceElemsToWHNF v) {-# COMPLETE UnsoundPureSignKeySimpleKES #-} -instance ( DSIGNMAlgorithm d - , KnownNat t - , KnownNat (SeedSizeDSIGN d * t) - , KnownNat (SizeVerKeyDSIGN d * t) - , KnownNat (SizeSignKeyDSIGN d * t) - ) - => KESAlgorithm (SimpleKES d t) where - - type SeedSizeKES (SimpleKES d t) = SeedSizeDSIGN d * t - - -- - -- Key and signature types - -- - - newtype VerKeyKES (SimpleKES d t) = - ThunkyVerKeySimpleKES (Vector (VerKeyDSIGN d)) - deriving Generic - - newtype SigKES (SimpleKES d t) = - SigSimpleKES (SigDSIGN d) - deriving Generic - - newtype SignKeyKES (SimpleKES d t) = - ThunkySignKeySimpleKES (Vector (SignKeyDSIGNM d)) - deriving Generic - - -- - -- Metadata and basic key operations - -- - - algorithmNameKES proxy = "simple_" ++ show (totalPeriodsKES proxy) - - totalPeriodsKES _ = fromIntegral (natVal (Proxy @t)) - - -- - -- Core algorithm operations - -- - - type ContextKES (SimpleKES d t) = ContextDSIGN d - type Signable (SimpleKES d t) = DSIGN.Signable d - - verifyKES ctxt (VerKeySimpleKES vks) j a (SigSimpleKES sig) = - case vks !? fromIntegral j of - Nothing -> Left "KES verification failed: out of range" - Just vk -> verifyDSIGN ctxt vk a sig - - -- - -- raw serialise/deserialise - -- - - type SizeVerKeyKES (SimpleKES d t) = SizeVerKeyDSIGN d * t - type SizeSignKeyKES (SimpleKES d t) = SizeSignKeyDSIGN d * t - type SizeSigKES (SimpleKES d t) = SizeSigDSIGN d - - rawSerialiseVerKeyKES (VerKeySimpleKES vks) = - BS.concat [ rawSerialiseVerKeyDSIGN vk | vk <- Vec.toList vks ] - - rawSerialiseSigKES (SigSimpleKES sig) = - rawSerialiseSigDSIGN sig - - rawDeserialiseVerKeyKES bs - | let duration = fromIntegral (natVal (Proxy :: Proxy t)) - sizeKey = fromIntegral (sizeVerKeyDSIGN (Proxy :: Proxy d)) - , vkbs <- splitsAt (replicate duration sizeKey) bs - , length vkbs == duration - , Just vks <- mapM rawDeserialiseVerKeyDSIGN vkbs - = Just $! VerKeySimpleKES (Vec.fromList vks) - - | otherwise - = Nothing - - rawDeserialiseSigKES = fmap SigSimpleKES . rawDeserialiseSigDSIGN - - deriveVerKeyKES (SignKeySimpleKES sks) = - VerKeySimpleKES <$!> Vec.mapM deriveVerKeyDSIGNM sks - - - signKES ctxt j a (SignKeySimpleKES sks) = - case sks !? fromIntegral j of - Nothing -> error ("SimpleKES.signKES: period out of range " ++ show j) - Just sk -> SigSimpleKES <$!> (signDSIGNM ctxt a $! sk) - - updateKESWith allocator _ (ThunkySignKeySimpleKES sk) t - | t+1 < fromIntegral (natVal (Proxy @t)) = do - sk' <- Vec.mapM (cloneKeyDSIGNMWith allocator) sk - return $! Just $! SignKeySimpleKES sk' - | otherwise = return Nothing - - - -- - -- Key generation - -- +instance + ( DSIGNMAlgorithm d + , KnownNat t + , KnownNat (SeedSizeDSIGN d * t) + , KnownNat (SizeVerKeyDSIGN d * t) + , KnownNat (SizeSignKeyDSIGN d * t) + ) => + KESAlgorithm (SimpleKES d t) + where + type SeedSizeKES (SimpleKES d t) = SeedSizeDSIGN d * t + + -- + -- Key and signature types + -- + + newtype VerKeyKES (SimpleKES d t) + = ThunkyVerKeySimpleKES (Vector (VerKeyDSIGN d)) + deriving (Generic) + + newtype SigKES (SimpleKES d t) + = SigSimpleKES (SigDSIGN d) + deriving (Generic) + + newtype SignKeyKES (SimpleKES d t) + = ThunkySignKeySimpleKES (Vector (SignKeyDSIGNM d)) + deriving (Generic) + + -- + -- Metadata and basic key operations + -- + + algorithmNameKES proxy = "simple_" ++ show (totalPeriodsKES proxy) + + totalPeriodsKES _ = fromIntegral (natVal (Proxy @t)) + + -- + -- Core algorithm operations + -- + + type ContextKES (SimpleKES d t) = ContextDSIGN d + type Signable (SimpleKES d t) = DSIGN.Signable d + + verifyKES ctxt (VerKeySimpleKES vks) j a (SigSimpleKES sig) = + case vks !? fromIntegral j of + Nothing -> Left "KES verification failed: out of range" + Just vk -> verifyDSIGN ctxt vk a sig + + -- + -- raw serialise/deserialise + -- + + type SizeVerKeyKES (SimpleKES d t) = SizeVerKeyDSIGN d * t + type SizeSignKeyKES (SimpleKES d t) = SizeSignKeyDSIGN d * t + type SizeSigKES (SimpleKES d t) = SizeSigDSIGN d + + rawSerialiseVerKeyKES (VerKeySimpleKES vks) = + BS.concat [rawSerialiseVerKeyDSIGN vk | vk <- Vec.toList vks] + + rawSerialiseSigKES (SigSimpleKES sig) = + rawSerialiseSigDSIGN sig + + rawDeserialiseVerKeyKES bs + | let duration = fromIntegral (natVal (Proxy :: Proxy t)) + sizeKey = fromIntegral (sizeVerKeyDSIGN (Proxy :: Proxy d)) + , vkbs <- splitsAt (replicate duration sizeKey) bs + , length vkbs == duration + , Just vks <- mapM rawDeserialiseVerKeyDSIGN vkbs = + Just $! VerKeySimpleKES (Vec.fromList vks) + | otherwise = + Nothing + + rawDeserialiseSigKES = fmap SigSimpleKES . rawDeserialiseSigDSIGN + + deriveVerKeyKES (SignKeySimpleKES sks) = + VerKeySimpleKES <$!> Vec.mapM deriveVerKeyDSIGNM sks + + signKES ctxt j a (SignKeySimpleKES sks) = + case sks !? fromIntegral j of + Nothing -> error ("SimpleKES.signKES: period out of range " ++ show j) + Just sk -> SigSimpleKES <$!> (signDSIGNM ctxt a $! sk) + + updateKESWith allocator _ (ThunkySignKeySimpleKES sk) t + | t + 1 < fromIntegral (natVal (Proxy @t)) = do + sk' <- Vec.mapM (cloneKeyDSIGNMWith allocator) sk + return $! Just $! SignKeySimpleKES sk' + | otherwise = return Nothing + + -- + -- Key generation + -- + + genKeyKESWith allocator (MLockedSeed mlsb) = do + let seedSize = seedSizeDSIGN (Proxy :: Proxy d) + duration = fromIntegral (natVal (Proxy @t)) + sks <- Vec.generateM duration $ \t -> do + withMLSBChunk mlsb (fromIntegral t * fromIntegral seedSize) $ \mlsb' -> do + genKeyDSIGNMWith allocator (MLockedSeed mlsb') + return $! SignKeySimpleKES sks - genKeyKESWith allocator (MLockedSeed mlsb) = do - let seedSize = seedSizeDSIGN (Proxy :: Proxy d) - duration = fromIntegral (natVal (Proxy @t)) - sks <- Vec.generateM duration $ \t -> do - withMLSBChunk mlsb (fromIntegral t * fromIntegral seedSize) $ \mlsb' -> do - genKeyDSIGNMWith allocator (MLockedSeed mlsb') - return $! SignKeySimpleKES sks - - -- - -- Forgetting - -- + -- + -- Forgetting + -- - forgetSignKeyKESWith allocator (SignKeySimpleKES sks) = - Vec.mapM_ (forgetSignKeyDSIGNMWith allocator) sks + forgetSignKeyKESWith allocator (SignKeySimpleKES sks) = + Vec.mapM_ (forgetSignKeyDSIGNMWith allocator) sks -instance ( KESAlgorithm (SimpleKES d t) - , KnownNat t - , DSIGNAlgorithm d - , UnsoundDSIGNMAlgorithm d - ) - => UnsoundPureKESAlgorithm (SimpleKES d t) where - - newtype UnsoundPureSignKeyKES (SimpleKES d t) = - UnsoundPureThunkySignKeySimpleKES (Vector (SignKeyDSIGN d)) - deriving Generic - - unsoundPureGenKeyKES seed = - let seedSize = fromIntegral (seedSizeDSIGN (Proxy :: Proxy d)) - duration = fromIntegral (natVal (Proxy @t)) - seedChunk t = - mkSeedFromBytes (BS.take seedSize . BS.drop (seedSize * t) $ getSeedBytes seed) - in - UnsoundPureSignKeySimpleKES $ +instance + ( KESAlgorithm (SimpleKES d t) + , KnownNat t + , DSIGNAlgorithm d + , UnsoundDSIGNMAlgorithm d + ) => + UnsoundPureKESAlgorithm (SimpleKES d t) + where + newtype UnsoundPureSignKeyKES (SimpleKES d t) + = UnsoundPureThunkySignKeySimpleKES (Vector (SignKeyDSIGN d)) + deriving (Generic) + + unsoundPureGenKeyKES seed = + let seedSize = fromIntegral (seedSizeDSIGN (Proxy :: Proxy d)) + duration = fromIntegral (natVal (Proxy @t)) + seedChunk t = + mkSeedFromBytes (BS.take seedSize . BS.drop (seedSize * t) $ getSeedBytes seed) + in UnsoundPureSignKeySimpleKES $ Vec.generate duration (genKeyDSIGN . seedChunk) - unsoundPureSignKES ctxt j a (UnsoundPureSignKeySimpleKES sks) = - case sks !? fromIntegral j of - Nothing -> error ("SimpleKES.unsoundPureSignKES: period out of range " ++ show j) - Just sk -> SigSimpleKES $! signDSIGN ctxt a sk - - unsoundPureUpdateKES _ (UnsoundPureThunkySignKeySimpleKES sk) t - | t+1 < fromIntegral (natVal (Proxy @t)) - = Just $! UnsoundPureThunkySignKeySimpleKES sk - | otherwise - = Nothing - - unsoundPureDeriveVerKeyKES (UnsoundPureSignKeySimpleKES sks) = - VerKeySimpleKES $! Vec.map deriveVerKeyDSIGN sks - - unsoundPureSignKeyKESToSoundSignKeyKES (UnsoundPureThunkySignKeySimpleKES sks) = do - SignKeySimpleKES <$> mapM convertSK sks - where - convertSK = fmap (fromMaybe (error "unsoundPureSignKeyKESToSoundSignKeyKES: deserialisation failed")) - . rawDeserialiseSignKeyDSIGNM - . rawSerialiseSignKeyDSIGN - - rawSerialiseUnsoundPureSignKeyKES (UnsoundPureSignKeySimpleKES sks) = - foldMap rawSerialiseSignKeyDSIGN sks - - - rawDeserialiseUnsoundPureSignKeyKES bs - | let duration = fromIntegral (natVal (Proxy :: Proxy t)) - sizeKey = fromIntegral (sizeSignKeyDSIGN (Proxy :: Proxy d)) - skbs = splitsAt (replicate duration sizeKey) bs - , length skbs == duration - = do + unsoundPureSignKES ctxt j a (UnsoundPureSignKeySimpleKES sks) = + case sks !? fromIntegral j of + Nothing -> error ("SimpleKES.unsoundPureSignKES: period out of range " ++ show j) + Just sk -> SigSimpleKES $! signDSIGN ctxt a sk + + unsoundPureUpdateKES _ (UnsoundPureThunkySignKeySimpleKES sk) t + | t + 1 < fromIntegral (natVal (Proxy @t)) = + Just $! UnsoundPureThunkySignKeySimpleKES sk + | otherwise = + Nothing + + unsoundPureDeriveVerKeyKES (UnsoundPureSignKeySimpleKES sks) = + VerKeySimpleKES $! Vec.map deriveVerKeyDSIGN sks + + unsoundPureSignKeyKESToSoundSignKeyKES (UnsoundPureThunkySignKeySimpleKES sks) = do + SignKeySimpleKES <$> mapM convertSK sks + where + convertSK = + fmap (fromMaybe (error "unsoundPureSignKeyKESToSoundSignKeyKES: deserialisation failed")) + . rawDeserialiseSignKeyDSIGNM + . rawSerialiseSignKeyDSIGN + + rawSerialiseUnsoundPureSignKeyKES (UnsoundPureSignKeySimpleKES sks) = + foldMap rawSerialiseSignKeyDSIGN sks + + rawDeserialiseUnsoundPureSignKeyKES bs + | let duration = fromIntegral (natVal (Proxy :: Proxy t)) + sizeKey = fromIntegral (sizeSignKeyDSIGN (Proxy :: Proxy d)) + skbs = splitsAt (replicate duration sizeKey) bs + , length skbs == duration = + do sks <- mapM rawDeserialiseSignKeyDSIGN skbs return $! UnsoundPureSignKeySimpleKES (Vec.fromList sks) + | otherwise = + Nothing - | otherwise - = Nothing - - - -instance ( UnsoundDSIGNMAlgorithm d, KnownNat t, KESAlgorithm (SimpleKES d t)) - => UnsoundKESAlgorithm (SimpleKES d t) where - -- - -- raw serialise/deserialise - -- - - rawSerialiseSignKeyKES (SignKeySimpleKES sks) = - BS.concat <$!> mapM rawSerialiseSignKeyDSIGNM (Vec.toList sks) - - - rawDeserialiseSignKeyKESWith allocator bs - | let duration = fromIntegral (natVal (Proxy :: Proxy t)) - sizeKey = fromIntegral (sizeSignKeyDSIGN (Proxy :: Proxy d)) - , skbs <- splitsAt (replicate duration sizeKey) bs - , length skbs == duration - = runMaybeT $ do +instance + (UnsoundDSIGNMAlgorithm d, KnownNat t, KESAlgorithm (SimpleKES d t)) => + UnsoundKESAlgorithm (SimpleKES d t) + where + -- + -- raw serialise/deserialise + -- + + rawSerialiseSignKeyKES (SignKeySimpleKES sks) = + BS.concat <$!> mapM rawSerialiseSignKeyDSIGNM (Vec.toList sks) + + rawDeserialiseSignKeyKESWith allocator bs + | let duration = fromIntegral (natVal (Proxy :: Proxy t)) + sizeKey = fromIntegral (sizeSignKeyDSIGN (Proxy :: Proxy d)) + , skbs <- splitsAt (replicate duration sizeKey) bs + , length skbs == duration = + runMaybeT $ do sks <- mapM (MaybeT . rawDeserialiseSignKeyDSIGNMWith allocator) skbs return $! SignKeySimpleKES (Vec.fromList sks) - - | otherwise - = return Nothing + | otherwise = + return Nothing deriving instance DSIGNMAlgorithm d => Show (VerKeyKES (SimpleKES d t)) deriving instance (DSIGNMAlgorithm d, Show (SignKeyDSIGNM d)) => Show (SignKeyKES (SimpleKES d t)) -deriving instance (DSIGNMAlgorithm d, Show (SignKeyDSIGNM d)) => Show (UnsoundPureSignKeyKES (SimpleKES d t)) +deriving instance + (DSIGNMAlgorithm d, Show (SignKeyDSIGNM d)) => Show (UnsoundPureSignKeyKES (SimpleKES d t)) deriving instance DSIGNMAlgorithm d => Show (SigKES (SimpleKES d t)) deriving instance DSIGNMAlgorithm d => Eq (VerKeyKES (SimpleKES d t)) deriving instance DSIGNMAlgorithm d => Eq (SigKES (SimpleKES d t)) deriving instance Eq (SignKeyDSIGN d) => Eq (UnsoundPureSignKeyKES (SimpleKES d t)) -instance DSIGNMAlgorithm d => NoThunks (SigKES (SimpleKES d t)) +instance DSIGNMAlgorithm d => NoThunks (SigKES (SimpleKES d t)) instance DSIGNMAlgorithm d => NoThunks (SignKeyKES (SimpleKES d t)) instance DSIGNMAlgorithm d => NoThunks (UnsoundPureSignKeyKES (SimpleKES d t)) -instance DSIGNMAlgorithm d => NoThunks (VerKeyKES (SimpleKES d t)) - -instance ( DSIGNMAlgorithm d - , KnownNat t - , KnownNat (SeedSizeDSIGN d * t) - , KnownNat (SizeVerKeyDSIGN d * t) - , KnownNat (SizeSignKeyDSIGN d * t) - ) - => ToCBOR (VerKeyKES (SimpleKES d t)) where +instance DSIGNMAlgorithm d => NoThunks (VerKeyKES (SimpleKES d t)) + +instance + ( DSIGNMAlgorithm d + , KnownNat t + , KnownNat (SeedSizeDSIGN d * t) + , KnownNat (SizeVerKeyDSIGN d * t) + , KnownNat (SizeSignKeyDSIGN d * t) + ) => + ToCBOR (VerKeyKES (SimpleKES d t)) + where toCBOR = encodeVerKeyKES encodedSizeExpr _size = encodedVerKeyKESSizeExpr -instance ( DSIGNMAlgorithm d - , KnownNat t - , KnownNat (SeedSizeDSIGN d * t) - , KnownNat (SizeVerKeyDSIGN d * t) - , KnownNat (SizeSignKeyDSIGN d * t) - ) - => FromCBOR (VerKeyKES (SimpleKES d t)) where +instance + ( DSIGNMAlgorithm d + , KnownNat t + , KnownNat (SeedSizeDSIGN d * t) + , KnownNat (SizeVerKeyDSIGN d * t) + , KnownNat (SizeSignKeyDSIGN d * t) + ) => + FromCBOR (VerKeyKES (SimpleKES d t)) + where fromCBOR = decodeVerKeyKES -instance ( DSIGNMAlgorithm d - , KnownNat t - , KnownNat (SeedSizeDSIGN d * t) - , KnownNat (SizeVerKeyDSIGN d * t) - , KnownNat (SizeSignKeyDSIGN d * t) - ) - => ToCBOR (SigKES (SimpleKES d t)) where +instance + ( DSIGNMAlgorithm d + , KnownNat t + , KnownNat (SeedSizeDSIGN d * t) + , KnownNat (SizeVerKeyDSIGN d * t) + , KnownNat (SizeSignKeyDSIGN d * t) + ) => + ToCBOR (SigKES (SimpleKES d t)) + where toCBOR = encodeSigKES encodedSizeExpr _size = encodedSigKESSizeExpr -instance (DSIGNMAlgorithm d - , KnownNat t - , KnownNat (SeedSizeDSIGN d * t) - , KnownNat (SizeVerKeyDSIGN d * t) - , KnownNat (SizeSignKeyDSIGN d * t) - ) - => FromCBOR (SigKES (SimpleKES d t)) where +instance + ( DSIGNMAlgorithm d + , KnownNat t + , KnownNat (SeedSizeDSIGN d * t) + , KnownNat (SizeVerKeyDSIGN d * t) + , KnownNat (SizeSignKeyDSIGN d * t) + ) => + FromCBOR (SigKES (SimpleKES d t)) + where fromCBOR = decodeSigKES -instance (DirectSerialise (VerKeyDSIGN d)) => DirectSerialise (VerKeyKES (SimpleKES d t)) where +instance DirectSerialise (VerKeyDSIGN d) => DirectSerialise (VerKeyKES (SimpleKES d t)) where directSerialise push (VerKeySimpleKES vks) = mapM_ (directSerialise push) vks @@ -331,7 +335,7 @@ instance (DirectDeserialise (VerKeyDSIGN d), KnownNat t) => DirectDeserialise (V vks <- Vec.replicateM duration (directDeserialise pull) return $! VerKeySimpleKES vks -instance (DirectSerialise (SignKeyDSIGNM d)) => DirectSerialise (SignKeyKES (SimpleKES d t)) where +instance DirectSerialise (SignKeyDSIGNM d) => DirectSerialise (SignKeyKES (SimpleKES d t)) where directSerialise push (SignKeySimpleKES sks) = mapM_ (directSerialise push) sks diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES/Single.hs b/cardano-crypto-class/src/Cardano/Crypto/KES/Single.hs index 606badaef..5daf52250 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES/Single.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES/Single.hs @@ -29,162 +29,165 @@ -- 'DSIGNMAlgorithm' into an instance of 'KESAlgorithm' with a single period. -- -- See "Cardano.Crypto.KES.Sum" for the composition case. --- module Cardano.Crypto.KES.Single ( - SingleKES - , VerKeyKES (..) - , SignKeyKES (..) - , SigKES (..) - ) where + SingleKES, + VerKeyKES (..), + SignKeyKES (..), + SigKES (..), +) where -import Data.Proxy (Proxy(..)) +import Data.Proxy (Proxy (..)) import GHC.Generics (Generic) import NoThunks.Class (NoThunks) -import Control.Exception (assert) import Control.DeepSeq (NFData) +import Control.Exception (assert) import Control.Monad ((<$!>)) import Cardano.Binary (FromCBOR (..), ToCBOR (..)) -import Cardano.Crypto.Hash.Class import Cardano.Crypto.DSIGN.Class as DSIGN -import Cardano.Crypto.KES.Class import Cardano.Crypto.DirectSerialise +import Cardano.Crypto.Hash.Class +import Cardano.Crypto.KES.Class -- | A standard signature scheme is a forward-secure signature scheme with a -- single time period. --- data SingleKES d deriving instance NFData (VerKeyDSIGN d) => NFData (VerKeyKES (SingleKES d)) deriving instance NFData (SigDSIGN d) => NFData (SigKES (SingleKES d)) -deriving via (SignKeyDSIGNM d) instance NFData (SignKeyDSIGNM d) => NFData (SignKeyKES (SingleKES d)) - -instance (DSIGNMAlgorithm d) => KESAlgorithm (SingleKES d) where - type SeedSizeKES (SingleKES d) = SeedSizeDSIGN d +deriving via + (SignKeyDSIGNM d) + instance + NFData (SignKeyDSIGNM d) => NFData (SignKeyKES (SingleKES d)) - -- - -- Key and signature types - -- +instance DSIGNMAlgorithm d => KESAlgorithm (SingleKES d) where + type SeedSizeKES (SingleKES d) = SeedSizeDSIGN d - newtype VerKeyKES (SingleKES d) = VerKeySingleKES (VerKeyDSIGN d) - deriving Generic + -- + -- Key and signature types + -- - newtype SigKES (SingleKES d) = SigSingleKES (SigDSIGN d) - deriving Generic + newtype VerKeyKES (SingleKES d) = VerKeySingleKES (VerKeyDSIGN d) + deriving (Generic) - newtype SignKeyKES (SingleKES d) = SignKeySingleKES (SignKeyDSIGNM d) + newtype SigKES (SingleKES d) = SigSingleKES (SigDSIGN d) + deriving (Generic) + newtype SignKeyKES (SingleKES d) = SignKeySingleKES (SignKeyDSIGNM d) - type ContextKES (SingleKES d) = ContextDSIGN d - type Signable (SingleKES d) = DSIGN.Signable d + type ContextKES (SingleKES d) = ContextDSIGN d + type Signable (SingleKES d) = DSIGN.Signable d + -- + -- Metadata and basic key operations + -- - -- - -- Metadata and basic key operations - -- + algorithmNameKES _ = algorithmNameDSIGN (Proxy :: Proxy d) ++ "_kes_2^0" - algorithmNameKES _ = algorithmNameDSIGN (Proxy :: Proxy d) ++ "_kes_2^0" + totalPeriodsKES _ = 1 - totalPeriodsKES _ = 1 + verifyKES ctxt (VerKeySingleKES vk) t a (SigSingleKES sig) = + assert (t == 0) $ + verifyDSIGN ctxt vk a sig - verifyKES ctxt (VerKeySingleKES vk) t a (SigSingleKES sig) = - assert (t == 0) $ - verifyDSIGN ctxt vk a sig + -- + -- raw serialise/deserialise + -- - -- - -- raw serialise/deserialise - -- + type SizeVerKeyKES (SingleKES d) = SizeVerKeyDSIGN d + type SizeSignKeyKES (SingleKES d) = SizeSignKeyDSIGN d + type SizeSigKES (SingleKES d) = SizeSigDSIGN d - type SizeVerKeyKES (SingleKES d) = SizeVerKeyDSIGN d - type SizeSignKeyKES (SingleKES d) = SizeSignKeyDSIGN d - type SizeSigKES (SingleKES d) = SizeSigDSIGN d + hashVerKeyKES (VerKeySingleKES vk) = + castHash (hashVerKeyDSIGN vk) - hashVerKeyKES (VerKeySingleKES vk) = - castHash (hashVerKeyDSIGN vk) + rawSerialiseVerKeyKES (VerKeySingleKES vk) = rawSerialiseVerKeyDSIGN vk + rawSerialiseSigKES (SigSingleKES sig) = rawSerialiseSigDSIGN sig - rawSerialiseVerKeyKES (VerKeySingleKES vk) = rawSerialiseVerKeyDSIGN vk - rawSerialiseSigKES (SigSingleKES sig) = rawSerialiseSigDSIGN sig + rawDeserialiseVerKeyKES = fmap VerKeySingleKES . rawDeserialiseVerKeyDSIGN + {-# INLINE rawDeserialiseVerKeyKES #-} + rawDeserialiseSigKES = fmap SigSingleKES . rawDeserialiseSigDSIGN + {-# INLINE rawDeserialiseSigKES #-} - rawDeserialiseVerKeyKES = fmap VerKeySingleKES . rawDeserialiseVerKeyDSIGN - {-# INLINE rawDeserialiseVerKeyKES #-} - rawDeserialiseSigKES = fmap SigSingleKES . rawDeserialiseSigDSIGN - {-# INLINE rawDeserialiseSigKES #-} + deriveVerKeyKES (SignKeySingleKES v) = + VerKeySingleKES <$!> deriveVerKeyDSIGNM v + -- + -- Core algorithm operations + -- - deriveVerKeyKES (SignKeySingleKES v) = - VerKeySingleKES <$!> deriveVerKeyDSIGNM v + signKES ctxt t a (SignKeySingleKES sk) = + assert (t == 0) $! + SigSingleKES <$!> signDSIGNM ctxt a sk - -- - -- Core algorithm operations - -- + updateKESWith _allocator _ctx (SignKeySingleKES _sk) _to = return Nothing - signKES ctxt t a (SignKeySingleKES sk) = - assert (t == 0) $! - SigSingleKES <$!> signDSIGNM ctxt a sk + -- + -- Key generation + -- - updateKESWith _allocator _ctx (SignKeySingleKES _sk) _to = return Nothing + genKeyKESWith allocator seed = + SignKeySingleKES <$!> genKeyDSIGNMWith allocator seed - -- - -- Key generation - -- + -- + -- forgetting + -- + forgetSignKeyKESWith allocator (SignKeySingleKES v) = + forgetSignKeyDSIGNMWith allocator v - genKeyKESWith allocator seed = - SignKeySingleKES <$!> genKeyDSIGNMWith allocator seed +instance + ( KESAlgorithm (SingleKES d) + , UnsoundDSIGNMAlgorithm d + ) => + UnsoundPureKESAlgorithm (SingleKES d) + where + newtype UnsoundPureSignKeyKES (SingleKES d) = UnsoundPureSignKeySingleKES (SignKeyDSIGN d) + deriving (Generic) - -- - -- forgetting - -- - forgetSignKeyKESWith allocator (SignKeySingleKES v) = - forgetSignKeyDSIGNMWith allocator v + unsoundPureSignKES ctxt t a (UnsoundPureSignKeySingleKES sk) = + assert (t == 0) $! + SigSingleKES $! + signDSIGN ctxt a sk -instance ( KESAlgorithm (SingleKES d) - , UnsoundDSIGNMAlgorithm d - ) - => UnsoundPureKESAlgorithm (SingleKES d) where - newtype UnsoundPureSignKeyKES (SingleKES d) = UnsoundPureSignKeySingleKES (SignKeyDSIGN d) - deriving (Generic) + unsoundPureUpdateKES _ctx _sk _to = Nothing - unsoundPureSignKES ctxt t a (UnsoundPureSignKeySingleKES sk) = - assert (t == 0) $! - SigSingleKES $! signDSIGN ctxt a sk + -- + -- Key generation + -- - unsoundPureUpdateKES _ctx _sk _to = Nothing + unsoundPureGenKeyKES seed = + UnsoundPureSignKeySingleKES $! genKeyDSIGN seed - -- - -- Key generation - -- + unsoundPureDeriveVerKeyKES (UnsoundPureSignKeySingleKES v) = + VerKeySingleKES $! deriveVerKeyDSIGN v - unsoundPureGenKeyKES seed = - UnsoundPureSignKeySingleKES $! genKeyDSIGN seed + unsoundPureSignKeyKESToSoundSignKeyKES = + unsoundPureSignKeyKESToSoundSignKeyKESViaSer - unsoundPureDeriveVerKeyKES (UnsoundPureSignKeySingleKES v) = - VerKeySingleKES $! deriveVerKeyDSIGN v + rawSerialiseUnsoundPureSignKeyKES (UnsoundPureSignKeySingleKES sk) = + rawSerialiseSignKeyDSIGN sk + rawDeserialiseUnsoundPureSignKeyKES b = + UnsoundPureSignKeySingleKES <$> rawDeserialiseSignKeyDSIGN b - unsoundPureSignKeyKESToSoundSignKeyKES = - unsoundPureSignKeyKESToSoundSignKeyKESViaSer +instance + (KESAlgorithm (SingleKES d), UnsoundDSIGNMAlgorithm d) => + UnsoundKESAlgorithm (SingleKES d) + where + rawSerialiseSignKeyKES (SignKeySingleKES sk) = + rawSerialiseSignKeyDSIGNM sk - rawSerialiseUnsoundPureSignKeyKES (UnsoundPureSignKeySingleKES sk) = - rawSerialiseSignKeyDSIGN sk - rawDeserialiseUnsoundPureSignKeyKES b = - UnsoundPureSignKeySingleKES <$> rawDeserialiseSignKeyDSIGN b - -instance (KESAlgorithm (SingleKES d), UnsoundDSIGNMAlgorithm d) - => UnsoundKESAlgorithm (SingleKES d) where - rawSerialiseSignKeyKES (SignKeySingleKES sk) = - rawSerialiseSignKeyDSIGNM sk - - rawDeserialiseSignKeyKESWith allocator bs = - fmap SignKeySingleKES <$> rawDeserialiseSignKeyDSIGNMWith allocator bs + rawDeserialiseSignKeyKESWith allocator bs = + fmap SignKeySingleKES <$> rawDeserialiseSignKeyDSIGNMWith allocator bs -- -- VerKey instances -- deriving instance DSIGNAlgorithm d => Show (VerKeyKES (SingleKES d)) -deriving instance DSIGNAlgorithm d => Eq (VerKeyKES (SingleKES d)) +deriving instance DSIGNAlgorithm d => Eq (VerKeyKES (SingleKES d)) instance DSIGNMAlgorithm d => ToCBOR (VerKeyKES (SingleKES d)) where toCBOR = encodeVerKeyKES @@ -194,8 +197,7 @@ instance DSIGNMAlgorithm d => FromCBOR (VerKeyKES (SingleKES d)) where fromCBOR = decodeVerKeyKES {-# INLINE fromCBOR #-} -instance DSIGNMAlgorithm d => NoThunks (VerKeyKES (SingleKES d)) - +instance DSIGNMAlgorithm d => NoThunks (VerKeyKES (SingleKES d)) -- -- SignKey instances @@ -208,7 +210,7 @@ deriving via (SignKeyDSIGNM d) instance DSIGNMAlgorithm d => NoThunks (SignKeyKE -- deriving instance DSIGNAlgorithm d => Show (SigKES (SingleKES d)) -deriving instance DSIGNAlgorithm d => Eq (SigKES (SingleKES d)) +deriving instance DSIGNAlgorithm d => Eq (SigKES (SingleKES d)) instance DSIGNAlgorithm d => NoThunks (SigKES (SingleKES d)) @@ -224,29 +226,29 @@ instance DSIGNMAlgorithm d => FromCBOR (SigKES (SingleKES d)) where -- deriving instance DSIGNAlgorithm d => Show (UnsoundPureSignKeyKES (SingleKES d)) -deriving instance Eq (SignKeyDSIGN d) => Eq (UnsoundPureSignKeyKES (SingleKES d)) +deriving instance Eq (SignKeyDSIGN d) => Eq (UnsoundPureSignKeyKES (SingleKES d)) -instance (UnsoundDSIGNMAlgorithm d) => ToCBOR (UnsoundPureSignKeyKES (SingleKES d)) where +instance UnsoundDSIGNMAlgorithm d => ToCBOR (UnsoundPureSignKeyKES (SingleKES d)) where toCBOR = encodeUnsoundPureSignKeyKES encodedSizeExpr _size _skProxy = encodedSignKeyKESSizeExpr (Proxy :: Proxy (SignKeyKES (SingleKES d))) -instance (UnsoundDSIGNMAlgorithm d) => FromCBOR (UnsoundPureSignKeyKES (SingleKES d)) where +instance UnsoundDSIGNMAlgorithm d => FromCBOR (UnsoundPureSignKeyKES (SingleKES d)) where fromCBOR = decodeUnsoundPureSignKeyKES -instance DSIGNAlgorithm d => NoThunks (UnsoundPureSignKeyKES (SingleKES d)) +instance DSIGNAlgorithm d => NoThunks (UnsoundPureSignKeyKES (SingleKES d)) -- -- Direct ser/deser -- -instance (DirectSerialise (SignKeyDSIGNM d)) => DirectSerialise (SignKeyKES (SingleKES d)) where +instance DirectSerialise (SignKeyDSIGNM d) => DirectSerialise (SignKeyKES (SingleKES d)) where directSerialise push (SignKeySingleKES sk) = directSerialise push sk -instance (DirectDeserialise (SignKeyDSIGNM d)) => DirectDeserialise (SignKeyKES (SingleKES d)) where +instance DirectDeserialise (SignKeyDSIGNM d) => DirectDeserialise (SignKeyKES (SingleKES d)) where directDeserialise pull = SignKeySingleKES <$!> directDeserialise pull -instance (DirectSerialise (VerKeyDSIGN d)) => DirectSerialise (VerKeyKES (SingleKES d)) where +instance DirectSerialise (VerKeyDSIGN d) => DirectSerialise (VerKeyKES (SingleKES d)) where directSerialise push (VerKeySingleKES sk) = directSerialise push sk -instance (DirectDeserialise (VerKeyDSIGN d)) => DirectDeserialise (VerKeyKES (SingleKES d)) where +instance DirectDeserialise (VerKeyDSIGN d) => DirectDeserialise (VerKeyKES (SingleKES d)) where directDeserialise pull = VerKeySingleKES <$!> directDeserialise pull diff --git a/cardano-crypto-class/src/Cardano/Crypto/KES/Sum.hs b/cardano-crypto-class/src/Cardano/Crypto/KES/Sum.hs index f8fb26a40..c3124f71e 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/KES/Sum.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/KES/Sum.hs @@ -5,13 +5,13 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoStarIsType #-} -- | A key evolving signatures implementation. @@ -35,48 +35,48 @@ -- compilation times. Worse yet, this error will only appear when compiling -- code that depends on this module, not when compiling the module itself. module Cardano.Crypto.KES.Sum ( - SumKES - , VerKeyKES (..) - , SignKeyKES (..) - , SigKES (..) - - -- * Type aliases for powers of binary sums - , Sum0KES - , Sum1KES - , Sum2KES - , Sum3KES - , Sum4KES - , Sum5KES - , Sum6KES - , Sum7KES - ) where - -import Data.Proxy (Proxy(..)) -import GHC.Generics (Generic) + SumKES, + VerKeyKES (..), + SignKeyKES (..), + SigKES (..), + + -- * Type aliases for powers of binary sums + Sum0KES, + Sum1KES, + Sum2KES, + Sum3KES, + Sum4KES, + Sum5KES, + Sum6KES, + Sum7KES, +) where + +import Control.Monad (guard, (<$!>)) import qualified Data.ByteString as BS import qualified Data.ByteString.Internal as BS -import Control.Monad (guard, (<$!>)) -import NoThunks.Class (NoThunks, OnlyCheckWhnfNamed (..)) - -import Cardano.Binary (FromCBOR (..), ToCBOR (..)) - -import Cardano.Crypto.Hash.Class -import Cardano.Crypto.KES.Class -import Cardano.Crypto.KES.Single (SingleKES) -import Cardano.Crypto.Util -import Cardano.Crypto.Seed -import Cardano.Crypto.Libsodium.MLockedSeed -import Cardano.Crypto.Libsodium -import Cardano.Crypto.Libsodium.Memory -import Cardano.Crypto.DirectSerialise - -import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT) -import Control.DeepSeq (NFData (..)) -import GHC.TypeLits (KnownNat, type (+), type (*)) -import Foreign.Ptr (castPtr) +import Data.Proxy (Proxy (..)) +import GHC.Generics (Generic) +import NoThunks.Class (NoThunks, OnlyCheckWhnfNamed (..)) + +import Cardano.Binary (FromCBOR (..), ToCBOR (..)) + +import Cardano.Crypto.DirectSerialise +import Cardano.Crypto.Hash.Class +import Cardano.Crypto.KES.Class +import Cardano.Crypto.KES.Single (SingleKES) +import Cardano.Crypto.Libsodium +import Cardano.Crypto.Libsodium.MLockedSeed +import Cardano.Crypto.Libsodium.Memory +import Cardano.Crypto.Seed +import Cardano.Crypto.Util + +import Control.DeepSeq (NFData (..)) +import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT) +import Foreign.Ptr (castPtr) +import GHC.TypeLits (KnownNat, type (*), type (+)) -- | A 2^0 period KES -type Sum0KES d = SingleKES d +type Sum0KES d = SingleKES d -- | A 2^1 period KES type Sum1KES d h = SumKES h (Sum0KES d) @@ -99,7 +99,6 @@ type Sum6KES d h = SumKES h (Sum5KES d h) -- | A 2^7 period KES type Sum7KES d h = SumKES h (Sum6KES d h) - -- | A composition of two KES schemes to give a KES scheme with the sum of -- the time periods. -- @@ -107,250 +106,261 @@ type Sum7KES d h = SumKES h (Sum6KES d h) -- we only need it for two instances of the same scheme, and we save -- substantially on the size of the type and runtime dictionaries if we do it -- this way, especially when we start applying it recursively. --- data SumKES h d -instance (NFData (SigKES d), NFData (VerKeyKES d)) => - NFData (SigKES (SumKES h d)) where - -instance (NFData (SignKeyKES d), NFData (VerKeyKES d)) => - NFData (SignKeyKES (SumKES h d)) where - rnf (SignKeySumKES sk r vk1 vk2) = - rnf (sk, r, vk1, vk2) - -instance ( KESAlgorithm d - , SodiumHashAlgorithm h -- needed for secure forgetting - , SizeHash h ~ SeedSizeKES d -- can be relaxed - , KnownNat ((SizeSignKeyKES d + SeedSizeKES d) + (2 * SizeVerKeyKES d)) - , KnownNat (SizeSigKES d + (SizeVerKeyKES d * 2)) - ) - => KESAlgorithm (SumKES h d) where - -- | From Figure 3: @(sk_0, r_1, vk_0, vk_1)@ - -- - data SignKeyKES (SumKES h d) = - SignKeySumKES !(SignKeyKES d) - !(MLockedSeed (SeedSizeKES d)) - !(VerKeyKES d) - !(VerKeyKES d) - - - - type SeedSizeKES (SumKES h d) = SeedSizeKES d - - -- - -- Key and signature types - -- - - -- | From Section 3,1: - -- - -- The verification key @vk@ for the sum scheme is the hash of the - -- verification keys @vk_0, vk_1@ of the two constituent schemes. - -- - newtype VerKeyKES (SumKES h d) = - VerKeySumKES (Hash h (VerKeyKES d, VerKeyKES d)) - deriving Generic - deriving newtype NFData - - -- | From Figure 3: @(sigma, vk_0, vk_1)@ - -- - data SigKES (SumKES h d) = - SigSumKES !(SigKES d) - !(VerKeyKES d) - !(VerKeyKES d) - deriving Generic - - - -- - -- Metadata and basic key operations - -- - - algorithmNameKES _ = mungeName (algorithmNameKES (Proxy :: Proxy d)) - - -- The verification key in this scheme is actually a hash already - -- however the type of hashVerKeyKES says the caller gets to choose - -- the hash, not the implementation. So that's why we have to hash - -- the hash here. We could alternatively provide a "key identifier" - -- function and let the implementation choose what that is. - hashVerKeyKES (VerKeySumKES vk) = castHash (hashWith hashToBytes vk) - - - -- - -- Core algorithm operations - -- - - type Signable (SumKES h d) = Signable d - type ContextKES (SumKES h d) = ContextKES d - - verifyKES ctxt (VerKeySumKES vk) t a (SigSumKES sigma vk_0 vk_1) - | hashPairOfVKeys (vk_0, vk_1) /= vk - = Left "Reject" - | t < _T = verifyKES ctxt vk_0 t a sigma - | otherwise = verifyKES ctxt vk_1 (t - _T) a sigma - where - _T = totalPeriodsKES (Proxy :: Proxy d) - - totalPeriodsKES _ = 2 * totalPeriodsKES (Proxy :: Proxy d) - - -- - -- raw serialise/deserialise - -- - - type SizeVerKeyKES (SumKES h d) = SizeHash h - type SizeSignKeyKES (SumKES h d) = SizeSignKeyKES d - + SeedSizeKES d - + 2 * SizeVerKeyKES d - type SizeSigKES (SumKES h d) = SizeSigKES d - + SizeVerKeyKES d * 2 - - rawSerialiseVerKeyKES (VerKeySumKES vk) = hashToBytes vk - - rawSerialiseSigKES (SigSumKES sigma vk_0 vk_1) = +instance + (NFData (SigKES d), NFData (VerKeyKES d)) => + NFData (SigKES (SumKES h d)) + +instance + (NFData (SignKeyKES d), NFData (VerKeyKES d)) => + NFData (SignKeyKES (SumKES h d)) + where + rnf (SignKeySumKES sk r vk1 vk2) = + rnf (sk, r, vk1, vk2) + +instance + ( KESAlgorithm d + , SodiumHashAlgorithm h -- needed for secure forgetting + , SizeHash h ~ SeedSizeKES d -- can be relaxed + , KnownNat ((SizeSignKeyKES d + SeedSizeKES d) + (2 * SizeVerKeyKES d)) + , KnownNat (SizeSigKES d + (SizeVerKeyKES d * 2)) + ) => + KESAlgorithm (SumKES h d) + where + -- \| From Figure 3: @(sk_0, r_1, vk_0, vk_1)@ + data SignKeyKES (SumKES h d) + = SignKeySumKES + !(SignKeyKES d) + !(MLockedSeed (SeedSizeKES d)) + !(VerKeyKES d) + !(VerKeyKES d) + + type SeedSizeKES (SumKES h d) = SeedSizeKES d + + -- + -- Key and signature types + -- + + -- \| From Section 3,1: + -- + -- The verification key @vk@ for the sum scheme is the hash of the + -- verification keys @vk_0, vk_1@ of the two constituent schemes. + newtype VerKeyKES (SumKES h d) + = VerKeySumKES (Hash h (VerKeyKES d, VerKeyKES d)) + deriving (Generic) + deriving newtype (NFData) + + -- \| From Figure 3: @(sigma, vk_0, vk_1)@ + data SigKES (SumKES h d) + = SigSumKES + !(SigKES d) + !(VerKeyKES d) + !(VerKeyKES d) + deriving (Generic) + + -- + -- Metadata and basic key operations + -- + + algorithmNameKES _ = mungeName (algorithmNameKES (Proxy :: Proxy d)) + + -- The verification key in this scheme is actually a hash already + -- however the type of hashVerKeyKES says the caller gets to choose + -- the hash, not the implementation. So that's why we have to hash + -- the hash here. We could alternatively provide a "key identifier" + -- function and let the implementation choose what that is. + hashVerKeyKES (VerKeySumKES vk) = castHash (hashWith hashToBytes vk) + + -- + -- Core algorithm operations + -- + + type Signable (SumKES h d) = Signable d + type ContextKES (SumKES h d) = ContextKES d + + verifyKES ctxt (VerKeySumKES vk) t a (SigSumKES sigma vk_0 vk_1) + | hashPairOfVKeys (vk_0, vk_1) /= vk = + Left "Reject" + | t < _T = verifyKES ctxt vk_0 t a sigma + | otherwise = verifyKES ctxt vk_1 (t - _T) a sigma + where + _T = totalPeriodsKES (Proxy :: Proxy d) + + totalPeriodsKES _ = 2 * totalPeriodsKES (Proxy :: Proxy d) + + -- + -- raw serialise/deserialise + -- + + type SizeVerKeyKES (SumKES h d) = SizeHash h + type + SizeSignKeyKES (SumKES h d) = + SizeSignKeyKES d + + SeedSizeKES d + + 2 * SizeVerKeyKES d + type + SizeSigKES (SumKES h d) = + SizeSigKES d + + SizeVerKeyKES d * 2 + + rawSerialiseVerKeyKES (VerKeySumKES vk) = hashToBytes vk + + rawSerialiseSigKES (SigSumKES sigma vk_0 vk_1) = + mconcat + [ rawSerialiseSigKES sigma + , rawSerialiseVerKeyKES vk_0 + , rawSerialiseVerKeyKES vk_1 + ] + + rawDeserialiseVerKeyKES = fmap VerKeySumKES . hashFromBytes + {-# INLINE rawDeserialiseVerKeyKES #-} + + rawDeserialiseSigKES b = do + guard (BS.length b == fromIntegral size_total) + sigma <- rawDeserialiseSigKES b_sig + vk_0 <- rawDeserialiseVerKeyKES b_vk0 + vk_1 <- rawDeserialiseVerKeyKES b_vk1 + return (SigSumKES sigma vk_0 vk_1) + where + b_sig = slice off_sig size_sig b + b_vk0 = slice off_vk0 size_vk b + b_vk1 = slice off_vk1 size_vk b + + size_sig = sizeSigKES (Proxy :: Proxy d) + size_vk = sizeVerKeyKES (Proxy :: Proxy d) + size_total = sizeSigKES (Proxy :: Proxy (SumKES h d)) + + off_sig = 0 :: Word + off_vk0 = size_sig + off_vk1 = off_vk0 + size_vk + {-# INLINEABLE rawDeserialiseSigKES #-} + + deriveVerKeyKES (SignKeySumKES _ _ vk_0 vk_1) = + return $! VerKeySumKES (hashPairOfVKeys (vk_0, vk_1)) + + signKES ctxt t a (SignKeySumKES sk _r_1 vk_0 vk_1) = do + sigma <- getSigma + return $! SigSumKES sigma vk_0 vk_1 + where + getSigma + | t < _T = signKES ctxt t a sk + | otherwise = signKES ctxt (t - _T) a sk + + _T = totalPeriodsKES (Proxy :: Proxy d) + + {-# NOINLINE updateKESWith #-} + updateKESWith allocator ctx (SignKeySumKES sk r_1 vk_0 vk_1) t + | t + 1 < _T = + runMaybeT $! + do + sk' <- MaybeT $! updateKESWith allocator ctx sk t + r_1' <- MaybeT $! Just <$!> mlockedSeedCopy r_1 + return $! SignKeySumKES sk' r_1' vk_0 vk_1 + | t + 1 == _T = do + sk' <- genKeyKESWith allocator r_1 + r_1' <- mlockedSeedNewZeroWith allocator + return $! Just $! SignKeySumKES sk' r_1' vk_0 vk_1 + | otherwise = runMaybeT $ + do + sk' <- MaybeT $! updateKESWith allocator ctx sk (t - _T) + r_1' <- MaybeT $! Just <$!> mlockedSeedCopyWith allocator r_1 + return $! SignKeySumKES sk' r_1' vk_0 vk_1 + where + _T = totalPeriodsKES (Proxy :: Proxy d) + + -- + -- Key generation + -- + + {-# NOINLINE genKeyKESWith #-} + genKeyKESWith allocator r = do + (r0raw, r1raw) <- expandHashWith allocator (Proxy :: Proxy h) (mlockedSeedMLSB r) + let r0 = MLockedSeed r0raw + r1 = MLockedSeed r1raw + sk_0 <- genKeyKESWith allocator r0 + vk_0 <- deriveVerKeyKES sk_0 + sk_1 <- genKeyKESWith allocator r1 + vk_1 <- deriveVerKeyKES sk_1 + forgetSignKeyKES sk_1 + mlockedSeedFinalize r0 + return $! SignKeySumKES sk_0 r1 vk_0 vk_1 + + -- + -- forgetting + -- + forgetSignKeyKESWith allocator (SignKeySumKES sk_0 r1 _ _) = do + forgetSignKeyKESWith allocator sk_0 + mlockedSeedFinalize r1 + +instance + ( KESAlgorithm (SumKES h d) + , UnsoundKESAlgorithm d + ) => + UnsoundKESAlgorithm (SumKES h d) + where + -- + -- Raw serialise/deserialise - dangerous, do not use in production code. + -- + + {-# NOINLINE rawSerialiseSignKeyKES #-} + rawSerialiseSignKeyKES (SignKeySumKES sk r_1 vk_0 vk_1) = do + ssk <- rawSerialiseSignKeyKES sk + sr1 <- mlsbToByteString . mlockedSeedMLSB $ r_1 + return $ mconcat - [ rawSerialiseSigKES sigma + [ ssk + , sr1 , rawSerialiseVerKeyKES vk_0 , rawSerialiseVerKeyKES vk_1 ] - rawDeserialiseVerKeyKES = fmap VerKeySumKES . hashFromBytes - {-# INLINE rawDeserialiseVerKeyKES #-} - - rawDeserialiseSigKES b = do - guard (BS.length b == fromIntegral size_total) - sigma <- rawDeserialiseSigKES b_sig - vk_0 <- rawDeserialiseVerKeyKES b_vk0 - vk_1 <- rawDeserialiseVerKeyKES b_vk1 - return (SigSumKES sigma vk_0 vk_1) - where - b_sig = slice off_sig size_sig b - b_vk0 = slice off_vk0 size_vk b - b_vk1 = slice off_vk1 size_vk b - - size_sig = sizeSigKES (Proxy :: Proxy d) - size_vk = sizeVerKeyKES (Proxy :: Proxy d) - size_total = sizeSigKES (Proxy :: Proxy (SumKES h d)) - - off_sig = 0 :: Word - off_vk0 = size_sig - off_vk1 = off_vk0 + size_vk - {-# INLINEABLE rawDeserialiseSigKES #-} - - deriveVerKeyKES (SignKeySumKES _ _ vk_0 vk_1) = - return $! VerKeySumKES (hashPairOfVKeys (vk_0, vk_1)) - - signKES ctxt t a (SignKeySumKES sk _r_1 vk_0 vk_1) = do - sigma <- getSigma - return $! SigSumKES sigma vk_0 vk_1 - where - getSigma - | t < _T = signKES ctxt t a sk - | otherwise = signKES ctxt (t - _T) a sk - - _T = totalPeriodsKES (Proxy :: Proxy d) - - {-# NOINLINE updateKESWith #-} - updateKESWith allocator ctx (SignKeySumKES sk r_1 vk_0 vk_1) t - | t+1 < _T = runMaybeT $! - do - sk' <- MaybeT $! updateKESWith allocator ctx sk t - r_1' <- MaybeT $! Just <$!> mlockedSeedCopy r_1 - return $! SignKeySumKES sk' r_1' vk_0 vk_1 - | t+1 == _T = do - sk' <- genKeyKESWith allocator r_1 - r_1' <- mlockedSeedNewZeroWith allocator - return $! Just $! SignKeySumKES sk' r_1' vk_0 vk_1 - | otherwise = runMaybeT $ - do - sk' <- MaybeT $! updateKESWith allocator ctx sk (t - _T) - r_1' <- MaybeT $! Just <$!> mlockedSeedCopyWith allocator r_1 - return $! SignKeySumKES sk' r_1' vk_0 vk_1 - where - _T = totalPeriodsKES (Proxy :: Proxy d) - - -- - -- Key generation - -- - - {-# NOINLINE genKeyKESWith #-} - genKeyKESWith allocator r = do - (r0raw, r1raw) <- expandHashWith allocator (Proxy :: Proxy h) (mlockedSeedMLSB r) - let r0 = MLockedSeed r0raw - r1 = MLockedSeed r1raw - sk_0 <- genKeyKESWith allocator r0 - vk_0 <- deriveVerKeyKES sk_0 - sk_1 <- genKeyKESWith allocator r1 - vk_1 <- deriveVerKeyKES sk_1 - forgetSignKeyKES sk_1 - mlockedSeedFinalize r0 - return $! SignKeySumKES sk_0 r1 vk_0 vk_1 - - -- - -- forgetting - -- - forgetSignKeyKESWith allocator (SignKeySumKES sk_0 r1 _ _) = do - forgetSignKeyKESWith allocator sk_0 - mlockedSeedFinalize r1 - -instance ( KESAlgorithm (SumKES h d) - , UnsoundKESAlgorithm d - ) => UnsoundKESAlgorithm (SumKES h d) where - -- - -- Raw serialise/deserialise - dangerous, do not use in production code. - -- - - {-# NOINLINE rawSerialiseSignKeyKES #-} - rawSerialiseSignKeyKES (SignKeySumKES sk r_1 vk_0 vk_1) = do - ssk <- rawSerialiseSignKeyKES sk - sr1 <- mlsbToByteString . mlockedSeedMLSB $ r_1 - return $ mconcat - [ ssk - , sr1 - , rawSerialiseVerKeyKES vk_0 - , rawSerialiseVerKeyKES vk_1 - ] - - {-# NOINLINE rawDeserialiseSignKeyKESWith #-} - rawDeserialiseSignKeyKESWith allocator b = runMaybeT $ do - guard (BS.length b == fromIntegral size_total) - sk <- MaybeT $ rawDeserialiseSignKeyKESWith allocator b_sk - r <- MaybeT $ mlsbFromByteStringCheckWith allocator b_r - vk_0 <- MaybeT . return $ rawDeserialiseVerKeyKES b_vk0 - vk_1 <- MaybeT . return $ rawDeserialiseVerKeyKES b_vk1 - return (SignKeySumKES sk (MLockedSeed r) vk_0 vk_1) - where - b_sk = slice off_sk size_sk b - b_r = slice off_r size_r b - b_vk0 = slice off_vk0 size_vk b - b_vk1 = slice off_vk1 size_vk b - - size_sk = sizeSignKeyKES (Proxy :: Proxy d) - size_r = seedSizeKES (Proxy :: Proxy d) - size_vk = sizeVerKeyKES (Proxy :: Proxy d) - size_total = sizeSignKeyKES (Proxy :: Proxy (SumKES h d)) - - off_sk = 0 :: Word - off_r = size_sk - off_vk0 = off_r + size_r - off_vk1 = off_vk0 + size_vk - + {-# NOINLINE rawDeserialiseSignKeyKESWith #-} + rawDeserialiseSignKeyKESWith allocator b = runMaybeT $ do + guard (BS.length b == fromIntegral size_total) + sk <- MaybeT $ rawDeserialiseSignKeyKESWith allocator b_sk + r <- MaybeT $ mlsbFromByteStringCheckWith allocator b_r + vk_0 <- MaybeT . return $ rawDeserialiseVerKeyKES b_vk0 + vk_1 <- MaybeT . return $ rawDeserialiseVerKeyKES b_vk1 + return (SignKeySumKES sk (MLockedSeed r) vk_0 vk_1) + where + b_sk = slice off_sk size_sk b + b_r = slice off_r size_r b + b_vk0 = slice off_vk0 size_vk b + b_vk1 = slice off_vk1 size_vk b + + size_sk = sizeSignKeyKES (Proxy :: Proxy d) + size_r = seedSizeKES (Proxy :: Proxy d) + size_vk = sizeVerKeyKES (Proxy :: Proxy d) + size_total = sizeSignKeyKES (Proxy :: Proxy (SumKES h d)) + + off_sk = 0 :: Word + off_r = size_sk + off_vk0 = off_r + size_r + off_vk1 = off_vk0 + size_vk -- -- VerKey instances -- deriving instance HashAlgorithm h => Show (VerKeyKES (SumKES h d)) -deriving instance Eq (VerKeyKES (SumKES h d)) +deriving instance Eq (VerKeyKES (SumKES h d)) -instance (KESAlgorithm (SumKES h d), SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) - => ToCBOR (VerKeyKES (SumKES h d)) where +instance + (KESAlgorithm (SumKES h d), SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) => + ToCBOR (VerKeyKES (SumKES h d)) + where toCBOR = encodeVerKeyKES encodedSizeExpr _size = encodedVerKeyKESSizeExpr -instance (KESAlgorithm (SumKES h d), SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) - => FromCBOR (VerKeyKES (SumKES h d)) where +instance + (KESAlgorithm (SumKES h d), SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) => + FromCBOR (VerKeyKES (SumKES h d)) + where fromCBOR = decodeVerKeyKES {-# INLINE fromCBOR #-} -instance (KESAlgorithm d) => NoThunks (VerKeyKES (SumKES h d)) +instance KESAlgorithm d => NoThunks (VerKeyKES (SumKES h d)) -- -- SignKey instances @@ -368,8 +378,10 @@ instance (KESAlgorithm d) => NoThunks (VerKeyKES (SumKES h d)) -- => FromCBOR (SignKeyKES (SumKES h d)) where -- fromCBOR = decodeSignKeyKES -deriving via OnlyCheckWhnfNamed "SignKeyKES (SumKES h d)" (SignKeyKES (SumKES h d)) - instance NoThunks (SignKeyKES (SumKES h d)) +deriving via + OnlyCheckWhnfNamed "SignKeyKES (SumKES h d)" (SignKeyKES (SumKES h d)) + instance + NoThunks (SignKeyKES (SumKES h d)) -- -- Sig instances @@ -380,145 +392,164 @@ deriving instance (KESAlgorithm d, KESAlgorithm (SumKES h d)) => Eq (SigKES (Sum instance KESAlgorithm d => NoThunks (SigKES (SumKES h d)) -instance (KESAlgorithm (SumKES h d), SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) - => ToCBOR (SigKES (SumKES h d)) where +instance + (KESAlgorithm (SumKES h d), SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) => + ToCBOR (SigKES (SumKES h d)) + where toCBOR = encodeSigKES encodedSizeExpr _size = encodedSigKESSizeExpr -instance (KESAlgorithm (SumKES h d), SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) - => FromCBOR (SigKES (SumKES h d)) where +instance + (KESAlgorithm (SumKES h d), SodiumHashAlgorithm h, SizeHash h ~ SeedSizeKES d) => + FromCBOR (SigKES (SumKES h d)) + where fromCBOR = decodeSigKES -- -- Unsound pure KES API -- -instance ( KESAlgorithm (SumKES h d) - , HashAlgorithm h - , UnsoundPureKESAlgorithm d - ) - => UnsoundPureKESAlgorithm (SumKES h d) where - data UnsoundPureSignKeyKES (SumKES h d) = - UnsoundPureSignKeySumKES !(UnsoundPureSignKeyKES d) - !Seed - !(VerKeyKES d) - !(VerKeyKES d) - deriving (Generic) - - unsoundPureSignKES ctxt t a (UnsoundPureSignKeySumKES sk _r_1 vk_0 vk_1) = - SigSumKES sigma vk_0 vk_1 - where - sigma - | t < _T = unsoundPureSignKES ctxt t a sk - | otherwise = unsoundPureSignKES ctxt (t - _T) a sk - - _T = totalPeriodsKES (Proxy :: Proxy d) - - unsoundPureUpdateKES ctx (UnsoundPureSignKeySumKES sk r_1 vk_0 vk_1) t - | t+1 < _T = do - sk' <- unsoundPureUpdateKES ctx sk t - return $! UnsoundPureSignKeySumKES sk' r_1 vk_0 vk_1 - | t+1 == _T = do - let sk' = unsoundPureGenKeyKES r_1 - let r_1' = mkSeedFromBytes (BS.replicate (fromIntegral (seedSizeKES (Proxy @d))) 0) - return $! UnsoundPureSignKeySumKES sk' r_1' vk_0 vk_1 - | otherwise = do - sk' <- unsoundPureUpdateKES ctx sk (t - _T) - return $! UnsoundPureSignKeySumKES sk' r_1 vk_0 vk_1 - where - _T = totalPeriodsKES (Proxy :: Proxy d) - - -- - -- Key generation - -- - - unsoundPureGenKeyKES r = - let (r0, r1) = expandSeed (Proxy @h) r - sk_0 = unsoundPureGenKeyKES r0 - vk_0 = unsoundPureDeriveVerKeyKES sk_0 - sk_1 = unsoundPureGenKeyKES r1 - vk_1 = unsoundPureDeriveVerKeyKES sk_1 - in UnsoundPureSignKeySumKES sk_0 r1 vk_0 vk_1 - - unsoundPureDeriveVerKeyKES (UnsoundPureSignKeySumKES _ _ vk_0 vk_1) = - VerKeySumKES (hashPairOfVKeys (vk_0, vk_1)) - - unsoundPureSignKeyKESToSoundSignKeyKES (UnsoundPureSignKeySumKES sk r_1 vk_0 vk_1) = - SignKeySumKES - <$> unsoundPureSignKeyKESToSoundSignKeyKES sk - <*> (fmap MLockedSeed . mlsbFromByteString . getSeedBytes $ r_1) - <*> pure vk_0 - <*> pure vk_1 - - rawSerialiseUnsoundPureSignKeyKES (UnsoundPureSignKeySumKES sk r_1 vk_0 vk_1) = - let ssk = rawSerialiseUnsoundPureSignKeyKES sk - sr1 = getSeedBytes r_1 - in mconcat +instance + ( KESAlgorithm (SumKES h d) + , HashAlgorithm h + , UnsoundPureKESAlgorithm d + ) => + UnsoundPureKESAlgorithm (SumKES h d) + where + data UnsoundPureSignKeyKES (SumKES h d) + = UnsoundPureSignKeySumKES + !(UnsoundPureSignKeyKES d) + !Seed + !(VerKeyKES d) + !(VerKeyKES d) + deriving (Generic) + + unsoundPureSignKES ctxt t a (UnsoundPureSignKeySumKES sk _r_1 vk_0 vk_1) = + SigSumKES sigma vk_0 vk_1 + where + sigma + | t < _T = unsoundPureSignKES ctxt t a sk + | otherwise = unsoundPureSignKES ctxt (t - _T) a sk + + _T = totalPeriodsKES (Proxy :: Proxy d) + + unsoundPureUpdateKES ctx (UnsoundPureSignKeySumKES sk r_1 vk_0 vk_1) t + | t + 1 < _T = do + sk' <- unsoundPureUpdateKES ctx sk t + return $! UnsoundPureSignKeySumKES sk' r_1 vk_0 vk_1 + | t + 1 == _T = do + let sk' = unsoundPureGenKeyKES r_1 + let r_1' = mkSeedFromBytes (BS.replicate (fromIntegral (seedSizeKES (Proxy @d))) 0) + return $! UnsoundPureSignKeySumKES sk' r_1' vk_0 vk_1 + | otherwise = do + sk' <- unsoundPureUpdateKES ctx sk (t - _T) + return $! UnsoundPureSignKeySumKES sk' r_1 vk_0 vk_1 + where + _T = totalPeriodsKES (Proxy :: Proxy d) + + -- + -- Key generation + -- + + unsoundPureGenKeyKES r = + let (r0, r1) = expandSeed (Proxy @h) r + sk_0 = unsoundPureGenKeyKES r0 + vk_0 = unsoundPureDeriveVerKeyKES sk_0 + sk_1 = unsoundPureGenKeyKES r1 + vk_1 = unsoundPureDeriveVerKeyKES sk_1 + in UnsoundPureSignKeySumKES sk_0 r1 vk_0 vk_1 + + unsoundPureDeriveVerKeyKES (UnsoundPureSignKeySumKES _ _ vk_0 vk_1) = + VerKeySumKES (hashPairOfVKeys (vk_0, vk_1)) + + unsoundPureSignKeyKESToSoundSignKeyKES (UnsoundPureSignKeySumKES sk r_1 vk_0 vk_1) = + SignKeySumKES + <$> unsoundPureSignKeyKESToSoundSignKeyKES sk + <*> (fmap MLockedSeed . mlsbFromByteString . getSeedBytes $ r_1) + <*> pure vk_0 + <*> pure vk_1 + + rawSerialiseUnsoundPureSignKeyKES (UnsoundPureSignKeySumKES sk r_1 vk_0 vk_1) = + let ssk = rawSerialiseUnsoundPureSignKeyKES sk + sr1 = getSeedBytes r_1 + in mconcat [ ssk , sr1 , rawSerialiseVerKeyKES vk_0 , rawSerialiseVerKeyKES vk_1 ] - rawDeserialiseUnsoundPureSignKeyKES b = do - guard (BS.length b == fromIntegral size_total) - sk <- rawDeserialiseUnsoundPureSignKeyKES b_sk - let r = mkSeedFromBytes b_r - vk_0 <- rawDeserialiseVerKeyKES b_vk0 - vk_1 <- rawDeserialiseVerKeyKES b_vk1 - return (UnsoundPureSignKeySumKES sk r vk_0 vk_1) - where - b_sk = slice off_sk size_sk b - b_r = slice off_r size_r b - b_vk0 = slice off_vk0 size_vk b - b_vk1 = slice off_vk1 size_vk b - - size_sk = sizeSignKeyKES (Proxy :: Proxy d) - size_r = seedSizeKES (Proxy :: Proxy d) - size_vk = sizeVerKeyKES (Proxy :: Proxy d) - size_total = sizeSignKeyKES (Proxy :: Proxy (SumKES h d)) - - off_sk = 0 :: Word - off_r = size_sk - off_vk0 = off_r + size_r - off_vk1 = off_vk0 + size_vk - + rawDeserialiseUnsoundPureSignKeyKES b = do + guard (BS.length b == fromIntegral size_total) + sk <- rawDeserialiseUnsoundPureSignKeyKES b_sk + let r = mkSeedFromBytes b_r + vk_0 <- rawDeserialiseVerKeyKES b_vk0 + vk_1 <- rawDeserialiseVerKeyKES b_vk1 + return (UnsoundPureSignKeySumKES sk r vk_0 vk_1) + where + b_sk = slice off_sk size_sk b + b_r = slice off_r size_r b + b_vk0 = slice off_vk0 size_vk b + b_vk1 = slice off_vk1 size_vk b + + size_sk = sizeSignKeyKES (Proxy :: Proxy d) + size_r = seedSizeKES (Proxy :: Proxy d) + size_vk = sizeVerKeyKES (Proxy :: Proxy d) + size_total = sizeSignKeyKES (Proxy :: Proxy (SumKES h d)) + + off_sk = 0 :: Word + off_r = size_sk + off_vk0 = off_r + size_r + off_vk1 = off_vk0 + size_vk -- -- UnsoundPureSignKey instances -- -deriving instance (KESAlgorithm d, Show (UnsoundPureSignKeyKES d)) => Show (UnsoundPureSignKeyKES (SumKES h d)) -deriving instance (KESAlgorithm d, Eq (UnsoundPureSignKeyKES d)) => Eq (UnsoundPureSignKeyKES (SumKES h d)) - -instance ( SizeHash h ~ SeedSizeKES d - , UnsoundPureKESAlgorithm d - , SodiumHashAlgorithm h - , KnownNat (SizeVerKeyKES (SumKES h d)) - , KnownNat (SizeSignKeyKES (SumKES h d)) - , KnownNat (SizeSigKES (SumKES h d)) - ) => ToCBOR (UnsoundPureSignKeyKES (SumKES h d)) where +deriving instance + (KESAlgorithm d, Show (UnsoundPureSignKeyKES d)) => Show (UnsoundPureSignKeyKES (SumKES h d)) +deriving instance + (KESAlgorithm d, Eq (UnsoundPureSignKeyKES d)) => Eq (UnsoundPureSignKeyKES (SumKES h d)) + +instance + ( SizeHash h ~ SeedSizeKES d + , UnsoundPureKESAlgorithm d + , SodiumHashAlgorithm h + , KnownNat (SizeVerKeyKES (SumKES h d)) + , KnownNat (SizeSignKeyKES (SumKES h d)) + , KnownNat (SizeSigKES (SumKES h d)) + ) => + ToCBOR (UnsoundPureSignKeyKES (SumKES h d)) + where toCBOR = encodeUnsoundPureSignKeyKES encodedSizeExpr _size _skProxy = encodedSignKeyKESSizeExpr (Proxy :: Proxy (SignKeyKES (SumKES h d))) -instance ( SizeHash h ~ SeedSizeKES d - , UnsoundPureKESAlgorithm d - , SodiumHashAlgorithm h - , KnownNat (SizeVerKeyKES (SumKES h d)) - , KnownNat (SizeSignKeyKES (SumKES h d)) - , KnownNat (SizeSigKES (SumKES h d)) - ) => FromCBOR (UnsoundPureSignKeyKES (SumKES h d)) where +instance + ( SizeHash h ~ SeedSizeKES d + , UnsoundPureKESAlgorithm d + , SodiumHashAlgorithm h + , KnownNat (SizeVerKeyKES (SumKES h d)) + , KnownNat (SizeSignKeyKES (SumKES h d)) + , KnownNat (SizeSigKES (SumKES h d)) + ) => + FromCBOR (UnsoundPureSignKeyKES (SumKES h d)) + where fromCBOR = decodeUnsoundPureSignKeyKES -instance (NoThunks (UnsoundPureSignKeyKES d), KESAlgorithm d) => NoThunks (UnsoundPureSignKeyKES (SumKES h d)) +instance + (NoThunks (UnsoundPureSignKeyKES d), KESAlgorithm d) => + NoThunks (UnsoundPureSignKeyKES (SumKES h d)) -- -- Direct ser/deser -- -instance ( DirectSerialise (SignKeyKES d) - , DirectSerialise (VerKeyKES d) - , KESAlgorithm d - ) => DirectSerialise (SignKeyKES (SumKES h d)) where +instance + ( DirectSerialise (SignKeyKES d) + , DirectSerialise (VerKeyKES d) + , KESAlgorithm d + ) => + DirectSerialise (SignKeyKES (SumKES h d)) + where directSerialise push (SignKeySumKES sk r vk0 vk1) = do directSerialise push sk mlockedSeedUseAsCPtr r $ \ptr -> @@ -526,10 +557,13 @@ instance ( DirectSerialise (SignKeyKES d) directSerialise push vk0 directSerialise push vk1 -instance ( DirectDeserialise (SignKeyKES d) - , DirectDeserialise (VerKeyKES d) - , KESAlgorithm d - ) => DirectDeserialise (SignKeyKES (SumKES h d)) where +instance + ( DirectDeserialise (SignKeyKES d) + , DirectDeserialise (VerKeyKES d) + , KESAlgorithm d + ) => + DirectDeserialise (SignKeyKES (SumKES h d)) + where directDeserialise pull = do sk <- directDeserialise pull @@ -542,14 +576,15 @@ instance ( DirectDeserialise (SignKeyKES d) return $! SignKeySumKES sk r vk0 vk1 - instance DirectSerialise (VerKeyKES (SumKES h d)) where directSerialise push (VerKeySumKES h) = unpackByteStringCStringLen (hashToBytes h) $ \(ptr, len) -> push (castPtr ptr) (fromIntegral len) -instance (HashAlgorithm h) - => DirectDeserialise (VerKeyKES (SumKES h d)) where +instance + HashAlgorithm h => + DirectDeserialise (VerKeyKES (SumKES h d)) + where directDeserialise pull = do let len :: Num a => a len = fromIntegral $ sizeHash (Proxy @h) diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium.hs index eaad15d05..ad580f723 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium.hs @@ -5,7 +5,6 @@ module Cardano.Crypto.Libsodium ( -- * MLocked memory management MLockedForeignPtr, MLockedAllocator, - finalizeMLockedForeignPtr, mlockedAllocForeignPtr, mlockedMalloc, @@ -14,7 +13,6 @@ module Cardano.Crypto.Libsodium ( -- * MLocked bytes ('MLockedSizedBytes') MLockedSizedBytes, - mlsbAsByteString, mlsbCompare, mlsbCopy, @@ -42,7 +40,7 @@ module Cardano.Crypto.Libsodium ( SodiumHashAlgorithm (..), ) where -import Cardano.Crypto.Libsodium.Init -import Cardano.Crypto.Libsodium.Memory import Cardano.Crypto.Libsodium.Hash +import Cardano.Crypto.Libsodium.Init import Cardano.Crypto.Libsodium.MLockedBytes +import Cardano.Crypto.Libsodium.Memory diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/C.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/C.hs index 3fe9623ec..2f3c9a4d7 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/C.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/C.hs @@ -1,56 +1,64 @@ -{-# LANGUAGE CApiFFI #-} -{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE CApiFFI #-} +{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} + module Cardano.Crypto.Libsodium.C ( - -- * Initialization - c_sodium_init, - -- * Memory management - c_sodium_memzero, - c_sodium_malloc, - c_sodium_free, - c_sodium_free_funptr, - c_sodium_mlock, - c_sodium_munlock, - - -- * Hashing - -- ** SHA256 - c_crypto_hash_sha256, - c_crypto_hash_sha256_final, - c_crypto_hash_sha256_init, - c_crypto_hash_sha256_update, - -- ** Blake2b 256 - c_crypto_generichash_blake2b, - c_crypto_generichash_blake2b_final, - c_crypto_generichash_blake2b_init, - c_crypto_generichash_blake2b_update, - -- * ED25519 - c_crypto_sign_ed25519_seed_keypair, - c_crypto_sign_ed25519_sk_to_seed, - c_crypto_sign_ed25519_detached, - c_crypto_sign_ed25519_verify_detached, - c_crypto_sign_ed25519_sk_to_pk, - -- * RNG - c_sodium_randombytes_buf, - -- * Helpers - c_sodium_compare, - -- * Constants - CRYPTO_SHA256_BYTES, - CRYPTO_SHA512_BYTES, - CRYPTO_BLAKE2B_256_BYTES, - CRYPTO_SHA256_STATE_SIZE, - CRYPTO_SHA512_STATE_SIZE, - CRYPTO_BLAKE2B_256_STATE_SIZE, - CRYPTO_SIGN_ED25519_BYTES, - CRYPTO_SIGN_ED25519_SEEDBYTES, - CRYPTO_SIGN_ED25519_PUBLICKEYBYTES, - CRYPTO_SIGN_ED25519_SECRETKEYBYTES, - ) where + -- * Initialization + c_sodium_init, + + -- * Memory management + c_sodium_memzero, + c_sodium_malloc, + c_sodium_free, + c_sodium_free_funptr, + c_sodium_mlock, + c_sodium_munlock, + + -- * Hashing + + -- ** SHA256 + c_crypto_hash_sha256, + c_crypto_hash_sha256_final, + c_crypto_hash_sha256_init, + c_crypto_hash_sha256_update, + + -- ** Blake2b 256 + c_crypto_generichash_blake2b, + c_crypto_generichash_blake2b_final, + c_crypto_generichash_blake2b_init, + c_crypto_generichash_blake2b_update, + + -- * ED25519 + c_crypto_sign_ed25519_seed_keypair, + c_crypto_sign_ed25519_sk_to_seed, + c_crypto_sign_ed25519_detached, + c_crypto_sign_ed25519_verify_detached, + c_crypto_sign_ed25519_sk_to_pk, + + -- * RNG + c_sodium_randombytes_buf, + + -- * Helpers + c_sodium_compare, + + -- * Constants + CRYPTO_SHA256_BYTES, + CRYPTO_SHA512_BYTES, + CRYPTO_BLAKE2B_256_BYTES, + CRYPTO_SHA256_STATE_SIZE, + CRYPTO_SHA512_STATE_SIZE, + CRYPTO_BLAKE2B_256_STATE_SIZE, + CRYPTO_SIGN_ED25519_BYTES, + CRYPTO_SIGN_ED25519_SEEDBYTES, + CRYPTO_SIGN_ED25519_PUBLICKEYBYTES, + CRYPTO_SIGN_ED25519_SECRETKEYBYTES, +) where import Foreign.C.Types import Foreign.Ptr (FunPtr, Ptr) -import Cardano.Foreign import Cardano.Crypto.Libsodium.Constants +import Cardano.Foreign ------------------------------------------------------------------------------- -- Initialization @@ -59,7 +67,7 @@ import Cardano.Crypto.Libsodium.Constants -- | @void sodium_init();@ -- -- -foreign import capi "sodium.h sodium_init" c_sodium_init :: IO Int +foreign import capi "sodium.h sodium_init" c_sodium_init :: IO Int ------------------------------------------------------------------------------- -- Memory management @@ -74,7 +82,9 @@ foreign import capi unsafe "sodium.h sodium_memzero" c_sodium_memzero :: Ptr a - -- -- foreign import capi unsafe "sodium.h sodium_malloc" c_sodium_malloc :: CSize -> IO (Ptr a) + -- + -- | @void sodium_free(void *ptr);@ -- -- @@ -102,16 +112,21 @@ foreign import capi unsafe "sodium.h sodium_munlock" c_sodium_munlock :: Ptr a - -- | @int crypto_hash_sha256(unsigned char *out, const unsigned char *in, unsigned long long inlen);@ -- -- -foreign import capi unsafe "sodium.h crypto_hash_sha256" c_crypto_hash_sha256 :: SizedPtr CRYPTO_SHA256_BYTES -> Ptr CUChar -> CULLong -> IO Int +foreign import capi unsafe "sodium.h crypto_hash_sha256" + c_crypto_hash_sha256 :: SizedPtr CRYPTO_SHA256_BYTES -> Ptr CUChar -> CULLong -> IO Int -- | @int crypto_hash_sha256_init(crypto_hash_sha256_state *state);@ -foreign import capi unsafe "sodium.h crypto_hash_sha256_init" c_crypto_hash_sha256_init :: SizedPtr CRYPTO_SHA256_STATE_SIZE -> IO Int +foreign import capi unsafe "sodium.h crypto_hash_sha256_init" + c_crypto_hash_sha256_init :: SizedPtr CRYPTO_SHA256_STATE_SIZE -> IO Int -- | @int crypto_hash_sha256_update(crypto_hash_sha256_state *state, const unsigned char *in, unsigned long long inlen);@ -foreign import capi unsafe "sodium.h crypto_hash_sha256_update" c_crypto_hash_sha256_update :: SizedPtr CRYPTO_SHA256_STATE_SIZE -> Ptr CUChar -> CULLong -> IO Int +foreign import capi unsafe "sodium.h crypto_hash_sha256_update" + c_crypto_hash_sha256_update :: SizedPtr CRYPTO_SHA256_STATE_SIZE -> Ptr CUChar -> CULLong -> IO Int -- | @int crypto_hash_sha256_final(crypto_hash_sha256_state *state, unsigned char *out);@ -foreign import capi unsafe "sodium.h crypto_hash_sha256_final" c_crypto_hash_sha256_final :: SizedPtr CRYPTO_SHA256_STATE_SIZE -> SizedPtr CRYPTO_SHA256_BYTES -> IO Int +foreign import capi unsafe "sodium.h crypto_hash_sha256_final" + c_crypto_hash_sha256_final :: + SizedPtr CRYPTO_SHA256_STATE_SIZE -> SizedPtr CRYPTO_SHA256_BYTES -> IO Int ------------------------------------------------------------------------------- -- Hashing: Blake2b @@ -120,20 +135,30 @@ foreign import capi unsafe "sodium.h crypto_hash_sha256_final" c_crypto_hash_sha -- | @int crypto_generichash_blake2b(unsigned char *out, size_t outlen, const unsigned char *in, unsigned long long inlen, const unsigned char *key, size_t keylen);@ -- -- -foreign import capi unsafe "sodium.h crypto_generichash_blake2b" c_crypto_generichash_blake2b - :: Ptr out -> CSize - -> Ptr CUChar -> CULLong - -> Ptr key -> CSize - -> IO Int +foreign import capi unsafe "sodium.h crypto_generichash_blake2b" + c_crypto_generichash_blake2b :: + Ptr out -> + CSize -> + Ptr CUChar -> + CULLong -> + Ptr key -> + CSize -> + IO Int -- | @int crypto_generichash_blake2b_init(crypto_generichash_blake2b_state *state, const unsigned char *key, const size_t keylen, const size_t outlen);@ -foreign import capi unsafe "sodium.h crypto_generichash_blake2b_init" c_crypto_generichash_blake2b_init :: SizedPtr CRYPTO_BLAKE2B_256_STATE_SIZE -> Ptr key -> CSize -> CSize -> IO Int +foreign import capi unsafe "sodium.h crypto_generichash_blake2b_init" + c_crypto_generichash_blake2b_init :: + SizedPtr CRYPTO_BLAKE2B_256_STATE_SIZE -> Ptr key -> CSize -> CSize -> IO Int -- | @int crypto_generichash_blake2b_update(crypto_generichash_blake2b_state *state, const unsigned char *in, unsigned long long inlen);@ -foreign import capi unsafe "sodium.h crypto_generichash_blake2b_update" c_crypto_generichash_blake2b_update :: SizedPtr CRYPTO_BLAKE2B_256_STATE_SIZE -> Ptr CUChar -> CULLong -> IO Int +foreign import capi unsafe "sodium.h crypto_generichash_blake2b_update" + c_crypto_generichash_blake2b_update :: + SizedPtr CRYPTO_BLAKE2B_256_STATE_SIZE -> Ptr CUChar -> CULLong -> IO Int -- | @int crypto_generichash_blake2b_final(crypto_generichash_blake2b_state *state, unsigned char *out, const size_t outlen);@ -foreign import capi unsafe "sodium.h crypto_generichash_blake2b_final" c_crypto_generichash_blake2b_final :: SizedPtr CRYPTO_BLAKE2B_256_STATE_SIZE -> Ptr out -> CSize -> IO Int +foreign import capi unsafe "sodium.h crypto_generichash_blake2b_final" + c_crypto_generichash_blake2b_final :: + SizedPtr CRYPTO_BLAKE2B_256_STATE_SIZE -> Ptr out -> CSize -> IO Int ------------------------------------------------------------------------------- -- Signing: ED25519 @@ -142,39 +167,45 @@ foreign import capi unsafe "sodium.h crypto_generichash_blake2b_final" c_crypto_ -- https://github.com/jedisct1/libsodium/blob/7b67cd1b32915bc957d750e7a15229f2a938ff1a/src/libsodium/include/sodium/crypto_sign_ed25519.h -- | @int crypto_sign_ed25519_seed_keypair(unsigned char *pk, unsigned char *sk, const unsigned char *seed);@ -foreign import capi unsafe "sodium.h crypto_sign_ed25519_seed_keypair" c_crypto_sign_ed25519_seed_keypair - :: SizedPtr CRYPTO_SIGN_ED25519_PUBLICKEYBYTES - -> SizedPtr CRYPTO_SIGN_ED25519_SECRETKEYBYTES - -> SizedPtr CRYPTO_SIGN_ED25519_SEEDBYTES - -> IO Int +foreign import capi unsafe "sodium.h crypto_sign_ed25519_seed_keypair" + c_crypto_sign_ed25519_seed_keypair :: + SizedPtr CRYPTO_SIGN_ED25519_PUBLICKEYBYTES -> + SizedPtr CRYPTO_SIGN_ED25519_SECRETKEYBYTES -> + SizedPtr CRYPTO_SIGN_ED25519_SEEDBYTES -> + IO Int -- | @int crypto_sign_ed25519_sk_to_seed(unsigned char *seed, const unsigned char *sk);@ -foreign import capi unsafe "sodium.h crypto_sign_ed25519_sk_to_seed" c_crypto_sign_ed25519_sk_to_seed - :: SizedPtr CRYPTO_SIGN_ED25519_SEEDBYTES - -> SizedPtr CRYPTO_SIGN_ED25519_SECRETKEYBYTES - -> IO Int +foreign import capi unsafe "sodium.h crypto_sign_ed25519_sk_to_seed" + c_crypto_sign_ed25519_sk_to_seed :: + SizedPtr CRYPTO_SIGN_ED25519_SEEDBYTES -> + SizedPtr CRYPTO_SIGN_ED25519_SECRETKEYBYTES -> + IO Int -- | @int crypto_sign_ed25519_detached(unsigned char *sig, unsigned long long *siglen_p, const unsigned char *m, unsigned long long mlen, const unsigned char *sk);@ -foreign import capi unsafe "sodium.h crypto_sign_ed25519_detached" c_crypto_sign_ed25519_detached - :: SizedPtr CRYPTO_SIGN_ED25519_BYTES - -> Ptr CULLong - -> Ptr CUChar - -> CULLong - -> SizedPtr CRYPTO_SIGN_ED25519_SECRETKEYBYTES - -> IO Int +foreign import capi unsafe "sodium.h crypto_sign_ed25519_detached" + c_crypto_sign_ed25519_detached :: + SizedPtr CRYPTO_SIGN_ED25519_BYTES -> + Ptr CULLong -> + Ptr CUChar -> + CULLong -> + SizedPtr CRYPTO_SIGN_ED25519_SECRETKEYBYTES -> + IO Int -- | @int crypto_sign_ed25519_verify_detached(const unsigned char *sig, const unsigned char *m, unsigned long long mlen, const unsigned char *pk);@ -foreign import capi unsafe "sodium.h crypto_sign_ed25519_verify_detached" c_crypto_sign_ed25519_verify_detached - :: SizedPtr CRYPTO_SIGN_ED25519_BYTES - -> Ptr CUChar - -> CULLong - -> SizedPtr CRYPTO_SIGN_ED25519_PUBLICKEYBYTES - -> IO Int +foreign import capi unsafe "sodium.h crypto_sign_ed25519_verify_detached" + c_crypto_sign_ed25519_verify_detached :: + SizedPtr CRYPTO_SIGN_ED25519_BYTES -> + Ptr CUChar -> + CULLong -> + SizedPtr CRYPTO_SIGN_ED25519_PUBLICKEYBYTES -> + IO Int -- | @int crypto_sign_ed25519_sk_to_pk(unsigned char *pk, const unsigned char *sk);@ -foreign import capi unsafe "sodium.h crypto_sign_ed25519_sk_to_pk" c_crypto_sign_ed25519_sk_to_pk - :: SizedPtr CRYPTO_SIGN_ED25519_PUBLICKEYBYTES - -> SizedPtr CRYPTO_SIGN_ED25519_SECRETKEYBYTES -> IO Int +foreign import capi unsafe "sodium.h crypto_sign_ed25519_sk_to_pk" + c_crypto_sign_ed25519_sk_to_pk :: + SizedPtr CRYPTO_SIGN_ED25519_PUBLICKEYBYTES -> + SizedPtr CRYPTO_SIGN_ED25519_SECRETKEYBYTES -> + IO Int ------------------------------------------------------------------------------- -- Helpers @@ -183,7 +214,9 @@ foreign import capi unsafe "sodium.h crypto_sign_ed25519_sk_to_pk" c_crypto_sign -- | @int sodium_compare(const void * const b1_, const void * const b2_, size_t len);@ -- -- -foreign import capi unsafe "sodium.h sodium_compare" c_sodium_compare :: Ptr a -> Ptr a -> CSize -> IO Int +foreign import capi unsafe "sodium.h sodium_compare" + c_sodium_compare :: Ptr a -> Ptr a -> CSize -> IO Int -- | @void randombytes_buf(void * const buf, const size_t size);@ -foreign import capi unsafe "sodium/randombytes.h randombytes_buf" c_sodium_randombytes_buf :: Ptr a -> CSize -> IO () +foreign import capi unsafe "sodium/randombytes.h randombytes_buf" + c_sodium_randombytes_buf :: Ptr a -> CSize -> IO () diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Hash.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Hash.hs index 4c579fd2d..abcc4141e 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Hash.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Hash.hs @@ -1,28 +1,29 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE RoleAnnotations #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} + module Cardano.Crypto.Libsodium.Hash ( - SodiumHashAlgorithm (..), - digestMLockedStorable, - digestMLockedBS, - expandHash, - expandHashWith, + SodiumHashAlgorithm (..), + digestMLockedStorable, + digestMLockedBS, + expandHash, + expandHashWith, ) where import Data.Proxy (Proxy (..)) +import Data.Word (Word8) import Foreign.C.Types (CSize) import Foreign.Ptr (castPtr, plusPtr) import Foreign.Storable (Storable (poke)) -import Data.Word (Word8) import GHC.TypeLits -import Cardano.Crypto.Hash (HashAlgorithm(SizeHash)) -import Cardano.Crypto.Libsodium.Memory +import Cardano.Crypto.Hash (HashAlgorithm (SizeHash)) import Cardano.Crypto.Libsodium.Hash.Class import Cardano.Crypto.Libsodium.MLockedBytes.Internal +import Cardano.Crypto.Libsodium.Memory import Control.Monad.Class.MonadST (MonadST (..)) import Control.Monad.Class.MonadThrow (MonadThrow) import Control.Monad.ST.Unsafe (unsafeIOToST) @@ -31,40 +32,39 @@ import Control.Monad.ST.Unsafe (unsafeIOToST) -- Hash expansion ------------------------------------------------------------------------------- -expandHash - :: forall h m proxy. - (SodiumHashAlgorithm h, MonadST m, MonadThrow m) - => proxy h - -> MLockedSizedBytes (SizeHash h) - -> m (MLockedSizedBytes (SizeHash h), MLockedSizedBytes (SizeHash h)) +expandHash :: + forall h m proxy. + (SodiumHashAlgorithm h, MonadST m, MonadThrow m) => + proxy h -> + MLockedSizedBytes (SizeHash h) -> + m (MLockedSizedBytes (SizeHash h), MLockedSizedBytes (SizeHash h)) expandHash = expandHashWith mlockedMalloc -expandHashWith - :: forall h m proxy. - (SodiumHashAlgorithm h, MonadST m, MonadThrow m) - => MLockedAllocator m - -> proxy h - -> MLockedSizedBytes (SizeHash h) - -> m (MLockedSizedBytes (SizeHash h), MLockedSizedBytes (SizeHash h)) +expandHashWith :: + forall h m proxy. + (SodiumHashAlgorithm h, MonadST m, MonadThrow m) => + MLockedAllocator m -> + proxy h -> + MLockedSizedBytes (SizeHash h) -> + m (MLockedSizedBytes (SizeHash h), MLockedSizedBytes (SizeHash h)) expandHashWith allocator h (MLSB sfptr) = do - withMLockedForeignPtr sfptr $ \ptr -> do - l <- mlockedAllocaWith allocator size1 $ \ptr' -> do - stToIO . unsafeIOToST $ do - poke ptr' (1 :: Word8) - copyMem (castPtr (plusPtr ptr' 1)) ptr size - naclDigestPtr h ptr' (fromIntegral size1) + withMLockedForeignPtr sfptr $ \ptr -> do + l <- mlockedAllocaWith allocator size1 $ \ptr' -> do + stToIO . unsafeIOToST $ do + poke ptr' (1 :: Word8) + copyMem (castPtr (plusPtr ptr' 1)) ptr size + naclDigestPtr h ptr' (fromIntegral size1) - r <- mlockedAllocaWith allocator size1 $ \ptr' -> do - stToIO . unsafeIOToST $ do - poke ptr' (2 :: Word8) - copyMem (castPtr (plusPtr ptr' 1)) ptr size - naclDigestPtr h ptr' (fromIntegral size1) + r <- mlockedAllocaWith allocator size1 $ \ptr' -> do + stToIO . unsafeIOToST $ do + poke ptr' (2 :: Word8) + copyMem (castPtr (plusPtr ptr' 1)) ptr size + naclDigestPtr h ptr' (fromIntegral size1) - return (l, r) + return (l, r) where size1 :: CSize size1 = size + 1 size :: CSize size = fromInteger $ natVal (Proxy @(SizeHash h)) - diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Hash/Class.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Hash/Class.hs index 65cb992d8..984924ab7 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Hash/Class.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Hash/Class.hs @@ -1,30 +1,31 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE InstanceSigs #-} -{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RoleAnnotations #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -{-# LANGUAGE MultiParamTypeClasses #-} + module Cardano.Crypto.Libsodium.Hash.Class ( - SodiumHashAlgorithm (..), - digestMLockedStorable, - digestMLockedBS, + SodiumHashAlgorithm (..), + digestMLockedStorable, + digestMLockedBS, ) where import Control.Monad (unless) import Data.Proxy (Proxy (..)) +import Data.Type.Equality ((:~:) (..)) import Foreign.C.Error (errnoToIOError, getErrno) import Foreign.Ptr (Ptr, castPtr, nullPtr) import Foreign.Storable (Storable (sizeOf)) -import Data.Type.Equality ((:~:)(..)) import GHC.IO.Exception (ioException) import GHC.TypeLits import qualified Data.ByteString as BS -import Cardano.Crypto.Hash (HashAlgorithm(SizeHash), SHA256, Blake2b_256) +import Cardano.Crypto.Hash (Blake2b_256, HashAlgorithm (SizeHash), SHA256) import Cardano.Crypto.Libsodium.C import Cardano.Crypto.Libsodium.MLockedBytes.Internal @@ -33,28 +34,32 @@ import Cardano.Crypto.Libsodium.MLockedBytes.Internal ------------------------------------------------------------------------------- class HashAlgorithm h => SodiumHashAlgorithm h where - -- This function is in IO, it is "morally pure" - -- and can be 'unsafePerformDupableIO'd. - naclDigestPtr - :: proxy h - -> Ptr a -- ^ input - -> Int -- ^ input length - -> IO (MLockedSizedBytes (SizeHash h)) + -- This function is in IO, it is "morally pure" + -- and can be 'unsafePerformDupableIO'd. + naclDigestPtr :: + proxy h -> + -- | input + Ptr a -> + -- | input length + Int -> + IO (MLockedSizedBytes (SizeHash h)) - -- TODO: provide interface for multi-part? - -- That will be useful to hashing ('1' <> oldseed). +-- TODO: provide interface for multi-part? +-- That will be useful to hashing ('1' <> oldseed). -digestMLockedStorable - :: forall h a proxy. (SodiumHashAlgorithm h, Storable a) - => proxy h -> Ptr a -> IO (MLockedSizedBytes (SizeHash h)) +digestMLockedStorable :: + forall h a proxy. + (SodiumHashAlgorithm h, Storable a) => + proxy h -> Ptr a -> IO (MLockedSizedBytes (SizeHash h)) digestMLockedStorable p ptr = - naclDigestPtr p ptr ((sizeOf (undefined :: a))) + naclDigestPtr p ptr ((sizeOf (undefined :: a))) -digestMLockedBS - :: forall h proxy. (SodiumHashAlgorithm h) - => proxy h -> BS.ByteString -> IO (MLockedSizedBytes (SizeHash h)) +digestMLockedBS :: + forall h proxy. + SodiumHashAlgorithm h => + proxy h -> BS.ByteString -> IO (MLockedSizedBytes (SizeHash h)) digestMLockedBS p bs = - BS.useAsCStringLen bs $ \(ptr, len) -> + BS.useAsCStringLen bs $ \(ptr, len) -> naclDigestPtr p (castPtr ptr) len ------------------------------------------------------------------------------- @@ -62,33 +67,40 @@ digestMLockedBS p bs = ------------------------------------------------------------------------------- instance SodiumHashAlgorithm SHA256 where - naclDigestPtr :: forall proxy a. proxy SHA256 -> Ptr a -> Int -> IO (MLockedSizedBytes (SizeHash SHA256)) - naclDigestPtr _ input inputlen = do - output <- mlsbNew - mlsbUseAsSizedPtr output $ \output' -> do - res <- c_crypto_hash_sha256 output' (castPtr input) (fromIntegral inputlen) - unless (res == 0) $ do - errno <- getErrno - ioException $ errnoToIOError "digestMLocked @SHA256: c_crypto_hash_sha256" errno Nothing Nothing - return output + naclDigestPtr :: + forall proxy a. proxy SHA256 -> Ptr a -> Int -> IO (MLockedSizedBytes (SizeHash SHA256)) + naclDigestPtr _ input inputlen = do + output <- mlsbNew + mlsbUseAsSizedPtr output $ \output' -> do + res <- c_crypto_hash_sha256 output' (castPtr input) (fromIntegral inputlen) + unless (res == 0) $ do + errno <- getErrno + ioException $ errnoToIOError "digestMLocked @SHA256: c_crypto_hash_sha256" errno Nothing Nothing + return output -- Test that manually written numbers are the same as in libsodium _testSHA256 :: SizeHash SHA256 :~: CRYPTO_SHA256_BYTES _testSHA256 = Refl instance SodiumHashAlgorithm Blake2b_256 where - naclDigestPtr :: forall proxy a. proxy Blake2b_256 -> Ptr a -> Int -> IO (MLockedSizedBytes (SizeHash Blake2b_256)) - naclDigestPtr _ input inputlen = do - output <- mlsbNew - mlsbUseAsCPtr output $ \output' -> do - res <- c_crypto_generichash_blake2b - output' (fromInteger $ natVal (Proxy @CRYPTO_BLAKE2B_256_BYTES)) -- output - (castPtr input) (fromIntegral inputlen) -- input - nullPtr 0 -- key, unused - unless (res == 0) $ do - errno <- getErrno - ioException $ errnoToIOError "digestMLocked @Blake2b_256: c_crypto_hash_sha256" errno Nothing Nothing - return output + naclDigestPtr :: + forall proxy a. proxy Blake2b_256 -> Ptr a -> Int -> IO (MLockedSizedBytes (SizeHash Blake2b_256)) + naclDigestPtr _ input inputlen = do + output <- mlsbNew + mlsbUseAsCPtr output $ \output' -> do + res <- + c_crypto_generichash_blake2b + output' + (fromInteger $ natVal (Proxy @CRYPTO_BLAKE2B_256_BYTES)) -- output + (castPtr input) + (fromIntegral inputlen) -- input + nullPtr + 0 -- key, unused + unless (res == 0) $ do + errno <- getErrno + ioException $ + errnoToIOError "digestMLocked @Blake2b_256: c_crypto_hash_sha256" errno Nothing Nothing + return output _testBlake2b256 :: SizeHash Blake2b_256 :~: CRYPTO_BLAKE2B_256_BYTES _testBlake2b256 = Refl diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Init.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Init.hs index d890d86f1..0c66fe975 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Init.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Init.hs @@ -13,9 +13,7 @@ import Cardano.Crypto.Libsodium.C -- sodiumInit :: IO () sodiumInit = do - res <- c_sodium_init - -- sodium_init() returns 0 on success, -1 on failure, and 1 if the library - -- had already been initialized. - unless (res == 0 || res == 1) $ fail "sodium_init failed" - - + res <- c_sodium_init + -- sodium_init() returns 0 on success, -1 on failure, and 1 if the library + -- had already been initialized. + unless (res == 0 || res == 1) $ fail "sodium_init failed" diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedBytes.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedBytes.hs index a08391552..6a1ebec28 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedBytes.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedBytes.hs @@ -1,28 +1,27 @@ module Cardano.Crypto.Libsodium.MLockedBytes ( - MLockedSizedBytes, - SizedVoid, - withMLSB, - withMLSBChunk, - mlsbNew, - mlsbNewZero, - mlsbZero, - mlsbFromByteString, - mlsbFromByteStringCheck, - mlsbAsByteString, - mlsbToByteString, - mlsbUseAsCPtr, - mlsbUseAsSizedPtr, - mlsbFinalize, - mlsbCopy, - traceMLSB, - mlsbCompare, - mlsbEq, - - mlsbNewWith, - mlsbNewZeroWith, - mlsbCopyWith, - mlsbFromByteStringWith, - mlsbFromByteStringCheckWith, + MLockedSizedBytes, + SizedVoid, + withMLSB, + withMLSBChunk, + mlsbNew, + mlsbNewZero, + mlsbZero, + mlsbFromByteString, + mlsbFromByteStringCheck, + mlsbAsByteString, + mlsbToByteString, + mlsbUseAsCPtr, + mlsbUseAsSizedPtr, + mlsbFinalize, + mlsbCopy, + traceMLSB, + mlsbCompare, + mlsbEq, + mlsbNewWith, + mlsbNewZeroWith, + mlsbCopyWith, + mlsbFromByteStringWith, + mlsbFromByteStringCheckWith, ) where import Cardano.Crypto.Libsodium.MLockedBytes.Internal diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedBytes/Internal.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedBytes/Internal.hs index dcdef2d43..05a3687bc 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedBytes/Internal.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedBytes/Internal.hs @@ -1,43 +1,42 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} {-# LANGUAGE KindSignatures #-} +{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} module Cardano.Crypto.Libsodium.MLockedBytes.Internal ( - -- * The MLockesSizedBytes type - MLockedSizedBytes (..), - SizedVoid, - - -- * Safe Functions - mlsbNew, - mlsbNewZero, - mlsbZero, - mlsbUseAsCPtr, - mlsbUseAsSizedPtr, - mlsbCopy, - mlsbFinalize, - mlsbCompare, - mlsbEq, - withMLSB, - withMLSBChunk, - - mlsbNewWith, - mlsbNewZeroWith, - mlsbCopyWith, - - -- * Dangerous Functions - traceMLSB, - mlsbFromByteString, - mlsbFromByteStringCheck, - mlsbAsByteString, - mlsbToByteString, - mlsbFromByteStringWith, - mlsbFromByteStringCheckWith, + -- * The MLockesSizedBytes type + MLockedSizedBytes (..), + SizedVoid, + + -- * Safe Functions + mlsbNew, + mlsbNewZero, + mlsbZero, + mlsbUseAsCPtr, + mlsbUseAsSizedPtr, + mlsbCopy, + mlsbFinalize, + mlsbCompare, + mlsbEq, + withMLSB, + withMLSBChunk, + mlsbNewWith, + mlsbNewZeroWith, + mlsbCopyWith, + + -- * Dangerous Functions + traceMLSB, + mlsbFromByteString, + mlsbFromByteStringCheck, + mlsbAsByteString, + mlsbToByteString, + mlsbFromByteStringWith, + mlsbFromByteStringCheckWith, ) where import Control.DeepSeq (NFData (..)) @@ -51,14 +50,14 @@ import Foreign.Ptr (Ptr, castPtr, plusPtr) import GHC.TypeLits (KnownNat, Nat, natVal) import NoThunks.Class (NoThunks) -import Cardano.Foreign +import Cardano.Crypto.Libsodium.C import Cardano.Crypto.Libsodium.Memory import Cardano.Crypto.Libsodium.Memory.Internal (MLockedForeignPtr (..)) -import Cardano.Crypto.Libsodium.C +import Cardano.Foreign +import Data.Bits (Bits, shiftL) import qualified Data.ByteString as BS import qualified Data.ByteString.Internal as BSI -import Data.Bits (Bits, shiftL) -- | A void type with a type-level size attached to it. We need this in order -- to express \"pointer to a block of memory of a particular size that can be @@ -69,8 +68,8 @@ data SizedVoid (n :: Nat) -- | A block of raw memory of a known size, protected with @mlock()@. newtype MLockedSizedBytes (n :: Nat) = MLSB (MLockedForeignPtr (SizedVoid n)) - deriving newtype NoThunks - deriving newtype NFData + deriving newtype (NoThunks) + deriving newtype (NFData) -- | This instance is /unsafe/, it will leak secrets from mlocked memory to the -- Haskell heap. Do not use outside of testing. @@ -90,31 +89,32 @@ nextPowerOf2 i = go :: n -> n go c = let c' = c `shiftL` 1 - in if c >= i then c else go c' + in if c >= i then c else go c' traceMLSB :: KnownNat n => MLockedSizedBytes n -> IO () traceMLSB = print {-# DEPRECATED traceMLSB "Don't leave traceMLockedForeignPtr in production" #-} -withMLSB :: forall b n m. (MonadST m) => MLockedSizedBytes n -> (Ptr (SizedVoid n) -> m b) -> m b +withMLSB :: forall b n m. MonadST m => MLockedSizedBytes n -> (Ptr (SizedVoid n) -> m b) -> m b withMLSB (MLSB fptr) action = withMLockedForeignPtr fptr action -withMLSBChunk :: forall b n n' m. - (MonadST m, KnownNat n, KnownNat n') - => MLockedSizedBytes n - -> Int - -> (MLockedSizedBytes n' -> m b) - -> m b +withMLSBChunk :: + forall b n n' m. + (MonadST m, KnownNat n, KnownNat n') => + MLockedSizedBytes n -> + Int -> + (MLockedSizedBytes n' -> m b) -> + m b withMLSBChunk mlsb offset action - | offset < 0 - = error "Negative offset not allowed" - | offset > parentSize - chunkSize - = error $ "Overrun (" ++ show offset ++ " + " ++ show chunkSize ++ " > " ++ show parentSize ++ ")" - | otherwise - = withMLSB mlsb $ \ptr -> do - fptr <- - stToIO $ unsafeIOToST (newForeignPtr_ . castPtr $ plusPtr ptr offset) - action (MLSB $! SFP $! fptr) + | offset < 0 = + error "Negative offset not allowed" + | offset > parentSize - chunkSize = + error $ "Overrun (" ++ show offset ++ " + " ++ show chunkSize ++ " > " ++ show parentSize ++ ")" + | otherwise = + withMLSB mlsb $ \ptr -> do + fptr <- + stToIO $ unsafeIOToST (newForeignPtr_ . castPtr $ plusPtr ptr offset) + action (MLSB $! SFP $! fptr) where chunkSize = fromIntegral (natVal (Proxy @n')) parentSize = fromIntegral (natVal mlsb) @@ -141,7 +141,8 @@ mlsbNewWith allocator = mlsbNewZero :: forall n m. (KnownNat n, MonadST m) => m (MLockedSizedBytes n) mlsbNewZero = mlsbNewZeroWith mlockedMalloc -mlsbNewZeroWith :: forall n m. (KnownNat n, MonadST m) => MLockedAllocator m -> m (MLockedSizedBytes n) +mlsbNewZeroWith :: + forall n m. (KnownNat n, MonadST m) => MLockedAllocator m -> m (MLockedSizedBytes n) mlsbNewZeroWith allocator = do mlsb <- mlsbNewWith allocator mlsbZero mlsb @@ -153,16 +154,19 @@ mlsbZero mlsb = do withMLSB mlsb $ \ptr -> zeroMem ptr (mlsbSize mlsb) -- | Create a deep mlocked copy of an 'MLockedSizedBytes'. -mlsbCopy :: forall n m. (KnownNat n, MonadST m) - => MLockedSizedBytes n - -> m (MLockedSizedBytes n) +mlsbCopy :: + forall n m. + (KnownNat n, MonadST m) => + MLockedSizedBytes n -> + m (MLockedSizedBytes n) mlsbCopy = mlsbCopyWith mlockedMalloc mlsbCopyWith :: - forall n m. (KnownNat n, MonadST m) - => MLockedAllocator m - -> MLockedSizedBytes n - -> m (MLockedSizedBytes n) + forall n m. + (KnownNat n, MonadST m) => + MLockedAllocator m -> + MLockedSizedBytes n -> + m (MLockedSizedBytes n) mlsbCopyWith allocator src = mlsbUseAsCPtr src $ \ptrSrc -> do dst <- mlsbNewWith allocator withMLSB dst $ \ptrDst -> do @@ -177,17 +181,21 @@ mlsbCopyWith allocator src = mlsbUseAsCPtr src $ \ptrSrc -> do -- 'mlsbNew' or 'mlsbNewZero' to create 'MLockedSizedBytes' values, and -- manipulate them through 'withMLSB', 'mlsbUseAsCPtr', or 'mlsbUseAsSizedPtr'. -- (See also 'mlsbFromByteStringCheck') -mlsbFromByteString :: forall n m. (KnownNat n, MonadST m) - => BS.ByteString -> m (MLockedSizedBytes n) +mlsbFromByteString :: + forall n m. + (KnownNat n, MonadST m) => + BS.ByteString -> m (MLockedSizedBytes n) mlsbFromByteString = mlsbFromByteStringWith mlockedMalloc -mlsbFromByteStringWith :: forall n m. (KnownNat n, MonadST m) - => MLockedAllocator m -> BS.ByteString -> m (MLockedSizedBytes n) +mlsbFromByteStringWith :: + forall n m. + (KnownNat n, MonadST m) => + MLockedAllocator m -> BS.ByteString -> m (MLockedSizedBytes n) mlsbFromByteStringWith allocator bs = do dst <- mlsbNewWith allocator withMLSB dst $ \ptr -> stToIO . unsafeIOToST $ do - BS.useAsCStringLen bs $ \(ptrBS, len) -> do - copyMem (castPtr ptr) ptrBS (min (fromIntegral len) (mlsbSize dst)) + BS.useAsCStringLen bs $ \(ptrBS, len) -> do + copyMem (castPtr ptr) ptrBS (min (fromIntegral len) (mlsbSize dst)) return dst -- | Allocate a new 'MLockedSizedBytes', and fill it with the contents of a @@ -198,21 +206,24 @@ mlsbFromByteStringWith allocator bs = do -- 'mlsbNew' or 'mlsbNewZero' to create 'MLockedSizedBytes' values, and -- manipulate them through 'withMLSB', 'mlsbUseAsCPtr', or 'mlsbUseAsSizedPtr'. -- (See also 'mlsbFromByteString') -mlsbFromByteStringCheck :: forall n m. (KnownNat n, MonadST m) - => BS.ByteString - -> m (Maybe (MLockedSizedBytes n)) +mlsbFromByteStringCheck :: + forall n m. + (KnownNat n, MonadST m) => + BS.ByteString -> + m (Maybe (MLockedSizedBytes n)) mlsbFromByteStringCheck = mlsbFromByteStringCheckWith mlockedMalloc mlsbFromByteStringCheckWith :: - forall n m. (KnownNat n, MonadST m) - => MLockedAllocator m - -> BS.ByteString - -> m (Maybe (MLockedSizedBytes n)) + forall n m. + (KnownNat n, MonadST m) => + MLockedAllocator m -> + BS.ByteString -> + m (Maybe (MLockedSizedBytes n)) mlsbFromByteStringCheckWith allocator bs - | BS.length bs /= size = return Nothing - | otherwise = Just <$> mlsbFromByteStringWith allocator bs + | BS.length bs /= size = return Nothing + | otherwise = Just <$> mlsbFromByteStringWith allocator bs where - size :: Int + size :: Int size = fromInteger (natVal (Proxy @n)) -- | /Note:/ the resulting 'BS.ByteString' will still refer to secure memory, @@ -224,7 +235,7 @@ mlsbFromByteStringCheckWith allocator bs mlsbAsByteString :: forall n. KnownNat n => MLockedSizedBytes n -> BS.ByteString mlsbAsByteString mlsb@(MLSB (SFP fptr)) = BSI.PS (castForeignPtr fptr) 0 size where - size :: Int + size :: Int size = fromIntegral (mlsbSize mlsb) -- | /Note:/ this function will leak mlocked memory to the Haskell heap @@ -234,7 +245,7 @@ mlsbToByteString mlsb = withMLSB mlsb $ \ptr -> stToIO . unsafeIOToST $ BS.packCStringLen (castPtr ptr, size) where - size :: Int + size :: Int size = fromIntegral (mlsbSize mlsb) -- | Use an 'MLockedSizedBytes' value as a raw C pointer. Care should be taken @@ -249,18 +260,18 @@ mlsbUseAsCPtr (MLSB x) k = -- should be taken to never copy the contents of the 'MLockedSizedBytes' value -- into managed memory through the sized pointer, because that would violate -- the secure-forgetting property of mlocked memory. -mlsbUseAsSizedPtr :: forall n r m. (MonadST m) => MLockedSizedBytes n -> (SizedPtr n -> m r) -> m r +mlsbUseAsSizedPtr :: forall n r m. MonadST m => MLockedSizedBytes n -> (SizedPtr n -> m r) -> m r mlsbUseAsSizedPtr (MLSB x) k = withMLockedForeignPtr x (k . SizedPtr . castPtr) -- | Calls 'finalizeMLockedForeignPtr' on underlying pointer. -- This function invalidates argument. --- mlsbFinalize :: MonadST m => MLockedSizedBytes n -> m () mlsbFinalize (MLSB ptr) = finalizeMLockedForeignPtr ptr -- | 'compareM' on 'MLockedSizedBytes' -mlsbCompare :: forall n m. (MonadST m, KnownNat n) => MLockedSizedBytes n -> MLockedSizedBytes n -> m Ordering +mlsbCompare :: + forall n m. (MonadST m, KnownNat n) => MLockedSizedBytes n -> MLockedSizedBytes n -> m Ordering mlsbCompare (MLSB x) (MLSB y) = withMLockedForeignPtr x $ \x' -> withMLockedForeignPtr y $ \y' -> do @@ -270,5 +281,6 @@ mlsbCompare (MLSB x) (MLSB y) = size = fromInteger $ natVal (Proxy @n) -- | 'equalsM' on 'MLockedSizedBytes' -mlsbEq :: forall n m. (MonadST m, KnownNat n) => MLockedSizedBytes n -> MLockedSizedBytes n -> m Bool +mlsbEq :: + forall n m. (MonadST m, KnownNat n) => MLockedSizedBytes n -> MLockedSizedBytes n -> m Bool mlsbEq a b = (== EQ) <$> mlsbCompare a b diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedSeed.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedSeed.hs index 7dab9880f..c2afa248a 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedSeed.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/MLockedSeed.hs @@ -9,6 +9,9 @@ module Cardano.Crypto.Libsodium.MLockedSeed where import Cardano.Crypto.DirectSerialise +import Cardano.Crypto.Libsodium.C ( + c_sodium_randombytes_buf, + ) import Cardano.Crypto.Libsodium.MLockedBytes ( MLockedSizedBytes, mlsbCopyWith, @@ -22,9 +25,6 @@ import Cardano.Crypto.Libsodium.Memory ( MLockedAllocator, mlockedMalloc, ) -import Cardano.Crypto.Libsodium.C ( - c_sodium_randombytes_buf, - ) import Cardano.Foreign (SizedPtr) import Control.DeepSeq (NFData) import Control.Monad.Class.MonadST (MonadST) @@ -52,22 +52,22 @@ instance KnownNat n => DirectDeserialise (MLockedSeed n) where pull (castPtr ptr) (fromIntegral $ natVal seed) return seed -withMLockedSeedAsMLSB - :: Functor m - => (MLockedSizedBytes n -> m (MLockedSizedBytes n)) - -> MLockedSeed n - -> m (MLockedSeed n) +withMLockedSeedAsMLSB :: + Functor m => + (MLockedSizedBytes n -> m (MLockedSizedBytes n)) -> + MLockedSeed n -> + m (MLockedSeed n) withMLockedSeedAsMLSB action = fmap MLockedSeed . action . mlockedSeedMLSB mlockedSeedCopy :: (KnownNat n, MonadST m) => MLockedSeed n -> m (MLockedSeed n) mlockedSeedCopy = mlockedSeedCopyWith mlockedMalloc -mlockedSeedCopyWith - :: (KnownNat n, MonadST m) - => MLockedAllocator m - -> MLockedSeed n - -> m (MLockedSeed n) +mlockedSeedCopyWith :: + (KnownNat n, MonadST m) => + MLockedAllocator m -> + MLockedSeed n -> + m (MLockedSeed n) mlockedSeedCopyWith allocator = withMLockedSeedAsMLSB (mlsbCopyWith allocator) mlockedSeedNew :: (KnownNat n, MonadST m) => m (MLockedSeed n) @@ -84,10 +84,10 @@ mlockedSeedNewZeroWith :: (KnownNat n, MonadST m) => MLockedAllocator m -> m (ML mlockedSeedNewZeroWith allocator = MLockedSeed <$> mlsbNewZeroWith allocator -mlockedSeedNewRandom :: forall n. (KnownNat n) => IO (MLockedSeed n) +mlockedSeedNewRandom :: forall n. KnownNat n => IO (MLockedSeed n) mlockedSeedNewRandom = mlockedSeedNewRandomWith mlockedMalloc -mlockedSeedNewRandomWith :: forall n. (KnownNat n) => MLockedAllocator IO -> IO (MLockedSeed n) +mlockedSeedNewRandomWith :: forall n. KnownNat n => MLockedAllocator IO -> IO (MLockedSeed n) mlockedSeedNewRandomWith allocator = do mls <- MLockedSeed <$> mlsbNewZeroWith allocator mlockedSeedUseAsCPtr mls $ \dst -> do @@ -96,11 +96,11 @@ mlockedSeedNewRandomWith allocator = do where size = fromIntegral $ natVal (Proxy @n) -mlockedSeedFinalize :: (MonadST m) => MLockedSeed n -> m () +mlockedSeedFinalize :: MonadST m => MLockedSeed n -> m () mlockedSeedFinalize = mlsbFinalize . mlockedSeedMLSB -mlockedSeedUseAsCPtr :: (MonadST m) => MLockedSeed n -> (Ptr Word8 -> m b) -> m b +mlockedSeedUseAsCPtr :: MonadST m => MLockedSeed n -> (Ptr Word8 -> m b) -> m b mlockedSeedUseAsCPtr seed = mlsbUseAsCPtr (mlockedSeedMLSB seed) -mlockedSeedUseAsSizedPtr :: (MonadST m) => MLockedSeed n -> (SizedPtr n -> m b) -> m b +mlockedSeedUseAsSizedPtr :: MonadST m => MLockedSeed n -> (SizedPtr n -> m b) -> m b mlockedSeedUseAsSizedPtr seed = mlsbUseAsSizedPtr (mlockedSeedMLSB seed) diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Memory.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Memory.hs index cd927cb42..acf46e320 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Memory.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Memory.hs @@ -8,7 +8,6 @@ module Cardano.Crypto.Libsodium.Memory ( -- * MLocked allocations mlockedMalloc, MLockedAllocator (..), - mlockedAlloca, mlockedAllocaSized, mlockedAllocForeignPtr, diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Memory/Internal.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Memory/Internal.hs index 345a18342..57653019a 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Memory/Internal.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/Memory/Internal.hs @@ -6,6 +6,7 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} + module Cardano.Crypto.Libsodium.Memory.Internal ( -- * High-level memory management MLockedForeignPtr (..), @@ -16,7 +17,6 @@ module Cardano.Crypto.Libsodium.Memory.Internal ( -- * MLocked allocations mlockedMalloc, MLockedAllocator (..), - mlockedAlloca, mlockedAllocaSized, mlockedAllocForeignPtr, @@ -43,21 +43,22 @@ module Cardano.Crypto.Libsodium.Memory.Internal ( packByteStringCStringLen, -- * Helper - unsafeIOToMonadST + unsafeIOToMonadST, ) where import Control.DeepSeq (NFData (..), rwhnf) import Control.Exception (Exception, mask_) -import Control.Monad (when, void) +import Control.Monad (void, when) import Control.Monad.Class.MonadST (MonadST, stToIO) import Control.Monad.Class.MonadThrow (MonadThrow (bracket)) -import Control.Monad.ST (RealWorld, ST) import Control.Monad.Primitive (touch) +import Control.Monad.ST (RealWorld, ST) import Control.Monad.ST.Unsafe (unsafeIOToST) import Data.ByteString (ByteString) import qualified Data.ByteString as BS import qualified Data.ByteString.Unsafe as BS import Data.Coerce (coerce) +import Data.Kind import Data.Typeable import Debug.Trace (traceShowM) import Foreign.C.Error (errnoToIOError, getErrno) @@ -65,24 +66,23 @@ import Foreign.C.String (CStringLen) import Foreign.C.Types (CSize (..)) import qualified Foreign.Concurrent as Foreign import qualified Foreign.ForeignPtr as Foreign hiding (newForeignPtr) -import qualified Foreign.ForeignPtr.Unsafe as Foreign import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr) +import qualified Foreign.ForeignPtr.Unsafe as Foreign import Foreign.Marshal.Utils (fillBytes) -import Foreign.Ptr (Ptr, nullPtr, castPtr) -import Foreign.Storable (Storable (peek), sizeOf, alignment) +import Foreign.Ptr (Ptr, castPtr, nullPtr) +import Foreign.Storable (Storable (peek), alignment, sizeOf) import GHC.IO.Exception (ioException) import GHC.TypeLits (KnownNat, natVal) import NoThunks.Class (NoThunks, OnlyCheckWhnfNamed (..)) import System.IO.Unsafe (unsafePerformIO) -import Data.Kind import Cardano.Crypto.Libsodium.C -import Cardano.Foreign (c_memset, c_memcpy, SizedPtr (..)) -import Cardano.Memory.Pool (initPool, grabNextBlock, Pool) +import Cardano.Foreign (SizedPtr (..), c_memcpy, c_memset) +import Cardano.Memory.Pool (Pool, grabNextBlock, initPool) -- | Foreign pointer to securely allocated memory. -newtype MLockedForeignPtr a = SFP { _unwrapMLockedForeignPtr :: Foreign.ForeignPtr a } - deriving NoThunks via OnlyCheckWhnfNamed "MLockedForeignPtr" (MLockedForeignPtr a) +newtype MLockedForeignPtr a = SFP {_unwrapMLockedForeignPtr :: Foreign.ForeignPtr a} + deriving (NoThunks) via OnlyCheckWhnfNamed "MLockedForeignPtr" (MLockedForeignPtr a) instance NFData (MLockedForeignPtr a) where rnf = rwhnf . _unwrapMLockedForeignPtr @@ -97,11 +97,10 @@ finalizeMLockedForeignPtr (SFP fptr) = unsafeIOToMonadST $ Foreign.finalizeForeignPtr fptr {-# WARNING traceMLockedForeignPtr "Do not use traceMLockedForeignPtr in production" #-} - traceMLockedForeignPtr :: (Storable a, Show a, MonadST m) => MLockedForeignPtr a -> m () traceMLockedForeignPtr fptr = withMLockedForeignPtr fptr $ \ptr -> do - a <- unsafeIOToMonadST (peek ptr) - traceShowM a + a <- unsafeIOToMonadST (peek ptr) + traceShowM a unsafeIOToMonadST :: MonadST m => IO a -> m a unsafeIOToMonadST = stToIO . unsafeIOToST @@ -110,12 +109,12 @@ makeMLockedPool :: forall n s. KnownNat n => ST s (Pool n s) makeMLockedPool = do initPool (max 1 . fromIntegral $ 4096 `div` natVal (Proxy @n) `div` 64) - (\size -> unsafeIOToST $ mask_ $ do - ptr <- sodiumMalloc (fromIntegral size) - Foreign.newForeignPtr ptr (sodiumFree ptr (fromIntegral size)) + ( \size -> unsafeIOToST $ mask_ $ do + ptr <- sodiumMalloc (fromIntegral size) + Foreign.newForeignPtr ptr (sodiumFree ptr (fromIntegral size)) ) - (\ptr -> do - eraseMem (Proxy @n) ptr + ( \ptr -> do + eraseMem (Proxy @n) ptr ) eraseMem :: forall n a. KnownNat n => Proxy n -> Ptr a -> IO () @@ -141,46 +140,47 @@ mlockedPool512 :: Pool 512 RealWorld mlockedPool512 = unsafePerformIO $ stToIO makeMLockedPool {-# NOINLINE mlockedPool512 #-} -data AllocatorException = - AllocatorNoTracer +data AllocatorException + = AllocatorNoTracer | AllocatorNoGenerator - deriving Show + deriving (Show) instance Exception AllocatorException mlockedMalloc :: MonadST m => MLockedAllocator m mlockedMalloc = - MLockedAllocator { mlAllocate = unsafeIOToMonadST . mlockedMallocIO } + MLockedAllocator {mlAllocate = unsafeIOToMonadST . mlockedMallocIO} mlockedMallocIO :: CSize -> IO (MLockedForeignPtr a) -mlockedMallocIO size = SFP <$> do - if - | size <= 32 -> do - fmap coerce $ stToIO $ grabNextBlock mlockedPool32 - | size <= 64 -> do - fmap coerce $ stToIO $ grabNextBlock mlockedPool64 - | size <= 128 -> do - fmap coerce $ stToIO $ grabNextBlock mlockedPool128 - | size <= 256 -> do - fmap coerce $ stToIO $ grabNextBlock mlockedPool256 - | size <= 512 -> do - fmap coerce $ stToIO $ grabNextBlock mlockedPool512 - | otherwise -> do - mask_ $ do - ptr <- sodiumMalloc size - Foreign.newForeignPtr ptr $ do - sodiumFree ptr size +mlockedMallocIO size = + SFP <$> do + if + | size <= 32 -> do + fmap coerce $ stToIO $ grabNextBlock mlockedPool32 + | size <= 64 -> do + fmap coerce $ stToIO $ grabNextBlock mlockedPool64 + | size <= 128 -> do + fmap coerce $ stToIO $ grabNextBlock mlockedPool128 + | size <= 256 -> do + fmap coerce $ stToIO $ grabNextBlock mlockedPool256 + | size <= 512 -> do + fmap coerce $ stToIO $ grabNextBlock mlockedPool512 + | otherwise -> do + mask_ $ do + ptr <- sodiumMalloc size + Foreign.newForeignPtr ptr $ do + sodiumFree ptr size sodiumMalloc :: CSize -> IO (Ptr a) sodiumMalloc size = do ptr <- c_sodium_malloc size when (ptr == nullPtr) $ do - errno <- getErrno - ioException $ errnoToIOError "c_sodium_malloc" errno Nothing Nothing + errno <- getErrno + ioException $ errnoToIOError "c_sodium_malloc" errno Nothing Nothing res <- c_sodium_mlock ptr size when (res /= 0) $ do - errno <- getErrno - ioException $ errnoToIOError "c_sodium_mlock" errno Nothing Nothing + errno <- getErrno + ioException $ errnoToIOError "c_sodium_mlock" errno Nothing Nothing return ptr sodiumFree :: Ptr a -> CSize -> IO () @@ -200,16 +200,16 @@ copyMem dst src size = unsafeIOToMonadST . void $ c_memcpy (castPtr dst) (castPt -- | A 'ForeignPtr' type, generalized to 'MonadST'. The type is tagged with -- the correct Monad @m@ in order to ensure that foreign pointers created in -- one ST context can only be used within the same ST context. -newtype ForeignPtr (m :: Type -> Type) a = ForeignPtr { unsafeRawForeignPtr :: Foreign.ForeignPtr a } +newtype ForeignPtr (m :: Type -> Type) a = ForeignPtr {unsafeRawForeignPtr :: Foreign.ForeignPtr a} -mallocForeignPtrBytes :: (MonadST m) => Int -> m (ForeignPtr m a) +mallocForeignPtrBytes :: MonadST m => Int -> m (ForeignPtr m a) mallocForeignPtrBytes size = ForeignPtr <$> unsafeIOToMonadST (Foreign.mallocForeignPtrBytes size) -- | 'Foreign.withForeignPtr', generalized to 'MonadST'. -- Caveat: if the monadic action passed to 'withForeignPtr' does not terminate -- (e.g., 'forever'), the 'ForeignPtr' finalizer may run prematurely. -withForeignPtr :: (MonadST m) => ForeignPtr m a -> (Ptr a -> m b) -> m b +withForeignPtr :: MonadST m => ForeignPtr m a -> (Ptr a -> m b) -> m b withForeignPtr (ForeignPtr fptr) f = do result <- f $ Foreign.unsafeForeignPtrToPtr fptr stToIO $ touch fptr @@ -234,20 +234,23 @@ packByteStringCStringLen :: MonadST m => CStringLen -> m ByteString packByteStringCStringLen = unsafeIOToMonadST . BS.packCStringLen -newtype MLockedAllocator m = - MLockedAllocator - { mlAllocate :: forall a. CSize -> m (MLockedForeignPtr a) - } +newtype MLockedAllocator m + = MLockedAllocator + { mlAllocate :: forall a. CSize -> m (MLockedForeignPtr a) + } -mlockedAllocaSized :: forall m n b. (MonadST m, MonadThrow m, KnownNat n) => (SizedPtr n -> m b) -> m b +mlockedAllocaSized :: + forall m n b. (MonadST m, MonadThrow m, KnownNat n) => (SizedPtr n -> m b) -> m b mlockedAllocaSized = mlockedAllocaSizedWith mlockedMalloc mlockedAllocaSizedWith :: - forall m n b. (MonadST m, MonadThrow m, KnownNat n) - => MLockedAllocator m - -> (SizedPtr n -> m b) - -> m b -mlockedAllocaSizedWith allocator k = mlockedAllocaWith allocator size (k . SizedPtr) where + forall m n b. + (MonadST m, MonadThrow m, KnownNat n) => + MLockedAllocator m -> + (SizedPtr n -> m b) -> + m b +mlockedAllocaSizedWith allocator k = mlockedAllocaWith allocator size (k . SizedPtr) + where size :: CSize size = fromInteger (natVal (Proxy @n)) @@ -262,18 +265,19 @@ mlockedAllocForeignPtrBytesWith allocator size align = do where size' :: CSize size' - | m == 0 = size - | otherwise = (q + 1) * align + | m == 0 = size + | otherwise = (q + 1) * align where - (q,m) = size `quotRem` align + (q, m) = size `quotRem` align -mlockedAllocForeignPtr :: forall a m . (MonadST m, Storable a) => m (MLockedForeignPtr a) +mlockedAllocForeignPtr :: forall a m. (MonadST m, Storable a) => m (MLockedForeignPtr a) mlockedAllocForeignPtr = mlockedAllocForeignPtrWith mlockedMalloc mlockedAllocForeignPtrWith :: - forall a m. Storable a - => MLockedAllocator m - -> m (MLockedForeignPtr a) + forall a m. + Storable a => + MLockedAllocator m -> + m (MLockedForeignPtr a) mlockedAllocForeignPtrWith allocator = mlockedAllocForeignPtrBytesWith allocator size align where @@ -290,11 +294,12 @@ mlockedAlloca :: forall a b m. (MonadST m, MonadThrow m) => CSize -> (Ptr a -> m mlockedAlloca = mlockedAllocaWith mlockedMalloc mlockedAllocaWith :: - forall a b m. (MonadThrow m, MonadST m) - => MLockedAllocator m - -> CSize - -> (Ptr a -> m b) - -> m b + forall a b m. + (MonadThrow m, MonadST m) => + MLockedAllocator m -> + CSize -> + (Ptr a -> m b) -> + m b mlockedAllocaWith allocator size = bracket alloc finalizeMLockedForeignPtr . flip withMLockedForeignPtr where diff --git a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/UnsafeC.hs b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/UnsafeC.hs index 05e195c43..eb7d3816a 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Libsodium/UnsafeC.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Libsodium/UnsafeC.hs @@ -1,10 +1,12 @@ -{-# LANGUAGE CApiFFI #-} +{-# LANGUAGE CApiFFI #-} + module Cardano.Crypto.Libsodium.UnsafeC ( - c_sodium_compare_unsafe, - ) where + c_sodium_compare_unsafe, +) where import Foreign.C.Types (CSize (..)) import Foreign.Ptr (Ptr) -- | Unsafe variant of 'c_sodium_compare'. -foreign import capi unsafe "sodium.h sodium_compare" c_sodium_compare_unsafe :: Ptr a -> Ptr a -> CSize -> IO Int +foreign import capi unsafe "sodium.h sodium_compare" + c_sodium_compare_unsafe :: Ptr a -> Ptr a -> CSize -> IO Int diff --git a/cardano-crypto-class/src/Cardano/Crypto/PackedBytes.hs b/cardano-crypto-class/src/Cardano/Crypto/PackedBytes.hs index 42e555072..e7cf0300b 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/PackedBytes.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/PackedBytes.hs @@ -11,6 +11,7 @@ {-# LANGUAGE TypeFamilyDependencies #-} {-# LANGUAGE UnboxedTuples #-} +{- FOURMOLU_DISABLE -} module Cardano.Crypto.PackedBytes ( PackedBytes(..) , packBytes diff --git a/cardano-crypto-class/src/Cardano/Crypto/PinnedSizedBytes.hs b/cardano-crypto-class/src/Cardano/Crypto/PinnedSizedBytes.hs index 6f840c596..52826164a 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/PinnedSizedBytes.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/PinnedSizedBytes.hs @@ -1,56 +1,59 @@ -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DerivingVia #-} -{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DerivingVia #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE KindSignatures #-} -{-# LANGUAGE MagicHash #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE UnboxedTuples #-} -{-# LANGUAGE QuasiQuotes #-} -{-# LANGUAGE TemplateHaskellQuotes #-} -module Cardano.Crypto.PinnedSizedBytes - ( - PinnedSizedBytes, - -- * Initialization - psbZero, - -- * Conversions - psbFromBytes, - psbToBytes, - psbFromByteString, - psbFromByteStringCheck, - psbToByteString, - -- * C usage - psbUseAsCPtr, - psbUseAsCPtrLen, - psbUseAsSizedPtr, - psbCreate, - psbCreateLen, - psbCreateSized, - psbCreateResult, - psbCreateResultLen, - psbCreateSizedResult, - ptrPsbToSizedPtr, - ) where +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE MagicHash #-} +{-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskellQuotes #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE UnboxedTuples #-} + +module Cardano.Crypto.PinnedSizedBytes ( + PinnedSizedBytes, + + -- * Initialization + psbZero, + + -- * Conversions + psbFromBytes, + psbToBytes, + psbFromByteString, + psbFromByteStringCheck, + psbToByteString, + + -- * C usage + psbUseAsCPtr, + psbUseAsCPtrLen, + psbUseAsSizedPtr, + psbCreate, + psbCreateLen, + psbCreateSized, + psbCreateResult, + psbCreateResultLen, + psbCreateSizedResult, + ptrPsbToSizedPtr, +) where -import Data.Kind (Type) import Control.DeepSeq (NFData) +import Control.Monad.Class.MonadST (MonadST, stToIO) +import Control.Monad.Primitive (primitive_, touch) import Control.Monad.ST (runST) import Control.Monad.ST.Unsafe (unsafeIOToST) -import Control.Monad.Class.MonadST (MonadST, stToIO) -import Control.Monad.Primitive (primitive_, touch) -import Data.Primitive.ByteArray - ( ByteArray (..) - , MutableByteArray (..) - , copyByteArrayToAddr - , newPinnedByteArray - , unsafeFreezeByteArray - , foldrByteArray - , byteArrayContents - , writeByteArray - , mutableByteArrayContents - ) +import Data.Kind (Type) +import Data.Primitive.ByteArray ( + ByteArray (..), + MutableByteArray (..), + byteArrayContents, + copyByteArrayToAddr, + foldrByteArray, + mutableByteArrayContents, + newPinnedByteArray, + unsafeFreezeByteArray, + writeByteArray, + ) import Data.Proxy (Proxy (..)) import Data.String (IsString (..)) import Data.Word (Word8) @@ -58,21 +61,21 @@ import Foreign.C.Types (CSize) import Foreign.Ptr (FunPtr, castPtr) import Foreign.Storable (Storable (..)) import GHC.TypeLits (KnownNat, Nat, natVal) +import Language.Haskell.TH.Syntax (Q, TExp (..)) +import Language.Haskell.TH.Syntax.Compat (Code (..), examineSplice) import NoThunks.Class (NoThunks, OnlyCheckWhnfNamed (..)) -import Language.Haskell.TH.Syntax (Q, TExp(..)) -import Language.Haskell.TH.Syntax.Compat (Code(..), examineSplice) import Numeric (showHex) import System.IO.Unsafe (unsafeDupablePerformIO) import GHC.Exts (Int (..), copyAddrToByteArray#) import GHC.Ptr (Ptr (..)) -import qualified Data.Primitive as Prim import qualified Data.ByteString as BS +import qualified Data.Primitive as Prim -import Cardano.Foreign import Cardano.Crypto.Libsodium.C (c_sodium_compare) import Cardano.Crypto.Util (decodeHexString) +import Cardano.Foreign {- HLINT ignore "Reduce duplication" -} @@ -91,36 +94,35 @@ import Cardano.Crypto.Util (decodeHexString) -- 'ForeignPtr' + offset (and size). -- -- I'm sorry for adding more types for bytes. :( --- newtype PinnedSizedBytes (n :: Nat) = PSB ByteArray - deriving NoThunks via OnlyCheckWhnfNamed "PinnedSizedBytes" (PinnedSizedBytes n) - deriving NFData + deriving (NoThunks) via OnlyCheckWhnfNamed "PinnedSizedBytes" (PinnedSizedBytes n) + deriving (NFData) instance Show (PinnedSizedBytes n) where - showsPrec _ (PSB ba) - = showChar '"' - . foldrByteArray (\w acc -> show8 w . acc) id ba - . showChar '"' - where - show8 :: Word8 -> ShowS - show8 w | w < 16 = showChar '0' . showHex w - | otherwise = showHex w + showsPrec _ (PSB ba) = + showChar '"' + . foldrByteArray (\w acc -> show8 w . acc) id ba + . showChar '"' + where + show8 :: Word8 -> ShowS + show8 w + | w < 16 = showChar '0' . showHex w + | otherwise = showHex w -- | The comparison is done in constant time for a given size @n@. instance KnownNat n => Eq (PinnedSizedBytes n) where - x == y = compare x y == EQ + x == y = compare x y == EQ instance KnownNat n => Ord (PinnedSizedBytes n) where - compare x y = - runST $ - psbUseAsCPtr x $ \xPtr -> - psbUseAsCPtr y $ \yPtr -> do - res <- unsafeIOToST $ c_sodium_compare xPtr yPtr size - return (compare res 0) - where - size :: CSize - size = fromInteger (natVal (Proxy :: Proxy n)) - + compare x y = + runST $ + psbUseAsCPtr x $ \xPtr -> + psbUseAsCPtr y $ \yPtr -> do + res <- unsafeIOToST $ c_sodium_compare xPtr yPtr size + return (compare res 0) + where + size :: CSize + size = fromInteger (natVal (Proxy :: Proxy n)) -- | This instance is meant to be used with @TemplateHaskell@ -- @@ -146,11 +148,11 @@ instance KnownNat n => Ord (PinnedSizedBytes n) where -- In the expression: $$("nogood") :: PinnedSizedBytes 5 -- In an equation for ‘bsb’: bsb = $$("nogood") :: PinnedSizedBytes 5 instance KnownNat n => IsString (Q (TExp (PinnedSizedBytes n))) where - fromString hexStr = do - let n = fromInteger $ natVal (Proxy :: Proxy n) - case decodeHexString hexStr n of - Left err -> fail $ ": " ++ err - Right _ -> examineSplice [|| either error psbFromByteString (decodeHexString hexStr n) ||] + fromString hexStr = do + let n = fromInteger $ natVal (Proxy :: Proxy n) + case decodeHexString hexStr n of + Left err -> fail $ ": " ++ err + Right _ -> examineSplice [||either error psbFromByteString (decodeHexString hexStr n)||] instance KnownNat n => IsString (Code Q (PinnedSizedBytes n)) where fromString = Code . fromString @@ -172,7 +174,6 @@ psbToByteString = BS.pack . psbToBytes -- -- >>> psbToBytes . (id @(PinnedSizedBytes 4)) . psbFromBytes $ [1,2,3,4,5,6] -- [3,4,5,6] --- {-# DEPRECATED psbFromBytes "This is not referentially transparent" #-} psbFromBytes :: forall n. KnownNat n => [Word8] -> PinnedSizedBytes n psbFromBytes ws0 = PSB (pinnedByteArrayFromListN size ws) @@ -181,10 +182,11 @@ psbFromBytes ws0 = PSB (pinnedByteArrayFromListN size ws) size = fromInteger (natVal (Proxy :: Proxy n)) ws :: [Word8] - ws = reverse - $ take size - $ (++ repeat 0) - $ reverse ws0 + ws = + reverse $ + take size $ + (++ repeat 0) $ + reverse ws0 -- | Convert a ByteString into PinnedSizedBytes. Input should contain the exact -- number of bytes as expected by type level @n@ size, otherwise error. @@ -196,37 +198,38 @@ psbFromByteString bs = psbFromByteStringCheck :: forall n. KnownNat n => BS.ByteString -> Maybe (PinnedSizedBytes n) psbFromByteStringCheck bs - | BS.length bs == size = Just $ unsafeDupablePerformIO $ + | BS.length bs == size = Just $ + unsafeDupablePerformIO $ BS.useAsCStringLen bs $ \(Ptr addr#, _) -> do - marr@(MutableByteArray marr#) <- newPinnedByteArray size - primitive_ $ copyAddrToByteArray# addr# marr# 0# (case size of I# s -> s) - arr <- unsafeFreezeByteArray marr - return (PSB arr) - | otherwise = Nothing + marr@(MutableByteArray marr#) <- newPinnedByteArray size + primitive_ $ copyAddrToByteArray# addr# marr# 0# (case size of I# s -> s) + arr <- unsafeFreezeByteArray marr + return (PSB arr) + | otherwise = Nothing where size :: Int size = fromInteger (natVal (Proxy :: Proxy n)) {-# DEPRECATED psbZero "This is not referentially transparent" #-} -psbZero :: KnownNat n => PinnedSizedBytes n +psbZero :: KnownNat n => PinnedSizedBytes n psbZero = psbFromBytes [] instance KnownNat n => Storable (PinnedSizedBytes n) where - sizeOf _ = fromInteger (natVal (Proxy :: Proxy n)) - alignment _ = alignment (undefined :: FunPtr (Int -> Int)) - - peek (Ptr addr#) = do - let size :: Int - size = fromInteger (natVal (Proxy :: Proxy n)) - marr@(MutableByteArray marr#) <- newPinnedByteArray size - primitive_ $ copyAddrToByteArray# addr# marr# 0# (case size of I# s -> s) - arr <- unsafeFreezeByteArray marr - return (PSB arr) - - poke p (PSB arr) = do - let size :: Int - size = fromInteger (natVal (Proxy :: Proxy n)) - copyByteArrayToAddr (castPtr p) arr 0 size + sizeOf _ = fromInteger (natVal (Proxy :: Proxy n)) + alignment _ = alignment (undefined :: FunPtr (Int -> Int)) + + peek (Ptr addr#) = do + let size :: Int + size = fromInteger (natVal (Proxy :: Proxy n)) + marr@(MutableByteArray marr#) <- newPinnedByteArray size + primitive_ $ copyAddrToByteArray# addr# marr# 0# (case size of I# s -> s) + arr <- unsafeFreezeByteArray marr + return (PSB arr) + + poke p (PSB arr) = do + let size :: Int + size = fromInteger (natVal (Proxy :: Proxy n)) + copyByteArrayToAddr (castPtr p) arr 0 size -- | Use a 'PinnedSizedBytes' in a setting where its size is \'forgotten\' -- temporarily. @@ -237,8 +240,8 @@ instance KnownNat n => Storable (PinnedSizedBytes n) where -- type @r@. {-# INLINE psbUseAsCPtr #-} psbUseAsCPtr :: - forall (n :: Nat) (r :: Type) (m :: Type -> Type) . - (MonadST m) => + forall (n :: Nat) (r :: Type) (m :: Type -> Type). + MonadST m => PinnedSizedBytes n -> (Ptr Word8 -> m r) -> m r @@ -260,7 +263,7 @@ psbUseAsCPtr (PSB ba) = runAndTouch ba -- 'psbUseAsCPtr'. {-# INLINE psbUseAsCPtrLen #-} psbUseAsCPtrLen :: - forall (n :: Nat) (r :: Type) (m :: Type -> Type) . + forall (n :: Nat) (r :: Type) (m :: Type -> Type). (KnownNat n, MonadST m) => PinnedSizedBytes n -> (Ptr Word8 -> CSize -> m r) -> @@ -273,22 +276,22 @@ psbUseAsCPtrLen (PSB ba) f = do -- -- The same caveats apply to this use of this function as to the use of -- 'psbUseAsCPtr'. -{-# INLINE psbUseAsSizedPtr #-} +{-# INLINE psbUseAsSizedPtr #-} psbUseAsSizedPtr :: - forall (n :: Nat) (r :: Type) (m :: Type -> Type) . - (MonadST m) => + forall (n :: Nat) (r :: Type) (m :: Type -> Type). + MonadST m => PinnedSizedBytes n -> (SizedPtr n -> m r) -> m r psbUseAsSizedPtr (PSB ba) k = do - r <- k (SizedPtr $ castPtr $ byteArrayContents ba) - r <$ stToIO (touch ba) + r <- k (SizedPtr $ castPtr $ byteArrayContents ba) + r <$ stToIO (touch ba) -- | As 'psbCreateResult', but presumes that no useful value is produced: that -- is, the function argument is run only for its side effects. -{-# INLINE psbCreate #-} +{-# INLINE psbCreate #-} psbCreate :: - forall (n :: Nat) (m :: Type -> Type) . + forall (n :: Nat) (m :: Type -> Type). (KnownNat n, MonadST m) => (Ptr Word8 -> m ()) -> m (PinnedSizedBytes n) @@ -296,9 +299,9 @@ psbCreate f = fst <$> psbCreateResult f -- | As 'psbCreateResultLen', but presumes that no useful value is produced: -- that is, the function argument is run only for its side effects. -{-# INLINE psbCreateLen #-} +{-# INLINE psbCreateLen #-} psbCreateLen :: - forall (n :: Nat) (m :: Type -> Type) . + forall (n :: Nat) (m :: Type -> Type). (KnownNat n, MonadST m) => (Ptr Word8 -> CSize -> m ()) -> m (PinnedSizedBytes n) @@ -319,9 +322,9 @@ psbCreateLen f = fst <$> psbCreateResultLen f -- which can lead to segfaults or out-of-bounds reads. -- -- This poses both correctness /and/ security risks, so please don't do it. -{-# INLINE psbCreateResult #-} +{-# INLINE psbCreateResult #-} psbCreateResult :: - forall (n :: Nat) (r :: Type) (m :: Type -> Type) . + forall (n :: Nat) (r :: Type) (m :: Type -> Type). (KnownNat n, MonadST m) => (Ptr Word8 -> m r) -> m (PinnedSizedBytes n, r) @@ -339,7 +342,7 @@ psbCreateResult f = psbCreateResultLen (\p _ -> f p) -- -- The same caveats apply to this function as to 'psbCreateResult': the 'Ptr' -- given to the function argument /must not/ be returned as @r@. -{-# INLINE psbCreateResultLen #-} +{-# INLINE psbCreateResultLen #-} psbCreateResultLen :: forall (n :: Nat) (r :: Type) (m :: Type -> Type). (KnownNat n, MonadST m) => @@ -354,9 +357,9 @@ psbCreateResultLen f = do -- | As 'psbCreateSizedResult', but presumes that no useful value is produced: -- that is, the function argument is run only for its side effects. -{-# INLINE psbCreateSized #-} +{-# INLINE psbCreateSized #-} psbCreateSized :: - forall (n :: Nat) (m :: Type -> Type) . + forall (n :: Nat) (m :: Type -> Type). (KnownNat n, MonadST m) => (SizedPtr n -> m ()) -> m (PinnedSizedBytes n) @@ -365,9 +368,9 @@ psbCreateSized k = psbCreate (k . SizedPtr . castPtr) -- | As 'psbCreateResult', but gives a 'SizedPtr' to the function argument. The -- same caveats apply to this function as to 'psbCreateResult': the 'SizedPtr' -- given to the function argument /must not/ be resulted as @r@. -{-# INLINE psbCreateSizedResult #-} +{-# INLINE psbCreateSizedResult #-} psbCreateSizedResult :: - forall (n :: Nat) (r :: Type) (m :: Type -> Type) . + forall (n :: Nat) (r :: Type) (m :: Type -> Type). (KnownNat n, MonadST m) => (SizedPtr n -> m r) -> m (PinnedSizedBytes n, r) @@ -385,31 +388,33 @@ ptrPsbToSizedPtr = SizedPtr . castPtr -- then this throws an exception. pinnedByteArrayFromListN :: forall a. Prim.Prim a => Int -> [a] -> ByteArray pinnedByteArrayFromListN 0 _ = - die "pinnedByteArrayFromListN" "list length zero #1" + die "pinnedByteArrayFromListN" "list length zero #1" pinnedByteArrayFromListN n ys = runST $ do - let headYs = case ys of - [] -> die "pinnedByteArrayFromListN" "list length zero #2" - (y:_) -> y - marr <- newPinnedByteArray (n * Prim.sizeOf headYs) - let go !ix [] = if ix == n + let headYs = case ys of + [] -> die "pinnedByteArrayFromListN" "list length zero #2" + (y : _) -> y + marr <- newPinnedByteArray (n * Prim.sizeOf headYs) + let go !ix [] = + if ix == n then return () else die "pinnedByteArrayFromListN" "list length less than specified size" - go !ix (x : xs) = if ix < n + go !ix (x : xs) = + if ix < n then do writeByteArray marr ix x go (ix + 1) xs else die "pinnedByteArrayFromListN" "list length greater than specified size" - go 0 ys - unsafeFreezeByteArray marr + go 0 ys + unsafeFreezeByteArray marr die :: String -> String -> a die fun problem = error $ "PinnedSizedBytes." ++ fun ++ ": " ++ problem -- Wrapper that combines applying a function, then touching -{-# INLINE runAndTouch #-} +{-# INLINE runAndTouch #-} runAndTouch :: - forall (a :: Type) (m :: Type -> Type) . - (MonadST m) => + forall (a :: Type) (m :: Type -> Type). + MonadST m => ByteArray -> (Ptr Word8 -> m a) -> m a diff --git a/cardano-crypto-class/src/Cardano/Crypto/SECP256K1/C.hs b/cardano-crypto-class/src/Cardano/Crypto/SECP256K1/C.hs index 4e401f332..29f9989cc 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/SECP256K1/C.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/SECP256K1/C.hs @@ -1,7 +1,7 @@ {-# LANGUAGE CApiFFI #-} +{-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE DataKinds #-} module Cardano.Crypto.SECP256K1.C ( SECP256k1Context, @@ -23,27 +23,27 @@ module Cardano.Crypto.SECP256K1.C ( secpEcdsaSignatureSerializeCompact, secpEcdsaSignatureParseCompact, secpEcPubkeyParse, - ) where +) where -import Control.Exception (mask_) -import Data.Bits ((.|.)) -import Foreign.ForeignPtr (ForeignPtr, FinalizerPtr, newForeignPtr) -import Foreign.Ptr (Ptr) -import System.IO.Unsafe (unsafePerformIO) -import Foreign.C.Types (CUChar, CSize (CSize), CInt (CInt), CUInt (CUInt)) -import Cardano.Foreign (SizedPtr (SizedPtr)) import Cardano.Crypto.SECP256K1.Constants ( + SECP256K1_ECDSA_MESSAGE_BYTES, + SECP256K1_ECDSA_PRIVKEY_BYTES, + SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL, + SECP256K1_ECDSA_SIGNATURE_BYTES, + SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL, SECP256K1_SCHNORR_KEYPAIR_BYTES, SECP256K1_SCHNORR_PRIVKEY_BYTES, - SECP256K1_SCHNORR_SIGNATURE_BYTES, - SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL, SECP256K1_SCHNORR_PUBKEY_BYTES, - SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL, - SECP256K1_ECDSA_PRIVKEY_BYTES, - SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL, - SECP256K1_ECDSA_SIGNATURE_BYTES, - SECP256K1_ECDSA_MESSAGE_BYTES, - ) + SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL, + SECP256K1_SCHNORR_SIGNATURE_BYTES, + ) +import Cardano.Foreign (SizedPtr (SizedPtr)) +import Control.Exception (mask_) +import Data.Bits ((.|.)) +import Foreign.C.Types (CInt (CInt), CSize (CSize), CUChar, CUInt (CUInt)) +import Foreign.ForeignPtr (FinalizerPtr, ForeignPtr, newForeignPtr) +import Foreign.Ptr (Ptr) +import System.IO.Unsafe (unsafePerformIO) data SECP256k1Context @@ -66,8 +66,8 @@ foreign import ccall unsafe "secp256k1.h &secp256k1_context_destroy" foreign import ccall unsafe "secp256k1.h secp256k1_context_create" secpContextCreate :: - CUInt -- flags - -> IO (Ptr SECP256k1Context) + CUInt -> -- flags + IO (Ptr SECP256k1Context) foreign import capi "secp256k1.h value SECP256K1_CONTEXT_SIGN" secpContextSign :: CUInt @@ -83,104 +83,104 @@ foreign import capi "secp256k1.h value SECP256K1_EC_COMPRESSED" foreign import ccall unsafe "secp256k1_extrakeys.h secp256k1_keypair_create" secpKeyPairCreate :: - Ptr SECP256k1Context -- context initialized for signing - -> SizedPtr SECP256K1_SCHNORR_KEYPAIR_BYTES -- out-param for keypair to initialize - -> SizedPtr SECP256K1_SCHNORR_PRIVKEY_BYTES -- secret key (32 bytes) - -> IO CInt -- 1 on success, 0 on failure + Ptr SECP256k1Context -> -- context initialized for signing + SizedPtr SECP256K1_SCHNORR_KEYPAIR_BYTES -> -- out-param for keypair to initialize + SizedPtr SECP256K1_SCHNORR_PRIVKEY_BYTES -> -- secret key (32 bytes) + IO CInt -- 1 on success, 0 on failure foreign import ccall unsafe "secp256k1_schnorrsig.h secp256k1_schnorrsig_sign_custom" secpSchnorrSigSignCustom :: - Ptr SECP256k1Context -- context initialized for signing - -> SizedPtr SECP256K1_SCHNORR_SIGNATURE_BYTES -- out-param for signature (64 bytes) - -> Ptr CUChar -- message to sign - -> CSize -- message length in bytes - -> SizedPtr SECP256K1_SCHNORR_KEYPAIR_BYTES -- initialized keypair - -> Ptr SECP256k1SchnorrExtraParams -- not used - -> IO CInt -- 1 on success, 0 on failure + Ptr SECP256k1Context -> -- context initialized for signing + SizedPtr SECP256K1_SCHNORR_SIGNATURE_BYTES -> -- out-param for signature (64 bytes) + Ptr CUChar -> -- message to sign + CSize -> -- message length in bytes + SizedPtr SECP256K1_SCHNORR_KEYPAIR_BYTES -> -- initialized keypair + Ptr SECP256k1SchnorrExtraParams -> -- not used + IO CInt -- 1 on success, 0 on failure foreign import ccall unsafe "secp256k1_extrakeys.h secp256k1_keypair_xonly_pub" secpKeyPairXOnlyPub :: - Ptr SECP256k1Context -- an initialized context - -> SizedPtr SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL -- out-param for xonly pubkey - -> Ptr CInt -- parity (not used) - -> SizedPtr SECP256K1_SCHNORR_KEYPAIR_BYTES -- keypair - -> IO CInt -- 1 on success, 0 on error + Ptr SECP256k1Context -> -- an initialized context + SizedPtr SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL -> -- out-param for xonly pubkey + Ptr CInt -> -- parity (not used) + SizedPtr SECP256K1_SCHNORR_KEYPAIR_BYTES -> -- keypair + IO CInt -- 1 on success, 0 on error foreign import ccall unsafe "secp256k1_schnorrsig.h secp256k1_schnorrsig_verify" secpSchnorrSigVerify :: - Ptr SECP256k1Context -- context initialized for verifying - -> SizedPtr SECP256K1_SCHNORR_SIGNATURE_BYTES -- signature to verify (64 bytes) - -> Ptr CUChar -- message to verify - -> CSize -- message length in bytes - -> SizedPtr SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL -- pubkey to verify with - -> CInt -- 1 on success, 0 on failure + Ptr SECP256k1Context -> -- context initialized for verifying + SizedPtr SECP256K1_SCHNORR_SIGNATURE_BYTES -> -- signature to verify (64 bytes) + Ptr CUChar -> -- message to verify + CSize -> -- message length in bytes + SizedPtr SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL -> -- pubkey to verify with + CInt -- 1 on success, 0 on failure foreign import ccall unsafe "secp256k1_extrakeys.h secp256k1_xonly_pubkey_serialize" secpXOnlyPubkeySerialize :: - Ptr SECP256k1Context -- an initialized context - -> SizedPtr SECP256K1_SCHNORR_PUBKEY_BYTES -- out-param for serialized representation - -> SizedPtr SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL -- the xonly pubkey to serialize - -> IO CInt -- 1 on success, 0 on error + Ptr SECP256k1Context -> -- an initialized context + SizedPtr SECP256K1_SCHNORR_PUBKEY_BYTES -> -- out-param for serialized representation + SizedPtr SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL -> -- the xonly pubkey to serialize + IO CInt -- 1 on success, 0 on error foreign import ccall unsafe "secp256k1_extrakeys.h secp256k1_xonly_pubkey_parse" secpXOnlyPubkeyParse :: - Ptr SECP256k1Context -- an initialized context - -> SizedPtr SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL -- out-param for deserialized representation - -> Ptr CUChar -- bytes to deserialize - -> IO CInt -- 1 if the parse succeeded, 0 if the parse failed (due to invalid representation) + Ptr SECP256k1Context -> -- an initialized context + SizedPtr SECP256K1_SCHNORR_PUBKEY_BYTES_INTERNAL -> -- out-param for deserialized representation + Ptr CUChar -> -- bytes to deserialize + IO CInt -- 1 if the parse succeeded, 0 if the parse failed (due to invalid representation) foreign import ccall unsafe "secp256k1.h secp256k1_ec_pubkey_create" secpEcPubkeyCreate :: - Ptr SECP256k1Context -- an initialized context - -> SizedPtr SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL -- out-param for generated key - -> SizedPtr SECP256K1_ECDSA_PRIVKEY_BYTES -- seed private key - -> IO CInt -- 1 on success, 0 on error + Ptr SECP256k1Context -> -- an initialized context + SizedPtr SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL -> -- out-param for generated key + SizedPtr SECP256K1_ECDSA_PRIVKEY_BYTES -> -- seed private key + IO CInt -- 1 on success, 0 on error foreign import ccall unsafe "secp256k1.h secp256k1_ecdsa_sign" secpEcdsaSign :: - Ptr SECP256k1Context -- context initialized for signing - -> SizedPtr SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL -- out-param for signature - -> SizedPtr SECP256K1_ECDSA_MESSAGE_BYTES -- pointer to hashed message data - -> SizedPtr SECP256K1_ECDSA_PRIVKEY_BYTES -- private key to sign with - -> Ptr CUChar -- pointer to a nonce (not used) - -> Ptr CUChar -- pointer to arbitrary data for nonce generation (not used) - -> IO CInt -- 1 on success, 0 on error + Ptr SECP256k1Context -> -- context initialized for signing + SizedPtr SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL -> -- out-param for signature + SizedPtr SECP256K1_ECDSA_MESSAGE_BYTES -> -- pointer to hashed message data + SizedPtr SECP256K1_ECDSA_PRIVKEY_BYTES -> -- private key to sign with + Ptr CUChar -> -- pointer to a nonce (not used) + Ptr CUChar -> -- pointer to arbitrary data for nonce generation (not used) + IO CInt -- 1 on success, 0 on error foreign import ccall unsafe "secp256k1.h secp256k1_ecdsa_verify" secpEcdsaVerify :: - Ptr SECP256k1Context -- context initialized for verification - -> SizedPtr SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL -- signature to verify - -> SizedPtr SECP256K1_ECDSA_MESSAGE_BYTES -- pointer to hashed message data - -> SizedPtr SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL -- public key to verify with - -> CInt -- 1 if valid, 0 if invalid or malformed signature + Ptr SECP256k1Context -> -- context initialized for verification + SizedPtr SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL -> -- signature to verify + SizedPtr SECP256K1_ECDSA_MESSAGE_BYTES -> -- pointer to hashed message data + SizedPtr SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL -> -- public key to verify with + CInt -- 1 if valid, 0 if invalid or malformed signature foreign import ccall unsafe "secp256k1.h secp256k1_ec_pubkey_serialize" secpEcPubkeySerialize :: - Ptr SECP256k1Context -- an initialized context - -> Ptr CUChar -- allocated buffer to write to - -> Ptr CSize -- pointer to number of bytes to write, will be overwritten with how much we actually wrote - -> SizedPtr SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL -- public key to serialize - -> CUInt -- flags (only secpEcCompressed available) - -> IO CInt -- always 1 + Ptr SECP256k1Context -> -- an initialized context + Ptr CUChar -> -- allocated buffer to write to + Ptr CSize -> -- pointer to number of bytes to write, will be overwritten with how much we actually wrote + SizedPtr SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL -> -- public key to serialize + CUInt -> -- flags (only secpEcCompressed available) + IO CInt -- always 1 foreign import ccall unsafe "secp256k1.h secp256k1_ecdsa_signature_serialize_compact" secpEcdsaSignatureSerializeCompact :: - Ptr SECP256k1Context -- an initialized context - -> SizedPtr SECP256K1_ECDSA_SIGNATURE_BYTES -- allocated buffer to write to - -> SizedPtr SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL -- signature to serialize - -> IO CInt -- always 1 + Ptr SECP256k1Context -> -- an initialized context + SizedPtr SECP256K1_ECDSA_SIGNATURE_BYTES -> -- allocated buffer to write to + SizedPtr SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL -> -- signature to serialize + IO CInt -- always 1 foreign import ccall unsafe "secp256k1.h secp256k1_ecdsa_signature_parse_compact" secpEcdsaSignatureParseCompact :: - Ptr SECP256k1Context -- an initialized context - -> SizedPtr SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL -- allocated buffer to write to - -> SizedPtr SECP256K1_ECDSA_SIGNATURE_BYTES -- signature to deserialize - -> IO CInt -- 1 if parsed successfully, 0 if parse failed + Ptr SECP256k1Context -> -- an initialized context + SizedPtr SECP256K1_ECDSA_SIGNATURE_BYTES_INTERNAL -> -- allocated buffer to write to + SizedPtr SECP256K1_ECDSA_SIGNATURE_BYTES -> -- signature to deserialize + IO CInt -- 1 if parsed successfully, 0 if parse failed foreign import ccall unsafe "secp256k1.h secp256k1_ec_pubkey_parse" secpEcPubkeyParse :: - Ptr SECP256k1Context -- an initialized context - -> SizedPtr SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL -- allocated buffer to write to - -> Ptr CUChar -- input data (must be 33 bytes long) - -> CSize -- number of bytes to read (must be 33) - -> IO CInt -- 1 if parsed successfully, 0 if parse failed + Ptr SECP256k1Context -> -- an initialized context + SizedPtr SECP256K1_ECDSA_PUBKEY_BYTES_INTERNAL -> -- allocated buffer to write to + Ptr CUChar -> -- input data (must be 33 bytes long) + CSize -> -- number of bytes to read (must be 33) + IO CInt -- 1 if parsed successfully, 0 if parse failed diff --git a/cardano-crypto-class/src/Cardano/Crypto/Seed.hs b/cardano-crypto-class/src/Cardano/Crypto/Seed.hs index 1cbc0aeb5..68eab971d 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Seed.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Seed.hs @@ -1,58 +1,55 @@ -{-# LANGUAGE RankNTypes #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE GeneralisedNewtypeDeriving #-} +{-# LANGUAGE RankNTypes #-} -- | Seeds for key generation. --- -module Cardano.Crypto.Seed - ( Seed - -- * Constructing seeds - , mkSeedFromBytes - , getSeedBytes - , readSeedFromSystemEntropy - , splitSeed - , expandSeed - -- * Using seeds - , getBytesFromSeed - , getBytesFromSeedT - , getBytesFromSeedEither - , getSeedSize - , runMonadRandomWithSeed - , SeedBytesExhausted(..) - ) where - -import Data.ByteString (ByteString) +module Cardano.Crypto.Seed ( + Seed, + + -- * Constructing seeds + mkSeedFromBytes, + getSeedBytes, + readSeedFromSystemEntropy, + splitSeed, + expandSeed, + + -- * Using seeds + getBytesFromSeed, + getBytesFromSeedT, + getBytesFromSeedEither, + getSeedSize, + runMonadRandomWithSeed, + SeedBytesExhausted (..), +) where + +import Data.ByteArray as BA (convert) +import Data.ByteString (ByteString) import qualified Data.ByteString as BS -import Data.ByteArray as BA (convert) - -import Control.DeepSeq (NFData) -import Control.Exception (Exception(..), throw) -import Data.Functor.Identity -import Data.Bifunctor (first) -import Control.Monad.Trans.Except -import Control.Monad.Trans.State -import NoThunks.Class (NoThunks) +import Control.DeepSeq (NFData) +import Control.Exception (Exception (..), throw) -import Crypto.Random (MonadRandom(..)) -import Crypto.Random.Entropy (getEntropy) -import Cardano.Crypto.Hash.Class (HashAlgorithm(digest)) +import Control.Monad.Trans.Except +import Control.Monad.Trans.State +import Data.Bifunctor (first) +import Data.Functor.Identity +import NoThunks.Class (NoThunks) +import Cardano.Crypto.Hash.Class (HashAlgorithm (digest)) +import Crypto.Random (MonadRandom (..)) +import Crypto.Random.Entropy (getEntropy) -- | A seed contains a finite number of bytes, and is used for seeding -- cryptographic algorithms including key generation. -- -- This is not itself a PRNG, but can be used to seed a PRNG. --- newtype Seed = Seed ByteString deriving (Show, Eq, Semigroup, Monoid, NoThunks, NFData) -- | Construct a 'Seed' deterministically from a number of bytes. --- mkSeedFromBytes :: ByteString -> Seed mkSeedFromBytes = Seed - -- | Extract the full bytes from a seed. Note that this function does not -- guarantee that the result is sufficiently long for the desired seed size! getSeedBytes :: Seed -> ByteString @@ -65,7 +62,6 @@ getSeedSize (Seed bs) = -- | Get a number of bytes from the seed. This will fail if not enough bytes -- are available. This can be chained multiple times provided the seed is big -- enough to cover each use. --- getBytesFromSeed :: Word -> Seed -> Maybe (ByteString, Seed) getBytesFromSeed n s = case getBytesFromSeedEither n s of @@ -74,10 +70,10 @@ getBytesFromSeed n s = getBytesFromSeedEither :: Word -> Seed -> Either SeedBytesExhausted (ByteString, Seed) getBytesFromSeedEither n (Seed s) - | n == fromIntegral (BS.length b) - = Right (b, Seed s') - | otherwise - = Left $ SeedBytesExhausted (fromIntegral $ BS.length b) (fromIntegral n) + | n == fromIntegral (BS.length b) = + Right (b, Seed s') + | otherwise = + Left $ SeedBytesExhausted (fromIntegral $ BS.length b) (fromIntegral n) where (b, s') = BS.splitAt (fromIntegral n) s @@ -91,7 +87,6 @@ getBytesFromSeedT n s = -- number of bytes large, and the second is the remaining. This will fail if -- not enough bytes are available. This can be chained multiple times provided -- the seed is big enough to cover each use. --- splitSeed :: Word -> Seed -> Maybe (Seed, Seed) splitSeed n s = first Seed <$> getBytesFromSeed n s @@ -99,16 +94,13 @@ splitSeed n s = -- | Expand a seed into a pair of seeds using a cryptographic hash function (in -- the role of a crypto PRNG). The whole input seed is consumed. The output -- seeds are the size of the hash output. --- expandSeed :: HashAlgorithm h => proxy h -> Seed -> (Seed, Seed) expandSeed p (Seed s) = - ( Seed (digest p (BS.cons 1 s)) - , Seed (digest p (BS.cons 2 s)) - ) - + ( Seed (digest p (BS.cons 1 s)) + , Seed (digest p (BS.cons 2 s)) + ) -- | Obtain a 'Seed' by reading @n@ bytes of entropy from the operating system. --- readSeedFromSystemEntropy :: Word -> IO Seed readSeedFromSystemEntropy n = mkSeedFromBytes <$> getEntropy (fromIntegral n) @@ -123,35 +115,34 @@ readSeedFromSystemEntropy n = mkSeedFromBytes <$> getEntropy (fromIntegral n) -- -- So this is only really suitable for key generation where there is a known -- upper bound on the amount of entropy that will be requested. --- runMonadRandomWithSeed :: Seed -> (forall m. MonadRandom m => m a) -> a runMonadRandomWithSeed s a = - case runIdentity (runExceptT (evalStateT (unMonadRandomFromSeed a) s)) of - Right x -> x - Left e -> throw e + case runIdentity (runExceptT (evalStateT (unMonadRandomFromSeed a) s)) of + Right x -> x + Left e -> throw e -data SeedBytesExhausted = - SeedBytesExhausted - { seedBytesSupplied :: Int - , seedBytesDemanded :: Int - } - deriving Show +data SeedBytesExhausted + = SeedBytesExhausted + { seedBytesSupplied :: Int + , seedBytesDemanded :: Int + } + deriving (Show) instance Exception SeedBytesExhausted -newtype MonadRandomFromSeed a = - MonadRandomFromSeed { - unMonadRandomFromSeed :: StateT Seed (ExceptT SeedBytesExhausted Identity) a - } +newtype MonadRandomFromSeed a + = MonadRandomFromSeed + { unMonadRandomFromSeed :: StateT Seed (ExceptT SeedBytesExhausted Identity) a + } deriving newtype (Functor, Applicative, Monad) getRandomBytesFromSeed :: Int -> MonadRandomFromSeed ByteString getRandomBytesFromSeed n = - MonadRandomFromSeed $ - StateT $ \s -> - ExceptT $ - Identity $ - getBytesFromSeedEither (fromIntegral n) s + MonadRandomFromSeed $ + StateT $ \s -> + ExceptT $ + Identity $ + getBytesFromSeedEither (fromIntegral n) s instance MonadRandom MonadRandomFromSeed where getRandomBytes n = BA.convert <$> getRandomBytesFromSeed n diff --git a/cardano-crypto-class/src/Cardano/Crypto/Util.hs b/cardano-crypto-class/src/Cardano/Crypto/Util.hs index 46a855bc7..fbe5acd22 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/Util.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/Util.hs @@ -1,56 +1,56 @@ {-# LANGUAGE BangPatterns #-} -{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE CPP #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE UnboxedTuples #-} -module Cardano.Crypto.Util - ( Empty - , SignableRepresentation(..) - , getRandomWord64 +module Cardano.Crypto.Util ( + Empty, + SignableRepresentation (..), + getRandomWord64, - -- * Simple serialisation used in mock instances - , readBinaryWord64 - , writeBinaryWord64 - , readBinaryNatural - , writeBinaryNatural - , splitsAt + -- * Simple serialisation used in mock instances + readBinaryWord64, + writeBinaryWord64, + readBinaryNatural, + writeBinaryNatural, + splitsAt, -- * Low level conversions - , bytesToNatural - , naturalToBytes + bytesToNatural, + naturalToBytes, -- * ByteString manipulation - , slice + slice, -- * Base16 conversion - , decodeHexByteString - , decodeHexString - , decodeHexStringQ - ) + decodeHexByteString, + decodeHexString, + decodeHexStringQ, +) where -import Control.Monad (unless) -import Data.Bifunctor (first) -import Data.Char (isAscii) -import Data.Word -import Numeric.Natural -import Data.Bits +import Control.Monad (unless) +import Data.Bifunctor (first) +import Data.Bits +import Data.ByteString (ByteString) import qualified Data.ByteString as BS +import Data.ByteString.Base16 as BS16 import qualified Data.ByteString.Char8 as BSC8 import qualified Data.ByteString.Internal as BS -import Data.ByteString (ByteString) -import Data.ByteString.Base16 as BS16 -import Language.Haskell.TH - -import GHC.Exts (Addr#, Int#, Word#) -import qualified GHC.Exts as GHC +import Data.Char (isAscii) +import Data.Word +import Language.Haskell.TH +import Numeric.Natural + +import Foreign.ForeignPtr (withForeignPtr) +import GHC.Exts (Addr#, Int#, Word#) +import qualified GHC.Exts as GHC import qualified GHC.Natural as GHC -import Foreign.ForeignPtr (withForeignPtr) -import Crypto.Random (MonadRandom (..)) +import Crypto.Random (MonadRandom (..)) #if __GLASGOW_HASKELL__ >= 900 -- Use the GHC version here because this is compiler dependent, and only indirectly lib dependent. @@ -64,21 +64,17 @@ import GHC.IO (unsafeDupablePerformIO) class Empty a instance Empty a - - -- -- Signable -- -- | A class of types that have a representation in bytes that can be used -- for signing and verifying. --- class SignableRepresentation a where - getSignableRepresentation :: a -> ByteString + getSignableRepresentation :: a -> ByteString instance SignableRepresentation ByteString where - getSignableRepresentation = id - + getSignableRepresentation = id -- -- Random source used in some mock instances @@ -87,7 +83,6 @@ instance SignableRepresentation ByteString where getRandomWord64 :: MonadRandom m => m Word64 getRandomWord64 = readBinaryWord64 <$> getRandomBytes 8 - -- -- Really simple serialisation used in some mock instances -- @@ -96,57 +91,54 @@ readBinaryWord64 :: ByteString -> Word64 readBinaryWord64 = BS.foldl' (\acc w8 -> unsafeShiftL acc 8 + fromIntegral w8) 0 - readBinaryNatural :: ByteString -> Natural readBinaryNatural = BS.foldl' (\acc w8 -> unsafeShiftL acc 8 + fromIntegral w8) 0 - writeBinaryWord64 :: Word64 -> ByteString writeBinaryWord64 = - BS.reverse . fst - . BS.unfoldrN 8 (\w -> Just (fromIntegral w, unsafeShiftR w 8)) + BS.reverse + . fst + . BS.unfoldrN 8 (\w -> Just (fromIntegral w, unsafeShiftR w 8)) writeBinaryNatural :: Int -> Natural -> ByteString writeBinaryNatural bytes = - BS.reverse . fst - . BS.unfoldrN bytes (\w -> Just (fromIntegral w, unsafeShiftR w 8)) + BS.reverse + . fst + . BS.unfoldrN bytes (\w -> Just (fromIntegral w, unsafeShiftR w 8)) splitsAt :: [Int] -> ByteString -> [ByteString] splitsAt = go 0 where - go !_ [] bs - | BS.null bs = [] - | otherwise = [bs] - - go !off (sz:szs) bs - | BS.length bs >= sz = BS.take sz bs : go (off+sz) szs (BS.drop sz bs) - | otherwise = [] + go !_ [] bs + | BS.null bs = [] + | otherwise = [bs] + go !off (sz : szs) bs + | BS.length bs >= sz = BS.take sz bs : go (off + sz) szs (BS.drop sz bs) + | otherwise = [] -- | Create a 'Natural' out of a 'ByteString', in big endian. -- -- This is fast enough to use in production. --- bytesToNatural :: ByteString -> Natural bytesToNatural = GHC.naturalFromInteger . bytesToInteger -- | The inverse of 'bytesToNatural'. Note that this is a naive implementation -- and only suitable for tests. --- naturalToBytes :: Int -> Natural -> ByteString naturalToBytes = writeBinaryNatural bytesToInteger :: ByteString -> Integer bytesToInteger (BS.PS fp (GHC.I# off#) (GHC.I# len#)) = - -- This should be safe since we're simply reading from ByteString (which is - -- immutable) and GMP allocates a new memory for the Integer, i.e., there is - -- no mutation involved. - unsafeDupablePerformIO $ - withForeignPtr fp $ \(GHC.Ptr addr#) -> - let addrOff# = addr# `GHC.plusAddr#` off# - -- The last parmaeter (`1#`) tells the import function to use big - -- endian encoding. - in importIntegerFromAddr addrOff# (GHC.int2Word# len#) 1# + -- This should be safe since we're simply reading from ByteString (which is + -- immutable) and GMP allocates a new memory for the Integer, i.e., there is + -- no mutation involved. + unsafeDupablePerformIO $ + withForeignPtr fp $ \(GHC.Ptr addr#) -> + let addrOff# = addr# `GHC.plusAddr#` off# + in -- The last parmaeter (`1#`) tells the import function to use big + -- endian encoding. + importIntegerFromAddr addrOff# (GHC.int2Word# len#) 1# where importIntegerFromAddr :: Addr# -> Word# -> Int# -> IO Integer #if __GLASGOW_HASKELL__ >= 900 @@ -157,8 +149,9 @@ bytesToInteger (BS.PS fp (GHC.I# off#) (GHC.I# len#)) = #endif slice :: Word -> Word -> ByteString -> ByteString -slice offset size = BS.take (fromIntegral size) - . BS.drop (fromIntegral offset) +slice offset size = + BS.take (fromIntegral size) + . BS.drop (fromIntegral offset) -- | Decode base16 ByteString, while ensuring expected length. decodeHexByteString :: ByteString -> Int -> Either String ByteString @@ -166,18 +159,20 @@ decodeHexByteString bsHex lenExpected = do bs <- first ("Malformed hex: " ++) $ BS16.decode bsHex let lenActual = BS.length bs unless (lenExpected == lenActual) $ - Left $ "Expected in decoded form to be: " ++ - show lenExpected ++ " bytes, but got: " ++ show lenActual + Left $ + "Expected in decoded form to be: " + ++ show lenExpected + ++ " bytes, but got: " + ++ show lenActual pure bs - -- | Decode base16 String, while ensuring expected length. Unlike -- `decodeHexByteString` this function expects a '0x' prefix. decodeHexString :: String -> Int -> Either String ByteString decodeHexString hexStr' lenExpected = do let hexStr = case hexStr' of - '0':'x':str -> str + '0' : 'x' : str -> str str -> str unless (all isAscii hexStr) $ Left $ "Input string contains invalid characters: " ++ hexStr decodeHexByteString (BSC8.pack hexStr) lenExpected @@ -187,4 +182,4 @@ decodeHexStringQ :: String -> Int -> Q Exp decodeHexStringQ hexStr n = do case decodeHexString hexStr n of Left err -> fail $ ": " ++ err - Right _ -> [| either error id (decodeHexString hexStr n) |] + Right _ -> [|either error id (decodeHexString hexStr n)|] diff --git a/cardano-crypto-class/src/Cardano/Crypto/VRF.hs b/cardano-crypto-class/src/Cardano/Crypto/VRF.hs index 4252d808d..c5535a064 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/VRF.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/VRF.hs @@ -1,7 +1,7 @@ -- | Verifiable random functions. -module Cardano.Crypto.VRF - ( module X - ) +module Cardano.Crypto.VRF ( + module X, +) where import Cardano.Crypto.VRF.Class as X diff --git a/cardano-crypto-class/src/Cardano/Crypto/VRF/Class.hs b/cardano-crypto-class/src/Cardano/Crypto/VRF/Class.hs index 3678fb121..c9da58a26 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/VRF/Class.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/VRF/Class.hs @@ -13,82 +13,86 @@ {-# LANGUAGE UndecidableInstances #-} -- | Abstract Verifiable Random Functions. -module Cardano.Crypto.VRF.Class - ( - -- * VRF algorithm class - VRFAlgorithm (..) - - -- ** VRF output - , OutputVRF(..) - , getOutputVRFNatural - , mkTestOutputVRF - - -- * 'CertifiedVRF' wrapper - , CertifiedVRF (..) - , evalCertified - , verifyCertified - - -- * CBOR encoding and decoding - , encodeVerKeyVRF - , decodeVerKeyVRF - , encodeSignKeyVRF - , decodeSignKeyVRF - , encodeCertVRF - , decodeCertVRF - - - -- * Encoded 'Size' expressions - , encodedVerKeyVRFSizeExpr - , encodedSignKeyVRFSizeExpr - , encodedCertVRFSizeExpr +module Cardano.Crypto.VRF.Class ( + -- * VRF algorithm class + VRFAlgorithm (..), + + -- ** VRF output + OutputVRF (..), + getOutputVRFNatural, + mkTestOutputVRF, + + -- * 'CertifiedVRF' wrapper + CertifiedVRF (..), + evalCertified, + verifyCertified, + + -- * CBOR encoding and decoding + encodeVerKeyVRF, + decodeVerKeyVRF, + encodeSignKeyVRF, + decodeSignKeyVRF, + encodeCertVRF, + decodeCertVRF, + + -- * Encoded 'Size' expressions + encodedVerKeyVRFSizeExpr, + encodedSignKeyVRFSizeExpr, + encodedCertVRFSizeExpr, ) where import Control.DeepSeq (NFData) import Data.ByteString (ByteString) import Data.Kind (Type) -import Data.Proxy (Proxy(..)) +import Data.Proxy (Proxy (..)) import Data.Typeable (Typeable) import GHC.Exts (Constraint) import GHC.Generics (Generic) import GHC.Stack -import GHC.TypeLits (TypeError, ErrorMessage (..)) +import GHC.TypeLits (ErrorMessage (..), TypeError) import NoThunks.Class (NoThunks) import Numeric.Natural (Natural) import qualified Data.ByteString as BS -import Cardano.Binary - (Decoder, Encoding, FromCBOR (..), ToCBOR (..), Size, - encodeListLen, enforceSize, decodeBytes, encodeBytes, - withWordSize) - -import Cardano.Crypto.Util (Empty, bytesToNatural, naturalToBytes) +import Cardano.Binary ( + Decoder, + Encoding, + FromCBOR (..), + Size, + ToCBOR (..), + decodeBytes, + encodeBytes, + encodeListLen, + enforceSize, + withWordSize, + ) + +import Cardano.Crypto.Hash.Class (Hash, HashAlgorithm, hashWith) import Cardano.Crypto.Seed (Seed) -import Cardano.Crypto.Hash.Class (HashAlgorithm, Hash, hashWith) - - -class ( Typeable v - , Show (VerKeyVRF v) - , Eq (VerKeyVRF v) - , Show (SignKeyVRF v) - , Show (CertVRF v) - , Eq (CertVRF v) - , NoThunks (CertVRF v) - , NoThunks (VerKeyVRF v) - , NoThunks (SignKeyVRF v) - ) - => VRFAlgorithm v where - +import Cardano.Crypto.Util (Empty, bytesToNatural, naturalToBytes) +class + ( Typeable v + , Show (VerKeyVRF v) + , Eq (VerKeyVRF v) + , Show (SignKeyVRF v) + , Show (CertVRF v) + , Eq (CertVRF v) + , NoThunks (CertVRF v) + , NoThunks (VerKeyVRF v) + , NoThunks (SignKeyVRF v) + ) => + VRFAlgorithm v + where -- -- Key and signature types -- - data VerKeyVRF v :: Type + data VerKeyVRF v :: Type data SignKeyVRF v :: Type - data CertVRF v :: Type - + data CertVRF v :: Type -- -- Metadata and basic key operations @@ -109,25 +113,26 @@ class ( Typeable v -- -- Unit by default (no context required) type ContextVRF v :: Type + type ContextVRF v = () type Signable v :: Type -> Constraint type Signable c = Empty - evalVRF - :: (HasCallStack, Signable v a) - => ContextVRF v - -> a - -> SignKeyVRF v - -> (OutputVRF v, CertVRF v) - - verifyVRF - :: (HasCallStack, Signable v a) - => ContextVRF v - -> VerKeyVRF v - -> a - -> CertVRF v - -> Maybe (OutputVRF v) + evalVRF :: + (HasCallStack, Signable v a) => + ContextVRF v -> + a -> + SignKeyVRF v -> + (OutputVRF v, CertVRF v) + + verifyVRF :: + (HasCallStack, Signable v a) => + ContextVRF v -> + VerKeyVRF v -> + a -> + CertVRF v -> + Maybe (OutputVRF v) -- -- Key generation @@ -141,85 +146,84 @@ class ( Typeable v genKeyPairVRF = \seed -> let sk = genKeyVRF seed - in (sk, deriveVerKeyVRF sk) + in (sk, deriveVerKeyVRF sk) -- | The upper bound on the 'Seed' size needed by 'genKeyVRF', in bytes. seedSizeVRF :: proxy v -> Word - -- -- Serialisation/(de)serialisation in fixed-size raw format -- - sizeVerKeyVRF :: proxy v -> Word + sizeVerKeyVRF :: proxy v -> Word sizeSignKeyVRF :: proxy v -> Word - sizeCertVRF :: proxy v -> Word - sizeOutputVRF :: proxy v -> Word + sizeCertVRF :: proxy v -> Word + sizeOutputVRF :: proxy v -> Word - rawSerialiseVerKeyVRF :: VerKeyVRF v -> ByteString - rawSerialiseSignKeyVRF :: SignKeyVRF v -> ByteString - rawSerialiseCertVRF :: CertVRF v -> ByteString + rawSerialiseVerKeyVRF :: VerKeyVRF v -> ByteString + rawSerialiseSignKeyVRF :: SignKeyVRF v -> ByteString + rawSerialiseCertVRF :: CertVRF v -> ByteString - rawDeserialiseVerKeyVRF :: ByteString -> Maybe (VerKeyVRF v) + rawDeserialiseVerKeyVRF :: ByteString -> Maybe (VerKeyVRF v) rawDeserialiseSignKeyVRF :: ByteString -> Maybe (SignKeyVRF v) - rawDeserialiseCertVRF :: ByteString -> Maybe (CertVRF v) + rawDeserialiseCertVRF :: ByteString -> Maybe (CertVRF v) {-# MINIMAL - algorithmNameVRF - , deriveVerKeyVRF - , evalVRF - , verifyVRF - , seedSizeVRF - , (genKeyVRF | genKeyPairVRF) - , rawSerialiseVerKeyVRF - , rawSerialiseSignKeyVRF - , rawSerialiseCertVRF - , rawDeserialiseVerKeyVRF - , rawDeserialiseSignKeyVRF - , rawDeserialiseCertVRF - , sizeVerKeyVRF - , sizeSignKeyVRF - , sizeCertVRF - , sizeOutputVRF + algorithmNameVRF + , deriveVerKeyVRF + , evalVRF + , verifyVRF + , seedSizeVRF + , (genKeyVRF | genKeyPairVRF) + , rawSerialiseVerKeyVRF + , rawSerialiseSignKeyVRF + , rawSerialiseCertVRF + , rawDeserialiseVerKeyVRF + , rawDeserialiseSignKeyVRF + , rawDeserialiseCertVRF + , sizeVerKeyVRF + , sizeSignKeyVRF + , sizeCertVRF + , sizeOutputVRF #-} -- -- Do not provide Ord instances for keys, see #38 -- -instance ( TypeError ('Text "Ord not supported for signing keys, use the hash instead") - , Eq (SignKeyVRF v) - ) - => Ord (SignKeyVRF v) where - compare = error "unsupported" +instance + ( TypeError ('Text "Ord not supported for signing keys, use the hash instead") + , Eq (SignKeyVRF v) + ) => + Ord (SignKeyVRF v) + where + compare = error "unsupported" -instance ( TypeError ('Text "Ord not supported for verification keys, use the hash instead") - , Eq (VerKeyVRF v) - ) - => Ord (VerKeyVRF v) where - compare = error "unsupported" +instance + ( TypeError ('Text "Ord not supported for verification keys, use the hash instead") + , Eq (VerKeyVRF v) + ) => + Ord (VerKeyVRF v) + where + compare = error "unsupported" -- | The output bytes of the VRF. -- -- The output size is a fixed number of bytes and is given by 'sizeOutputVRF'. --- -newtype OutputVRF v = OutputVRF { getOutputVRFBytes :: ByteString } +newtype OutputVRF v = OutputVRF {getOutputVRFBytes :: ByteString} deriving (Eq, Ord, Show, ToCBOR, FromCBOR, NoThunks) - deriving newtype NFData - + deriving newtype (NFData) -- | The output bytes of the VRF interpreted as a big endian natural number. -- -- The range of this number is determined by the size of the VRF output bytes. -- It is thus in the range @0 .. 2 ^ (8 * sizeOutputVRF proxy) - 1@. --- getOutputVRFNatural :: OutputVRF v -> Natural getOutputVRFNatural = bytesToNatural . getOutputVRFBytes -- | For testing purposes, make an 'OutputVRF' from a 'Natural'. -- -- The 'OutputVRF' will be of the appropriate size for the 'VRFAlgorithm'. --- mkTestOutputVRF :: forall v. VRFAlgorithm v => Natural -> OutputVRF v mkTestOutputVRF = OutputVRF . naturalToBytes sz where @@ -242,69 +246,82 @@ encodeCertVRF = encodeBytes . rawSerialiseCertVRF decodeVerKeyVRF :: forall v s. VRFAlgorithm v => Decoder s (VerKeyVRF v) decodeVerKeyVRF = do - bs <- decodeBytes - case rawDeserialiseVerKeyVRF bs of - Just vk -> return vk - Nothing - | actual /= expected - -> fail ("decodeVerKeyVRF: wrong length, expected " ++ - show expected ++ " bytes but got " ++ show actual) - | otherwise -> fail "decodeVerKeyVRF: cannot decode key" - where - expected = fromIntegral (sizeVerKeyVRF (Proxy :: Proxy v)) - actual = BS.length bs + bs <- decodeBytes + case rawDeserialiseVerKeyVRF bs of + Just vk -> return vk + Nothing + | actual /= expected -> + fail + ( "decodeVerKeyVRF: wrong length, expected " + ++ show expected + ++ " bytes but got " + ++ show actual + ) + | otherwise -> fail "decodeVerKeyVRF: cannot decode key" + where + expected = fromIntegral (sizeVerKeyVRF (Proxy :: Proxy v)) + actual = BS.length bs {-# INLINEABLE decodeVerKeyVRF #-} decodeSignKeyVRF :: forall v s. VRFAlgorithm v => Decoder s (SignKeyVRF v) decodeSignKeyVRF = do - bs <- decodeBytes - case rawDeserialiseSignKeyVRF bs of - Just sk -> return sk - Nothing - | actual /= expected - -> fail ("decodeSignKeyVRF: wrong length, expected " ++ - show expected ++ " bytes but got " ++ show actual) - | otherwise -> fail "decodeSignKeyVRF: cannot decode key" - where - expected = fromIntegral (sizeSignKeyVRF (Proxy :: Proxy v)) - actual = BS.length bs + bs <- decodeBytes + case rawDeserialiseSignKeyVRF bs of + Just sk -> return sk + Nothing + | actual /= expected -> + fail + ( "decodeSignKeyVRF: wrong length, expected " + ++ show expected + ++ " bytes but got " + ++ show actual + ) + | otherwise -> fail "decodeSignKeyVRF: cannot decode key" + where + expected = fromIntegral (sizeSignKeyVRF (Proxy :: Proxy v)) + actual = BS.length bs decodeCertVRF :: forall v s. VRFAlgorithm v => Decoder s (CertVRF v) decodeCertVRF = do - bs <- decodeBytes - case rawDeserialiseCertVRF bs of - Just crt -> return crt - Nothing - | actual /= expected - -> fail ("decodeCertVRF: wrong length, expected " ++ - show expected ++ " bytes but got " ++ show actual) - | otherwise -> fail "decodeCertVRF: cannot decode key" - where - expected = fromIntegral (sizeCertVRF (Proxy :: Proxy v)) - actual = BS.length bs + bs <- decodeBytes + case rawDeserialiseCertVRF bs of + Just crt -> return crt + Nothing + | actual /= expected -> + fail + ( "decodeCertVRF: wrong length, expected " + ++ show expected + ++ " bytes but got " + ++ show actual + ) + | otherwise -> fail "decodeCertVRF: cannot decode key" + where + expected = fromIntegral (sizeCertVRF (Proxy :: Proxy v)) + actual = BS.length bs {-# INLINEABLE decodeCertVRF #-} data CertifiedVRF v a = CertifiedVRF - { certifiedOutput :: !(OutputVRF v) - , certifiedProof :: !(CertVRF v) - } - deriving Generic + { certifiedOutput :: !(OutputVRF v) + , certifiedProof :: !(CertVRF v) + } + deriving (Generic) deriving instance VRFAlgorithm v => Show (CertifiedVRF v a) -deriving instance VRFAlgorithm v => Eq (CertifiedVRF v a) +deriving instance VRFAlgorithm v => Eq (CertifiedVRF v a) instance VRFAlgorithm v => NoThunks (CertifiedVRF v a) - -- use generic instance + +-- use generic instance instance (VRFAlgorithm v, Typeable a) => ToCBOR (CertifiedVRF v a) where toCBOR cvrf = - encodeListLen 2 <> - toCBOR (certifiedOutput cvrf) <> - encodeCertVRF (certifiedProof cvrf) + encodeListLen 2 + <> toCBOR (certifiedOutput cvrf) + <> encodeCertVRF (certifiedProof cvrf) encodedSizeExpr _size proxy = - 1 + 1 + certifiedOutputSize (certifiedOutput <$> proxy) + fromIntegral (sizeCertVRF (Proxy :: Proxy v)) where @@ -314,31 +331,31 @@ instance (VRFAlgorithm v, Typeable a) => ToCBOR (CertifiedVRF v a) where instance (VRFAlgorithm v, Typeable a) => FromCBOR (CertifiedVRF v a) where fromCBOR = - CertifiedVRF <$ - enforceSize "CertifiedVRF" 2 <*> - fromCBOR <*> - decodeCertVRF + CertifiedVRF + <$ enforceSize "CertifiedVRF" 2 + <*> fromCBOR + <*> decodeCertVRF {-# INLINE fromCBOR #-} -evalCertified - :: (VRFAlgorithm v, Signable v a) - => ContextVRF v - -> a - -> SignKeyVRF v - -> CertifiedVRF v a +evalCertified :: + (VRFAlgorithm v, Signable v a) => + ContextVRF v -> + a -> + SignKeyVRF v -> + CertifiedVRF v a evalCertified ctxt a key = uncurry CertifiedVRF $ evalVRF ctxt a key -verifyCertified - :: (VRFAlgorithm v, Signable v a) - => ContextVRF v - -> VerKeyVRF v - -> a - -> CertifiedVRF v a - -> Bool +verifyCertified :: + (VRFAlgorithm v, Signable v a) => + ContextVRF v -> + VerKeyVRF v -> + a -> + CertifiedVRF v a -> + Bool verifyCertified ctxt vk a CertifiedVRF {certifiedOutput, certifiedProof} = - case verifyVRF ctxt vk a certifiedProof of - Nothing -> False - Just output -> output == certifiedOutput + case verifyVRF ctxt vk a certifiedProof of + Nothing -> False + Just output -> output == certifiedOutput -- -- 'Size' expressions for 'ToCBOR' instances @@ -346,30 +363,27 @@ verifyCertified ctxt vk a CertifiedVRF {certifiedOutput, certifiedProof} = -- | 'Size' expression for 'VerKeyVRF' which is using 'sizeVerKeyVRF' encoded as -- 'Size'. --- encodedVerKeyVRFSizeExpr :: forall v. VRFAlgorithm v => Proxy (VerKeyVRF v) -> Size encodedVerKeyVRFSizeExpr _proxy = - -- 'encodeBytes' envelope - fromIntegral ((withWordSize :: Word -> Integer) (sizeVerKeyVRF (Proxy :: Proxy v))) - -- payload + -- 'encodeBytes' envelope + fromIntegral ((withWordSize :: Word -> Integer) (sizeVerKeyVRF (Proxy :: Proxy v))) + -- payload + fromIntegral (sizeVerKeyVRF (Proxy :: Proxy v)) -- | 'Size' expression for 'SignKeyVRF' which is using 'sizeSignKeyVRF' encoded -- as 'Size' --- encodedSignKeyVRFSizeExpr :: forall v. VRFAlgorithm v => Proxy (SignKeyVRF v) -> Size encodedSignKeyVRFSizeExpr _proxy = - -- 'encodeBytes' envelope - fromIntegral ((withWordSize :: Word -> Integer) (sizeSignKeyVRF (Proxy :: Proxy v))) - -- payload + -- 'encodeBytes' envelope + fromIntegral ((withWordSize :: Word -> Integer) (sizeSignKeyVRF (Proxy :: Proxy v))) + -- payload + fromIntegral (sizeSignKeyVRF (Proxy :: Proxy v)) -- | 'Size' expression for 'CertVRF' which is using 'sizeCertVRF' encoded as -- 'Size'. --- encodedCertVRFSizeExpr :: forall v. VRFAlgorithm v => Proxy (CertVRF v) -> Size encodedCertVRFSizeExpr _proxy = - -- 'encodeBytes' envelope - fromIntegral ((withWordSize :: Word -> Integer) (sizeCertVRF (Proxy :: Proxy v))) - -- payload + -- 'encodeBytes' envelope + fromIntegral ((withWordSize :: Word -> Integer) (sizeCertVRF (Proxy :: Proxy v))) + -- payload + fromIntegral (sizeCertVRF (Proxy :: Proxy v)) diff --git a/cardano-crypto-class/src/Cardano/Crypto/VRF/Mock.hs b/cardano-crypto-class/src/Cardano/Crypto/VRF/Mock.hs index 6935a1009..5be7725a9 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/VRF/Mock.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/VRF/Mock.hs @@ -5,41 +5,40 @@ {-# LANGUAGE TypeFamilies #-} -- | Mock implementations of verifiable random functions. -module Cardano.Crypto.VRF.Mock - ( MockVRF - , VerKeyVRF (..) - , SignKeyVRF (..) - ) +module Cardano.Crypto.VRF.Mock ( + MockVRF, + VerKeyVRF (..), + SignKeyVRF (..), +) where -import Data.Word (Word64) import Data.Proxy (Proxy (..)) +import Data.Word (Word64) import GHC.Generics (Generic) import NoThunks.Class (NoThunks) -import Cardano.Binary (FromCBOR, ToCBOR (..), FromCBOR(..)) +import Cardano.Binary (FromCBOR (..), ToCBOR (..)) import Cardano.Crypto.Hash -import Cardano.Crypto.Util import Cardano.Crypto.Seed +import Cardano.Crypto.Util import Cardano.Crypto.VRF.Class data MockVRF instance VRFAlgorithm MockVRF where - -- -- Key and signature types -- newtype VerKeyVRF MockVRF = VerKeyMockVRF Word64 - deriving (Show, Eq, Ord, Generic, NoThunks) + deriving (Show, Eq, Ord, Generic, NoThunks) newtype SignKeyVRF MockVRF = SignKeyMockVRF Word64 - deriving (Show, Eq, Ord, Generic, NoThunks) + deriving (Show, Eq, Ord, Generic, NoThunks) newtype CertVRF MockVRF = CertMockVRF Word64 - deriving (Show, Eq, Ord, Generic, NoThunks) + deriving (Show, Eq, Ord, Generic, NoThunks) -- -- Metadata and basic key operations @@ -49,7 +48,6 @@ instance VRFAlgorithm MockVRF where deriveVerKeyVRF (SignKeyMockVRF n) = VerKeyMockVRF n - -- -- Core algorithm operations -- @@ -59,8 +57,8 @@ instance VRFAlgorithm MockVRF where evalVRF () a sk = evalVRF' a sk verifyVRF () (VerKeyMockVRF n) a c - | c == c' = Just o - | otherwise = Nothing + | c == c' = Just o + | otherwise = Nothing where (o, c') = evalVRF' a (SignKeyMockVRF n) @@ -70,48 +68,43 @@ instance VRFAlgorithm MockVRF where -- Key generation -- - seedSizeVRF _ = 8 + seedSizeVRF _ = 8 genKeyVRF seed = SignKeyMockVRF sk where sk = runMonadRandomWithSeed seed getRandomWord64 - -- -- raw serialise/deserialise -- - sizeVerKeyVRF _ = 8 + sizeVerKeyVRF _ = 8 sizeSignKeyVRF _ = 8 - sizeCertVRF _ = 8 + sizeCertVRF _ = 8 - rawSerialiseVerKeyVRF (VerKeyMockVRF k) = writeBinaryWord64 k + rawSerialiseVerKeyVRF (VerKeyMockVRF k) = writeBinaryWord64 k rawSerialiseSignKeyVRF (SignKeyMockVRF k) = writeBinaryWord64 k - rawSerialiseCertVRF (CertMockVRF k) = writeBinaryWord64 k + rawSerialiseCertVRF (CertMockVRF k) = writeBinaryWord64 k rawDeserialiseVerKeyVRF bs | [kb] <- splitsAt [8] bs - , let k = readBinaryWord64 kb - = Just $! VerKeyMockVRF k - - | otherwise - = Nothing + , let k = readBinaryWord64 kb = + Just $! VerKeyMockVRF k + | otherwise = + Nothing rawDeserialiseSignKeyVRF bs | [kb] <- splitsAt [8] bs - , let k = readBinaryWord64 kb - = Just $! SignKeyMockVRF k - - | otherwise - = Nothing + , let k = readBinaryWord64 kb = + Just $! SignKeyMockVRF k + | otherwise = + Nothing rawDeserialiseCertVRF bs | [kb] <- splitsAt [8] bs - , let k = readBinaryWord64 kb - = Just $! CertMockVRF k - - | otherwise - = Nothing - + , let k = readBinaryWord64 kb = + Just $! CertMockVRF k + | otherwise = + Nothing instance ToCBOR (VerKeyVRF MockVRF) where toCBOR = encodeVerKeyVRF @@ -134,12 +127,14 @@ instance ToCBOR (CertVRF MockVRF) where instance FromCBOR (CertVRF MockVRF) where fromCBOR = decodeCertVRF - -evalVRF' :: SignableRepresentation a - => a - -> SignKeyVRF MockVRF - -> (OutputVRF MockVRF, CertVRF MockVRF) +evalVRF' :: + SignableRepresentation a => + a -> + SignKeyVRF MockVRF -> + (OutputVRF MockVRF, CertVRF MockVRF) evalVRF' a sk@(SignKeyMockVRF n) = - let y = hashToBytes $ hashWithSerialiser @ShortHash id $ + let y = + hashToBytes $ + hashWithSerialiser @ShortHash id $ toCBOR (getSignableRepresentation a) <> toCBOR sk - in (OutputVRF y, CertMockVRF n) + in (OutputVRF y, CertMockVRF n) diff --git a/cardano-crypto-class/src/Cardano/Crypto/VRF/NeverUsed.hs b/cardano-crypto-class/src/Cardano/Crypto/VRF/NeverUsed.hs index 8253d8425..daf288c94 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/VRF/NeverUsed.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/VRF/NeverUsed.hs @@ -2,12 +2,13 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} -module Cardano.Crypto.VRF.NeverUsed - ( NeverVRF - , VerKeyVRF (..) - , SignKeyVRF (..) - , CertVRF (..) - ) + +module Cardano.Crypto.VRF.NeverUsed ( + NeverVRF, + VerKeyVRF (..), + SignKeyVRF (..), + CertVRF (..), +) where import GHC.Generics (Generic) @@ -15,7 +16,6 @@ import NoThunks.Class (NoThunks) import Cardano.Crypto.VRF.Class - -- | VRF not available -- -- The type of keys and certificates is isomorphic to unit, but when actually @@ -23,7 +23,6 @@ import Cardano.Crypto.VRF.Class data NeverVRF instance VRFAlgorithm NeverVRF where - data VerKeyVRF NeverVRF = NeverUsedVerKeyVRF deriving (Show, Eq, Generic, NoThunks) @@ -46,14 +45,14 @@ instance VRFAlgorithm NeverVRF where genKeyVRF _ = NeverUsedSignKeyVRF seedSizeVRF _ = 0 - sizeVerKeyVRF _ = 0 + sizeVerKeyVRF _ = 0 sizeSignKeyVRF _ = 0 - sizeCertVRF _ = 0 + sizeCertVRF _ = 0 - rawSerialiseVerKeyVRF _ = mempty + rawSerialiseVerKeyVRF _ = mempty rawSerialiseSignKeyVRF _ = mempty - rawSerialiseCertVRF _ = mempty + rawSerialiseCertVRF _ = mempty - rawDeserialiseVerKeyVRF _ = Just NeverUsedVerKeyVRF + rawDeserialiseVerKeyVRF _ = Just NeverUsedVerKeyVRF rawDeserialiseSignKeyVRF _ = Just NeverUsedSignKeyVRF - rawDeserialiseCertVRF _ = Just NeverUsedCertVRF + rawDeserialiseCertVRF _ = Just NeverUsedCertVRF diff --git a/cardano-crypto-class/src/Cardano/Crypto/VRF/Simple.hs b/cardano-crypto-class/src/Cardano/Crypto/VRF/Simple.hs index afd5d5ccd..17042b079 100644 --- a/cardano-crypto-class/src/Cardano/Crypto/VRF/Simple.hs +++ b/cardano-crypto-class/src/Cardano/Crypto/VRF/Simple.hs @@ -11,27 +11,27 @@ {-# LANGUAGE TypeFamilies #-} -- | Mock implementations of verifiable random functions. -module Cardano.Crypto.VRF.Simple - ( SimpleVRF - , pointFromMaybe - ) +module Cardano.Crypto.VRF.Simple ( + SimpleVRF, + pointFromMaybe, +) where -import Control.DeepSeq (NFData, force) -import Data.Proxy (Proxy (..)) -import GHC.Generics (Generic) -import NoThunks.Class (NoThunks, InspectHeap(..)) -import Numeric.Natural (Natural) +import Control.DeepSeq (NFData, force) +import Data.Proxy (Proxy (..)) +import GHC.Generics (Generic) +import NoThunks.Class (InspectHeap (..), NoThunks) +import Numeric.Natural (Natural) -import Cardano.Binary (Encoding, FromCBOR (..), ToCBOR (..)) +import Cardano.Binary (Encoding, FromCBOR (..), ToCBOR (..)) import qualified Crypto.PubKey.ECC.Prim as C import qualified Crypto.PubKey.ECC.Types as C -import Cardano.Crypto.Hash -import Cardano.Crypto.Seed -import Cardano.Crypto.Util -import Cardano.Crypto.VRF.Class +import Cardano.Crypto.Hash +import Cardano.Crypto.Seed +import Cardano.Crypto.Util +import Cardano.Crypto.VRF.Class data SimpleVRF @@ -39,6 +39,7 @@ type H = ShortHash curve :: C.Curve curve = C.getCurveByName C.SEC_t113r1 + -- C.curveSizeBits curve = 113 bits, 15 bytes q :: Integer @@ -46,8 +47,8 @@ q = C.ecc_n $ C.common_curve curve newtype Point = ThunkyPoint C.Point deriving (Eq, Generic) - deriving NoThunks via InspectHeap C.Point - deriving newtype NFData + deriving (NoThunks) via InspectHeap C.Point + deriving newtype (NFData) -- | Smart constructor for @Point@ that evaluates the wrapped 'C.Point' to -- normal form. This is needed because 'C.Point' has a constructor with two @@ -96,28 +97,27 @@ h' :: Encoding -> Integer -> Point h' enc l = pow $ mod (l * (fromIntegral . bytesToNatural $ h enc)) q instance VRFAlgorithm SimpleVRF where - -- -- Key and signature types -- newtype VerKeyVRF SimpleVRF = VerKeySimpleVRF Point - deriving stock (Show, Eq, Generic) + deriving stock (Show, Eq, Generic) deriving newtype (NoThunks) deriving anyclass (NFData) newtype SignKeyVRF SimpleVRF = SignKeySimpleVRF C.PrivateNumber - deriving stock (Show, Eq, Generic) - deriving NoThunks via InspectHeap C.PrivateNumber + deriving stock (Show, Eq, Generic) + deriving (NoThunks) via InspectHeap C.PrivateNumber deriving anyclass (NFData) data CertVRF SimpleVRF = CertSimpleVRF - { certU :: !Point -- 15 byte point numbers, round up to 16 - , certC :: !Natural -- md5 hash, so 16 bytes - , certS :: !Integer -- at most q, so 15 bytes, round up to 16 - } - deriving stock (Show, Eq, Generic) + { certU :: !Point -- 15 byte point numbers, round up to 16 + , certC :: !Natural -- md5 hash, so 16 bytes + , certS :: !Integer -- at most q, so 15 bytes, round up to 16 + } + deriving stock (Show, Eq, Generic) deriving anyclass (NoThunks) deriving anyclass (NFData) @@ -130,10 +130,9 @@ instance VRFAlgorithm SimpleVRF where deriveVerKeyVRF (SignKeySimpleVRF k) = VerKeySimpleVRF $ pow k - sizeVerKeyVRF _ = 32 + sizeVerKeyVRF _ = 32 sizeSignKeyVRF _ = 16 - sizeCertVRF _ = 64 - + sizeCertVRF _ = 64 -- -- Core algorithm operations @@ -150,7 +149,7 @@ instance VRFAlgorithm SimpleVRF where r = fromIntegral (bytesToNatural y) `mod` q c = h $ toCBOR a <> toCBOR v <> toCBOR (pow r) <> toCBOR (h' (toCBOR a) r) s = mod (r + k * fromIntegral (bytesToNatural c)) q - in (OutputVRF y, CertSimpleVRF u (bytesToNatural c) s) + in (OutputVRF y, CertSimpleVRF u (bytesToNatural c) s) verifyVRF () (VerKeySimpleVRF v) a' cert = let a = getSignableRepresentation a' @@ -160,25 +159,25 @@ instance VRFAlgorithm SimpleVRF where s = certS cert o = h (toCBOR a <> toCBOR u) rhs = - h $ toCBOR a <> - toCBOR v <> - toCBOR (pow s <> pow' v c') <> - toCBOR (h' (toCBOR a) s <> pow' u c') - in if c == bytesToNatural rhs - then Just (OutputVRF o) - else Nothing + h $ + toCBOR a + <> toCBOR v + <> toCBOR (pow s <> pow' v c') + <> toCBOR (h' (toCBOR a) s <> pow' u c') + in if c == bytesToNatural rhs + then Just (OutputVRF o) + else Nothing sizeOutputVRF _ = sizeHash (Proxy :: Proxy H) - -- -- Key generation -- - seedSizeVRF _ = 16 * 100 -- size of SEC_t113r1 * up to 100 iterations - genKeyVRF seed = SignKeySimpleVRF - (runMonadRandomWithSeed seed (C.scalarGenerate curve)) - + seedSizeVRF _ = 16 * 100 -- size of SEC_t113r1 * up to 100 iterations + genKeyVRF seed = + SignKeySimpleVRF + (runMonadRandomWithSeed seed (C.scalarGenerate curve)) -- -- raw serialise/deserialise @@ -187,49 +186,46 @@ instance VRFAlgorithm SimpleVRF where -- All the integers here are 15 or 16 bytes big, we round up to 16. rawSerialiseVerKeyVRF (VerKeySimpleVRF (Point C.PointO)) = - error "rawSerialiseVerKeyVRF: Point at infinity" + error "rawSerialiseVerKeyVRF: Point at infinity" rawSerialiseVerKeyVRF (VerKeySimpleVRF (Point (C.Point p1 p2))) = - writeBinaryNatural 16 (fromInteger p1) - <> writeBinaryNatural 16 (fromInteger p2) + writeBinaryNatural 16 (fromInteger p1) + <> writeBinaryNatural 16 (fromInteger p2) rawSerialiseSignKeyVRF (SignKeySimpleVRF sk) = - writeBinaryNatural 16 (fromInteger sk) + writeBinaryNatural 16 (fromInteger sk) rawSerialiseCertVRF (CertSimpleVRF (Point C.PointO) _ _) = - error "rawSerialiseCertVRF: Point at infinity" + error "rawSerialiseCertVRF: Point at infinity" rawSerialiseCertVRF (CertSimpleVRF (Point (C.Point p1 p2)) c s) = - writeBinaryNatural 16 (fromInteger p1) - <> writeBinaryNatural 16 (fromInteger p2) - <> writeBinaryNatural 16 c - <> writeBinaryNatural 16 (fromInteger s) + writeBinaryNatural 16 (fromInteger p1) + <> writeBinaryNatural 16 (fromInteger p2) + <> writeBinaryNatural 16 c + <> writeBinaryNatural 16 (fromInteger s) rawDeserialiseVerKeyVRF bs - | [p1b, p2b] <- splitsAt [16,16] bs + | [p1b, p2b] <- splitsAt [16, 16] bs , let p1 = toInteger (readBinaryNatural p1b) - p2 = toInteger (readBinaryNatural p2b) - = Just $! VerKeySimpleVRF (Point (C.Point p1 p2)) - - | otherwise - = Nothing + p2 = toInteger (readBinaryNatural p2b) = + Just $! VerKeySimpleVRF (Point (C.Point p1 p2)) + | otherwise = + Nothing rawDeserialiseSignKeyVRF bs | [skb] <- splitsAt [16] bs - , let sk = toInteger (readBinaryNatural skb) - = Just $! SignKeySimpleVRF sk - - | otherwise - = Nothing + , let sk = toInteger (readBinaryNatural skb) = + Just $! SignKeySimpleVRF sk + | otherwise = + Nothing rawDeserialiseCertVRF bs - | [p1b, p2b, cb, sb] <- splitsAt [16,16,16,16] bs + | [p1b, p2b, cb, sb] <- splitsAt [16, 16, 16, 16] bs , let p1 = toInteger (readBinaryNatural p1b) p2 = toInteger (readBinaryNatural p2b) - c = readBinaryNatural cb - s = toInteger (readBinaryNatural sb) - = Just $! CertSimpleVRF (Point (C.Point p1 p2)) c s - - | otherwise - = Nothing + c = readBinaryNatural cb + s = toInteger (readBinaryNatural sb) = + Just $! CertSimpleVRF (Point (C.Point p1 p2)) c s + | otherwise = + Nothing instance ToCBOR (VerKeyVRF SimpleVRF) where toCBOR = encodeVerKeyVRF diff --git a/cardano-crypto-class/src/Cardano/Foreign.hs b/cardano-crypto-class/src/Cardano/Foreign.hs index 8a9ad9fbd..c8bf80744 100644 --- a/cardano-crypto-class/src/Cardano/Foreign.hs +++ b/cardano-crypto-class/src/Cardano/Foreign.hs @@ -1,27 +1,28 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE KindSignatures #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} -- | Utilities for FFI module Cardano.Foreign ( - -- * Sized pointer - SizedPtr (..), - allocaSized, - memcpySized, - memsetSized, - -- * Low-level C functions - c_memcpy, - c_memset, + -- * Sized pointer + SizedPtr (..), + allocaSized, + memcpySized, + memsetSized, + + -- * Low-level C functions + c_memcpy, + c_memset, ) where import Control.Monad (void) +import Data.Proxy (Proxy (..)) import Data.Void (Void) import Data.Word (Word8) -import Data.Proxy (Proxy (..)) -import Foreign.Ptr (Ptr) import Foreign.C.Types (CSize (..)) import Foreign.Marshal.Alloc (allocaBytes) +import Foreign.Ptr (Ptr) import GHC.TypeLits ------------------------------------------------------------------------------- @@ -58,10 +59,10 @@ memsetSized (SizedPtr s) c = void (c_memset s (fromIntegral c) size) -- -- Note: this is safe foreign import foreign import ccall "memcpy" - c_memcpy :: Ptr a -> Ptr a -> CSize -> IO (Ptr ()) + c_memcpy :: Ptr a -> Ptr a -> CSize -> IO (Ptr ()) -- | @void *memset(void *s, int c, size_t n);@ -- -- Note: for sure zeroing memory use @c_sodium_memzero@. foreign import ccall "memset" - c_memset :: Ptr a -> Int -> CSize -> IO (Ptr ()) + c_memset :: Ptr a -> Int -> CSize -> IO (Ptr ()) diff --git a/cardano-crypto-praos/src/Cardano/Crypto/RandomBytes.hs b/cardano-crypto-praos/src/Cardano/Crypto/RandomBytes.hs index 3332d8bcc..0167e5c68 100644 --- a/cardano-crypto-praos/src/Cardano/Crypto/RandomBytes.hs +++ b/cardano-crypto-praos/src/Cardano/Crypto/RandomBytes.hs @@ -1,4 +1,5 @@ {-# LANGUAGE ForeignFunctionInterface #-} + module Cardano.Crypto.RandomBytes where diff --git a/cardano-crypto-praos/src/Cardano/Crypto/VRF/Praos.hs b/cardano-crypto-praos/src/Cardano/Crypto/VRF/Praos.hs index 0dc1f827a..df8e86031 100644 --- a/cardano-crypto-praos/src/Cardano/Crypto/VRF/Praos.hs +++ b/cardano-crypto-praos/src/Cardano/Crypto/VRF/Praos.hs @@ -13,59 +13,54 @@ -- | Verifiable Random Function (VRF) implemented as FFI wrappers around the -- implementation in -module Cardano.Crypto.VRF.Praos - ( +module Cardano.Crypto.VRF.Praos ( -- * VRFAlgorithm API - PraosVRF + PraosVRF, -- * Key sizes - , certSizeVRF - , signKeySizeVRF - , verKeySizeVRF - , vrfKeySizeVRF + certSizeVRF, + signKeySizeVRF, + verKeySizeVRF, + vrfKeySizeVRF, -- * Seed and key generation - , Seed - , genSeed - , keypairFromSeed + Seed, + genSeed, + keypairFromSeed, -- * Conversions - , outputBytes - , proofBytes - , skBytes - , vkBytes - , skToVerKey - , skToSeed - - , proofFromBytes - , skFromBytes - , vkFromBytes - - , vkToBatchCompat - , skToBatchCompat - , outputToBatchCompat - + outputBytes, + proofBytes, + skBytes, + vkBytes, + skToVerKey, + skToSeed, + proofFromBytes, + skFromBytes, + vkFromBytes, + vkToBatchCompat, + skToBatchCompat, + outputToBatchCompat, -- * Core VRF operations - , prove - , verify - - , SignKeyVRF (..) - , VerKeyVRF (..) - , CertVRF (..) + prove, + verify, + SignKeyVRF (..), + VerKeyVRF (..), + CertVRF (..), -- * Internal types - , Proof - , SignKey - , VerKey - , Output - ) + Proof, + SignKey, + VerKey, + Output, +) where -import Cardano.Binary - ( FromCBOR (..) - , ToCBOR (..) - ) +import Cardano.Binary ( + FromCBOR (..), + ToCBOR (..), + ) import Cardano.Crypto.RandomBytes (randombytes_buf) import Cardano.Crypto.Seed (getBytesFromSeedT) import Cardano.Crypto.Util (SignableRepresentation (..)) @@ -125,40 +120,40 @@ type OutputPtr = Ptr OutputValue -- finalizers that automatically free the memory for us. -- | A random seed, used to derive a key pair. -newtype Seed = Seed { unSeed :: ForeignPtr SeedValue } - deriving NoThunks via OnlyCheckWhnf Seed +newtype Seed = Seed {unSeed :: ForeignPtr SeedValue} + deriving (NoThunks) via OnlyCheckWhnf Seed -- | Signing key. In this implementation, the signing key is actually a 64-byte -- value that contains both the 32-byte signing key and the corresponding -- 32-byte verification key. -newtype SignKey = SignKey { unSignKey :: ForeignPtr SignKeyValue } +newtype SignKey = SignKey {unSignKey :: ForeignPtr SignKeyValue} deriving (Generic) - deriving NoThunks via OnlyCheckWhnf SignKey + deriving (NoThunks) via OnlyCheckWhnf SignKey instance NFData SignKey where rnf a = seq a () -- | Verification key. -newtype VerKey = VerKey { unVerKey :: ForeignPtr VerKeyValue } +newtype VerKey = VerKey {unVerKey :: ForeignPtr VerKeyValue} deriving (Generic) - deriving NoThunks via OnlyCheckWhnf VerKey + deriving (NoThunks) via OnlyCheckWhnf VerKey instance NFData VerKey where rnf a = seq a () -- | A proof, as constructed by the 'prove' function. -newtype Proof = Proof { unProof :: ForeignPtr ProofValue } +newtype Proof = Proof {unProof :: ForeignPtr ProofValue} deriving (Generic) - deriving NoThunks via OnlyCheckWhnf Proof + deriving (NoThunks) via OnlyCheckWhnf Proof instance NFData Proof where rnf a = seq a () -- | Hashed output of a proof verification, as returned by the 'verify' -- function. -newtype Output = Output { unOutput :: ForeignPtr OutputValue } +newtype Output = Output {unOutput :: ForeignPtr OutputValue} deriving (Generic) - deriving NoThunks via OnlyCheckWhnf Output + deriving (NoThunks) via OnlyCheckWhnf Output -- Raw low-level FFI bindings. -- @@ -234,9 +229,12 @@ copyFromByteString ptr bs lenExpected = BS.unsafeUseAsCStringLen bs $ \(cstr, lenActual) -> if lenActual >= lenExpected then copyBytes (castPtr ptr) cstr lenExpected - else error $ - "Invalid input size, expected at least " <> - show lenExpected <> ", but got " <> show lenActual + else + error $ + "Invalid input size, expected at least " + <> show lenExpected + <> ", but got " + <> show lenActual seedFromBytes :: ByteString -> Seed seedFromBytes bs = unsafePerformIO $ do @@ -326,19 +324,18 @@ mkProof = fmap Proof $ newForeignPtr finalizerFree =<< mallocBytes certSizeVRF proofFromBytes :: MonadFail m => ByteString -> m Proof proofFromBytes bs | bsLen /= certSizeVRF = - fail $ - "Invalid proof length " - <> show @Int bsLen - <> ", expecting " - <> show @Int certSizeVRF + fail $ + "Invalid proof length " + <> show @Int bsLen + <> ", expecting " + <> show @Int certSizeVRF | otherwise = pure $! unsafePerformIO $ do proof <- mkProof withForeignPtr (unProof proof) $ \ptr -> copyFromByteString ptr bs certSizeVRF return proof - where - bsLen = BS.length bs - + where + bsLen = BS.length bs skFromBytes :: MonadFail m => ByteString -> m SignKey skFromBytes bs = do @@ -366,12 +363,11 @@ vkFromBytes bs = do <> show @Int bsLen <> ", expecting " <> show @Int verKeySizeVRF - else - pure $! unsafePerformIO $ do - pk <- mkVerKey - withForeignPtr (unVerKey pk) $ \ptr -> - copyFromByteString ptr bs verKeySizeVRF - return pk + else pure $! unsafePerformIO $ do + pk <- mkVerKey + withForeignPtr (unVerKey pk) $ \ptr -> + copyFromByteString ptr bs verKeySizeVRF + return pk where bsLen = BS.length bs @@ -441,10 +437,9 @@ skToBatchCompat praosSk = outputToBatchCompat :: OutputVRF PraosVRF -> OutputVRF BC.PraosBatchCompatVRF outputToBatchCompat praosOutput = if vrfKeySizeVRF /= BC.vrfKeySizeVRF - then error "OutputVRF: Unable to convert PraosSK to BatchCompatSK." - else - OutputVRF (getOutputVRFBytes praosOutput) - + then error "OutputVRF: Unable to convert PraosSK to BatchCompatSK." + else + OutputVRF (getOutputVRFBytes praosOutput) -- | Verify a VRF proof and validate the Verification Key. Returns 'Just' a hash of -- the verification result on success, 'Nothing' if the verification did not @@ -478,21 +473,21 @@ data PraosVRF instance VRFAlgorithm PraosVRF where newtype VerKeyVRF PraosVRF = VerKeyPraosVRF VerKey - deriving stock (Show, Eq, Generic) + deriving stock (Show, Eq, Generic) deriving newtype (ToCBOR, FromCBOR) - deriving NoThunks via OnlyCheckWhnfNamed "VerKeyVRF PraosVRF" VerKey + deriving (NoThunks) via OnlyCheckWhnfNamed "VerKeyVRF PraosVRF" VerKey deriving newtype (NFData) newtype SignKeyVRF PraosVRF = SignKeyPraosVRF SignKey - deriving stock (Show, Eq, Generic) + deriving stock (Show, Eq, Generic) deriving newtype (ToCBOR, FromCBOR) - deriving NoThunks via OnlyCheckWhnfNamed "SignKeyVRF PraosVRF" SignKey + deriving (NoThunks) via OnlyCheckWhnfNamed "SignKeyVRF PraosVRF" SignKey deriving newtype (NFData) newtype CertVRF PraosVRF = CertPraosVRF Proof - deriving stock (Show, Eq, Generic) + deriving stock (Show, Eq, Generic) deriving newtype (ToCBOR, FromCBOR) - deriving NoThunks via OnlyCheckWhnfNamed "CertKeyVRF PraosVRF" Proof + deriving (NoThunks) via OnlyCheckWhnfNamed "CertKeyVRF PraosVRF" Proof deriving newtype (NFData) type Signable PraosVRF = SignableRepresentation diff --git a/cardano-crypto-praos/src/Cardano/Crypto/VRF/PraosBatchCompat.hs b/cardano-crypto-praos/src/Cardano/Crypto/VRF/PraosBatchCompat.hs index bf7855933..265f660de 100644 --- a/cardano-crypto-praos/src/Cardano/Crypto/VRF/PraosBatchCompat.hs +++ b/cardano-crypto-praos/src/Cardano/Crypto/VRF/PraosBatchCompat.hs @@ -2,74 +2,72 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE ForeignFunctionInterface #-} -{-# LANGUAGE LambdaCase #-} -- | Verifiable Random Function (VRF) implemented as FFI wrappers around the -- implementation in https://github.com/input-output-hk/libsodium -module Cardano.Crypto.VRF.PraosBatchCompat - ( +module Cardano.Crypto.VRF.PraosBatchCompat ( -- * VRFAlgorithm API - PraosBatchCompatVRF + PraosBatchCompatVRF, -- * Low-level size specifiers + -- -- Sizes of various value types involved in the VRF calculations. Users of -- this module will not need these, we are only exporting them for unit -- testing purposes. - , crypto_vrf_ietfdraft13_bytes_batchcompat - , crypto_vrf_ietfdraft13_publickeybytes - , crypto_vrf_ietfdraft13_secretkeybytes - , crypto_vrf_ietfdraft13_seedbytes - , crypto_vrf_ietfdraft13_outputbytes - - , io_crypto_vrf_ietfdraft13_publickeybytes - , io_crypto_vrf_ietfdraft13_secretkeybytes + crypto_vrf_ietfdraft13_bytes_batchcompat, + crypto_vrf_ietfdraft13_publickeybytes, + crypto_vrf_ietfdraft13_secretkeybytes, + crypto_vrf_ietfdraft13_seedbytes, + crypto_vrf_ietfdraft13_outputbytes, + io_crypto_vrf_ietfdraft13_publickeybytes, + io_crypto_vrf_ietfdraft13_secretkeybytes, -- * Key sizes - , certSizeVRF - , signKeySizeVRF - , verKeySizeVRF - , vrfKeySizeVRF + certSizeVRF, + signKeySizeVRF, + verKeySizeVRF, + vrfKeySizeVRF, -- * Seed and key generation - , Seed - , genSeed - , keypairFromSeed + Seed, + genSeed, + keypairFromSeed, -- * Conversions - , unsafeRawSeed - , outputBytes - , proofBytes - , skBytes - , vkBytes - , skToVerKey - , skToSeed + unsafeRawSeed, + outputBytes, + proofBytes, + skBytes, + vkBytes, + skToVerKey, + skToSeed, -- * Core VRF operations - , prove - , verify - - , SignKeyVRF (..) - , VerKeyVRF (..) - , CertVRF (..) - ) + prove, + verify, + SignKeyVRF (..), + VerKeyVRF (..), + CertVRF (..), +) where -import Cardano.Binary - ( FromCBOR (..) - , ToCBOR (..) - ) +import Cardano.Binary ( + FromCBOR (..), + ToCBOR (..), + ) -import Cardano.Crypto.VRF.Class -import Cardano.Crypto.Seed (getBytesFromSeedT) import Cardano.Crypto.RandomBytes (randombytes_buf) -import Cardano.Crypto.Util (SignableRepresentation(..)) +import Cardano.Crypto.Seed (getBytesFromSeedT) +import Cardano.Crypto.Util (SignableRepresentation (..)) +import Cardano.Crypto.VRF.Class import Control.DeepSeq (NFData (..)) import Control.Monad (void) @@ -124,51 +122,57 @@ type OutputPtr = Ptr OutputValue -- finalizers that automatically free the memory for us. -- | A random seed, used to derive a key pair. -newtype Seed = Seed { unSeed :: ForeignPtr SeedValue } - deriving NoThunks via OnlyCheckWhnf Seed +newtype Seed = Seed {unSeed :: ForeignPtr SeedValue} + deriving (NoThunks) via OnlyCheckWhnf Seed -- | Signing key. In this implementation, the signing key is actually a 64-byte -- value that contains both the 32-byte signing key and the corresponding -- 32-byte verification key. -newtype SignKey = SignKey { unSignKey :: ForeignPtr SignKeyValue } +newtype SignKey = SignKey {unSignKey :: ForeignPtr SignKeyValue} deriving (Generic) - deriving NoThunks via OnlyCheckWhnf SignKey + deriving (NoThunks) via OnlyCheckWhnf SignKey instance NFData SignKey where rnf a = seq a () -- | Verification key. -newtype VerKey = VerKey { unVerKey :: ForeignPtr VerKeyValue } +newtype VerKey = VerKey {unVerKey :: ForeignPtr VerKeyValue} deriving (Generic) - deriving NoThunks via OnlyCheckWhnf VerKey + deriving (NoThunks) via OnlyCheckWhnf VerKey instance NFData VerKey where rnf a = seq a () -- | A proof, as constructed by the 'prove' function. -newtype Proof = Proof { unProof :: ForeignPtr ProofValue } +newtype Proof = Proof {unProof :: ForeignPtr ProofValue} deriving (Generic) - deriving NoThunks via OnlyCheckWhnf Proof + deriving (NoThunks) via OnlyCheckWhnf Proof instance NFData Proof where rnf a = seq a () -- | Hashed output of a proof verification, as returned by the 'verify' -- function. -newtype Output = Output { unOutput :: ForeignPtr OutputValue } +newtype Output = Output {unOutput :: ForeignPtr OutputValue} deriving (Generic) - deriving NoThunks via OnlyCheckWhnf Output + deriving (NoThunks) via OnlyCheckWhnf Output -- Raw low-level FFI bindings. -- -foreign import ccall "crypto_vrf_ietfdraft13_bytes_batchcompat" crypto_vrf_ietfdraft13_bytes_batchcompat :: CSize -foreign import ccall "crypto_vrf_ietfdraft13_publickeybytes" crypto_vrf_ietfdraft13_publickeybytes :: CSize -foreign import ccall "crypto_vrf_ietfdraft13_secretkeybytes" crypto_vrf_ietfdraft13_secretkeybytes :: CSize +foreign import ccall "crypto_vrf_ietfdraft13_bytes_batchcompat" + crypto_vrf_ietfdraft13_bytes_batchcompat :: CSize +foreign import ccall "crypto_vrf_ietfdraft13_publickeybytes" + crypto_vrf_ietfdraft13_publickeybytes :: CSize +foreign import ccall "crypto_vrf_ietfdraft13_secretkeybytes" + crypto_vrf_ietfdraft13_secretkeybytes :: CSize foreign import ccall "crypto_vrf_ietfdraft13_seedbytes" crypto_vrf_ietfdraft13_seedbytes :: CSize -foreign import ccall "crypto_vrf_ietfdraft13_outputbytes" crypto_vrf_ietfdraft13_outputbytes :: CSize +foreign import ccall "crypto_vrf_ietfdraft13_outputbytes" + crypto_vrf_ietfdraft13_outputbytes :: CSize -foreign import ccall "crypto_vrf_ietfdraft13_publickeybytes" io_crypto_vrf_ietfdraft13_publickeybytes :: IO CSize -foreign import ccall "crypto_vrf_ietfdraft13_secretkeybytes" io_crypto_vrf_ietfdraft13_secretkeybytes :: IO CSize +foreign import ccall "crypto_vrf_ietfdraft13_publickeybytes" + io_crypto_vrf_ietfdraft13_publickeybytes :: IO CSize +foreign import ccall "crypto_vrf_ietfdraft13_secretkeybytes" + io_crypto_vrf_ietfdraft13_secretkeybytes :: IO CSize foreign import ccall "crypto_vrf_seed_keypair" crypto_vrf_ietfdraft13_keypair_from_seed :: VerKeyPtr -> SignKeyPtr -> SeedPtr -> IO CInt @@ -177,9 +181,11 @@ foreign import ccall "crypto_vrf_sk_to_pk" foreign import ccall "crypto_vrf_sk_to_seed" crypto_vrf_ietfdraft13_sk_to_seed :: SeedPtr -> SignKeyPtr -> IO CInt foreign import ccall "crypto_vrf_ietfdraft13_prove_batchcompat" - crypto_vrf_ietfdraft13_prove_batchcompat :: ProofPtr -> SignKeyPtr -> Ptr CChar -> CULLong -> IO CInt + crypto_vrf_ietfdraft13_prove_batchcompat :: + ProofPtr -> SignKeyPtr -> Ptr CChar -> CULLong -> IO CInt foreign import ccall "crypto_vrf_ietfdraft13_verify_batchcompat" - crypto_vrf_ietfdraft13_verify_batchcompat :: OutputPtr -> VerKeyPtr -> ProofPtr -> Ptr CChar -> CULLong -> IO CInt + crypto_vrf_ietfdraft13_verify_batchcompat :: + OutputPtr -> VerKeyPtr -> ProofPtr -> Ptr CChar -> CULLong -> IO CInt foreign import ccall "crypto_vrf_ietfdraft13_proof_to_hash_batchcompat" crypto_vrf_ietfdraft13_proof_to_hash_batchcompat :: OutputPtr -> ProofPtr -> IO CInt @@ -232,14 +238,17 @@ genSeed = do copyFromByteString :: Ptr a -> ByteString -> Int -> IO () copyFromByteString ptr bs lenExpected = BS.useAsCStringLen bs $ \(cstr, lenActual) -> - if lenActual >= lenExpected then - copyBytes (castPtr ptr) cstr lenExpected - else - error $ "Invalid input size, expected at least " <> show lenExpected <> ", but got " <> show lenActual + if lenActual >= lenExpected + then + copyBytes (castPtr ptr) cstr lenExpected + else + error $ + "Invalid input size, expected at least " <> show lenExpected <> ", but got " <> show lenActual seedFromBytes :: ByteString -> Seed -seedFromBytes bs | BS.length bs < fromIntegral crypto_vrf_ietfdraft13_seedbytes = - error "Not enough bytes for seed" +seedFromBytes bs + | BS.length bs < fromIntegral crypto_vrf_ietfdraft13_seedbytes = + error "Not enough bytes for seed" seedFromBytes bs = unsafePerformIO $ do seed <- mkSeed withForeignPtr (unSeed seed) $ \ptr -> @@ -290,7 +299,6 @@ instance ToCBOR Proof where instance FromCBOR Proof where fromCBOR = proofFromBytes <$> fromCBOR - instance Show SignKey where show = show . skBytes @@ -305,7 +313,6 @@ instance ToCBOR SignKey where instance FromCBOR SignKey where fromCBOR = skFromBytes <$> fromCBOR - instance Show VerKey where show = show . vkBytes @@ -337,21 +344,28 @@ mkProof = fmap Proof $ newForeignPtr finalizerFree =<< mallocBytes certSizeVRF proofFromBytes :: ByteString -> Proof proofFromBytes bs - | BS.length bs /= certSizeVRF - = error "Invalid proof length" - | otherwise - = unsafePerformIO $ do - proof <- mkProof - withForeignPtr (unProof proof) $ \ptr -> - copyFromByteString ptr bs certSizeVRF - return proof + | BS.length bs /= certSizeVRF = + error "Invalid proof length" + | otherwise = + unsafePerformIO $ do + proof <- mkProof + withForeignPtr (unProof proof) $ \ptr -> + copyFromByteString ptr bs certSizeVRF + return proof skFromBytes :: ByteString -> SignKey skFromBytes bs = unsafePerformIO $ do if bsLen /= signKeySizeVRF then do ioSize <- ioSignKeySizeVRF - error ("Invalid sk length " <> show @Int bsLen <> ", expecting " <> show @Int signKeySizeVRF <> " or " <> show @Int ioSize) + error + ( "Invalid sk length " + <> show @Int bsLen + <> ", expecting " + <> show @Int signKeySizeVRF + <> " or " + <> show @Int ioSize + ) else do sk <- mkSignKey withForeignPtr (unSignKey sk) $ \ptr -> @@ -365,7 +379,14 @@ vkFromBytes bs = unsafePerformIO $ do if BS.length bs /= verKeySizeVRF then do ioSize <- ioVerKeySizeVRF - error ("Invalid pk length " <> show @Int bsLen <> ", expecting " <> show @Int verKeySizeVRF <> " or " <> show @Int ioSize) + error + ( "Invalid pk length " + <> show @Int bsLen + <> ", expecting " + <> show @Int verKeySizeVRF + <> " or " + <> show @Int ioSize + ) else do pk <- mkVerKey withForeignPtr (unVerKey pk) $ \ptr -> @@ -377,7 +398,9 @@ vkFromBytes bs = unsafePerformIO $ do -- | Allocate an Output and attach a finalizer. The allocated memory will -- not be initialized. mkOutput :: IO Output -mkOutput = fmap Output $ newForeignPtr finalizerFree =<< mallocBytes (fromIntegral crypto_vrf_ietfdraft13_outputbytes) +mkOutput = + fmap Output $ + newForeignPtr finalizerFree =<< mallocBytes (fromIntegral crypto_vrf_ietfdraft13_outputbytes) -- | Derive a key pair (Sign + Verify) from a seed. keypairFromSeed :: Seed -> (VerKey, SignKey) @@ -454,21 +477,21 @@ data PraosBatchCompatVRF instance VRFAlgorithm PraosBatchCompatVRF where newtype VerKeyVRF PraosBatchCompatVRF = VerKeyPraosBatchCompatVRF VerKey - deriving stock (Show, Eq, Generic) + deriving stock (Show, Eq, Generic) deriving newtype (ToCBOR, FromCBOR) - deriving NoThunks via OnlyCheckWhnfNamed "VerKeyVRF PraosBatchCompatVRF" VerKey + deriving (NoThunks) via OnlyCheckWhnfNamed "VerKeyVRF PraosBatchCompatVRF" VerKey deriving newtype (NFData) newtype SignKeyVRF PraosBatchCompatVRF = SignKeyPraosBatchCompatVRF SignKey - deriving stock (Show, Eq, Generic) + deriving stock (Show, Eq, Generic) deriving newtype (ToCBOR, FromCBOR) - deriving NoThunks via OnlyCheckWhnfNamed "SignKeyVRF PraosBatchCompatVRF" SignKey + deriving (NoThunks) via OnlyCheckWhnfNamed "SignKeyVRF PraosBatchCompatVRF" SignKey deriving newtype (NFData) newtype CertVRF PraosBatchCompatVRF = CertPraosBatchCompatVRF Proof - deriving stock (Show, Eq, Generic) + deriving stock (Show, Eq, Generic) deriving newtype (ToCBOR, FromCBOR) - deriving NoThunks via OnlyCheckWhnfNamed "CertKeyVRF PraosBatchCompatVRF" Proof + deriving (NoThunks) via OnlyCheckWhnfNamed "CertKeyVRF PraosBatchCompatVRF" Proof deriving newtype (NFData) type Signable PraosBatchCompatVRF = SignableRepresentation @@ -481,8 +504,9 @@ instance VRFAlgorithm PraosBatchCompatVRF where let msgBS = getSignableRepresentation msg proof = fromMaybe (error "Invalid Key") $ prove sk msgBS output = fromMaybe (error "Invalid Proof") $ outputFromProof proof - in output `seq` proof `seq` - (OutputVRF (outputBytes output), CertPraosBatchCompatVRF proof) + in output `seq` + proof `seq` + (OutputVRF (outputBytes output), CertPraosBatchCompatVRF proof) verifyVRF = \_ (VerKeyPraosBatchCompatVRF pk) msg (CertPraosBatchCompatVRF proof) -> (OutputVRF . outputBytes) <$> verify pk proof (getSignableRepresentation msg) @@ -491,9 +515,10 @@ instance VRFAlgorithm PraosBatchCompatVRF where seedSizeVRF _ = fromIntegral crypto_vrf_ietfdraft13_seedbytes genKeyPairVRF = \cryptoseed -> - let seed = seedFromBytes . fst . getBytesFromSeedT (fromIntegral crypto_vrf_ietfdraft13_seedbytes) $ cryptoseed + let seed = + seedFromBytes . fst . getBytesFromSeedT (fromIntegral crypto_vrf_ietfdraft13_seedbytes) $ cryptoseed (pk, sk) = keypairFromSeed seed - in sk `seq` pk `seq` (SignKeyPraosBatchCompatVRF sk, VerKeyPraosBatchCompatVRF pk) + in sk `seq` pk `seq` (SignKeyPraosBatchCompatVRF sk, VerKeyPraosBatchCompatVRF pk) rawSerialiseVerKeyVRF (VerKeyPraosBatchCompatVRF pk) = vkBytes pk rawSerialiseSignKeyVRF (SignKeyPraosBatchCompatVRF sk) = skBytes sk @@ -508,7 +533,7 @@ instance VRFAlgorithm PraosBatchCompatVRF where assertLength :: Int -> ByteString -> Maybe ByteString assertLength l bs - | BS.length bs == l - = Just bs - | otherwise - = Nothing + | BS.length bs == l = + Just bs + | otherwise = + Nothing diff --git a/cardano-crypto-tests/bench/Main.hs b/cardano-crypto-tests/bench/Main.hs index 3ca2964da..234939c79 100644 --- a/cardano-crypto-tests/bench/Main.hs +++ b/cardano-crypto-tests/bench/Main.hs @@ -1,12 +1,12 @@ module Main (main) where -import Criterion.Main import Cardano.Crypto.Libsodium.Init +import Criterion.Main import qualified Bench.Crypto.DSIGN (benchmarks) -import qualified Bench.Crypto.HASH (benchmarks) -import qualified Bench.Crypto.KES (benchmarks) -import qualified Bench.Crypto.VRF (benchmarks) +import qualified Bench.Crypto.HASH (benchmarks) +import qualified Bench.Crypto.KES (benchmarks) +import qualified Bench.Crypto.VRF (benchmarks) main :: IO () main = do diff --git a/cardano-crypto-tests/src/Bench/Crypto/BenchData.hs b/cardano-crypto-tests/src/Bench/Crypto/BenchData.hs index c66519bc4..5458932e3 100644 --- a/cardano-crypto-tests/src/Bench/Crypto/BenchData.hs +++ b/cardano-crypto-tests/src/Bench/Crypto/BenchData.hs @@ -1,14 +1,14 @@ module Bench.Crypto.BenchData where +import Data.ByteString (ByteString) import qualified Data.ByteString as BS -import Data.ByteString (ByteString) - -import Cardano.Crypto.Seed +import Cardano.Crypto.Seed testSeed :: Seed testSeed = mkSeedFromBytes testBytes +{- FOURMOLU_DISABLE -} testBytes :: ByteString testBytes = BS.pack -- Totally random, determined by fair dice rolls @@ -37,4 +37,4 @@ typicalMsg = BS.pack , 0x39, 0xde, 0x6c, 0xc3, 0x29, 0x6a, 0xf2, 0xd5 , 0xff, 0x0e, 0xbc, 0xf6, 0xac, 0x81, 0xc2, 0x02 ] - +{- FOURMOLU_ENABLE -} diff --git a/cardano-crypto-tests/src/Bench/Crypto/DSIGN.hs b/cardano-crypto-tests/src/Bench/Crypto/DSIGN.hs index e1a088276..48dd9658e 100644 --- a/cardano-crypto-tests/src/Bench/Crypto/DSIGN.hs +++ b/cardano-crypto-tests/src/Bench/Crypto/DSIGN.hs @@ -1,11 +1,14 @@ {-# LANGUAGE CPP #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FunctionalDependencies #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} + +{- FOURMOLU_DISABLE -} + module Bench.Crypto.DSIGN ( benchmarks ) where diff --git a/cardano-crypto-tests/src/Bench/Crypto/HASH.hs b/cardano-crypto-tests/src/Bench/Crypto/HASH.hs index 2a935ab40..41beef960 100644 --- a/cardano-crypto-tests/src/Bench/Crypto/HASH.hs +++ b/cardano-crypto-tests/src/Bench/Crypto/HASH.hs @@ -1,39 +1,41 @@ -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleContexts #-} -module Bench.Crypto.HASH - ( benchmarks - ) where +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} + +module Bench.Crypto.HASH ( + benchmarks, +) where -import Data.Proxy import Cardano.Binary +import Data.Proxy -import Cardano.Crypto.Hash.Class import Cardano.Crypto.Hash.Blake2b +import Cardano.Crypto.Hash.Class import Criterion import Bench.Crypto.BenchData - benchmarks :: Benchmark benchmarks = - bgroup "HASH" + bgroup + "HASH" [ benchHASH (Proxy @Blake2b_224) "Blake2b_224" , benchHASH (Proxy @Blake2b_256) "Blake2b_256" ] benchHASH :: - forall proxy h. HashAlgorithm h - => proxy h - -> [Char] - -> Benchmark + forall proxy h. + HashAlgorithm h => + proxy h -> + [Char] -> + Benchmark benchHASH _ lbl = - bgroup lbl + bgroup + lbl [ bench "hashWith" $ nf (hashWith @h id) testBytes - , env (return (serialize' (hashWith @h id testBytes))) $ - bench "decodeHash" . - nf (either (error . show) (id @(Hash h ByteString)) . decodeFull') + bench "decodeHash" + . nf (either (error . show) (id @(Hash h ByteString)) . decodeFull') ] diff --git a/cardano-crypto-tests/src/Bench/Crypto/KES.hs b/cardano-crypto-tests/src/Bench/Crypto/KES.hs index 38369ee55..ccb1ba3d1 100644 --- a/cardano-crypto-tests/src/Bench/Crypto/KES.hs +++ b/cardano-crypto-tests/src/Bench/Crypto/KES.hs @@ -1,35 +1,35 @@ -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -module Bench.Crypto.KES - ( benchmarks - ) where -import Data.Proxy +module Bench.Crypto.KES ( + benchmarks, +) where + import Data.Maybe (fromJust) +import Data.Proxy import Control.DeepSeq import Cardano.Crypto.DSIGN.Ed25519 import Cardano.Crypto.Hash.Blake2b import Cardano.Crypto.KES.Class -import Cardano.Crypto.KES.Sum import Cardano.Crypto.KES.CompactSum +import Cardano.Crypto.KES.Sum - +import Cardano.Crypto.Libsodium as NaCl +import Cardano.Crypto.Libsodium.MLockedSeed import Criterion import qualified Data.ByteString as BS (ByteString) import Data.Either (fromRight) -import Cardano.Crypto.Libsodium as NaCl -import Cardano.Crypto.Libsodium.MLockedSeed -import System.IO.Unsafe (unsafePerformIO) -import GHC.TypeLits (KnownNat) import Data.Kind (Type) +import GHC.TypeLits (KnownNat) +import System.IO.Unsafe (unsafePerformIO) import Bench.Crypto.BenchData @@ -40,33 +40,36 @@ testSeedML :: forall n. KnownNat n => MLockedSeed n testSeedML = MLockedSeed . unsafePerformIO $ NaCl.mlsbFromByteString testBytes benchmarks :: Benchmark -benchmarks = bgroup "KES" - [ benchKES @Proxy @(Sum6KES Ed25519DSIGN Blake2b_256) Proxy "Sum6KES" - , benchKES @Proxy @(Sum7KES Ed25519DSIGN Blake2b_256) Proxy "Sum7KES" - , benchKES @Proxy @(CompactSum6KES Ed25519DSIGN Blake2b_256) Proxy "CompactSum6KES" - , benchKES @Proxy @(CompactSum7KES Ed25519DSIGN Blake2b_256) Proxy "CompactSum7KES" - ] - - +benchmarks = + bgroup + "KES" + [ benchKES @Proxy @(Sum6KES Ed25519DSIGN Blake2b_256) Proxy "Sum6KES" + , benchKES @Proxy @(Sum7KES Ed25519DSIGN Blake2b_256) Proxy "Sum7KES" + , benchKES @Proxy @(CompactSum6KES Ed25519DSIGN Blake2b_256) Proxy "CompactSum6KES" + , benchKES @Proxy @(CompactSum7KES Ed25519DSIGN Blake2b_256) Proxy "CompactSum7KES" + ] {-# NOINLINE benchKES #-} -benchKES :: forall (proxy :: forall k. k -> Type) v - . ( KESAlgorithm v - , ContextKES v ~ () - , Signable v BS.ByteString - , NFData (SignKeyKES v) - , NFData (SigKES v) - ) - => proxy v - -> [Char] - -> Benchmark +benchKES :: + forall (proxy :: forall k. k -> Type) v. + ( KESAlgorithm v + , ContextKES v ~ () + , Signable v BS.ByteString + , NFData (SignKeyKES v) + , NFData (SigKES v) + ) => + proxy v -> + [Char] -> + Benchmark benchKES _ lbl = - bgroup lbl + bgroup + lbl [ bench "genKey" $ - nfIO $ genKeyKES @v testSeedML >>= forgetSignKeyKES @v + nfIO $ + genKeyKES @v testSeedML >>= forgetSignKeyKES @v , bench "signKES" $ nfIO $ - (\sk -> do { sig <- signKES @v() 0 typicalMsg sk; forgetSignKeyKES sk; return sig }) + (\sk -> do sig <- signKES @v () 0 typicalMsg sk; forgetSignKeyKES sk; return sig) =<< genKeyKES @v testSeedML , bench "verifyKES" $ nfIO $ do diff --git a/cardano-crypto-tests/src/Bench/Crypto/VRF.hs b/cardano-crypto-tests/src/Bench/Crypto/VRF.hs index 5b7ae4ae3..96ee0e8bb 100644 --- a/cardano-crypto-tests/src/Bench/Crypto/VRF.hs +++ b/cardano-crypto-tests/src/Bench/Crypto/VRF.hs @@ -1,57 +1,60 @@ -{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -{-# LANGUAGE FlexibleContexts #-} -module Bench.Crypto.VRF - ( benchmarks - ) where -import Data.Proxy +module Bench.Crypto.VRF ( + benchmarks, +) where + import Data.ByteString (ByteString) +import Data.Proxy import Control.DeepSeq import Cardano.Crypto.VRF.Class -import Cardano.Crypto.VRF.Simple import Cardano.Crypto.VRF.Praos hiding (Seed) +import Cardano.Crypto.VRF.Simple import Criterion import Bench.Crypto.BenchData - benchmarks :: Benchmark benchmarks = - bgroup "VRF" + bgroup + "VRF" [ benchVRF (Proxy @SimpleVRF) "SimpleVRF" , benchVRF (Proxy @PraosVRF) "PraosVRF" ] -benchVRF :: forall proxy v - . ( VRFAlgorithm v - , ContextVRF v ~ () - , Signable v ByteString - , NFData (CertVRF v) - , NFData (SignKeyVRF v) - , NFData (VerKeyVRF v) - ) - => proxy v - -> [Char] - -> Benchmark +benchVRF :: + forall proxy v. + ( VRFAlgorithm v + , ContextVRF v ~ () + , Signable v ByteString + , NFData (CertVRF v) + , NFData (SignKeyVRF v) + , NFData (VerKeyVRF v) + ) => + proxy v -> + [Char] -> + Benchmark benchVRF _ lbl = - bgroup lbl + bgroup + lbl [ bench "genKey" $ nf (genKeyVRF @v) testSeed - , env (return (genKeyVRF @v testSeed)) $ \signKey -> - bench "eval" $ - nf (evalVRF @v () typicalMsg) signKey - - , env (let (sk, vk) = genKeyPairVRF @v testSeed - (_output, cert) = evalVRF @v () typicalMsg sk - in return (vk, cert) - ) $ \ ~(vk, cert) -> - bench "verify" $ - nf (verifyVRF () vk typicalMsg) cert + bench "eval" $ + nf (evalVRF @v () typicalMsg) signKey + , env + ( let (sk, vk) = genKeyPairVRF @v testSeed + (_output, cert) = evalVRF @v () typicalMsg sk + in return (vk, cert) + ) + $ \ ~(vk, cert) -> + bench "verify" $ + nf (verifyVRF () vk typicalMsg) cert ] diff --git a/cardano-crypto-tests/src/Test/Crypto/AllocLog.hs b/cardano-crypto-tests/src/Test/Crypto/AllocLog.hs index 8e9afd478..6075f34e2 100644 --- a/cardano-crypto-tests/src/Test/Crypto/AllocLog.hs +++ b/cardano-crypto-tests/src/Test/Crypto/AllocLog.hs @@ -2,15 +2,16 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} + module Test.Crypto.AllocLog where import Control.Tracer import Data.Typeable -import Foreign.Ptr import Foreign.Concurrent +import Foreign.Ptr import Cardano.Crypto.Libsodium (withMLockedForeignPtr) -import Cardano.Crypto.Libsodium.Memory (MLockedAllocator(..)) +import Cardano.Crypto.Libsodium.Memory (MLockedAllocator (..)) import Cardano.Crypto.Libsodium.Memory.Internal (MLockedForeignPtr (..)) -- | Allocation log event. These are emitted automatically whenever mlocked @@ -30,9 +31,9 @@ mkLoggingAllocator tracer ioAllocator = MLockedAllocator { mlAllocate = \size -> do - sfptr@(SFP fptr) <- mlAllocate ioAllocator size - addr <- withMLockedForeignPtr sfptr (return . ptrToWordPtr) - traceWith tracer (AllocEv addr) - addForeignPtrFinalizer fptr (traceWith tracer (FreeEv addr)) - return sfptr + sfptr@(SFP fptr) <- mlAllocate ioAllocator size + addr <- withMLockedForeignPtr sfptr (return . ptrToWordPtr) + traceWith tracer (AllocEv addr) + addForeignPtrFinalizer fptr (traceWith tracer (FreeEv addr)) + return sfptr } diff --git a/cardano-crypto-tests/src/Test/Crypto/DSIGN.hs b/cardano-crypto-tests/src/Test/Crypto/DSIGN.hs index 102bdedf4..15fdd4558 100644 --- a/cardano-crypto-tests/src/Test/Crypto/DSIGN.hs +++ b/cardano-crypto-tests/src/Test/Crypto/DSIGN.hs @@ -1,13 +1,14 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE NumericUnderscores #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE NumericUnderscores #-} +{- FOURMOLU_DISABLE -} module Test.Crypto.DSIGN ( tests ) diff --git a/cardano-crypto-tests/src/Test/Crypto/EllipticCurve.hs b/cardano-crypto-tests/src/Test/Crypto/EllipticCurve.hs index 0f72916fa..032d0c8ab 100644 --- a/cardano-crypto-tests/src/Test/Crypto/EllipticCurve.hs +++ b/cardano-crypto-tests/src/Test/Crypto/EllipticCurve.hs @@ -1,9 +1,8 @@ -{-# OPTIONS_GHC -Wno-orphans #-} - -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{-# OPTIONS_GHC -Wno-orphans #-} module Test.Crypto.EllipticCurve where @@ -15,32 +14,34 @@ import Test.Crypto.Util (eitherShowError) import qualified Cardano.Crypto.EllipticCurve.BLS12_381 as BLS import qualified Cardano.Crypto.EllipticCurve.BLS12_381.Internal as BLS import Cardano.Crypto.Hash (SHA256, digest) +import Data.Bits (shiftL) +import qualified Data.ByteString as BS +import qualified Data.ByteString.Base16 as Base16 +import qualified Data.ByteString.Char8 as BS8 +import qualified Data.Foldable as F (foldl') +import Data.Proxy (Proxy (..)) +import System.IO.Unsafe (unsafePerformIO) import Test.Crypto.Instances () import Test.QuickCheck ( - (===), - (==>), - Arbitrary(..), - Property, - choose, - chooseAny, - oneof, - suchThatMap, - ) + Arbitrary (..), + Property, + choose, + chooseAny, + oneof, + suchThatMap, + (===), + (==>), + ) import Test.Tasty (TestTree, testGroup) +import Test.Tasty.HUnit (assertBool, assertEqual, testCase) import Test.Tasty.QuickCheck (testProperty) -import Test.Tasty.HUnit (testCase, assertBool, assertEqual) -import Data.Proxy (Proxy (..)) -import qualified Data.ByteString as BS -import qualified Data.ByteString.Char8 as BS8 -import qualified Data.ByteString.Base16 as Base16 -import System.IO.Unsafe (unsafePerformIO) -import Data.Bits (shiftL) -import qualified Data.Foldable as F (foldl') tests :: TestTree tests = - testGroup "Crypto.EllipticCurve" - [ testGroup "BLS12_381" + testGroup + "Crypto.EllipticCurve" + [ testGroup + "BLS12_381" [ testUtil "Utility" , testScalar "Scalar" , testBLSCurve "Curve 1" (Proxy @BLS.Curve1) @@ -53,12 +54,13 @@ tests = testUtil :: String -> TestTree testUtil name = - testGroup name + testGroup + name [ testProperty "Integer / C-String 32 round-trip" $ \n -> n >= 0 ==> - n < (1 `shiftL` 32 * 8) ==> - n === unsafePerformIO (BLS.integerAsCStrL 32 n BLS.cstrToInteger) + n < (1 `shiftL` 32 * 8) ==> + n === unsafePerformIO (BLS.integerAsCStrL 32 n BLS.cstrToInteger) , testProperty "padBS min length" $ \n bsw -> BS.length (BLS.padBS n (BS.pack bsw)) >= n , testProperty "padBS adds zeroes to front" $ \bsw -> @@ -70,7 +72,8 @@ testUtil name = testScalar :: String -> TestTree testScalar name = - testGroup name + testGroup + name [ testProperty "self-equality" $ \(a :: BLS.Scalar) -> a === a , testProperty "to/from BS round-trip" $ @@ -81,31 +84,41 @@ testScalar name = \s -> s === unsafePerformIO (BLS.scalarToInteger s >>= BLS.scalarFromInteger) , testCase "integer from scalar" $ do s <- case BLS.scalarFromBS (BLS.padBS 32 (BS.pack [0x12, 0x34])) of - Left err -> error (show err) - Right x -> return x + Left err -> error (show err) + Right x -> return x let expected = 0x1234 actual <- BLS.scalarToInteger s assertEqual "0x1234" expected actual ] -testBLSCurve :: forall curve. BLS.BLS curve - => String -> Proxy curve -> TestTree +testBLSCurve :: + forall curve. + BLS.BLS curve => + String -> Proxy curve -> TestTree testBLSCurve name _ = - testGroup name + testGroup + name [ testCase "generator in group" $ assertBool "" (BLS.blsInGroup (BLS.blsGenerator @curve)) , testCase "neg generator in group" $ assertBool "" (BLS.blsInGroup (BLS.blsNeg (BLS.blsGenerator @curve))) , testCase "add generator to itself" $ - assertBool "" (BLS.blsInGroup (BLS.blsAddOrDouble (BLS.blsGenerator @curve) (BLS.blsGenerator @curve))) + assertBool + "" + (BLS.blsInGroup (BLS.blsAddOrDouble (BLS.blsGenerator @curve) (BLS.blsGenerator @curve))) , testProperty "in group" (BLS.blsInGroup @curve) , testProperty "neg in group" (BLS.blsInGroup @curve . BLS.blsNeg) - , testProperty "self-equality" (\(a :: BLS.Point curve) -> a === a) , testProperty "double negation" (\(a :: BLS.Point curve) -> a === BLS.blsNeg (BLS.blsNeg a)) - , testProperty "adding infinity yields equality" (\(a :: BLS.Point curve) -> BLS.blsAddOrDouble a (BLS.blsZero @curve) === a) - , testProperty "addition associative" (testAssoc (BLS.blsAddOrDouble :: BLS.Point curve -> BLS.Point curve -> BLS.Point curve)) - , testProperty "addition commutative" (testCommut (BLS.blsAddOrDouble :: BLS.Point curve -> BLS.Point curve -> BLS.Point curve)) + , testProperty + "adding infinity yields equality" + (\(a :: BLS.Point curve) -> BLS.blsAddOrDouble a (BLS.blsZero @curve) === a) + , testProperty + "addition associative" + (testAssoc (BLS.blsAddOrDouble :: BLS.Point curve -> BLS.Point curve -> BLS.Point curve)) + , testProperty + "addition commutative" + (testCommut (BLS.blsAddOrDouble :: BLS.Point curve -> BLS.Point curve -> BLS.Point curve)) , testProperty "adding negation yields infinity" (testAddNegYieldsInf @curve) , testProperty "round-trip serialization" $ testRoundTripEither @(BLS.Point curve) BLS.blsSerialize BLS.blsDeserialize @@ -119,12 +132,12 @@ testBLSCurve name _ = BLS.blsMult (BLS.blsMult a b) c === BLS.blsMult (BLS.blsMult a c) b , testProperty "scalar mult distributive left" $ \(a :: BLS.Point curve) (BigInteger b) (BigInteger c) -> BLS.blsMult a (b + c) === BLS.blsAddOrDouble (BLS.blsMult a b) (BLS.blsMult a c) - , testProperty "scalar mult distributive right" $ \ (a :: BLS.Point curve) (b :: BLS.Point curve) (BigInteger c) -> + , testProperty "scalar mult distributive right" $ \(a :: BLS.Point curve) (b :: BLS.Point curve) (BigInteger c) -> BLS.blsMult (BLS.blsAddOrDouble a b) c === BLS.blsAddOrDouble (BLS.blsMult a c) (BLS.blsMult b c) , testProperty "mult by zero is inf" $ \(a :: BLS.Point curve) -> BLS.blsIsInf (BLS.blsMult a 0) , testProperty "mult by -1 is equal to neg" $ \(a :: BLS.Point curve) -> - BLS.blsMult a (-1) === BLS.blsNeg a + BLS.blsMult a (-1) === BLS.blsNeg a , testProperty "modular multiplication" $ \(BigInteger a) (BigInteger b) (p :: BLS.Point curve) -> BLS.blsMult p a === BLS.blsMult p (a + b * BLS.scalarPeriod) , testProperty "repeated addition" (prop_repeatedAddition @curve) @@ -133,10 +146,13 @@ testBLSCurve name _ = testPT :: String -> TestTree testPT name = - testGroup name - [ testProperty "mult associative" + testGroup + name + [ testProperty + "mult associative" (testAssoc BLS.ptMult) - , testProperty "mult commutative" + , testProperty + "mult commutative" (testCommut BLS.ptMult) , testProperty "self-equality" (\(a :: BLS.PT) -> a === a) , testProperty "self-final-verify" (\(a :: BLS.PT) -> BLS.ptFinalVerify a a) @@ -144,7 +160,8 @@ testPT name = testPairing :: String -> TestTree testPairing name = - testGroup name + testGroup + name [ testProperty "identity" $ \a b -> pairingCheck (a, b) @@ -165,8 +182,8 @@ testPairing name = , testProperty "four pairings" prop_fourPairings , testProperty "finalVerify fails on random inputs" prop_randomFailsFinalVerify ] - where - pairingCheck (a, b) (c, d) = BLS.ptFinalVerify (BLS.millerLoop a b) (BLS.millerLoop c d) + where + pairingCheck (a, b) (c, d) = BLS.ptFinalVerify (BLS.millerLoop a b) (BLS.millerLoop c d) loadHexFile :: String -> IO [BS.ByteString] loadHexFile filename = do @@ -174,7 +191,8 @@ loadHexFile filename = do testVectors :: String -> TestTree testVectors name = - testGroup name + testGroup + name [ testVectorPairings "pairings" , testVectorOperations "operations" , testVectorSerDe "serialization/compression" @@ -185,16 +203,18 @@ testVectors name = testVectorPairings :: String -> TestTree testVectorPairings name = testCase name $ do - [ p_raw, - aP_raw, - bP_raw, - apbP_raw, - axbP_raw, - q_raw, - aQ_raw, - bQ_raw, - apbQ_raw, - axbQ_raw ] <- loadHexFile =<< getDataFileName "bls12-381-test-vectors/test_vectors/pairing_test_vectors" + [ p_raw + , aP_raw + , bP_raw + , apbP_raw + , axbP_raw + , q_raw + , aQ_raw + , bQ_raw + , apbQ_raw + , axbQ_raw + ] <- + loadHexFile =<< getDataFileName "bls12-381-test-vectors/test_vectors/pairing_test_vectors" p <- eitherShowError $ BLS.blsUncompress p_raw q <- eitherShowError $ BLS.blsUncompress q_raw @@ -235,18 +255,20 @@ testVectorPairings name = testVectorOperations :: String -> TestTree testVectorOperations name = testCase name $ do - [ g1p_raw, - g1q_raw, - g1add_raw, - g1sub_raw, - g1mul_raw, - g1neg_raw, - g2p_raw, - g2q_raw, - g2add_raw, - g2sub_raw, - g2mul_raw, - g2neg_raw ] <- loadHexFile =<< getDataFileName "bls12-381-test-vectors/test_vectors/ec_operations_test_vectors" + [ g1p_raw + , g1q_raw + , g1add_raw + , g1sub_raw + , g1mul_raw + , g1neg_raw + , g2p_raw + , g2q_raw + , g2add_raw + , g2sub_raw + , g2mul_raw + , g2neg_raw + ] <- + loadHexFile =<< getDataFileName "bls12-381-test-vectors/test_vectors/ec_operations_test_vectors" let scalar = 0x40df499974f62e2f268cd5096b0d952073900054122ffce0a27c9d96932891a5 g1p :: BLS.Point1 <- eitherShowError $ BLS.blsUncompress g1p_raw @@ -262,74 +284,99 @@ testVectorOperations name = g2mul :: BLS.Point2 <- eitherShowError $ BLS.blsUncompress g2mul_raw g2neg :: BLS.Point2 <- eitherShowError $ BLS.blsUncompress g2neg_raw - assertEqual "g1 add" - g1add (BLS.blsAddOrDouble g1p g1q) - assertEqual "g1 sub" - g1sub (BLS.blsAddOrDouble g1p (BLS.blsNeg g1q)) - assertEqual "g1 mul" - g1mul (BLS.blsMult g1q scalar) - assertEqual "g1 neg" - g1neg (BLS.blsNeg g1p) - - assertEqual "g2 add" - g2add (BLS.blsAddOrDouble g2p g2q) - assertEqual "g2 sub" - g2sub (BLS.blsAddOrDouble g2p (BLS.blsNeg g2q)) - assertEqual "g2 mul" - g2mul (BLS.blsMult g2q scalar) - assertEqual "g2 neg" - g2neg (BLS.blsNeg g2p) + assertEqual + "g1 add" + g1add + (BLS.blsAddOrDouble g1p g1q) + assertEqual + "g1 sub" + g1sub + (BLS.blsAddOrDouble g1p (BLS.blsNeg g1q)) + assertEqual + "g1 mul" + g1mul + (BLS.blsMult g1q scalar) + assertEqual + "g1 neg" + g1neg + (BLS.blsNeg g1p) + + assertEqual + "g2 add" + g2add + (BLS.blsAddOrDouble g2p g2q) + assertEqual + "g2 sub" + g2sub + (BLS.blsAddOrDouble g2p (BLS.blsNeg g2q)) + assertEqual + "g2 mul" + g2mul + (BLS.blsMult g2q scalar) + assertEqual + "g2 neg" + g2neg + (BLS.blsNeg g2p) testVectorSerDe :: String -> TestTree testVectorSerDe name = testCase name $ do - [ g1UncompNotOnCurve, - g1CompNotOnCurve, - g1CompNotInGroup, - g1UncompNotInGroup, - g2UncompNotOnCurve, - g2CompNotOnCurve, - g2CompNotInGroup, - g2UncompNotInGroup ] <- loadHexFile =<< getDataFileName "bls12-381-test-vectors/test_vectors/serde_test_vectors" - - assertEqual "g1UncompNotOnCurve" + [ g1UncompNotOnCurve + , g1CompNotOnCurve + , g1CompNotInGroup + , g1UncompNotInGroup + , g2UncompNotOnCurve + , g2CompNotOnCurve + , g2CompNotInGroup + , g2UncompNotInGroup + ] <- + loadHexFile =<< getDataFileName "bls12-381-test-vectors/test_vectors/serde_test_vectors" + + assertEqual + "g1UncompNotOnCurve" (Left BLS.BLST_POINT_NOT_ON_CURVE) (BLS.blsDeserialize g1UncompNotOnCurve :: Either BLS.BLSTError BLS.Point1) - assertEqual "g1CompNotInGroup" + assertEqual + "g1CompNotInGroup" (Left BLS.BLST_POINT_NOT_IN_GROUP) (BLS.blsUncompress g1CompNotInGroup :: Either BLS.BLSTError BLS.Point1) - assertEqual "g1CompNotOnCurve" + assertEqual + "g1CompNotOnCurve" (Left BLS.BLST_POINT_NOT_ON_CURVE) (BLS.blsUncompress g1CompNotOnCurve :: Either BLS.BLSTError BLS.Point1) - assertEqual "g1UncompNotInGroup" + assertEqual + "g1UncompNotInGroup" (Left BLS.BLST_POINT_NOT_IN_GROUP) (BLS.blsDeserialize g1UncompNotInGroup :: Either BLS.BLSTError BLS.Point1) - - assertEqual "g2UncompNotOnCurve" + assertEqual + "g2UncompNotOnCurve" (Left BLS.BLST_POINT_NOT_ON_CURVE) (BLS.blsDeserialize g2UncompNotOnCurve :: Either BLS.BLSTError BLS.Point2) - assertEqual "g2CompNotInGroup" + assertEqual + "g2CompNotInGroup" (Left BLS.BLST_POINT_NOT_IN_GROUP) (BLS.blsUncompress g2CompNotInGroup :: Either BLS.BLSTError BLS.Point2) - assertEqual "g2CompNotOnCurve" + assertEqual + "g2CompNotOnCurve" (Left BLS.BLST_POINT_NOT_ON_CURVE) (BLS.blsUncompress g2CompNotOnCurve :: Either BLS.BLSTError BLS.Point2) - assertEqual "g2UncompNotInGroup" + assertEqual + "g2UncompNotInGroup" (Left BLS.BLST_POINT_NOT_IN_GROUP) (BLS.blsDeserialize g2UncompNotInGroup :: Either BLS.BLSTError BLS.Point2) - testVectorSigAug :: String -> TestTree testVectorSigAug name = testCase name $ do - [ sig_raw, pk_raw ] <- loadHexFile =<< getDataFileName "bls12-381-test-vectors/test_vectors/bls_sig_aug_test_vectors" + [sig_raw, pk_raw] <- + loadHexFile =<< getDataFileName "bls12-381-test-vectors/test_vectors/bls_sig_aug_test_vectors" let dst = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_" let msg = "blst is such a blast" let aug = "Random value for test aug. " @@ -345,14 +392,17 @@ testVectorSigAug name = testVectorLargeDst :: String -> TestTree testVectorLargeDst name = testCase name $ do - [ msg_raw, large_dst_raw, output_raw ] <- loadHexFile =<< getDataFileName "bls12-381-test-vectors/test_vectors/h2c_large_dst" + [msg_raw, large_dst_raw, output_raw] <- + loadHexFile =<< getDataFileName "bls12-381-test-vectors/test_vectors/h2c_large_dst" let prefix = "H2C-OVERSIZE-DST-" let dst_sha = digest (Proxy @SHA256) (prefix <> large_dst_raw) let hashedMsg = BLS.blsHash msg_raw (Just dst_sha) Nothing expected_output :: BLS.Point1 <- eitherShowError $ BLS.blsUncompress output_raw - assertEqual "expected hash output" - hashedMsg expected_output + assertEqual + "expected hash output" + hashedMsg + expected_output testAssoc :: (Show a, Eq a) => (a -> a -> a) -> a -> a -> a -> Property testAssoc f a b c = @@ -364,21 +414,25 @@ testCommut f a b = prop_repeatedAddition :: forall curve. BLS.BLS curve => Int -> BLS.Point curve -> Property prop_repeatedAddition a p = BLS.blsMult p (fromIntegral a) === repeatedAdd a p - where + where repeatedAdd :: Int -> BLS.Point curve -> BLS.Point curve repeatedAdd scalar point = - F.foldl' BLS.blsAddOrDouble BLS.blsZero $ replicate (abs scalar) (BLS.blsCneg point (scalar < 0)) + F.foldl' BLS.blsAddOrDouble BLS.blsZero $ replicate (abs scalar) (BLS.blsCneg point (scalar < 0)) -testAddNegYieldsInf :: forall curve. BLS.BLS curve - => BLS.Point curve -> Bool +testAddNegYieldsInf :: + forall curve. + BLS.BLS curve => + BLS.Point curve -> Bool testAddNegYieldsInf p = BLS.blsIsInf (BLS.blsAddOrDouble p (BLS.blsNeg p)) -testRoundTripEither :: forall p a err. (Show p, Show err, Eq p, Eq err) - => (p -> a) - -> (a -> Either err p) - -> p - -> Property +testRoundTripEither :: + forall p a err. + (Show p, Show err, Eq p, Eq err) => + (p -> a) -> + (a -> Either err p) -> + p -> + Property testRoundTripEither encode decode p = Right p === (decode . encode) p @@ -401,13 +455,13 @@ prop_fourPairings a1 a2 a3 b = BLS.ptFinalVerify tt t4 prop_randomFailsFinalVerify :: BLS.Point1 -> BLS.Point1 -> BLS.Point2 -> BLS.Point2 -> Property prop_randomFailsFinalVerify a b c d = - a /= b && c /= d ==> + a /= b && c /= d ==> BLS.ptFinalVerify (BLS.millerLoop a c) (BLS.millerLoop b d) === False newtype BigInteger = BigInteger Integer deriving (Eq, Show) instance Arbitrary BigInteger where - arbitrary = BigInteger <$> oneof [arbitrary, chooseAny, choose (- 2 ^ (128 :: Int), 2 ^ (128 ::Int))] + arbitrary = BigInteger <$> oneof [arbitrary, chooseAny, choose (-2 ^ (128 :: Int), 2 ^ (128 :: Int))] instance BLS.BLS curve => Arbitrary (BLS.Point curve) where arbitrary = do @@ -427,11 +481,10 @@ instance Show BLS.PT where instance Arbitrary BLS.Scalar where arbitrary = (BLS.scalarFromBS . BS.pack <$> arbitrary) - `suchThatMap` - (\case - Left _ -> Nothing - Right v -> Just v - ) + `suchThatMap` ( \case + Left _ -> Nothing + Right v -> Just v + ) instance Show BLS.Scalar where show = show . BLS.scalarToBS diff --git a/cardano-crypto-tests/src/Test/Crypto/EqST.hs b/cardano-crypto-tests/src/Test/Crypto/EqST.hs index 5dd4f2f85..d3a4192d2 100644 --- a/cardano-crypto-tests/src/Test/Crypto/EqST.hs +++ b/cardano-crypto-tests/src/Test/Crypto/EqST.hs @@ -6,15 +6,15 @@ module Test.Crypto.EqST where -import GHC.TypeLits (KnownNat) -import qualified Data.Vector as Vec import Control.Monad.Class.MonadST (MonadST) +import qualified Data.Vector as Vec +import GHC.TypeLits (KnownNat) -import Cardano.Crypto.Libsodium.MLockedBytes.Internal -import Cardano.Crypto.Libsodium.MLockedSeed -import Cardano.Crypto.DSIGN.Ed25519 import Cardano.Crypto.DSIGN.Class +import Cardano.Crypto.DSIGN.Ed25519 import Cardano.Crypto.KES.Simple +import Cardano.Crypto.Libsodium.MLockedBytes.Internal +import Cardano.Crypto.Libsodium.MLockedSeed -- | Monadic flavor of 'Eq', for things that can only be compared in a monadic -- context that satisfies 'MonadST'. @@ -29,11 +29,13 @@ nequalsM a b = not <$> equalsM a b -- | Infix version of 'equalsM' (==!) :: (MonadST m, EqST a) => a -> a -> m Bool (==!) = equalsM + infix 4 ==! -- | Infix version of 'nequalsM' (!=!) :: (MonadST m, EqST a) => a -> a -> m Bool (!=!) = nequalsM + infix 4 !=! instance EqST a => EqST (Maybe a) where @@ -76,8 +78,10 @@ deriving via instance KnownNat n => EqST (MLockedSeed n) -deriving via (MLockedSizedBytes (SizeSignKeyDSIGN Ed25519DSIGN)) - instance EqST (SignKeyDSIGNM Ed25519DSIGN) +deriving via + (MLockedSizedBytes (SizeSignKeyDSIGN Ed25519DSIGN)) + instance + EqST (SignKeyDSIGNM Ed25519DSIGN) instance EqST (SignKeyDSIGNM d) => EqST (SignKeyKES (SimpleKES d t)) where equalsM (ThunkySignKeySimpleKES a) (ThunkySignKeySimpleKES b) = diff --git a/cardano-crypto-tests/src/Test/Crypto/Hash.hs b/cardano-crypto-tests/src/Test/Crypto/Hash.hs index a8464eae9..e97c46c82 100644 --- a/cardano-crypto-tests/src/Test/Crypto/Hash.hs +++ b/cardano-crypto-tests/src/Test/Crypto/Hash.hs @@ -2,26 +2,25 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} - {-# OPTIONS_GHC -Wno-orphans #-} -module Test.Crypto.Hash - ( tests - ) +module Test.Crypto.Hash ( + tests, +) where import Cardano.Crypto.Hash +import Control.Exception (bracket) import Data.Bifunctor import qualified Data.Bits as Bits (xor) import qualified Data.ByteString as BS import qualified Data.ByteString.Short as SBS import Data.Maybe (fromJust) import Data.MemPack -import Data.Proxy (Proxy(..)) +import Data.Proxy (Proxy (..)) import Data.String (fromString) import GHC.TypeLits -import Control.Exception (bracket) -import Test.Crypto.Util (prop_cbor, prop_cbor_size, prop_no_thunks, Lock, withLock) +import Test.Crypto.Util (Lock, prop_cbor, prop_cbor_size, prop_no_thunks, withLock) import Test.QuickCheck import Test.QuickCheck.Instances () import Test.Tasty (TestTree, testGroup) @@ -34,55 +33,60 @@ import qualified Cardano.Crypto.Libsodium as NaCl -- tests :: Lock -> TestTree tests lock = - testGroup "Crypto.Hash" - [testHashAlgorithm (Proxy :: Proxy SHA256) + testGroup + "Crypto.Hash" + [ testHashAlgorithm (Proxy :: Proxy SHA256) , testHashAlgorithm (Proxy :: Proxy SHA3_256) , testHashAlgorithm (Proxy :: Proxy Blake2b_224) , testHashAlgorithm (Proxy :: Proxy Blake2b_256) , testHashAlgorithm (Proxy :: Proxy Keccak256) - , testSodiumHashAlgorithm lock (Proxy :: Proxy SHA256) , testSodiumHashAlgorithm lock (Proxy :: Proxy Blake2b_256) - , testPackedBytes ] -testHashAlgorithm - :: forall proxy h. HashAlgorithm h - => proxy h - -> TestTree +testHashAlgorithm :: + forall proxy h. + HashAlgorithm h => + proxy h -> + TestTree testHashAlgorithm p = - testGroup n + testGroup + n [ testProperty "hash size" $ prop_hash_correct_sizeHash @h @[Int] , testProperty "serialise" $ prop_hash_cbor @h , testProperty "ToCBOR size" $ prop_hash_cbor_size @h + , -- TODO The following property is wrong because show and fromString are not inverses of each other + -- Commenting the following out to fix CI and unblock other unrelated PRs to this project. - -- TODO The following property is wrong because show and fromString are not inverses of each other - -- Commenting the following out to fix CI and unblock other unrelated PRs to this project. - - , testProperty "hashFromStringAsHex/hashToStringFromHash" $ prop_hash_hashFromStringAsHex_hashToStringFromHash @h @Float + testProperty "hashFromStringAsHex/hashToStringFromHash" $ + prop_hash_hashFromStringAsHex_hashToStringFromHash @h @Float , testProperty "hashFromStringAsHex/fromString" $ prop_hash_hashFromStringAsHex_fromString @h @Float , testProperty "show/read" $ prop_hash_show_read @h @Float , testProperty "NoThunks" $ prop_no_thunks @(Hash h Int) , testProperty "MemPack RoundTrip" $ prop_MemPackRoundTrip @(Hash h Int) ] - where n = hashAlgorithmName p + where + n = hashAlgorithmName p prop_MemPackRoundTrip :: forall a. (MemPack a, Eq a, Show a) => a -> Property prop_MemPackRoundTrip a = - unpackError (pack a) === a .&&. - unpackError (packByteString a) === a - -testSodiumHashAlgorithm - :: forall proxy h. NaCl.SodiumHashAlgorithm h - => Lock - -> proxy h - -> TestTree + unpackError (pack a) === a + .&&. unpackError (packByteString a) === a + +testSodiumHashAlgorithm :: + forall proxy h. + NaCl.SodiumHashAlgorithm h => + Lock -> + proxy h -> + TestTree testSodiumHashAlgorithm lock p = - testGroup n + testGroup + n [ testProperty "sodium and crypton work the same" $ prop_libsodium_model @h lock Proxy ] - where n = hashAlgorithmName p + where + n = hashAlgorithmName p testPackedBytesN :: forall n. KnownNat n => TestHash n -> TestTree testPackedBytesN h = do @@ -138,41 +142,46 @@ prop_hash_cbor = prop_cbor prop_hash_cbor_size :: HashAlgorithm h => Hash h Int -> Property prop_hash_cbor_size = prop_cbor_size -prop_hash_correct_sizeHash - :: forall h a. HashAlgorithm h - => Hash h a - -> Property +prop_hash_correct_sizeHash :: + forall h a. + HashAlgorithm h => + Hash h a -> + Property prop_hash_correct_sizeHash h = BS.length (hashToBytes h) === fromIntegral (sizeHash (Proxy :: Proxy h)) -prop_hash_show_read - :: forall h a. HashAlgorithm h - => Hash h a -> Property +prop_hash_show_read :: + forall h a. + HashAlgorithm h => + Hash h a -> Property prop_hash_show_read h = read (show h) === h -prop_hash_hashFromStringAsHex_fromString - :: forall h a. HashAlgorithm h - => Hash h a -> Property +prop_hash_hashFromStringAsHex_fromString :: + forall h a. + HashAlgorithm h => + Hash h a -> Property prop_hash_hashFromStringAsHex_fromString h = let s = hashToStringAsHex h in fromJust (hashFromStringAsHex @h @a s) === fromString s -prop_hash_hashFromStringAsHex_hashToStringFromHash - :: forall h a. HashAlgorithm h - => Hash h a -> Property +prop_hash_hashFromStringAsHex_hashToStringFromHash :: + forall h a. + HashAlgorithm h => + Hash h a -> Property prop_hash_hashFromStringAsHex_hashToStringFromHash h = fromJust (hashFromStringAsHex @h @a (hashToStringAsHex h)) === h -prop_libsodium_model - :: forall h. NaCl.SodiumHashAlgorithm h - => Lock -> Proxy h -> BS.ByteString -> Property +prop_libsodium_model :: + forall h. + NaCl.SodiumHashAlgorithm h => + Lock -> Proxy h -> BS.ByteString -> Property prop_libsodium_model lock p bs = ioProperty . withLock lock $ do - actual <- bracket - (NaCl.digestMLockedBS p bs) - NaCl.mlsbFinalize - NaCl.mlsbToByteString + actual <- + bracket + (NaCl.digestMLockedBS p bs) + NaCl.mlsbFinalize + NaCl.mlsbToByteString return (expected === actual) where expected = digest p bs - -- -- Arbitrary instances -- @@ -193,22 +202,24 @@ instance KnownNat n => HashAlgorithm (TestHash n) where digest px _ = BS.pack (replicate (fromIntegral (sizeHash px)) 0) prop_roundtrip :: - forall n. KnownNat n - => TestHash n - -> Property + forall n. + KnownNat n => + TestHash n -> + Property prop_roundtrip h = forAll (vectorOf (fromInteger (natVal h)) arbitrary) $ \xs -> let sbs = SBS.pack xs bs = SBS.fromShort sbs sbsHash = hashFromBytesShort sbs :: Maybe (Hash (TestHash n) ()) bsHash = hashFromBytes bs :: Maybe (Hash (TestHash n) ()) - in fmap hashToBytesShort sbsHash === Just sbs .&&. - fmap hashToBytes bsHash === Just bs + in fmap hashToBytesShort sbsHash === Just sbs + .&&. fmap hashToBytes bsHash === Just bs prop_compare :: - forall n. KnownNat n - => TestHash n - -> Property + forall n. + KnownNat n => + TestHash n -> + Property prop_compare h = let n = fromInteger (natVal h) distinct k = splitAt k <$> vectorOf (k * 2) arbitrary @@ -220,17 +231,21 @@ prop_compare h = sbs2 = SBS.pack xs2 in compare (hashFromBytesShort sbs1 :: Maybe (Hash (TestHash n) ())) - (hashFromBytesShort sbs2 :: Maybe (Hash (TestHash n) ())) === - compare sbs1 sbs2 + (hashFromBytesShort sbs2 :: Maybe (Hash (TestHash n) ())) + === compare sbs1 sbs2 prop_xor :: - forall n. KnownNat n - => TestHash n - -> Property + forall n. + KnownNat n => + TestHash n -> + Property prop_xor h = let n = fromInteger (natVal h) in forAll (bimap BS.pack BS.pack . splitAt n <$> vectorOf (n * 2) arbitrary) $ \(bs1, bs2) -> - Just (BS.pack (BS.zipWith Bits.xor bs1 bs2)) === - (hashToBytes <$> - (xor <$> (hashFromBytes bs1 :: Maybe (Hash (TestHash n) ())) - <*> (hashFromBytes bs2 :: Maybe (Hash (TestHash n) ())))) + Just (BS.pack (BS.zipWith Bits.xor bs1 bs2)) + === ( hashToBytes + <$> ( xor + <$> (hashFromBytes bs1 :: Maybe (Hash (TestHash n) ())) + <*> (hashFromBytes bs2 :: Maybe (Hash (TestHash n) ())) + ) + ) diff --git a/cardano-crypto-tests/src/Test/Crypto/Instances.hs b/cardano-crypto-tests/src/Test/Crypto/Instances.hs index 7119b4c0e..c3ea5c60f 100644 --- a/cardano-crypto-tests/src/Test/Crypto/Instances.hs +++ b/cardano-crypto-tests/src/Test/Crypto/Instances.hs @@ -1,22 +1,23 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -Wno-orphans #-} -module Test.Crypto.Instances -( withMLSBFromPSB -, withMLockedSeedFromPSB + +module Test.Crypto.Instances ( + withMLSBFromPSB, + withMLockedSeedFromPSB, ) where +import Cardano.Crypto.Libsodium +import Cardano.Crypto.Libsodium.MLockedSeed +import Cardano.Crypto.PinnedSizedBytes +import Control.Monad.Class.MonadST +import Control.Monad.Class.MonadThrow import Data.Maybe (mapMaybe) -import GHC.Exts (fromListN, toList, fromList) import Data.Proxy (Proxy (Proxy)) +import GHC.Exts (fromList, fromListN, toList) import GHC.TypeLits (KnownNat, natVal) import Test.QuickCheck (Arbitrary (..)) import qualified Test.QuickCheck.Gen as Gen -import Cardano.Crypto.Libsodium -import Cardano.Crypto.Libsodium.MLockedSeed -import Cardano.Crypto.PinnedSizedBytes -import Control.Monad.Class.MonadThrow -import Control.Monad.Class.MonadST -- We cannot allow this instance, because it doesn't guarantee timely -- forgetting of the MLocked memory, and in a QuickCheck context, where @@ -36,7 +37,8 @@ import Control.Monad.Class.MonadST mlsbFromPSB :: (MonadST m, KnownNat n) => PinnedSizedBytes n -> m (MLockedSizedBytes n) mlsbFromPSB = mlsbFromByteString . psbToByteString -withMLSBFromPSB :: (MonadST m, MonadThrow m, KnownNat n) => PinnedSizedBytes n -> (MLockedSizedBytes n -> m a) -> m a +withMLSBFromPSB :: + (MonadST m, MonadThrow m, KnownNat n) => PinnedSizedBytes n -> (MLockedSizedBytes n -> m a) -> m a withMLSBFromPSB psb = bracket (mlsbFromPSB psb) @@ -45,16 +47,18 @@ withMLSBFromPSB psb = mlockedSeedFromPSB :: (MonadST m, KnownNat n) => PinnedSizedBytes n -> m (MLockedSeed n) mlockedSeedFromPSB = fmap MLockedSeed . mlsbFromPSB -withMLockedSeedFromPSB :: (MonadST m, MonadThrow m, KnownNat n) => PinnedSizedBytes n -> (MLockedSeed n -> m a) -> m a +withMLockedSeedFromPSB :: + (MonadST m, MonadThrow m, KnownNat n) => PinnedSizedBytes n -> (MLockedSeed n -> m a) -> m a withMLockedSeedFromPSB psb = bracket (mlockedSeedFromPSB psb) mlockedSeedFinalize instance KnownNat n => Arbitrary (PinnedSizedBytes n) where - arbitrary = do - let size :: Int = fromIntegral . natVal $ Proxy @n - Gen.suchThatMap (fromListN size <$> Gen.vectorOf size arbitrary) - psbFromByteStringCheck - shrink psb = case toList . psbToByteString $ psb of - bytes -> mapMaybe (psbFromByteStringCheck . fromList) . shrink $ bytes + arbitrary = do + let size :: Int = fromIntegral . natVal $ Proxy @n + Gen.suchThatMap + (fromListN size <$> Gen.vectorOf size arbitrary) + psbFromByteStringCheck + shrink psb = case toList . psbToByteString $ psb of + bytes -> mapMaybe (psbFromByteStringCheck . fromList) . shrink $ bytes diff --git a/cardano-crypto-tests/src/Test/Crypto/KES.hs b/cardano-crypto-tests/src/Test/Crypto/KES.hs index 3d285313b..cc66fae4b 100644 --- a/cardano-crypto-tests/src/Test/Crypto/KES.hs +++ b/cardano-crypto-tests/src/Test/Crypto/KES.hs @@ -1,36 +1,35 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DerivingVia #-} +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DerivingVia #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TypeOperators #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PolyKinds #-} -{-# LANGUAGE RankNTypes #-} {-# LANGUAGE QuantifiedConstraints #-} -{-# LANGUAGE MultiParamTypeClasses #-} - +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -Wno-orphans #-} {- HLINT ignore "Use head" -} -module Test.Crypto.KES - ( tests - ) +module Test.Crypto.KES ( + tests, +) where -import Data.Proxy (Proxy(..)) -import qualified Data.Foldable as F (foldl') import qualified Data.ByteString as BS +import qualified Data.Foldable as F (foldl') +import Data.IORef +import Data.Proxy (Proxy (..)) import Data.Set (Set) import qualified Data.Set as Set import Foreign.Ptr (WordPtr) -import Data.IORef import GHC.TypeNats (KnownNat, natVal) import Control.Monad (void) @@ -40,42 +39,42 @@ import Control.Monad.IO.Class (liftIO) import Control.Tracer import Cardano.Crypto.DSIGN hiding (Signable) +import Cardano.Crypto.DirectSerialise (DirectDeserialise, DirectSerialise) import Cardano.Crypto.Hash import Cardano.Crypto.KES -import Cardano.Crypto.DirectSerialise (DirectSerialise, DirectDeserialise) -import Cardano.Crypto.Util (SignableRepresentation(..)) -import Cardano.Crypto.Seed (mkSeedFromBytes) import Cardano.Crypto.Libsodium import Cardano.Crypto.Libsodium.MLockedSeed import Cardano.Crypto.PinnedSizedBytes +import Cardano.Crypto.Seed (mkSeedFromBytes) +import Cardano.Crypto.Util (SignableRepresentation (..)) import Test.QuickCheck -import Test.Tasty (TestTree, testGroup, adjustOption) -import Test.Tasty.QuickCheck (testProperty, QuickCheckMaxSize(..)) -import Test.Tasty.HUnit (testCase, Assertion, assertEqual, assertBool) +import Test.Tasty (TestTree, adjustOption, testGroup) +import Test.Tasty.HUnit (Assertion, assertBool, assertEqual, testCase) +import Test.Tasty.QuickCheck (QuickCheckMaxSize (..), testProperty) +import Test.Crypto.AllocLog +import Test.Crypto.EqST +import Test.Crypto.Instances (withMLockedSeedFromPSB) import Test.Crypto.Util ( - ToCBOR, FromCBOR, + Lock, Message, - prop_raw_serialise, - prop_size_serialise, - prop_cbor_with, + ToCBOR, + directDeserialiseFromBS, + directSerialiseToBS, + doesNotThrow, + hexBS, + noExceptionsThrown, prop_cbor, - prop_cbor_size, prop_cbor_direct_vs_class, + prop_cbor_size, + prop_cbor_with, prop_no_thunks_IO, - hexBS, - doesNotThrow, - noExceptionsThrown, - Lock, + prop_raw_serialise, + prop_size_serialise, withLock, - directSerialiseToBS, - directDeserialiseFromBS, - ) -import Test.Crypto.EqST -import Test.Crypto.Instances (withMLockedSeedFromPSB) -import Test.Crypto.AllocLog + ) {- HLINT ignore "Reduce duplication" -} {- HLINT ignore "Use head" -} @@ -85,20 +84,21 @@ import Test.Crypto.AllocLog -- tests :: Lock -> TestTree tests lock = - testGroup "Crypto.KES" - [ testKESAlloc (Proxy @(SingleKES Ed25519DSIGN)) "SingleKES" - , testKESAlloc (Proxy @(Sum1KES Ed25519DSIGN Blake2b_256)) "Sum1KES" - , testKESAlloc (Proxy @(Sum2KES Ed25519DSIGN Blake2b_256)) "Sum2KES" - , testKESAlgorithm @(MockKES 7) lock "MockKES" - , testKESAlgorithm @(SimpleKES Ed25519DSIGN 7) lock "SimpleKES" - , testKESAlgorithm @(SingleKES Ed25519DSIGN) lock "SingleKES" - , testKESAlgorithm @(Sum1KES Ed25519DSIGN Blake2b_256) lock "Sum1KES" - , testKESAlgorithm @(Sum2KES Ed25519DSIGN Blake2b_256) lock "Sum2KES" - , testKESAlgorithm @(Sum5KES Ed25519DSIGN Blake2b_256) lock "Sum5KES" - , testKESAlgorithm @(CompactSum1KES Ed25519DSIGN Blake2b_256) lock "CompactSum1KES" - , testKESAlgorithm @(CompactSum2KES Ed25519DSIGN Blake2b_256) lock "CompactSum2KES" - , testKESAlgorithm @(CompactSum5KES Ed25519DSIGN Blake2b_256) lock "CompactSum5KES" - ] + testGroup + "Crypto.KES" + [ testKESAlloc (Proxy @(SingleKES Ed25519DSIGN)) "SingleKES" + , testKESAlloc (Proxy @(Sum1KES Ed25519DSIGN Blake2b_256)) "Sum1KES" + , testKESAlloc (Proxy @(Sum2KES Ed25519DSIGN Blake2b_256)) "Sum2KES" + , testKESAlgorithm @(MockKES 7) lock "MockKES" + , testKESAlgorithm @(SimpleKES Ed25519DSIGN 7) lock "SimpleKES" + , testKESAlgorithm @(SingleKES Ed25519DSIGN) lock "SingleKES" + , testKESAlgorithm @(Sum1KES Ed25519DSIGN Blake2b_256) lock "Sum1KES" + , testKESAlgorithm @(Sum2KES Ed25519DSIGN Blake2b_256) lock "Sum2KES" + , testKESAlgorithm @(Sum5KES Ed25519DSIGN Blake2b_256) lock "Sum5KES" + , testKESAlgorithm @(CompactSum1KES Ed25519DSIGN Blake2b_256) lock "CompactSum1KES" + , testKESAlgorithm @(CompactSum2KES Ed25519DSIGN Blake2b_256) lock "CompactSum2KES" + , testKESAlgorithm @(CompactSum5KES Ed25519DSIGN Blake2b_256) lock "CompactSum5KES" + ] -------------------------------------------------------------------------------- -- Show and Eq instances @@ -112,7 +112,7 @@ instance Show (SignKeyKES (SingleKES Ed25519DSIGN)) where show (SignKeySingleKES (SignKeyEd25519DSIGNM mlsb)) = let bytes = mlsbAsByteString mlsb hexstr = hexBS bytes - in "SignKeySingleKES (SignKeyEd25519DSIGNM " ++ hexstr ++ ")" + in "SignKeySingleKES (SignKeyEd25519DSIGNM " ++ hexstr ++ ")" instance Show (SignKeyKES (SumKES h d)) where show _ = "" @@ -121,28 +121,34 @@ instance Show (SignKeyKES (CompactSingleKES Ed25519DSIGN)) where show (SignKeyCompactSingleKES (SignKeyEd25519DSIGNM mlsb)) = let bytes = mlsbAsByteString mlsb hexstr = hexBS bytes - in "SignKeyCompactSingleKES (SignKeyEd25519DSIGNM " ++ hexstr ++ ")" + in "SignKeyCompactSingleKES (SignKeyEd25519DSIGNM " ++ hexstr ++ ")" instance Show (SignKeyKES (CompactSumKES h d)) where show _ = "" deriving via (PureEqST (SignKeyKES (MockKES t))) instance EqST (SignKeyKES (MockKES t)) -deriving newtype instance (EqST (SignKeyDSIGNM d)) => EqST (SignKeyKES (SingleKES d)) +deriving newtype instance EqST (SignKeyDSIGNM d) => EqST (SignKeyKES (SingleKES d)) -instance ( EqST (SignKeyKES d) - , Eq (VerKeyKES d) - , KnownNat (SeedSizeKES d) - ) => EqST (SignKeyKES (SumKES h d)) where +instance + ( EqST (SignKeyKES d) + , Eq (VerKeyKES d) + , KnownNat (SeedSizeKES d) + ) => + EqST (SignKeyKES (SumKES h d)) + where equalsM (SignKeySumKES s r v1 v2) (SignKeySumKES s' r' v1' v2') = (s, r, PureEqST v1, PureEqST v2) ==! (s', r', PureEqST v1', PureEqST v2') -deriving newtype instance (EqST (SignKeyDSIGNM d)) => EqST (SignKeyKES (CompactSingleKES d)) +deriving newtype instance EqST (SignKeyDSIGNM d) => EqST (SignKeyKES (CompactSingleKES d)) -instance ( EqST (SignKeyKES d) - , Eq (VerKeyKES d) - , KnownNat (SeedSizeKES d) - ) => EqST (SignKeyKES (CompactSumKES h d)) where +instance + ( EqST (SignKeyKES d) + , Eq (VerKeyKES d) + , KnownNat (SeedSizeKES d) + ) => + EqST (SignKeyKES (CompactSumKES h d)) + where equalsM (SignKeyCompactSumKES s r v1 v2) (SignKeyCompactSumKES s' r' v1' v2') = (s, r, PureEqST v1, PureEqST v2) ==! (s', r', PureEqST v1', PureEqST v2') @@ -152,21 +158,21 @@ instance ( EqST (SignKeyKES d) genInitialSignKeyKES :: forall k. UnsoundPureKESAlgorithm k => Gen (UnsoundPureSignKeyKES k) genInitialSignKeyKES = do - bytes <- BS.pack <$> vector (fromIntegral $ seedSizeKES (Proxy @k)) - let seed = mkSeedFromBytes bytes - return $ unsoundPureGenKeyKES seed + bytes <- BS.pack <$> vector (fromIntegral $ seedSizeKES (Proxy @k)) + let seed = mkSeedFromBytes bytes + return $ unsoundPureGenKeyKES seed instance (UnsoundPureKESAlgorithm k, Arbitrary (ContextKES k)) => Arbitrary (UnsoundPureSignKeyKES k) where arbitrary = do ctx <- arbitrary let updateTo :: Period -> Period -> UnsoundPureSignKeyKES k -> Maybe (UnsoundPureSignKeyKES k) updateTo target current sk - | target == current - = Just sk - | target > current - = updateTo target (succ current) =<< unsoundPureUpdateKES ctx sk current - | otherwise - = Nothing + | target == current = + Just sk + | target > current = + updateTo target (succ current) =<< unsoundPureUpdateKES ctx sk current + | otherwise = + Nothing period <- chooseBoundedIntegral (0, totalPeriodsKES (Proxy @k) - 1) sk0 <- genInitialSignKeyKES let skMay = updateTo period 0 sk0 @@ -188,19 +194,20 @@ instance (UnsoundPureKESAlgorithm k, Signable k ByteString, Arbitrary (ContextKE -- Tests -------------------------------------------------------------------------------- -testKESAlloc - :: forall v. - ( KESAlgorithm v - ) - => Proxy v - -> String - -> TestTree +testKESAlloc :: + forall v. + KESAlgorithm v => + Proxy v -> + String -> + TestTree testKESAlloc _p n = - testGroup n - [ testGroup "Low-level mlocked allocations" - [ testCase "genKey" $ testMLockGenKeyKES _p - -- , testCase "updateKey" $ testMLockUpdateKeyKES _p - ] + testGroup + n + [ testGroup + "Low-level mlocked allocations" + [ testCase "genKey" $ testMLockGenKeyKES _p + -- , testCase "updateKey" $ testMLockUpdateKeyKES _p + ] ] eventTracer :: IORef [event] -> Tracer IO event @@ -213,11 +220,11 @@ matchAllocLog = F.foldl' (flip go) Set.empty go (FreeEv ptr) = Set.delete ptr go (MarkerEv _) = id -testMLockGenKeyKES - :: forall v. - KESAlgorithm v - => Proxy v - -> Assertion +testMLockGenKeyKES :: + forall v. + KESAlgorithm v => + Proxy v -> + Assertion testMLockGenKeyKES _p = do accumVar <- newIORef [] let tracer = eventTracer accumVar @@ -234,229 +241,236 @@ testMLockGenKeyKES _p = do traceWith tracer $ MarkerEv "done" after <- readIORef accumVar let evset = matchAllocLog after - assertBool "some allocations happened" (not . null $ [ () | AllocEv _ <- after ]) + assertBool "some allocations happened" (not . null $ [() | AllocEv _ <- after]) assertEqual "all allocations deallocated" Set.empty evset -{-# NOINLINE testKESAlgorithm#-} -testKESAlgorithm - :: forall v. - ( ToCBOR (VerKeyKES v) - , FromCBOR (VerKeyKES v) - , EqST (SignKeyKES v) -- only monadic EqST for signing keys - , Show (SignKeyKES v) -- fake instance defined locally - , Eq (UnsoundPureSignKeyKES v) - , Show (UnsoundPureSignKeyKES v) - , ToCBOR (SigKES v) - , FromCBOR (SigKES v) - , Signable v ~ SignableRepresentation - , ContextKES v ~ () - , UnsoundKESAlgorithm v - , UnsoundPureKESAlgorithm v - , DirectSerialise (SignKeyKES v) - , DirectSerialise (VerKeyKES v) - , DirectDeserialise (SignKeyKES v) - , DirectDeserialise (VerKeyKES v) - ) - => Lock - -> String - -> TestTree +{-# NOINLINE testKESAlgorithm #-} +testKESAlgorithm :: + forall v. + ( ToCBOR (VerKeyKES v) + , FromCBOR (VerKeyKES v) + , EqST (SignKeyKES v) -- only monadic EqST for signing keys + , Show (SignKeyKES v) -- fake instance defined locally + , Eq (UnsoundPureSignKeyKES v) + , Show (UnsoundPureSignKeyKES v) + , ToCBOR (SigKES v) + , FromCBOR (SigKES v) + , Signable v ~ SignableRepresentation + , ContextKES v ~ () + , UnsoundKESAlgorithm v + , UnsoundPureKESAlgorithm v + , DirectSerialise (SignKeyKES v) + , DirectSerialise (VerKeyKES v) + , DirectDeserialise (SignKeyKES v) + , DirectDeserialise (VerKeyKES v) + ) => + Lock -> + String -> + TestTree testKESAlgorithm lock n = - testGroup n + testGroup + n [ testProperty "only gen signkey" $ prop_onlyGenSignKeyKES @v lock , testProperty "only gen verkey" $ prop_onlyGenVerKeyKES @v lock , testProperty "one update signkey" $ prop_oneUpdateSignKeyKES @v lock , testProperty "all updates signkey" $ prop_allUpdatesSignKeyKES @v lock , testProperty "total periods" $ prop_totalPeriodsKES @v lock - , testGroup "NoThunks" - [ testProperty "VerKey" $ - ioPropertyWithSK @v lock $ \sk -> - prop_no_thunks_IO (deriveVerKeyKES sk) - , testProperty "SignKey" $ - ioPropertyWithSK @v lock $ - prop_no_thunks_IO . return - , testProperty "SignKey evolved" $ - ioPropertyWithSK @v lock $ \sk -> - bracket - (updateKES () sk 0) - (maybe (return ()) forgetSignKeyKES) - (prop_no_thunks_IO . return) - , testProperty "Sig" $ \seedPSB (msg :: Message) -> - ioProperty $ withLock lock $ fmap conjoin $ withAllUpdatesKES @v seedPSB $ \t sk -> do - prop_no_thunks_IO (signKES () t msg sk) - - , testProperty "VerKey DirectSerialise" $ - ioPropertyWithSK @v lock $ \sk -> do - vk :: VerKeyKES v <- deriveVerKeyKES sk - direct <- directSerialiseToBS (fromIntegral $ sizeVerKeyKES (Proxy @v)) vk - prop_no_thunks_IO (return $! direct) - , testProperty "SignKey DirectSerialise" $ - ioPropertyWithSK @v lock $ \sk -> do - direct <- directSerialiseToBS (fromIntegral $ sizeSignKeyKES (Proxy @v)) sk - prop_no_thunks_IO (return $! direct) - , testProperty "VerKey DirectDeserialise" $ - ioPropertyWithSK @v lock $ \sk -> do - vk :: VerKeyKES v <- deriveVerKeyKES sk - direct <- directSerialiseToBS (fromIntegral $ sizeVerKeyKES (Proxy @v)) $! vk - prop_no_thunks_IO (directDeserialiseFromBS @IO @(VerKeyKES v) $! direct) - , testProperty "SignKey DirectDeserialise" $ - ioPropertyWithSK @v lock $ \sk -> do - direct <- directSerialiseToBS (fromIntegral $ sizeSignKeyKES (Proxy @v)) sk - bracket - (directDeserialiseFromBS @IO @(SignKeyKES v) $! direct) - forgetSignKeyKES - (prop_no_thunks_IO . return) - ] - - , testProperty "same VerKey " $ prop_deriveVerKeyKES @v - , testProperty "no forgotten chunks in signkey" $ prop_noErasedBlocksInKey (Proxy @v) - , testGroup "serialisation" - - [ testGroup "raw ser only" - [ testProperty "VerKey" $ - ioPropertyWithSK @v lock $ \sk -> do - vk :: VerKeyKES v <- deriveVerKeyKES sk - return $ (rawDeserialiseVerKeyKES . rawSerialiseVerKeyKES $ vk) === Just vk - , testProperty "SignKey" $ - ioPropertyWithSK @v lock $ \sk -> do - serialized <- rawSerialiseSignKeyKES sk - equals <- bracket - (rawDeserialiseSignKeyKES serialized) - (maybe (return ()) forgetSignKeyKES) - (\msk' -> Just sk ==! msk') - return $ - counterexample (show serialized) equals - , testProperty "Sig" $ \(msg :: Message) -> - ioPropertyWithSK @v lock $ \sk -> do - sig :: SigKES v <- signKES () 0 msg sk - return $ (rawDeserialiseSigKES . rawSerialiseSigKES $ sig) === Just sig - ] - , testGroup "size" + , testGroup + "NoThunks" [ testProperty "VerKey" $ - ioPropertyWithSK @v lock $ \sk -> do - vk :: VerKeyKES v <- deriveVerKeyKES sk - return $ (fromIntegral . BS.length . rawSerialiseVerKeyKES $ vk) === sizeVerKeyKES (Proxy @v) + ioPropertyWithSK @v lock $ \sk -> + prop_no_thunks_IO (deriveVerKeyKES sk) , testProperty "SignKey" $ - ioPropertyWithSK @v lock $ \sk -> do - serialized <- rawSerialiseSignKeyKES sk - evaluate ((fromIntegral . BS.length $ serialized) == sizeSignKeyKES (Proxy @v)) - , testProperty "Sig" $ \(msg :: Message) -> - ioPropertyWithSK @v lock $ \sk -> do - sig :: SigKES v <- signKES () 0 msg sk - return $ (fromIntegral . BS.length . rawSerialiseSigKES $ sig) === sizeSigKES (Proxy @v) - ] - - , testGroup "direct CBOR" - [ testProperty "VerKey" $ + ioPropertyWithSK @v lock $ + prop_no_thunks_IO . return + , testProperty "SignKey evolved" $ + ioPropertyWithSK @v lock $ \sk -> + bracket + (updateKES () sk 0) + (maybe (return ()) forgetSignKeyKES) + (prop_no_thunks_IO . return) + , testProperty "Sig" $ \seedPSB (msg :: Message) -> + ioProperty $ withLock lock $ fmap conjoin $ withAllUpdatesKES @v seedPSB $ \t sk -> do + prop_no_thunks_IO (signKES () t msg sk) + , testProperty "VerKey DirectSerialise" $ ioPropertyWithSK @v lock $ \sk -> do vk :: VerKeyKES v <- deriveVerKeyKES sk - return $ prop_cbor_with encodeVerKeyKES decodeVerKeyKES vk - -- No CBOR testing for SignKey: sign keys are stored in MLocked memory - -- and require IO for access. - , testProperty "Sig" $ \(msg :: Message) -> + direct <- directSerialiseToBS (fromIntegral $ sizeVerKeyKES (Proxy @v)) vk + prop_no_thunks_IO (return $! direct) + , testProperty "SignKey DirectSerialise" $ ioPropertyWithSK @v lock $ \sk -> do - sig :: SigKES v <- signKES () 0 msg sk - return $ prop_cbor_with encodeSigKES decodeSigKES sig - , testProperty "UnsoundSignKeyKES" $ \seedPSB -> - let sk :: UnsoundPureSignKeyKES v = mkUnsoundPureSignKeyKES seedPSB - in prop_cbor_with encodeUnsoundPureSignKeyKES decodeUnsoundPureSignKeyKES sk - ] - - , testGroup "To/FromCBOR class" - [ testProperty "VerKey" $ + direct <- directSerialiseToBS (fromIntegral $ sizeSignKeyKES (Proxy @v)) sk + prop_no_thunks_IO (return $! direct) + , testProperty "VerKey DirectDeserialise" $ ioPropertyWithSK @v lock $ \sk -> do vk :: VerKeyKES v <- deriveVerKeyKES sk - return $ prop_cbor vk - -- No To/FromCBOR for 'SignKeyKES', see above. - , testProperty "Sig" $ \(msg :: Message) -> + direct <- directSerialiseToBS (fromIntegral $ sizeVerKeyKES (Proxy @v)) $! vk + prop_no_thunks_IO (directDeserialiseFromBS @IO @(VerKeyKES v) $! direct) + , testProperty "SignKey DirectDeserialise" $ ioPropertyWithSK @v lock $ \sk -> do - sig :: SigKES v <- signKES () 0 msg sk - return $ prop_cbor sig + direct <- directSerialiseToBS (fromIntegral $ sizeSignKeyKES (Proxy @v)) sk + bracket + (directDeserialiseFromBS @IO @(SignKeyKES v) $! direct) + forgetSignKeyKES + (prop_no_thunks_IO . return) ] - - , testGroup "ToCBOR size" - [ testProperty "VerKey" $ - ioPropertyWithSK @v lock $ \sk -> do - vk :: VerKeyKES v <- deriveVerKeyKES sk - return $ prop_cbor_size vk - -- No To/FromCBOR for 'SignKeyKES', see above. - , testProperty "Sig" $ \(msg :: Message) -> - ioPropertyWithSK @v lock $ \sk -> do - sig :: SigKES v <- signKES () 0 msg sk - return $ prop_cbor_size sig + , testProperty "same VerKey " $ prop_deriveVerKeyKES @v + , testProperty "no forgotten chunks in signkey" $ prop_noErasedBlocksInKey (Proxy @v) + , testGroup + "serialisation" + [ testGroup + "raw ser only" + [ testProperty "VerKey" $ + ioPropertyWithSK @v lock $ \sk -> do + vk :: VerKeyKES v <- deriveVerKeyKES sk + return $ (rawDeserialiseVerKeyKES . rawSerialiseVerKeyKES $ vk) === Just vk + , testProperty "SignKey" $ + ioPropertyWithSK @v lock $ \sk -> do + serialized <- rawSerialiseSignKeyKES sk + equals <- + bracket + (rawDeserialiseSignKeyKES serialized) + (maybe (return ()) forgetSignKeyKES) + (\msk' -> Just sk ==! msk') + return $ + counterexample (show serialized) equals + , testProperty "Sig" $ \(msg :: Message) -> + ioPropertyWithSK @v lock $ \sk -> do + sig :: SigKES v <- signKES () 0 msg sk + return $ (rawDeserialiseSigKES . rawSerialiseSigKES $ sig) === Just sig + ] + , testGroup + "size" + [ testProperty "VerKey" $ + ioPropertyWithSK @v lock $ \sk -> do + vk :: VerKeyKES v <- deriveVerKeyKES sk + return $ (fromIntegral . BS.length . rawSerialiseVerKeyKES $ vk) === sizeVerKeyKES (Proxy @v) + , testProperty "SignKey" $ + ioPropertyWithSK @v lock $ \sk -> do + serialized <- rawSerialiseSignKeyKES sk + evaluate ((fromIntegral . BS.length $ serialized) == sizeSignKeyKES (Proxy @v)) + , testProperty "Sig" $ \(msg :: Message) -> + ioPropertyWithSK @v lock $ \sk -> do + sig :: SigKES v <- signKES () 0 msg sk + return $ (fromIntegral . BS.length . rawSerialiseSigKES $ sig) === sizeSigKES (Proxy @v) + ] + , testGroup + "direct CBOR" + [ testProperty "VerKey" $ + ioPropertyWithSK @v lock $ \sk -> do + vk :: VerKeyKES v <- deriveVerKeyKES sk + return $ prop_cbor_with encodeVerKeyKES decodeVerKeyKES vk + , -- No CBOR testing for SignKey: sign keys are stored in MLocked memory + -- and require IO for access. + testProperty "Sig" $ \(msg :: Message) -> + ioPropertyWithSK @v lock $ \sk -> do + sig :: SigKES v <- signKES () 0 msg sk + return $ prop_cbor_with encodeSigKES decodeSigKES sig + , testProperty "UnsoundSignKeyKES" $ \seedPSB -> + let sk :: UnsoundPureSignKeyKES v = mkUnsoundPureSignKeyKES seedPSB + in prop_cbor_with encodeUnsoundPureSignKeyKES decodeUnsoundPureSignKeyKES sk + ] + , testGroup + "To/FromCBOR class" + [ testProperty "VerKey" $ + ioPropertyWithSK @v lock $ \sk -> do + vk :: VerKeyKES v <- deriveVerKeyKES sk + return $ prop_cbor vk + , -- No To/FromCBOR for 'SignKeyKES', see above. + testProperty "Sig" $ \(msg :: Message) -> + ioPropertyWithSK @v lock $ \sk -> do + sig :: SigKES v <- signKES () 0 msg sk + return $ prop_cbor sig + ] + , testGroup + "ToCBOR size" + [ testProperty "VerKey" $ + ioPropertyWithSK @v lock $ \sk -> do + vk :: VerKeyKES v <- deriveVerKeyKES sk + return $ prop_cbor_size vk + , -- No To/FromCBOR for 'SignKeyKES', see above. + testProperty "Sig" $ \(msg :: Message) -> + ioPropertyWithSK @v lock $ \sk -> do + sig :: SigKES v <- signKES () 0 msg sk + return $ prop_cbor_size sig + ] + , testGroup + "direct matches class" + [ testProperty "VerKey" $ + ioPropertyWithSK @v lock $ \sk -> do + vk :: VerKeyKES v <- deriveVerKeyKES sk + return $ prop_cbor_direct_vs_class encodeVerKeyKES vk + , -- No CBOR testing for SignKey: sign keys are stored in MLocked memory + -- and require IO for access. + testProperty "Sig" $ \(msg :: Message) -> + ioPropertyWithSK @v lock $ \sk -> do + sig :: SigKES v <- signKES () 0 msg sk + return $ prop_cbor_direct_vs_class encodeSigKES sig + ] + , testGroup + "DirectSerialise" + [ testProperty "VerKey" $ + ioPropertyWithSK @v lock $ \sk -> do + vk :: VerKeyKES v <- deriveVerKeyKES sk + serialized <- directSerialiseToBS (fromIntegral $ sizeVerKeyKES (Proxy @v)) vk + vk' <- directDeserialiseFromBS serialized + return $ vk === vk' + , testProperty "SignKey" $ + ioPropertyWithSK @v lock $ \sk -> do + serialized <- directSerialiseToBS (fromIntegral $ sizeSignKeyKES (Proxy @v)) sk + equals <- + bracket + (directDeserialiseFromBS serialized) + forgetSignKeyKES + (sk ==!) + return + $ counterexample + ("Serialized: " ++ hexBS serialized ++ " (length: " ++ show (BS.length serialized) ++ ")") + $ equals + ] + , testGroup + "DirectSerialise matches raw" + [ testProperty "VerKey" $ + ioPropertyWithSK @v lock $ \sk -> do + vk :: VerKeyKES v <- deriveVerKeyKES sk + direct <- directSerialiseToBS (fromIntegral $ sizeVerKeyKES (Proxy @v)) vk + let raw = rawSerialiseVerKeyKES vk + return $ direct === raw + , testProperty "SignKey" $ + ioPropertyWithSK @v lock $ \sk -> do + direct <- directSerialiseToBS (fromIntegral $ sizeSignKeyKES (Proxy @v)) sk + raw <- rawSerialiseSignKeyKES sk + return $ direct === raw + ] ] - - , testGroup "direct matches class" - [ testProperty "VerKey" $ - ioPropertyWithSK @v lock $ \sk -> do - vk :: VerKeyKES v <- deriveVerKeyKES sk - return $ prop_cbor_direct_vs_class encodeVerKeyKES vk - -- No CBOR testing for SignKey: sign keys are stored in MLocked memory - -- and require IO for access. - , testProperty "Sig" $ \(msg :: Message) -> - ioPropertyWithSK @v lock $ \sk -> do - sig :: SigKES v <- signKES () 0 msg sk - return $ prop_cbor_direct_vs_class encodeSigKES sig + , testGroup + "verify" + [ testProperty "positive" $ prop_verifyKES_positive @v + , testProperty "negative (key)" $ prop_verifyKES_negative_key @v + , testProperty "negative (message)" $ prop_verifyKES_negative_message @v + , adjustOption (\(QuickCheckMaxSize sz) -> QuickCheckMaxSize (min sz 50)) $ + testProperty "negative (period)" $ + prop_verifyKES_negative_period @v ] - - , testGroup "DirectSerialise" - [ testProperty "VerKey" $ - ioPropertyWithSK @v lock $ \sk -> do - vk :: VerKeyKES v <- deriveVerKeyKES sk - serialized <- directSerialiseToBS (fromIntegral $ sizeVerKeyKES (Proxy @v)) vk - vk' <- directDeserialiseFromBS serialized - return $ vk === vk' - , testProperty "SignKey" $ - ioPropertyWithSK @v lock $ \sk -> do - serialized <- directSerialiseToBS (fromIntegral $ sizeSignKeyKES (Proxy @v)) sk - equals <- bracket - (directDeserialiseFromBS serialized) - forgetSignKeyKES - (sk ==!) - return $ - counterexample ("Serialized: " ++ hexBS serialized ++ " (length: " ++ show (BS.length serialized) ++ ")") $ - equals + , testGroup + "serialisation of all KES evolutions" + [ testProperty "VerKey" $ prop_serialise_VerKeyKES @v + , testProperty "Sig" $ prop_serialise_SigKES @v ] - , testGroup "DirectSerialise matches raw" - [ testProperty "VerKey" $ - ioPropertyWithSK @v lock $ \sk -> do - vk :: VerKeyKES v <- deriveVerKeyKES sk - direct <- directSerialiseToBS (fromIntegral $ sizeVerKeyKES (Proxy @v)) vk - let raw = rawSerialiseVerKeyKES vk - return $ direct === raw - , testProperty "SignKey" $ - ioPropertyWithSK @v lock $ \sk -> do - direct <- directSerialiseToBS (fromIntegral $ sizeSignKeyKES (Proxy @v)) sk - raw <- rawSerialiseSignKeyKES sk - return $ direct === raw + , -- TODO: this doesn't pass right now, see + -- 'prop_key_overwritten_after_forget' for details. + -- + -- , testGroup "forgetting" + -- [ testProperty "key overwritten after forget" $ prop_key_overwritten_after_forget (Proxy @v) + -- ] + + testGroup + "unsound pure" + [ testProperty "genKey" $ prop_unsoundPureGenKey @v Proxy + , testProperty "updateKES" $ prop_unsoundPureUpdateKES @v Proxy + , testProperty "deriveVerKey" $ prop_unsoundPureDeriveVerKey @v Proxy + , testProperty "sign" $ prop_unsoundPureSign @v Proxy ] - ] - - , testGroup "verify" - [ testProperty "positive" $ prop_verifyKES_positive @v - , testProperty "negative (key)" $ prop_verifyKES_negative_key @v - , testProperty "negative (message)" $ prop_verifyKES_negative_message @v - , adjustOption (\(QuickCheckMaxSize sz) -> QuickCheckMaxSize (min sz 50)) $ - testProperty "negative (period)" $ prop_verifyKES_negative_period @v - ] - - , testGroup "serialisation of all KES evolutions" - [ testProperty "VerKey" $ prop_serialise_VerKeyKES @v - , testProperty "Sig" $ prop_serialise_SigKES @v - ] - - -- TODO: this doesn't pass right now, see - -- 'prop_key_overwritten_after_forget' for details. - -- - -- , testGroup "forgetting" - -- [ testProperty "key overwritten after forget" $ prop_key_overwritten_after_forget (Proxy @v) - -- ] - - , testGroup "unsound pure" - [ testProperty "genKey" $ prop_unsoundPureGenKey @v Proxy - , testProperty "updateKES" $ prop_unsoundPureUpdateKES @v Proxy - , testProperty "deriveVerKey" $ prop_unsoundPureDeriveVerKey @v Proxy - , testProperty "sign" $ prop_unsoundPureSign @v Proxy - ] ] -- | Wrap an IO action that requires a 'SignKeyKES' into one that takes an @@ -464,18 +478,20 @@ testKESAlgorithm lock n = -- timely forgetting. Special care must be taken to not leak the key outside of -- the wrapped action (be particularly mindful of thunks and unsafe key access -- here). -withSK :: KESAlgorithm v - => PinnedSizedBytes (SeedSizeKES v) -> (SignKeyKES v -> IO b) -> IO b +withSK :: + KESAlgorithm v => + PinnedSizedBytes (SeedSizeKES v) -> (SignKeyKES v -> IO b) -> IO b withSK seedPSB = bracket (withMLockedSeedFromPSB seedPSB genKeyKES) forgetSignKeyKES -mkUnsoundPureSignKeyKES :: UnsoundPureKESAlgorithm v - => PinnedSizedBytes (SeedSizeKES v) -> UnsoundPureSignKeyKES v +mkUnsoundPureSignKeyKES :: + UnsoundPureKESAlgorithm v => + PinnedSizedBytes (SeedSizeKES v) -> UnsoundPureSignKeyKES v mkUnsoundPureSignKeyKES psb = let seed = mkSeedFromBytes . psbToByteString $ psb - in unsoundPureGenKeyKES seed + in unsoundPureGenKeyKES seed -- | Wrap an IO action that requires a 'SignKeyKES' into a 'Property' that -- takes a non-mlocked seed (provided as a 'PinnedSizedBytes' of the @@ -484,11 +500,13 @@ mkUnsoundPureSignKeyKES psb = -- memory. Special care must be taken to not leak the key outside of the -- wrapped action (be particularly mindful of thunks and unsafe key access -- here). -ioPropertyWithSK :: forall v a. (Testable a, KESAlgorithm v) - => Lock - -> (SignKeyKES v -> IO a) - -> PinnedSizedBytes (SeedSizeKES v) - -> Property +ioPropertyWithSK :: + forall v a. + (Testable a, KESAlgorithm v) => + Lock -> + (SignKeyKES v -> IO a) -> + PinnedSizedBytes (SeedSizeKES v) -> + Property ioPropertyWithSK lock action seedPSB = ioProperty $ withLock lock $ withSK seedPSB action @@ -515,26 +533,26 @@ ioPropertyWithSK lock action seedPSB = -- -- return (before =/= after) -prop_onlyGenSignKeyKES - :: forall v. - KESAlgorithm v - => Lock -> PinnedSizedBytes (SeedSizeKES v) -> Property +prop_onlyGenSignKeyKES :: + forall v. + KESAlgorithm v => + Lock -> PinnedSizedBytes (SeedSizeKES v) -> Property prop_onlyGenSignKeyKES lock = ioPropertyWithSK @v lock $ const noExceptionsThrown -prop_onlyGenVerKeyKES - :: forall v. - KESAlgorithm v - => Lock -> PinnedSizedBytes (SeedSizeKES v) -> Property +prop_onlyGenVerKeyKES :: + forall v. + KESAlgorithm v => + Lock -> PinnedSizedBytes (SeedSizeKES v) -> Property prop_onlyGenVerKeyKES lock = ioPropertyWithSK @v lock $ doesNotThrow . deriveVerKeyKES -prop_oneUpdateSignKeyKES - :: forall v. - ( ContextKES v ~ () - , KESAlgorithm v - ) - => Lock -> PinnedSizedBytes (SeedSizeKES v) -> Property +prop_oneUpdateSignKeyKES :: + forall v. + ( ContextKES v ~ () + , KESAlgorithm v + ) => + Lock -> PinnedSizedBytes (SeedSizeKES v) -> Property prop_oneUpdateSignKeyKES lock seedPSB = ioProperty . withLock lock . withMLockedSeedFromPSB seedPSB $ \seed -> do sk <- genKeyKES @v seed @@ -543,12 +561,12 @@ prop_oneUpdateSignKeyKES lock seedPSB = maybe (return ()) forgetSignKeyKES msk' return True -prop_allUpdatesSignKeyKES - :: forall v. - ( ContextKES v ~ () - , KESAlgorithm v - ) - => Lock -> PinnedSizedBytes (SeedSizeKES v) -> Property +prop_allUpdatesSignKeyKES :: + forall v. + ( ContextKES v ~ () + , KESAlgorithm v + ) => + Lock -> PinnedSizedBytes (SeedSizeKES v) -> Property prop_allUpdatesSignKeyKES lock seedPSB = ioProperty . withLock lock $ do void $ withAllUpdatesKES_ @v seedPSB $ const (return ()) @@ -556,237 +574,243 @@ prop_allUpdatesSignKeyKES lock seedPSB = -- | If we start with a signing key, we can evolve it a number of times so that -- the total number of signing keys (including the initial one) equals the -- total number of periods for this algorithm. --- -prop_totalPeriodsKES - :: forall v. - ( ContextKES v ~ () - , KESAlgorithm v - ) - => Lock -> PinnedSizedBytes (SeedSizeKES v) -> Property +prop_totalPeriodsKES :: + forall v. + ( ContextKES v ~ () + , KESAlgorithm v + ) => + Lock -> PinnedSizedBytes (SeedSizeKES v) -> Property prop_totalPeriodsKES lock seed = - ioProperty . withLock lock $ do - sks <- withAllUpdatesKES_ @v seed (const . return $ ()) - return $ - totalPeriods > 0 ==> - counterexample (show totalPeriods) $ + ioProperty . withLock lock $ do + sks <- withAllUpdatesKES_ @v seed (const . return $ ()) + return $ + totalPeriods > 0 ==> + counterexample (show totalPeriods) $ counterexample (show $ length sks) $ - length sks === totalPeriods + length sks === totalPeriods where totalPeriods :: Int totalPeriods = fromIntegral (totalPeriodsKES (Proxy :: Proxy v)) - -- | If we start with a signing key, and all its evolutions, the verification -- keys we derive from each one are the same. --- -prop_deriveVerKeyKES - :: forall v. - ( ContextKES v ~ () - , KESAlgorithm v - ) - => PinnedSizedBytes (SeedSizeKES v) -> Property +prop_deriveVerKeyKES :: + forall v. + ( ContextKES v ~ () + , KESAlgorithm v + ) => + PinnedSizedBytes (SeedSizeKES v) -> Property prop_deriveVerKeyKES seedPSB = - ioProperty $ do - vk_0 <- do - sk_0 <- withMLockedSeedFromPSB seedPSB $ genKeyKES @v - vk_0 <- deriveVerKeyKES sk_0 - forgetSignKeyKES sk_0 - return vk_0 - - vks <- withAllUpdatesKES_ seedPSB deriveVerKeyKES - return $ - counterexample (show vks) $ - conjoin (map (vk_0 ===) vks) - + ioProperty $ do + vk_0 <- do + sk_0 <- withMLockedSeedFromPSB seedPSB $ genKeyKES @v + vk_0 <- deriveVerKeyKES sk_0 + forgetSignKeyKES sk_0 + return vk_0 + + vks <- withAllUpdatesKES_ seedPSB deriveVerKeyKES + return $ + counterexample (show vks) $ + conjoin (map (vk_0 ===) vks) -- | If we take an initial signing key, a sequence of messages to sign, and -- sign each one with an updated key, we can verify each one for the -- corresponding period. --- -prop_verifyKES_positive - :: forall v. - ( ContextKES v ~ () - , Signable v ~ SignableRepresentation - , KESAlgorithm v - ) - => PinnedSizedBytes (SeedSizeKES v) -> Gen Property +prop_verifyKES_positive :: + forall v. + ( ContextKES v ~ () + , Signable v ~ SignableRepresentation + , KESAlgorithm v + ) => + PinnedSizedBytes (SeedSizeKES v) -> Gen Property prop_verifyKES_positive seedPSB = do - xs :: [Message] <- vectorOf totalPeriods arbitrary - return $ checkCoverage $ + xs :: [Message] <- vectorOf totalPeriods arbitrary + return $ + checkCoverage $ cover 1 (length xs >= totalPeriods) "Message count covers total periods" $ - not (null xs) ==> - ioProperty $ fmap conjoin $ do - sk_0 <- withMLockedSeedFromPSB seedPSB $ genKeyKES @v - vk <- deriveVerKeyKES sk_0 - forgetSignKeyKES sk_0 - withAllUpdatesKES seedPSB $ \t sk -> do - let x = cycle xs !! fromIntegral t - sig <- signKES () t x sk - let verResult = verifyKES () vk t x sig - return $ - counterexample ("period " ++ show t ++ "/" ++ show totalPeriods) $ - verResult === Right () + not (null xs) ==> + ioProperty $ + fmap conjoin $ do + sk_0 <- withMLockedSeedFromPSB seedPSB $ genKeyKES @v + vk <- deriveVerKeyKES sk_0 + forgetSignKeyKES sk_0 + withAllUpdatesKES seedPSB $ \t sk -> do + let x = cycle xs !! fromIntegral t + sig <- signKES () t x sk + let verResult = verifyKES () vk t x sig + return $ + counterexample ("period " ++ show t ++ "/" ++ show totalPeriods) $ + verResult === Right () where totalPeriods :: Int totalPeriods = fromIntegral (totalPeriodsKES (Proxy :: Proxy v)) - -- | If we sign a message @a@with one list of signing key evolutions, if we -- try to verify the signature (and message @a@) using a verification key -- corresponding to a different signing key, then the verification fails. --- -prop_verifyKES_negative_key - :: forall v. - ( ContextKES v ~ () - , Signable v ~ SignableRepresentation - , KESAlgorithm v - ) - => PinnedSizedBytes (SeedSizeKES v) - -> PinnedSizedBytes (SeedSizeKES v) - -> Message - -> Property +prop_verifyKES_negative_key :: + forall v. + ( ContextKES v ~ () + , Signable v ~ SignableRepresentation + , KESAlgorithm v + ) => + PinnedSizedBytes (SeedSizeKES v) -> + PinnedSizedBytes (SeedSizeKES v) -> + Message -> + Property prop_verifyKES_negative_key seedPSB seedPSB' x = - seedPSB /= seedPSB' ==> ioProperty $ fmap conjoin $ do - sk_0' <- withMLockedSeedFromPSB seedPSB' $ genKeyKES @v - vk' <- deriveVerKeyKES sk_0' - forgetSignKeyKES sk_0' - withAllUpdatesKES seedPSB $ \t sk -> do - sig <- signKES () t x sk - let verResult = verifyKES () vk' t x sig - return $ - counterexample ("period " ++ show t) $ - verResult =/= Right () + seedPSB /= seedPSB' ==> ioProperty $ fmap conjoin $ do + sk_0' <- withMLockedSeedFromPSB seedPSB' $ genKeyKES @v + vk' <- deriveVerKeyKES sk_0' + forgetSignKeyKES sk_0' + withAllUpdatesKES seedPSB $ \t sk -> do + sig <- signKES () t x sk + let verResult = verifyKES () vk' t x sig + return $ + counterexample ("period " ++ show t) $ + verResult =/= Right () -- | If we sign a message @a@with one list of signing key evolutions, if we -- try to verify the signature with a message other than @a@, then the -- verification fails. --- -prop_verifyKES_negative_message - :: forall v. - ( ContextKES v ~ () - , Signable v ~ SignableRepresentation - , KESAlgorithm v - ) - => PinnedSizedBytes (SeedSizeKES v) - -> Message -> Message - -> Property +prop_verifyKES_negative_message :: + forall v. + ( ContextKES v ~ () + , Signable v ~ SignableRepresentation + , KESAlgorithm v + ) => + PinnedSizedBytes (SeedSizeKES v) -> + Message -> + Message -> + Property prop_verifyKES_negative_message seedPSB x x' = - x /= x' ==> ioProperty $ fmap conjoin $ do - sk_0 <- withMLockedSeedFromPSB seedPSB $ genKeyKES @v - vk <- deriveVerKeyKES sk_0 - forgetSignKeyKES sk_0 - withAllUpdatesKES seedPSB $ \t sk -> do - sig <- signKES () t x sk - let verResult = verifyKES () vk t x' sig - return $ - counterexample ("period " ++ show t) $ - verResult =/= Right () + x /= x' ==> ioProperty $ fmap conjoin $ do + sk_0 <- withMLockedSeedFromPSB seedPSB $ genKeyKES @v + vk <- deriveVerKeyKES sk_0 + forgetSignKeyKES sk_0 + withAllUpdatesKES seedPSB $ \t sk -> do + sig <- signKES () t x sk + let verResult = verifyKES () vk t x' sig + return $ + counterexample ("period " ++ show t) $ + verResult =/= Right () -- | If we sign a message @a@with one list of signing key evolutions, if we -- try to verify the signature (and message @a@) using the right verification -- key but at a different period than the key used for signing, then the -- verification fails. --- -prop_verifyKES_negative_period - :: forall v. - ( ContextKES v ~ () - , Signable v ~ SignableRepresentation - , KESAlgorithm v - ) - => PinnedSizedBytes (SeedSizeKES v) - -> Message - -> Property +prop_verifyKES_negative_period :: + forall v. + ( ContextKES v ~ () + , Signable v ~ SignableRepresentation + , KESAlgorithm v + ) => + PinnedSizedBytes (SeedSizeKES v) -> + Message -> + Property prop_verifyKES_negative_period seedPSB x = - ioProperty $ fmap conjoin $ do - sk_0 <- withMLockedSeedFromPSB seedPSB $ genKeyKES @v - vk <- deriveVerKeyKES sk_0 - forgetSignKeyKES sk_0 - withAllUpdatesKES seedPSB $ \t sk -> do - sig <- signKES () t x sk - return $ - conjoin [ counterexample ("periods " ++ show (t, t')) $ - verifyKES () vk t' x sig =/= Right () - | t' <- [0..totalPeriods-1] - , t /= t' - ] + ioProperty $ fmap conjoin $ do + sk_0 <- withMLockedSeedFromPSB seedPSB $ genKeyKES @v + vk <- deriveVerKeyKES sk_0 + forgetSignKeyKES sk_0 + withAllUpdatesKES seedPSB $ \t sk -> do + sig <- signKES () t x sk + return $ + conjoin + [ counterexample ("periods " ++ show (t, t')) $ + verifyKES () vk t' x sig =/= Right () + | t' <- [0 .. totalPeriods - 1] + , t /= t' + ] where totalPeriods :: Word totalPeriods = fromIntegral (totalPeriodsKES (Proxy :: Proxy v)) - -- | Check 'prop_raw_serialise', 'prop_cbor_with' and 'prop_size_serialise' -- for 'VerKeyKES' on /all/ the KES key evolutions. --- -prop_serialise_VerKeyKES - :: forall v. - ( ContextKES v ~ () - , KESAlgorithm v - ) - => PinnedSizedBytes (SeedSizeKES v) - -> Property +prop_serialise_VerKeyKES :: + forall v. + ( ContextKES v ~ () + , KESAlgorithm v + ) => + PinnedSizedBytes (SeedSizeKES v) -> + Property prop_serialise_VerKeyKES seedPSB = - ioProperty $ fmap conjoin $ do - withAllUpdatesKES @v seedPSB $ \t sk -> do - vk <- deriveVerKeyKES sk - return $ - counterexample ("period " ++ show t) $ - counterexample ("vkey " ++ show vk) $ - prop_raw_serialise rawSerialiseVerKeyKES - rawDeserialiseVerKeyKES vk - .&. prop_cbor_with encodeVerKeyKES - decodeVerKeyKES vk - .&. prop_size_serialise rawSerialiseVerKeyKES - (sizeVerKeyKES (Proxy @v)) vk + ioProperty $ fmap conjoin $ do + withAllUpdatesKES @v seedPSB $ \t sk -> do + vk <- deriveVerKeyKES sk + return $ + counterexample ("period " ++ show t) $ + counterexample ("vkey " ++ show vk) $ + prop_raw_serialise + rawSerialiseVerKeyKES + rawDeserialiseVerKeyKES + vk + .&. prop_cbor_with + encodeVerKeyKES + decodeVerKeyKES + vk + .&. prop_size_serialise + rawSerialiseVerKeyKES + (sizeVerKeyKES (Proxy @v)) + vk -- | Check 'prop_raw_serialise', 'prop_cbor_with' and 'prop_size_serialise' -- for 'SigKES' on /all/ the KES key evolutions. --- -prop_serialise_SigKES - :: forall v. - ( ContextKES v ~ () - , Signable v ~ SignableRepresentation - , Show (SignKeyKES v) - , KESAlgorithm v - ) - => PinnedSizedBytes (SeedSizeKES v) - -> Message - -> Property +prop_serialise_SigKES :: + forall v. + ( ContextKES v ~ () + , Signable v ~ SignableRepresentation + , Show (SignKeyKES v) + , KESAlgorithm v + ) => + PinnedSizedBytes (SeedSizeKES v) -> + Message -> + Property prop_serialise_SigKES seedPSB x = - ioProperty $ fmap conjoin $ do - withAllUpdatesKES @v seedPSB $ \t sk -> do - sig <- signKES () t x sk - return $ - counterexample ("period " ++ show t) $ - counterexample ("vkey " ++ show sk) $ - counterexample ("sig " ++ show sig) $ - prop_raw_serialise rawSerialiseSigKES - rawDeserialiseSigKES sig - .&. prop_cbor_with encodeSigKES - decodeSigKES sig - .&. prop_size_serialise rawSerialiseSigKES - (sizeSigKES (Proxy @v)) sig + ioProperty $ fmap conjoin $ do + withAllUpdatesKES @v seedPSB $ \t sk -> do + sig <- signKES () t x sk + return $ + counterexample ("period " ++ show t) $ + counterexample ("vkey " ++ show sk) $ + counterexample ("sig " ++ show sig) $ + prop_raw_serialise + rawSerialiseSigKES + rawDeserialiseSigKES + sig + .&. prop_cbor_with + encodeSigKES + decodeSigKES + sig + .&. prop_size_serialise + rawSerialiseSigKES + (sizeSigKES (Proxy @v)) + sig -- -- KES test utils -- -withAllUpdatesKES_ :: forall v a. - ( KESAlgorithm v - , ContextKES v ~ () - ) - => PinnedSizedBytes (SeedSizeKES v) - -> (SignKeyKES v -> IO a) - -> IO [a] +withAllUpdatesKES_ :: + forall v a. + ( KESAlgorithm v + , ContextKES v ~ () + ) => + PinnedSizedBytes (SeedSizeKES v) -> + (SignKeyKES v -> IO a) -> + IO [a] withAllUpdatesKES_ seedPSB f = do withAllUpdatesKES seedPSB (const f) -withAllUpdatesKES :: forall v a. - ( KESAlgorithm v - , ContextKES v ~ () - ) - => PinnedSizedBytes (SeedSizeKES v) - -> (Word -> SignKeyKES v -> IO a) - -> IO [a] +withAllUpdatesKES :: + forall v a. + ( KESAlgorithm v + , ContextKES v ~ () + ) => + PinnedSizedBytes (SeedSizeKES v) -> + (Word -> SignKeyKES v -> IO a) -> + IO [a] withAllUpdatesKES seedPSB f = withMLockedSeedFromPSB seedPSB $ \seed -> do sk_0 <- genKeyKES seed go sk_0 0 @@ -802,19 +826,22 @@ withAllUpdatesKES seedPSB f = withMLockedSeedFromPSB seedPSB $ \seed -> do Just sk' -> do forgetSignKeyKES sk xs <- go sk' (t + 1) - return $ x:xs + return $ x : xs withNullSeed :: forall m n a. (MonadThrow m, MonadST m, KnownNat n) => (MLockedSeed n -> m a) -> m a -withNullSeed = bracket - (MLockedSeed <$> mlsbFromByteString (BS.replicate (fromIntegral $ natVal (Proxy @n)) 0)) - mlockedSeedFinalize - -withNullSK :: forall m v a. (KESAlgorithm v, MonadThrow m, MonadST m) - => (SignKeyKES v -> m a) -> m a -withNullSK = bracket - (withNullSeed genKeyKES) - forgetSignKeyKES - +withNullSeed = + bracket + (MLockedSeed <$> mlsbFromByteString (BS.replicate (fromIntegral $ natVal (Proxy @n)) 0)) + mlockedSeedFinalize + +withNullSK :: + forall m v a. + (KESAlgorithm v, MonadThrow m, MonadST m) => + (SignKeyKES v -> m a) -> m a +withNullSK = + bracket + (withNullSeed genKeyKES) + forgetSignKeyKES -- | This test detects whether a sign key contains references to pool-allocated -- blocks of memory that have been forgotten by the time the key is complete. @@ -822,12 +849,12 @@ withNullSK = bracket -- by overwriting them with series of 0xff bytes; thus we cut the serialized -- key up into chunks of 16 bytes, and if any of those chunks is entirely -- filled with 0xff bytes, we assume that we're looking at erased memory. -prop_noErasedBlocksInKey - :: forall v. - UnsoundKESAlgorithm v - => DirectSerialise (SignKeyKES v) - => Proxy v - -> Property +prop_noErasedBlocksInKey :: + forall v. + UnsoundKESAlgorithm v => + DirectSerialise (SignKeyKES v) => + Proxy v -> + Property prop_noErasedBlocksInKey kesAlgorithm = ioProperty . withNullSK @IO @v $ \sk -> do let size :: Int = fromIntegral $ sizeSignKeyKES kesAlgorithm @@ -837,18 +864,19 @@ prop_noErasedBlocksInKey kesAlgorithm = hasLongRunOfFF :: ByteString -> Bool hasLongRunOfFF bs - | BS.length bs < 16 - = False - | otherwise - = let first16 = BS.take 16 bs - remainder = BS.drop 16 bs - in BS.all (== 0xFF) first16 || hasLongRunOfFF remainder - -prop_unsoundPureGenKey :: forall v. - ( UnsoundPureKESAlgorithm v - , EqST (SignKeyKES v) - ) - => Proxy v -> PinnedSizedBytes (SeedSizeKES v) -> Property + | BS.length bs < 16 = + False + | otherwise = + let first16 = BS.take 16 bs + remainder = BS.drop 16 bs + in BS.all (== 0xFF) first16 || hasLongRunOfFF remainder + +prop_unsoundPureGenKey :: + forall v. + ( UnsoundPureKESAlgorithm v + , EqST (SignKeyKES v) + ) => + Proxy v -> PinnedSizedBytes (SeedSizeKES v) -> Property prop_unsoundPureGenKey _ seedPSB = ioProperty $ do let seed = mkSeedFromBytes $ psbToByteString seedPSB let skPure = unsoundPureGenKeyKES @v seed @@ -858,10 +886,10 @@ prop_unsoundPureGenKey _ seedPSB = ioProperty $ do forgetSignKeyKES (equalsM sk) -prop_unsoundPureDeriveVerKey :: forall v. - ( UnsoundPureKESAlgorithm v - ) - => Proxy v -> PinnedSizedBytes (SeedSizeKES v) -> Property +prop_unsoundPureDeriveVerKey :: + forall v. + UnsoundPureKESAlgorithm v => + Proxy v -> PinnedSizedBytes (SeedSizeKES v) -> Property prop_unsoundPureDeriveVerKey _ seedPSB = ioProperty $ do let seed = mkSeedFromBytes $ psbToByteString seedPSB let skPure = unsoundPureGenKeyKES @v seed @@ -869,12 +897,13 @@ prop_unsoundPureDeriveVerKey _ seedPSB = ioProperty $ do vk <- withSK seedPSB deriveVerKeyKES return $ vkPure === vk -prop_unsoundPureUpdateKES :: forall v. - ( UnsoundPureKESAlgorithm v - , ContextKES v ~ () - , EqST (SignKeyKES v) - ) - => Proxy v -> PinnedSizedBytes (SeedSizeKES v) -> Property +prop_unsoundPureUpdateKES :: + forall v. + ( UnsoundPureKESAlgorithm v + , ContextKES v ~ () + , EqST (SignKeyKES v) + ) => + Proxy v -> PinnedSizedBytes (SeedSizeKES v) -> Property prop_unsoundPureUpdateKES _ seedPSB = ioProperty $ do let seed = mkSeedFromBytes $ psbToByteString seedPSB let skPure = unsoundPureGenKeyKES @v seed @@ -882,7 +911,8 @@ prop_unsoundPureUpdateKES _ seedPSB = ioProperty $ do withSK seedPSB $ \sk -> do bracket (updateKES () sk 0) - (maybe (return ()) forgetSignKeyKES) $ \sk'Maybe -> do + (maybe (return ()) forgetSignKeyKES) + $ \sk'Maybe -> do case skPure'Maybe of Nothing -> case sk'Maybe of @@ -891,26 +921,27 @@ prop_unsoundPureUpdateKES _ seedPSB = ioProperty $ do Just skPure' -> bracket (unsoundPureSignKeyKESToSoundSignKeyKES skPure') - forgetSignKeyKES $ \sk'' -> + forgetSignKeyKES + $ \sk'' -> case sk'Maybe of Nothing -> return (counterexample "pure updates, but shouldn't" $ property False) Just sk' -> property <$> equalsM sk' sk'' -prop_unsoundPureSign :: forall v. - ( UnsoundPureKESAlgorithm v - , ContextKES v ~ () - , Signable v Message - ) - => Proxy v - -> PinnedSizedBytes (SeedSizeKES v) - -> Message - -> Property +prop_unsoundPureSign :: + forall v. + ( UnsoundPureKESAlgorithm v + , ContextKES v ~ () + , Signable v Message + ) => + Proxy v -> + PinnedSizedBytes (SeedSizeKES v) -> + Message -> + Property prop_unsoundPureSign _ seedPSB msg = ioProperty $ do let seed = mkSeedFromBytes $ psbToByteString seedPSB let skPure = unsoundPureGenKeyKES @v seed sigPure = unsoundPureSignKES () 0 msg skPure sig <- withSK seedPSB $ signKES () 0 msg return $ sigPure === sig - diff --git a/cardano-crypto-tests/src/Test/Crypto/Regressions.hs b/cardano-crypto-tests/src/Test/Crypto/Regressions.hs index 55920a274..3a07feade 100644 --- a/cardano-crypto-tests/src/Test/Crypto/Regressions.hs +++ b/cardano-crypto-tests/src/Test/Crypto/Regressions.hs @@ -2,6 +2,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} +{- FOURMOLU_DISABLE -} module Test.Crypto.Regressions ( tests ) where diff --git a/cardano-crypto-tests/src/Test/Crypto/Util.hs b/cardano-crypto-tests/src/Test/Crypto/Util.hs index 39c91a0ce..b4d22ef12 100644 --- a/cardano-crypto-tests/src/Test/Crypto/Util.hs +++ b/cardano-crypto-tests/src/Test/Crypto/Util.hs @@ -1,162 +1,161 @@ {-# LANGUAGE BangPatterns #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DerivingVia #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE KindSignatures #-} -{-# LANGUAGE DerivingVia #-} {-# LANGUAGE RoleAnnotations #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE LambdaCase #-} -module Test.Crypto.Util - ( -- * CBOR - FromCBOR (..) - , ToCBOR (..) - , prop_cbor - , prop_cbor_size - , prop_cbor_with - , prop_cbor_valid - , prop_cbor_roundtrip - , prop_raw_serialise - , prop_raw_deserialise - , prop_size_serialise - , prop_cbor_direct_vs_class - - -- * NoThunks - , prop_no_thunks - , prop_no_thunks_IO - , prop_no_thunks_IO_from - , prop_no_thunks_IO_with - - -- * Test Seed - , TestSeed (..) - , withTestSeed - , testSeedToChaCha - , nullTestSeed - - -- * Seeds - , SizedSeed - , unSizedSeed - , arbitrarySeedOfSize - , arbitrarySeedBytesOfSize - - -- * test messages for signings - , Message(..) - - -- * Test generation and shrinker helpers - , BadInputFor - , genBadInputFor - , shrinkBadInputFor - , showBadInputFor - - -- * Formatting - , hexBS - - -- * Helpers for testing IO actions - , noExceptionsThrown - , doesNotThrow +module Test.Crypto.Util ( + -- * CBOR + FromCBOR (..), + ToCBOR (..), + prop_cbor, + prop_cbor_size, + prop_cbor_with, + prop_cbor_valid, + prop_cbor_roundtrip, + prop_raw_serialise, + prop_raw_deserialise, + prop_size_serialise, + prop_cbor_direct_vs_class, + + -- * NoThunks + prop_no_thunks, + prop_no_thunks_IO, + prop_no_thunks_IO_from, + prop_no_thunks_IO_with, + + -- * Test Seed + TestSeed (..), + withTestSeed, + testSeedToChaCha, + nullTestSeed, + + -- * Seeds + SizedSeed, + unSizedSeed, + arbitrarySeedOfSize, + arbitrarySeedBytesOfSize, + + -- * test messages for signings + Message (..), + + -- * Test generation and shrinker helpers + BadInputFor, + genBadInputFor, + shrinkBadInputFor, + showBadInputFor, + + -- * Formatting + hexBS, + + -- * Helpers for testing IO actions + noExceptionsThrown, + doesNotThrow, -- * Direct ser/deser helpers - , directSerialiseToBS - , directDeserialiseFromBS + directSerialiseToBS, + directDeserialiseFromBS, - -- * Error handling - , eitherShowError + -- * Error handling + eitherShowError, - -- * Locking - , Lock - , withLock - , mkLock - ) + -- * Locking + Lock, + withLock, + mkLock, +) where -import GHC.Exts (fromListN, fromList, toList) -import Text.Show.Pretty (ppShow) -import Data.Kind (Type) import Cardano.Binary ( - FromCBOR (fromCBOR), - ToCBOR (toCBOR), - Encoding, Decoder, + Encoding, + FromCBOR (fromCBOR), Range (Range), + ToCBOR (toCBOR), decodeFullDecoder, + encodedSizeExpr, + hi, + lo, serialize, szGreedy, szSimplify, - lo, - hi, - encodedSizeExpr - ) -import Codec.CBOR.FlatTerm ( + ) +import Cardano.Crypto.DirectSerialise +import Cardano.Crypto.Libsodium.Memory ( + allocaBytes, + packByteStringCStringLen, + unpackByteStringCStringLen, + ) +import Cardano.Crypto.Seed (Seed, mkSeedFromBytes) +import Cardano.Crypto.Util (SignableRepresentation (..)) +import Codec.CBOR.FlatTerm ( + toFlatTerm, validFlatTerm, - toFlatTerm - ) + ) import Codec.CBOR.Write ( - toStrictByteString - ) -import Cardano.Crypto.Seed (Seed, mkSeedFromBytes) -import Cardano.Crypto.Util (SignableRepresentation(..)) -import Cardano.Crypto.DirectSerialise -import Crypto.Random - ( ChaChaDRG - , MonadPseudoRandom - , drgNewTest - , withDRG - ) -import Cardano.Crypto.Libsodium.Memory - ( unpackByteStringCStringLen - , packByteStringCStringLen - , allocaBytes - ) + toStrictByteString, + ) +import Control.Concurrent.Class.MonadMVar ( + MVar, + newMVar, + withMVar, + ) +import Control.Monad (guard, when) +import Control.Monad.Class.MonadST (MonadST) +import Control.Monad.Class.MonadThrow (MonadThrow) +import Crypto.Random ( + ChaChaDRG, + MonadPseudoRandom, + drgNewTest, + withDRG, + ) import Data.ByteString (ByteString) import qualified Data.ByteString as BS -import qualified Data.ByteString.Char8 as BS8 import qualified Data.ByteString.Base16 as Base16 +import qualified Data.ByteString.Char8 as BS8 +import Data.Kind (Type) import Data.Proxy (Proxy (Proxy)) import Data.Word (Word64) -import NoThunks.Class (NoThunks, unsafeNoThunks, noThunks) -import Numeric.Natural (Natural) -import Test.QuickCheck - ( (.&&.) - , (===) - , Arbitrary - , Gen - , Property - , arbitrary - , arbitraryBoundedIntegral - , counterexample - , property - , shrink - , vector - , checkCoverage - , cover - , ioProperty - , forAllBlind - ) -import qualified Test.QuickCheck.Gen as Gen -import Control.Monad (guard, when) -import GHC.TypeLits (Nat, KnownNat, natVal) import Formatting.Buildable (Buildable (..), build) -import Control.Monad.Class.MonadST (MonadST) -import Control.Monad.Class.MonadThrow (MonadThrow) -import Control.Concurrent.Class.MonadMVar - ( MVar - , withMVar - , newMVar - , newMVar - ) +import GHC.Exts (fromList, fromListN, toList) import GHC.Stack (HasCallStack) +import GHC.TypeLits (KnownNat, Nat, natVal) +import NoThunks.Class (NoThunks, noThunks, unsafeNoThunks) +import Numeric.Natural (Natural) +import Test.QuickCheck ( + Arbitrary, + Gen, + Property, + arbitrary, + arbitraryBoundedIntegral, + checkCoverage, + counterexample, + cover, + forAllBlind, + ioProperty, + property, + shrink, + vector, + (.&&.), + (===), + ) +import qualified Test.QuickCheck.Gen as Gen +import Text.Show.Pretty (ppShow) -------------------------------------------------------------------------------- -- Connecting MonadRandom to Gen -------------------------------------------------------------------------------- newtype TestSeed = TestSeed - { getTestSeed :: (Word64, Word64, Word64, Word64, Word64) - } + { getTestSeed :: (Word64, Word64, Word64, Word64, Word64) + } deriving (Show, Eq, Ord, FromCBOR, ToCBOR) withTestSeed :: TestSeed -> MonadPseudoRandom ChaChaDRG a -> a @@ -170,7 +169,7 @@ nullTestSeed = TestSeed (0, 0, 0, 0, 0) instance Arbitrary TestSeed where arbitrary = - TestSeed <$> ((,,,,) <$> gen <*> gen <*> gen <*> gen <*> gen) + TestSeed <$> ((,,,,) <$> gen <*> gen <*> gen <*> gen <*> gen) where gen :: Gen Word64 gen = arbitraryBoundedIntegral @@ -180,10 +179,10 @@ instance Arbitrary TestSeed where -- Seeds -------------------------------------------------------------------------------- -newtype SizedSeed (n :: Nat) = SizedSeed { unSizedSeed :: Seed } deriving Show +newtype SizedSeed (n :: Nat) = SizedSeed {unSizedSeed :: Seed} deriving (Show) -instance (KnownNat n) => Arbitrary (SizedSeed n) where - arbitrary = SizedSeed <$> arbitrarySeedOfSize (fromIntegral $ natVal (Proxy :: Proxy n)) +instance KnownNat n => Arbitrary (SizedSeed n) where + arbitrary = SizedSeed <$> arbitrarySeedOfSize (fromIntegral $ natVal (Proxy :: Proxy n)) arbitrarySeedOfSize :: Word -> Gen Seed arbitrarySeedOfSize sz = @@ -197,24 +196,26 @@ arbitrarySeedBytesOfSize sz = -- Messages to sign -------------------------------------------------------------------------------- -newtype Message = Message { messageBytes :: ByteString } +newtype Message = Message {messageBytes :: ByteString} deriving (Eq, Show, SignableRepresentation) instance Arbitrary Message where arbitrary = Message . BS.pack <$> arbitrary - shrink = map (Message . BS.pack) . shrink . BS.unpack . messageBytes + shrink = map (Message . BS.pack) . shrink . BS.unpack . messageBytes -------------------------------------------------------------------------------- -- Serialisation properties -------------------------------------------------------------------------------- -prop_cbor :: (ToCBOR a, FromCBOR a, Eq a, Show a) - => a -> Property +prop_cbor :: + (ToCBOR a, FromCBOR a, Eq a, Show a) => + a -> Property prop_cbor = prop_cbor_with toCBOR fromCBOR prop_cbor_size :: forall a. ToCBOR a => a -> Property -prop_cbor_size a = counterexample (show lo ++ " ≰ " ++ show len) (lo <= len) - .&&. counterexample (show len ++ " ≰ " ++ show hi) (len <= hi) +prop_cbor_size a = + counterexample (show lo ++ " ≰ " ++ show len) (lo <= len) + .&&. counterexample (show len ++ " ≰ " ++ show hi) (len <= hi) where len, lo, hi :: Natural len = fromIntegral $ BS.length (toStrictByteString (toCBOR a)) @@ -223,72 +224,80 @@ prop_cbor_size a = counterexample (show lo ++ " ≰ " ++ show len) (lo <= len) Right x -> x Left err -> error . show . build $ err -prop_cbor_with :: (Eq a, Show a) - => (a -> Encoding) - -> (forall s. Decoder s a) - -> a - -> Property +prop_cbor_with :: + (Eq a, Show a) => + (a -> Encoding) -> + (forall s. Decoder s a) -> + a -> + Property prop_cbor_with encoder decoder x = - prop_cbor_valid encoder x - .&&. prop_cbor_roundtrip encoder decoder x + prop_cbor_valid encoder x + .&&. prop_cbor_roundtrip encoder decoder x prop_cbor_valid :: (a -> Encoding) -> a -> Property prop_cbor_valid encoder x = - counterexample errmsg $ - validFlatTerm term + counterexample errmsg $ + validFlatTerm term where - term = toFlatTerm encoding + term = toFlatTerm encoding encoding = encoder x - errmsg = "invalid flat term " ++ show term - ++ " from encoding " ++ show encoding + errmsg = + "invalid flat term " + ++ show term + ++ " from encoding " + ++ show encoding -- Written like this so that an Eq DeserialiseFailure is not required. -prop_cbor_roundtrip :: (Eq a, Show a) - => (a -> Encoding) - -> (forall s. Decoder s a) - -> a -> Property +prop_cbor_roundtrip :: + (Eq a, Show a) => + (a -> Encoding) -> + (forall s. Decoder s a) -> + a -> + Property prop_cbor_roundtrip encoder decoder x = - case decodeFullDecoder "" decoder (serialize (encoder x)) of - Right y -> y === x - Left err -> counterexample (show err) (property False) - -prop_raw_serialise :: (Eq a, Show a) - => (a -> ByteString) - -> (ByteString -> Maybe a) - -> a - -> Property + case decodeFullDecoder "" decoder (serialize (encoder x)) of + Right y -> y === x + Left err -> counterexample (show err) (property False) + +prop_raw_serialise :: + (Eq a, Show a) => + (a -> ByteString) -> + (ByteString -> Maybe a) -> + a -> + Property prop_raw_serialise serialise deserialise x = - case deserialise (serialise x) of - Just y -> y === x - Nothing -> property False + case deserialise (serialise x) of + Just y -> y === x + Nothing -> property False prop_raw_deserialise :: - forall (a :: Type) . - (Show a) => + forall (a :: Type). + Show a => (ByteString -> Maybe a) -> BadInputFor a -> Property prop_raw_deserialise deserialise (BadInputFor (forbiddenLen, bs)) = - checkCoverage . - cover 50.0 (BS.length bs > forbiddenLen) "too long" . - cover 50.0 (BS.length bs < forbiddenLen) "too short" $ - case deserialise bs of - Nothing -> property True - Just x -> counterexample (ppShow x) False + checkCoverage + . cover 50.0 (BS.length bs > forbiddenLen) "too long" + . cover 50.0 (BS.length bs < forbiddenLen) "too short" + $ case deserialise bs of + Nothing -> property True + Just x -> counterexample (ppShow x) False -- | The crypto algorithm classes have direct encoding functions, and the key -- types are also typically a member of the 'ToCBOR' class. Where a 'ToCBOR' -- instance is provided then these should match. --- -prop_cbor_direct_vs_class :: ToCBOR a - => (a -> Encoding) - -> a -> Property +prop_cbor_direct_vs_class :: + ToCBOR a => + (a -> Encoding) -> + a -> + Property prop_cbor_direct_vs_class encoder x = toFlatTerm (encoder x) === toFlatTerm (toCBOR x) prop_size_serialise :: (a -> ByteString) -> Word -> a -> Property prop_size_serialise serialise size x = - BS.length (serialise x) === fromIntegral size + BS.length (serialise x) === fromIntegral size -------------------------------------------------------------------------------- -- NoThunks @@ -297,13 +306,14 @@ prop_size_serialise serialise size x = -- | When forcing the given value to WHNF, it may no longer contain thunks. prop_no_thunks :: NoThunks a => a -> Property prop_no_thunks !a = case unsafeNoThunks a of - Nothing -> property True - Just msg -> counterexample (show msg) (property False) + Nothing -> property True + Just msg -> counterexample (show msg) (property False) prop_no_thunks_IO :: NoThunks a => IO a -> IO Property -prop_no_thunks_IO a = a >>= noThunks [] >>= \case - Nothing -> return $ property True - Just msg -> return $! counterexample (show msg) $! (property False) +prop_no_thunks_IO a = + a >>= noThunks [] >>= \case + Nothing -> return $ property True + Just msg -> return $! counterexample (show msg) $! (property False) prop_no_thunks_IO_from :: NoThunks a => (b -> IO a) -> b -> Property prop_no_thunks_IO_from mkX y = ioProperty $ do @@ -329,7 +339,7 @@ type role BadInputFor nominal -- Needed instead of an Arbitrary instance, as there's no (good) way of knowing -- what our forbidden (i.e. correct) length is. genBadInputFor :: - forall (a :: Type) . + forall (a :: Type). Int -> Gen (BadInputFor a) genBadInputFor forbiddenLen = @@ -347,17 +357,18 @@ genBadInputFor forbiddenLen = -- This ensures we don't \'shrink out of case\': we shrink too-longs to -- (smaller) too-longs, and too-shorts to (smaller) too-shorts. shrinkBadInputFor :: - forall (a :: Type) . + forall (a :: Type). BadInputFor a -> [BadInputFor a] -shrinkBadInputFor (BadInputFor (len, bs)) = BadInputFor . (len,) <$> do - bs' <- fromList <$> shrink (toList bs) - when (BS.length bs > len) (guard (BS.length bs' > len)) - pure bs' +shrinkBadInputFor (BadInputFor (len, bs)) = + BadInputFor . (len,) <$> do + bs' <- fromList <$> shrink (toList bs) + when (BS.length bs > len) (guard (BS.length bs' > len)) + pure bs' -- This shows only the ByteString, in hex. showBadInputFor :: - forall (a :: Type) . + forall (a :: Type). BadInputFor a -> String showBadInputFor (BadInputFor (_, bs)) = @@ -397,24 +408,26 @@ eitherShowError (Right a) = return a -- Helpers for direct ser/deser -------------------------------------------------------------------------------- -directSerialiseToBS :: forall m a. - DirectSerialise a - => MonadST m - => MonadThrow m - => Int - -> a - -> m ByteString +directSerialiseToBS :: + forall m a. + DirectSerialise a => + MonadST m => + MonadThrow m => + Int -> + a -> + m ByteString directSerialiseToBS dstsize val = do allocaBytes dstsize $ \dst -> do directSerialiseBufChecked dst dstsize val packByteStringCStringLen (dst, fromIntegral dstsize) -directDeserialiseFromBS :: forall m a. - DirectDeserialise a - => MonadST m - => MonadThrow m - => ByteString - -> m a +directDeserialiseFromBS :: + forall m a. + DirectDeserialise a => + MonadST m => + MonadThrow m => + ByteString -> + m a directDeserialiseFromBS bs = do unpackByteStringCStringLen bs $ \(src, srcsize) -> do directDeserialiseBufChecked src srcsize diff --git a/cardano-crypto-tests/src/Test/Crypto/VRF.hs b/cardano-crypto-tests/src/Test/Crypto/VRF.hs index 80b1be4aa..ea8239575 100644 --- a/cardano-crypto-tests/src/Test/Crypto/VRF.hs +++ b/cardano-crypto-tests/src/Test/Crypto/VRF.hs @@ -1,31 +1,36 @@ +{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE DataKinds #-} - {-# OPTIONS_GHC -Wno-orphans #-} -module Test.Crypto.VRF - ( tests - ) +module Test.Crypto.VRF ( + tests, +) where +import Cardano.Crypto.Util import Cardano.Crypto.VRF import Cardano.Crypto.VRF.Praos import Cardano.Crypto.VRF.PraosBatchCompat -import Cardano.Crypto.Util import qualified Data.ByteString as BS -import Data.Word (Word8, Word64) import Data.Proxy (Proxy (..)) +import Data.Word (Word64, Word8) import Test.Crypto.Util -import Test.QuickCheck - ((==>), (===), Arbitrary(..), Gen, Property, NonNegative(..), - counterexample) +import Test.QuickCheck ( + Arbitrary (..), + Gen, + NonNegative (..), + Property, + counterexample, + (===), + (==>), + ) import Test.Tasty (TestTree, testGroup) import Test.Tasty.QuickCheck (testProperty, vectorOf) @@ -35,170 +40,200 @@ import Test.Tasty.QuickCheck (testProperty, vectorOf) -- tests :: TestTree tests = - testGroup "Crypto.VRF" + testGroup + "Crypto.VRF" [ testVRFAlgorithm (Proxy :: Proxy MockVRF) "MockVRF" , testVRFAlgorithm (Proxy :: Proxy SimpleVRF) "SimpleVRF" , testVRFAlgorithm (Proxy :: Proxy PraosVRF) "PraosVRF" , testVRFAlgorithm (Proxy :: Proxy PraosBatchCompatVRF) "PraosBatchCompatVRF" - - , testGroup "OutputVRF" - [ testProperty "bytesToNatural" prop_bytesToNatural - , testProperty "naturalToBytes" prop_naturalToBytes - ] - , testGroup "ConvertingTypes" - [ testProperty "pubKeyToBatchCompat" prop_pubKeyToBatchComopat - , testProperty "signKeyToBatchCompat" prop_signKeyToBatchCompat - , testProperty "outputToBatchCompat" prop_outputToBatchComat - , testProperty "compatibleVerKeyConversion" prop_verKeyValidConversion - , testProperty "compatibleSignKeyConversion" prop_signKeyValidConversion - ] + , testGroup + "OutputVRF" + [ testProperty "bytesToNatural" prop_bytesToNatural + , testProperty "naturalToBytes" prop_naturalToBytes + ] + , testGroup + "ConvertingTypes" + [ testProperty "pubKeyToBatchCompat" prop_pubKeyToBatchComopat + , testProperty "signKeyToBatchCompat" prop_signKeyToBatchCompat + , testProperty "outputToBatchCompat" prop_outputToBatchComat + , testProperty "compatibleVerKeyConversion" prop_verKeyValidConversion + , testProperty "compatibleSignKeyConversion" prop_signKeyValidConversion + ] ] -testVRFAlgorithm - :: forall proxy v. ( VRFAlgorithm v - , ToCBOR (VerKeyVRF v) - , FromCBOR (VerKeyVRF v) - , ToCBOR (SignKeyVRF v) - , FromCBOR (SignKeyVRF v) - , ToCBOR (CertVRF v) - , FromCBOR (CertVRF v) - , Eq (SignKeyVRF v) -- no Eq for signing keys normally - , ContextVRF v ~ () - , Signable v ~ SignableRepresentation - ) - => proxy v - -> String - -> TestTree +testVRFAlgorithm :: + forall proxy v. + ( VRFAlgorithm v + , ToCBOR (VerKeyVRF v) + , FromCBOR (VerKeyVRF v) + , ToCBOR (SignKeyVRF v) + , FromCBOR (SignKeyVRF v) + , ToCBOR (CertVRF v) + , FromCBOR (CertVRF v) + , Eq (SignKeyVRF v) -- no Eq for signing keys normally + , ContextVRF v ~ () + , Signable v ~ SignableRepresentation + ) => + proxy v -> + String -> + TestTree testVRFAlgorithm _ n = - testGroup n - [ testGroup "serialisation" - [ testGroup "raw" - [ testProperty "VerKey" $ prop_raw_serialise @(VerKeyVRF v) - rawSerialiseVerKeyVRF - rawDeserialiseVerKeyVRF - , testProperty "SignKey" $ prop_raw_serialise @(SignKeyVRF v) - rawSerialiseSignKeyVRF - rawDeserialiseSignKeyVRF - , testProperty "Cert" $ prop_raw_serialise @(CertVRF v) - rawSerialiseCertVRF - rawDeserialiseCertVRF + testGroup + n + [ testGroup + "serialisation" + [ testGroup + "raw" + [ testProperty "VerKey" $ + prop_raw_serialise @(VerKeyVRF v) + rawSerialiseVerKeyVRF + rawDeserialiseVerKeyVRF + , testProperty "SignKey" $ + prop_raw_serialise @(SignKeyVRF v) + rawSerialiseSignKeyVRF + rawDeserialiseSignKeyVRF + , testProperty "Cert" $ + prop_raw_serialise @(CertVRF v) + rawSerialiseCertVRF + rawDeserialiseCertVRF + ] + , testGroup + "size" + [ testProperty "VerKey" $ + prop_size_serialise @(VerKeyVRF v) + rawSerialiseVerKeyVRF + (sizeVerKeyVRF (Proxy @v)) + , testProperty "SignKey" $ + prop_size_serialise @(SignKeyVRF v) + rawSerialiseSignKeyVRF + (sizeSignKeyVRF (Proxy @v)) + , testProperty "Cert" $ + prop_size_serialise @(CertVRF v) + rawSerialiseCertVRF + (sizeCertVRF (Proxy @v)) + ] + , testGroup + "direct CBOR" + [ testProperty "VerKey" $ + prop_cbor_with @(VerKeyVRF v) + encodeVerKeyVRF + decodeVerKeyVRF + , testProperty "SignKey" $ + prop_cbor_with @(SignKeyVRF v) + encodeSignKeyVRF + decodeSignKeyVRF + , testProperty "Cert" $ + prop_cbor_with @(CertVRF v) + encodeCertVRF + decodeCertVRF + ] + , testGroup + "To/FromCBOR class" + [ testProperty "VerKey" $ prop_cbor @(VerKeyVRF v) + , testProperty "SignKey" $ prop_cbor @(SignKeyVRF v) + , testProperty "Cert" $ prop_cbor @(CertVRF v) + ] + , testGroup + "ToCBOR size" + [ testProperty "VerKey" $ prop_cbor_size @(VerKeyVRF v) + , testProperty "SignKey" $ prop_cbor_size @(SignKeyVRF v) + , testProperty "Sig" $ prop_cbor_size @(CertVRF v) + ] + , testGroup + "direct matches class" + [ testProperty "VerKey" $ + prop_cbor_direct_vs_class @(VerKeyVRF v) + encodeVerKeyVRF + , testProperty "SignKey" $ + prop_cbor_direct_vs_class @(SignKeyVRF v) + encodeSignKeyVRF + , testProperty "Cert" $ + prop_cbor_direct_vs_class @(CertVRF v) + encodeCertVRF + ] ] - - , testGroup "size" - [ testProperty "VerKey" $ prop_size_serialise @(VerKeyVRF v) - rawSerialiseVerKeyVRF - (sizeVerKeyVRF (Proxy @v)) - , testProperty "SignKey" $ prop_size_serialise @(SignKeyVRF v) - rawSerialiseSignKeyVRF - (sizeSignKeyVRF (Proxy @v)) - , testProperty "Cert" $ prop_size_serialise @(CertVRF v) - rawSerialiseCertVRF - (sizeCertVRF (Proxy @v)) + , testGroup + "verify" + [ -- NOTE: we no longer test against maxVRF, because the maximum numeric + -- value isn't actually what we're interested in, as long as all + -- keys/hashes have the correct sizes, which 'prop_size_serialise' + -- tests already. + testProperty "verify positive" $ prop_vrf_verify_pos @v + , testProperty "verify negative" $ prop_vrf_verify_neg @v ] - - , testGroup "direct CBOR" - [ testProperty "VerKey" $ prop_cbor_with @(VerKeyVRF v) - encodeVerKeyVRF - decodeVerKeyVRF - , testProperty "SignKey" $ prop_cbor_with @(SignKeyVRF v) - encodeSignKeyVRF - decodeSignKeyVRF - , testProperty "Cert" $ prop_cbor_with @(CertVRF v) - encodeCertVRF - decodeCertVRF + , testGroup + "output" + [ testProperty "sizeOutputVRF" $ prop_vrf_output_size @v + , testProperty "mkTestOutputVRF" $ prop_vrf_output_natural @v ] - - , testGroup "To/FromCBOR class" - [ testProperty "VerKey" $ prop_cbor @(VerKeyVRF v) - , testProperty "SignKey" $ prop_cbor @(SignKeyVRF v) - , testProperty "Cert" $ prop_cbor @(CertVRF v) + , testGroup + "NoThunks" + [ testProperty "VerKey" $ prop_no_thunks @(VerKeyVRF v) + , testProperty "SignKey" $ prop_no_thunks @(SignKeyVRF v) + , testProperty "Cert" $ prop_no_thunks @(CertVRF v) ] - - , testGroup "ToCBOR size" - [ testProperty "VerKey" $ prop_cbor_size @(VerKeyVRF v) - , testProperty "SignKey" $ prop_cbor_size @(SignKeyVRF v) - , testProperty "Sig" $ prop_cbor_size @(CertVRF v) - ] - - , testGroup "direct matches class" - [ testProperty "VerKey" $ prop_cbor_direct_vs_class @(VerKeyVRF v) - encodeVerKeyVRF - , testProperty "SignKey" $ prop_cbor_direct_vs_class @(SignKeyVRF v) - encodeSignKeyVRF - , testProperty "Cert" $ prop_cbor_direct_vs_class @(CertVRF v) - encodeCertVRF - ] - ] - - , testGroup "verify" - [ -- NOTE: we no longer test against maxVRF, because the maximum numeric - -- value isn't actually what we're interested in, as long as all - -- keys/hashes have the correct sizes, which 'prop_size_serialise' - -- tests already. - testProperty "verify positive" $ prop_vrf_verify_pos @v - , testProperty "verify negative" $ prop_vrf_verify_neg @v - ] - - , testGroup "output" - [ testProperty "sizeOutputVRF" $ prop_vrf_output_size @v - , testProperty "mkTestOutputVRF" $ prop_vrf_output_natural @v - ] - - , testGroup "NoThunks" - [ testProperty "VerKey" $ prop_no_thunks @(VerKeyVRF v) - , testProperty "SignKey" $ prop_no_thunks @(SignKeyVRF v) - , testProperty "Cert" $ prop_no_thunks @(CertVRF v) - ] ] -prop_vrf_verify_pos - :: forall v. (VRFAlgorithm v, - ContextVRF v ~ (), Signable v ~ SignableRepresentation) - => Message - -> SignKeyVRF v - -> Bool +prop_vrf_verify_pos :: + forall v. + ( VRFAlgorithm v + , ContextVRF v ~ () + , Signable v ~ SignableRepresentation + ) => + Message -> + SignKeyVRF v -> + Bool prop_vrf_verify_pos a sk = let (y, c) = evalVRF () a sk vk = deriveVerKeyVRF sk - in verifyVRF () vk a c == Just y - -prop_vrf_verify_neg - :: forall v. (VRFAlgorithm v, Eq (SignKeyVRF v), - ContextVRF v ~ (), Signable v ~ SignableRepresentation) - => Message - -> SignKeyVRF v - -> SignKeyVRF v - -> Property + in verifyVRF () vk a c == Just y + +prop_vrf_verify_neg :: + forall v. + ( VRFAlgorithm v + , Eq (SignKeyVRF v) + , ContextVRF v ~ () + , Signable v ~ SignableRepresentation + ) => + Message -> + SignKeyVRF v -> + SignKeyVRF v -> + Property prop_vrf_verify_neg a sk sk' = - sk /= - sk' ==> - let (_y, c) = evalVRF () a sk' - vk = deriveVerKeyVRF sk - in verifyVRF () vk a c == Nothing - - -prop_vrf_output_size - :: forall v. (VRFAlgorithm v, - ContextVRF v ~ (), Signable v ~ SignableRepresentation) - => Message - -> SignKeyVRF v - -> Property + sk + /= sk' + ==> let (_y, c) = evalVRF () a sk' + vk = deriveVerKeyVRF sk + in verifyVRF () vk a c == Nothing + +prop_vrf_output_size :: + forall v. + ( VRFAlgorithm v + , ContextVRF v ~ () + , Signable v ~ SignableRepresentation + ) => + Message -> + SignKeyVRF v -> + Property prop_vrf_output_size a sk = let (out, _c) = evalVRF () a sk - in BS.length (getOutputVRFBytes out) - === fromIntegral (sizeOutputVRF (Proxy :: Proxy v)) - -prop_vrf_output_natural - :: forall v. (VRFAlgorithm v, - ContextVRF v ~ (), Signable v ~ SignableRepresentation) - => Message - -> SignKeyVRF v - -> Property + in BS.length (getOutputVRFBytes out) + === fromIntegral (sizeOutputVRF (Proxy :: Proxy v)) + +prop_vrf_output_natural :: + forall v. + ( VRFAlgorithm v + , ContextVRF v ~ () + , Signable v ~ SignableRepresentation + ) => + Message -> + SignKeyVRF v -> + Property prop_vrf_output_natural a sk = let (out, _c) = evalVRF () a sk - n = getOutputVRFNatural out + n = getOutputVRFNatural out in counterexample (show n) $ - mkTestOutputVRF n === out + mkTestOutputVRF n === out -- -- Natural <-> bytes conversion @@ -206,14 +241,14 @@ prop_vrf_output_natural a sk = prop_bytesToNatural :: [Word8] -> Bool prop_bytesToNatural ws = - naturalToBytes (BS.length bs) (bytesToNatural bs) == bs + naturalToBytes (BS.length bs) (bytesToNatural bs) == bs where bs = BS.pack ws prop_naturalToBytes :: NonNegative Int -> Word64 -> Property prop_naturalToBytes (NonNegative sz) n = - sz >= 8 ==> - bytesToNatural (naturalToBytes sz (fromIntegral n)) == fromIntegral n + sz >= 8 ==> + bytesToNatural (naturalToBytes sz (fromIntegral n)) == fromIntegral n -- -- Praos <-> BatchCompatPraos VerKey conversion @@ -247,7 +282,7 @@ prop_verKeyValidConversion sharedBytes msg = skBatchCompat = genKeyVRF . unSizedSeed $ sharedBytes vkBatchCompat = vkToBatchCompat vkPraos (y, c) = evalVRF () msg skBatchCompat - in + in verifyVRF () vkBatchCompat msg c == Just y -- @@ -259,7 +294,7 @@ prop_signKeyValidConversion sharedBytes = let skPraos = genKeyVRF . unSizedSeed $ sharedBytes skBatchCompat = genKeyVRF . unSizedSeed $ sharedBytes - in + in skBatchCompat == skToBatchCompat skPraos -- @@ -276,9 +311,13 @@ instance VRFAlgorithm v => Arbitrary (SignKeyVRF v) where seedSize = seedSizeVRF (Proxy :: Proxy v) shrink = const [] -instance (VRFAlgorithm v, - ContextVRF v ~ (), Signable v ~ SignableRepresentation) - => Arbitrary (CertVRF v) where +instance + ( VRFAlgorithm v + , ContextVRF v ~ () + , Signable v ~ SignableRepresentation + ) => + Arbitrary (CertVRF v) + where arbitrary = do a <- arbitrary :: Gen Message sk <- arbitrary diff --git a/cardano-crypto-tests/src/Test/Crypto/Vector/Secp256k1DSIGN.hs b/cardano-crypto-tests/src/Test/Crypto/Vector/Secp256k1DSIGN.hs index e05ffab5f..5b704f483 100644 --- a/cardano-crypto-tests/src/Test/Crypto/Vector/Secp256k1DSIGN.hs +++ b/cardano-crypto-tests/src/Test/Crypto/Vector/Secp256k1DSIGN.hs @@ -6,29 +6,29 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -module Test.Crypto.Vector.Secp256k1DSIGN - ( tests, - ) +module Test.Crypto.Vector.Secp256k1DSIGN ( + tests, +) where import Cardano.Binary (DecoderError (DecoderErrorDeserialiseFailure), FromCBOR, decodeFull') -import Cardano.Crypto.DSIGN - ( DSIGNAlgorithm - ( ContextDSIGN, - SigDSIGN, - SignKeyDSIGN, - Signable, - VerKeyDSIGN, - deriveVerKeyDSIGN, - signDSIGN, - verifyDSIGN - ), - EcdsaSecp256k1DSIGN, - MessageHash, - SchnorrSecp256k1DSIGN, - hashAndPack, - toMessageHash, - ) +import Cardano.Crypto.DSIGN ( + DSIGNAlgorithm ( + ContextDSIGN, + SigDSIGN, + SignKeyDSIGN, + Signable, + VerKeyDSIGN, + deriveVerKeyDSIGN, + signDSIGN, + verifyDSIGN + ), + EcdsaSecp256k1DSIGN, + MessageHash, + SchnorrSecp256k1DSIGN, + hashAndPack, + toMessageHash, + ) import Cardano.Crypto.Hash.SHA3_256 (SHA3_256) import Codec.CBOR.Read (DeserialiseFailure (..)) import Control.Monad (forM_) @@ -36,32 +36,36 @@ import Data.ByteString (ByteString) import Data.Either (isLeft, isRight) import Data.Maybe (isNothing) import Data.Proxy (Proxy (..)) -import Test.Crypto.Vector.SerializationUtils as Utils (HexStringInCBOR (..), dropBytes, hexByteStringLength) -import Test.Crypto.Vector.StringConstants - ( cannotDecodeVerificationKeyError, - invalidEcdsaSigLengthError, - invalidEcdsaVerKeyLengthError, - invalidSchnorrSigLengthError, - invalidSchnorrVerKeyLengthError, - unexpectedDecodingError, - ) -import Test.Crypto.Vector.Vectors - ( defaultMessage, - defaultSKey, - ecdsaMismatchMessageAndSignature, - ecdsaNegSigTestVectors, - ecdsaVerKeyAndSigVerifyTestVectors, - ecdsaWrongLengthSigTestVectorsRaw, - schnorrMismatchMessageAndSignature, - schnorrVerKeyAndSigVerifyTestVectors, - schnorrWrongLengthSigTestVectorsRaw, - signAndVerifyTestVectors, - verKeyNotOnCurveTestVectorRaw, - wrongEcdsaVerKeyTestVector, - wrongLengthMessageHashTestVectors, - wrongLengthVerKeyTestVectorsRaw, - wrongSchnorrVerKeyTestVector, - ) +import Test.Crypto.Vector.SerializationUtils as Utils ( + HexStringInCBOR (..), + dropBytes, + hexByteStringLength, + ) +import Test.Crypto.Vector.StringConstants ( + cannotDecodeVerificationKeyError, + invalidEcdsaSigLengthError, + invalidEcdsaVerKeyLengthError, + invalidSchnorrSigLengthError, + invalidSchnorrVerKeyLengthError, + unexpectedDecodingError, + ) +import Test.Crypto.Vector.Vectors ( + defaultMessage, + defaultSKey, + ecdsaMismatchMessageAndSignature, + ecdsaNegSigTestVectors, + ecdsaVerKeyAndSigVerifyTestVectors, + ecdsaWrongLengthSigTestVectorsRaw, + schnorrMismatchMessageAndSignature, + schnorrVerKeyAndSigVerifyTestVectors, + schnorrWrongLengthSigTestVectorsRaw, + signAndVerifyTestVectors, + verKeyNotOnCurveTestVectorRaw, + wrongEcdsaVerKeyTestVector, + wrongLengthMessageHashTestVectors, + wrongLengthVerKeyTestVectorsRaw, + wrongSchnorrVerKeyTestVector, + ) import Test.Tasty (TestTree, testGroup) import Test.Tasty.HUnit (assertBool, assertEqual, testCase) @@ -78,35 +82,47 @@ tests = [ -- Note : Proxies are here repetead due to specific test vectors need to be used with specific proxy testGroup "EcdsaSecp256k1" - [ signAndVerifyTest ecdsaProxy, - verifyOnlyTest ecdsaVerKeyAndSigVerifyTestVectors, - wrongMessageHashLengthTest, - mismatchSignKeyVerKeyTest wrongEcdsaVerKeyTestVector, - mismatchMessageSignatureTest ecdsaMismatchMessageAndSignature, - verKeyNotOnCurveParserTest ecdsaProxy verKeyNotOnCurveTestVectorRaw, - invalidLengthVerKeyParserTest ecdsaProxy wrongLengthVerKeyTestVectorsRaw invalidEcdsaVerKeyLengthError, - invalidLengthSignatureParserTest ecdsaProxy ecdsaWrongLengthSigTestVectorsRaw invalidEcdsaSigLengthError, - negativeSignatureTest ecdsaNegSigTestVectors - ], - testGroup + [ signAndVerifyTest ecdsaProxy + , verifyOnlyTest ecdsaVerKeyAndSigVerifyTestVectors + , wrongMessageHashLengthTest + , mismatchSignKeyVerKeyTest wrongEcdsaVerKeyTestVector + , mismatchMessageSignatureTest ecdsaMismatchMessageAndSignature + , verKeyNotOnCurveParserTest ecdsaProxy verKeyNotOnCurveTestVectorRaw + , invalidLengthVerKeyParserTest + ecdsaProxy + wrongLengthVerKeyTestVectorsRaw + invalidEcdsaVerKeyLengthError + , invalidLengthSignatureParserTest + ecdsaProxy + ecdsaWrongLengthSigTestVectorsRaw + invalidEcdsaSigLengthError + , negativeSignatureTest ecdsaNegSigTestVectors + ] + , testGroup "SchnorrSecp256k1" - [ signAndVerifyTest schnorrProxy, - verifyOnlyTest schnorrVerKeyAndSigVerifyTestVectors, - mismatchSignKeyVerKeyTest wrongSchnorrVerKeyTestVector, - mismatchMessageSignatureTest schnorrMismatchMessageAndSignature, - -- Note: First byte is dropped for schnorr as it doesn't require Y-cordinate information and assumed to be even and our vectors contains Y-information. - verKeyNotOnCurveParserTest schnorrProxy (Utils.dropBytes 1 verKeyNotOnCurveTestVectorRaw), - invalidLengthVerKeyParserTest schnorrProxy (map (Utils.dropBytes 1) wrongLengthVerKeyTestVectorsRaw) invalidSchnorrVerKeyLengthError, - invalidLengthSignatureParserTest schnorrProxy schnorrWrongLengthSigTestVectorsRaw invalidSchnorrSigLengthError + [ signAndVerifyTest schnorrProxy + , verifyOnlyTest schnorrVerKeyAndSigVerifyTestVectors + , mismatchSignKeyVerKeyTest wrongSchnorrVerKeyTestVector + , mismatchMessageSignatureTest schnorrMismatchMessageAndSignature + , -- Note: First byte is dropped for schnorr as it doesn't require Y-cordinate information and assumed to be even and our vectors contains Y-information. + verKeyNotOnCurveParserTest schnorrProxy (Utils.dropBytes 1 verKeyNotOnCurveTestVectorRaw) + , invalidLengthVerKeyParserTest + schnorrProxy + (map (Utils.dropBytes 1) wrongLengthVerKeyTestVectorsRaw) + invalidSchnorrVerKeyLengthError + , invalidLengthSignatureParserTest + schnorrProxy + schnorrWrongLengthSigTestVectorsRaw + invalidSchnorrSigLengthError ] ] negativeSignatureTest :: forall v a. - ( DSIGNAlgorithm v, - ContextDSIGN v ~ (), - Signable v a, - ToSignable v a + ( DSIGNAlgorithm v + , ContextDSIGN v ~ () + , Signable v a + , ToSignable v a ) => (VerKeyDSIGN v, ByteString, SigDSIGN v) -> TestTree @@ -119,8 +135,7 @@ type InvalidLengthErrorFunction = Integer -> String invalidLengthSignatureParserTest :: forall v. - ( FromCBOR (SigDSIGN v) - ) => + FromCBOR (SigDSIGN v) => Proxy v -> [HexStringInCBOR] -> InvalidLengthErrorFunction -> @@ -129,13 +144,15 @@ invalidLengthSignatureParserTest _ invalidLengthSigs errorF = testCase "Parsing should fail when using invalid length signatures." $ forM_ invalidLengthSigs $ \invalidSig -> do let (DeserialiseFailure _ actualError) = invalidSigParserTest (Proxy @v) invalidSig - assertEqual "Expected invalid length signature error.." (errorF $ Utils.hexByteStringLength invalidSig) actualError + assertEqual + "Expected invalid length signature error.." + (errorF $ Utils.hexByteStringLength invalidSig) + actualError -- Try to parse the raw string into signature key and return the deserialize error invalidSigParserTest :: forall v. - ( FromCBOR (SigDSIGN v) - ) => + FromCBOR (SigDSIGN v) => Proxy v -> HexStringInCBOR -> DeserialiseFailure @@ -149,8 +166,7 @@ invalidSigParserTest _ rawSig = do -- Signature parser using decodeFull fullSigParser :: forall v. - ( FromCBOR (SigDSIGN v) - ) => + FromCBOR (SigDSIGN v) => Proxy v -> HexStringInCBOR -> Either DecoderError (SigDSIGN v) @@ -159,8 +175,7 @@ fullSigParser _ (HexCBOR hs) = decodeFull' hs -- Try to parse invalid length raw verification key invalidLengthVerKeyParserTest :: forall v. - ( FromCBOR (VerKeyDSIGN v) - ) => + FromCBOR (VerKeyDSIGN v) => Proxy v -> [HexStringInCBOR] -> InvalidLengthErrorFunction -> @@ -169,13 +184,15 @@ invalidLengthVerKeyParserTest _ invalidLengthVKeys errorF = testCase "Parsing should fail when using invalid length verification keys." $ forM_ invalidLengthVKeys $ \invalidVKey -> do let (DeserialiseFailure _ actualError) = invalidVerKeyParserTest (Proxy @v) invalidVKey - assertEqual "Expected invalid length verification key error." (errorF $ Utils.hexByteStringLength invalidVKey) actualError + assertEqual + "Expected invalid length verification key error." + (errorF $ Utils.hexByteStringLength invalidVKey) + actualError -- Try to parse raw verification key string and expect decode key error. verKeyNotOnCurveParserTest :: forall v. - ( FromCBOR (VerKeyDSIGN v) - ) => + FromCBOR (VerKeyDSIGN v) => Proxy v -> HexStringInCBOR -> TestTree @@ -186,8 +203,7 @@ verKeyNotOnCurveParserTest _ rawVKey = testCase "Parsing should fail when trying -- Try to parse the raw string into verification key and return the deserialize error invalidVerKeyParserTest :: forall v. - ( FromCBOR (VerKeyDSIGN v) - ) => + FromCBOR (VerKeyDSIGN v) => Proxy v -> HexStringInCBOR -> DeserialiseFailure @@ -201,8 +217,7 @@ invalidVerKeyParserTest _ rawVKey = do -- Vkey parser using decodeFull fullVerKeyParser :: forall v. - ( FromCBOR (VerKeyDSIGN v) - ) => + FromCBOR (VerKeyDSIGN v) => Proxy v -> HexStringInCBOR -> Either DecoderError (VerKeyDSIGN v) @@ -211,16 +226,17 @@ fullVerKeyParser _ (HexCBOR hs) = decodeFull' hs -- Use mismatch messages and signature vectors to test how verification behaves on wrong message or wrong signature mismatchMessageSignatureTest :: forall v a. - ( DSIGNAlgorithm v, - ContextDSIGN v ~ (), - Signable v a, - ToSignable v a + ( DSIGNAlgorithm v + , ContextDSIGN v ~ () + , Signable v a + , ToSignable v a ) => [(ByteString, VerKeyDSIGN v, SigDSIGN v)] -> TestTree mismatchMessageSignatureTest mismatchMessageSignatureVectors = - testCase "Verification should not be successful when using mismatch message, signature and vice versa." $ - forM_ + testCase + "Verification should not be successful when using mismatch message, signature and vice versa." + $ forM_ mismatchMessageSignatureVectors ( \(msg, vKey, sig) -> do let result = verifyDSIGN () vKey (toSignable (Proxy @v) msg) sig @@ -230,11 +246,11 @@ mismatchMessageSignatureTest mismatchMessageSignatureVectors = -- Use mismatch verification key for the signature generated by another signing key mismatchSignKeyVerKeyTest :: forall v a. - ( DSIGNAlgorithm v, - ContextDSIGN v ~ (), - Signable v a, - ToSignable v a, - FromCBOR (SignKeyDSIGN v) + ( DSIGNAlgorithm v + , ContextDSIGN v ~ () + , Signable v a + , ToSignable v a + , FromCBOR (SignKeyDSIGN v) ) => VerKeyDSIGN v -> TestTree @@ -252,10 +268,10 @@ wrongMessageHashLengthTest = testCase "toMessageHash should return Nothing when -- Test for vKey, message and signature test vectors without using sign key verifyOnlyTest :: forall v a. - ( DSIGNAlgorithm v, - ContextDSIGN v ~ (), - Signable v a, - ToSignable v a + ( DSIGNAlgorithm v + , ContextDSIGN v ~ () + , Signable v a + , ToSignable v a ) => (VerKeyDSIGN v, ByteString, SigDSIGN v) -> TestTree @@ -264,11 +280,11 @@ verifyOnlyTest (vKey, msg, sig) = testCase "Verification only should be successf -- Sign using given sKey and verify it signAndVerifyTest :: forall v a. - ( DSIGNAlgorithm v, - ContextDSIGN v ~ (), - Signable v a, - ToSignable v a, - FromCBOR (SignKeyDSIGN v) + ( DSIGNAlgorithm v + , ContextDSIGN v ~ () + , Signable v a + , ToSignable v a + , FromCBOR (SignKeyDSIGN v) ) => Proxy v -> TestTree @@ -280,10 +296,10 @@ signAndVerifyTest _ = -- Used for testing whole sign and verification flow signAndVerify :: forall v a. - ( DSIGNAlgorithm v, - ContextDSIGN v ~ (), - Signable v a, - ToSignable v a + ( DSIGNAlgorithm v + , ContextDSIGN v ~ () + , Signable v a + , ToSignable v a ) => Proxy v -> SignKeyDSIGN v -> @@ -298,10 +314,10 @@ signAndVerify _ sKey msg = do -- Used for testing whole sign and verification flow signAndVerifyWithVkey :: forall v a. - ( DSIGNAlgorithm v, - ContextDSIGN v ~ (), - Signable v a, - ToSignable v a + ( DSIGNAlgorithm v + , ContextDSIGN v ~ () + , Signable v a + , ToSignable v a ) => Proxy v -> SignKeyDSIGN v -> @@ -315,10 +331,10 @@ signAndVerifyWithVkey _ sKey vKey msg = -- Use alreday given signature, message and vkey to verify the signature verifyOnly :: forall v a. - ( DSIGNAlgorithm v, - ContextDSIGN v ~ (), - Signable v a, - ToSignable v a + ( DSIGNAlgorithm v + , ContextDSIGN v ~ () + , Signable v a + , ToSignable v a ) => Proxy v -> VerKeyDSIGN v -> diff --git a/cardano-crypto-tests/src/Test/Crypto/Vector/SerializationUtils.hs b/cardano-crypto-tests/src/Test/Crypto/Vector/SerializationUtils.hs index cd6721be9..1674ece20 100644 --- a/cardano-crypto-tests/src/Test/Crypto/Vector/SerializationUtils.hs +++ b/cardano-crypto-tests/src/Test/Crypto/Vector/SerializationUtils.hs @@ -1,23 +1,23 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} -module Test.Crypto.Vector.SerializationUtils - ( unHex, - unsafeUnHex, - SignatureResult, - HexStringInCBOR (..), - sKeyParser, - vKeyParser, - sigParser, - dropBytes, - hexByteStringLength, - ) +module Test.Crypto.Vector.SerializationUtils ( + unHex, + unsafeUnHex, + SignatureResult, + HexStringInCBOR (..), + sKeyParser, + vKeyParser, + sigParser, + dropBytes, + hexByteStringLength, +) where import Cardano.Binary (FromCBOR, serialize', unsafeDeserialize') -import Cardano.Crypto.DSIGN - ( DSIGNAlgorithm (SigDSIGN, SignKeyDSIGN, VerKeyDSIGN), - ) +import Cardano.Crypto.DSIGN ( + DSIGNAlgorithm (SigDSIGN, SignKeyDSIGN, VerKeyDSIGN), + ) import Data.ByteString (ByteString) import qualified Data.ByteString as BS import qualified Data.ByteString.Base16 as BS16 @@ -37,7 +37,7 @@ instance IsString HexStringInCBOR where instance Show HexStringInCBOR where show (HexCBOR bs) = BS8.unpack $ BS16.encode bs ---Drop from actual bytestring without cbor then recalculate +-- Drop from actual bytestring without cbor then recalculate dropBytes :: Int -> HexStringInCBOR -> HexStringInCBOR dropBytes n (HexCBOR bs) = HexCBOR $ serialize' $ BS.drop n (unsafeDeserialize' bs) @@ -54,11 +54,11 @@ unsafeUnHex hexBs = case unHex hexBs of type SignatureResult = (Either String ()) -sKeyParser :: forall d. (FromCBOR (SignKeyDSIGN d)) => HexStringInCBOR -> SignKeyDSIGN d +sKeyParser :: forall d. FromCBOR (SignKeyDSIGN d) => HexStringInCBOR -> SignKeyDSIGN d sKeyParser (HexCBOR bs) = unsafeDeserialize' bs -vKeyParser :: forall d. (FromCBOR (VerKeyDSIGN d)) => HexStringInCBOR -> VerKeyDSIGN d +vKeyParser :: forall d. FromCBOR (VerKeyDSIGN d) => HexStringInCBOR -> VerKeyDSIGN d vKeyParser (HexCBOR bs) = unsafeDeserialize' bs -sigParser :: forall d. (FromCBOR (SigDSIGN d)) => HexStringInCBOR -> SigDSIGN d -sigParser (HexCBOR bs) = unsafeDeserialize' bs \ No newline at end of file +sigParser :: forall d. FromCBOR (SigDSIGN d) => HexStringInCBOR -> SigDSIGN d +sigParser (HexCBOR bs) = unsafeDeserialize' bs diff --git a/cardano-crypto-tests/src/Test/Crypto/Vector/StringConstants.hs b/cardano-crypto-tests/src/Test/Crypto/Vector/StringConstants.hs index dfb22ed3b..3704026b7 100644 --- a/cardano-crypto-tests/src/Test/Crypto/Vector/StringConstants.hs +++ b/cardano-crypto-tests/src/Test/Crypto/Vector/StringConstants.hs @@ -1,19 +1,23 @@ - {-# LANGUAGE TypeApplications #-} -module Test.Crypto.Vector.StringConstants - ( invalidEcdsaSigLengthError, - invalidSchnorrVerKeyLengthError, - invalidEcdsaVerKeyLengthError, - invalidSchnorrSigLengthError, - cannotDecodeVerificationKeyError, - unexpectedDecodingError, - ) +module Test.Crypto.Vector.StringConstants ( + invalidEcdsaSigLengthError, + invalidSchnorrVerKeyLengthError, + invalidEcdsaVerKeyLengthError, + invalidSchnorrSigLengthError, + cannotDecodeVerificationKeyError, + unexpectedDecodingError, +) where +import Cardano.Crypto.SECP256K1.Constants ( + SECP256K1_ECDSA_PUBKEY_BYTES, + SECP256K1_ECDSA_SIGNATURE_BYTES, + SECP256K1_SCHNORR_PUBKEY_BYTES, + SECP256K1_SCHNORR_SIGNATURE_BYTES, + ) import Data.Data (Proxy (Proxy)) import GHC.TypeLits (natVal) -import Cardano.Crypto.SECP256K1.Constants (SECP256K1_ECDSA_PUBKEY_BYTES, SECP256K1_SCHNORR_PUBKEY_BYTES, SECP256K1_ECDSA_SIGNATURE_BYTES, SECP256K1_SCHNORR_SIGNATURE_BYTES) invalidEcdsaVerKeyLengthError :: Integer -> String invalidEcdsaVerKeyLengthError = invalidVerKeyLengthError $ natVal $ Proxy @SECP256K1_ECDSA_PUBKEY_BYTES @@ -23,7 +27,10 @@ invalidSchnorrVerKeyLengthError = invalidVerKeyLengthError $ natVal $ Proxy @SEC invalidVerKeyLengthError :: Integer -> Integer -> String invalidVerKeyLengthError expectedLength actualLength = - "decodeVerKeyDSIGN: wrong length, expected " ++ show expectedLength ++ " bytes but got " ++ show actualLength + "decodeVerKeyDSIGN: wrong length, expected " + ++ show expectedLength + ++ " bytes but got " + ++ show actualLength invalidEcdsaSigLengthError :: Integer -> String invalidEcdsaSigLengthError = invalidSigLengthError $ natVal $ Proxy @SECP256K1_ECDSA_SIGNATURE_BYTES @@ -33,7 +40,10 @@ invalidSchnorrSigLengthError = invalidSigLengthError $ natVal $ Proxy @SECP256K1 invalidSigLengthError :: Integer -> Integer -> String invalidSigLengthError expectedLength actualLength = - "decodeSigDSIGN: wrong length, expected " ++ show expectedLength ++ " bytes but got " ++ show actualLength + "decodeSigDSIGN: wrong length, expected " + ++ show expectedLength + ++ " bytes but got " + ++ show actualLength cannotDecodeVerificationKeyError :: String cannotDecodeVerificationKeyError = "decodeVerKeyDSIGN: cannot decode key" diff --git a/cardano-crypto-tests/src/Test/Crypto/Vector/Vectors.hs b/cardano-crypto-tests/src/Test/Crypto/Vector/Vectors.hs index bf6976c45..69a8de878 100644 --- a/cardano-crypto-tests/src/Test/Crypto/Vector/Vectors.hs +++ b/cardano-crypto-tests/src/Test/Crypto/Vector/Vectors.hs @@ -2,92 +2,102 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} -module Test.Crypto.Vector.Vectors - ( defaultSKey, - defaultMessage, - signAndVerifyTestVectors, - wrongEcdsaVerKeyTestVector, - wrongSchnorrVerKeyTestVector, - wrongLengthMessageHashTestVectors, - ecdsaVerKeyAndSigVerifyTestVectors, - schnorrVerKeyAndSigVerifyTestVectors, - ecdsaMismatchMessageAndSignature, - schnorrMismatchMessageAndSignature, - verKeyNotOnCurveTestVectorRaw, - wrongLengthVerKeyTestVectorsRaw, - ecdsaWrongLengthSigTestVectorsRaw, - schnorrWrongLengthSigTestVectorsRaw, - ecdsaNegSigTestVectors, - ) +module Test.Crypto.Vector.Vectors ( + defaultSKey, + defaultMessage, + signAndVerifyTestVectors, + wrongEcdsaVerKeyTestVector, + wrongSchnorrVerKeyTestVector, + wrongLengthMessageHashTestVectors, + ecdsaVerKeyAndSigVerifyTestVectors, + schnorrVerKeyAndSigVerifyTestVectors, + ecdsaMismatchMessageAndSignature, + schnorrMismatchMessageAndSignature, + verKeyNotOnCurveTestVectorRaw, + wrongLengthVerKeyTestVectorsRaw, + ecdsaWrongLengthSigTestVectorsRaw, + schnorrWrongLengthSigTestVectorsRaw, + ecdsaNegSigTestVectors, +) where import Cardano.Binary (FromCBOR) -import Cardano.Crypto.DSIGN - ( DSIGNAlgorithm (SigDSIGN, SignKeyDSIGN, VerKeyDSIGN), - EcdsaSecp256k1DSIGN, - SchnorrSecp256k1DSIGN, - ) +import Cardano.Crypto.DSIGN ( + DSIGNAlgorithm (SigDSIGN, SignKeyDSIGN, VerKeyDSIGN), + EcdsaSecp256k1DSIGN, + SchnorrSecp256k1DSIGN, + ) import Data.ByteString (ByteString) -import Test.Crypto.Vector.SerializationUtils - ( HexStringInCBOR (..), - sKeyParser, - sigParser, - vKeyParser, - ) - -defaultSKey :: forall d. (FromCBOR (SignKeyDSIGN d)) => SignKeyDSIGN d +import Test.Crypto.Vector.SerializationUtils ( + HexStringInCBOR (..), + sKeyParser, + sigParser, + vKeyParser, + ) + +defaultSKey :: forall d. FromCBOR (SignKeyDSIGN d) => SignKeyDSIGN d defaultSKey = sKeyParser "B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF" defaultMessage :: ByteString defaultMessage = "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89" -- These vectors contains secret key which first signs the given message and verifies using generated signature and derived vKey -signAndVerifyTestVectors :: forall d. (FromCBOR (SignKeyDSIGN d)) => [(SignKeyDSIGN d, ByteString)] +signAndVerifyTestVectors :: forall d. FromCBOR (SignKeyDSIGN d) => [(SignKeyDSIGN d, ByteString)] signAndVerifyTestVectors = map (\(sk, m) -> (sKeyParser sk, m)) - [ ( "0000000000000000000000000000000000000000000000000000000000000003", - "0000000000000000000000000000000000000000000000000000000000000000" - ), - ( "B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF", - "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89" - ), - ( "C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9", - "7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C" - ), - ( "0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + [ + ( "0000000000000000000000000000000000000000000000000000000000000003" + , "0000000000000000000000000000000000000000000000000000000000000000" + ) + , + ( "B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF" + , "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89" + ) + , + ( "C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9" + , "7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C" + ) + , + ( "0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710" + , "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" ) ] -- It is used for testing already given message, signature and vKey so that Ver should be sucessful without needing secret key to sign the message for ecdsa. -ecdsaVerKeyAndSigVerifyTestVectors :: (VerKeyDSIGN EcdsaSecp256k1DSIGN, ByteString, SigDSIGN EcdsaSecp256k1DSIGN) +ecdsaVerKeyAndSigVerifyTestVectors :: + (VerKeyDSIGN EcdsaSecp256k1DSIGN, ByteString, SigDSIGN EcdsaSecp256k1DSIGN) ecdsaVerKeyAndSigVerifyTestVectors = - ( vKeyParser "02599de3e582e2a3779208a210dfeae8f330b9af00a47a7fb22e9bb8ef596f301b", - "0000000000000000000000000000000000000000000000000000000000000000", - sigParser "354b868c757ef0b796003f7c23dd754d2d1726629145be2c7b7794a25fec80a06254f0915935f33b91bceb16d46ff2814f659e9b6791a4a21ff8764b78d7e114" + ( vKeyParser "02599de3e582e2a3779208a210dfeae8f330b9af00a47a7fb22e9bb8ef596f301b" + , "0000000000000000000000000000000000000000000000000000000000000000" + , sigParser + "354b868c757ef0b796003f7c23dd754d2d1726629145be2c7b7794a25fec80a06254f0915935f33b91bceb16d46ff2814f659e9b6791a4a21ff8764b78d7e114" ) -ecdsaNegSigTestVectors :: (VerKeyDSIGN EcdsaSecp256k1DSIGN, ByteString, SigDSIGN EcdsaSecp256k1DSIGN) +ecdsaNegSigTestVectors :: + (VerKeyDSIGN EcdsaSecp256k1DSIGN, ByteString, SigDSIGN EcdsaSecp256k1DSIGN) ecdsaNegSigTestVectors = - ( vKeyParser "02599de3e582e2a3779208a210dfeae8f330b9af00a47a7fb22e9bb8ef596f301b", - "0000000000000000000000000000000000000000000000000000000000000000", - sigParser "354b868c757ef0b796003f7c23dd754d2d1726629145be2c7b7794a25fec80a09dab0f6ea6ca0cc46e4314e92b900d7d6b493e4b47b6fb999fd9e841575e602d" + ( vKeyParser "02599de3e582e2a3779208a210dfeae8f330b9af00a47a7fb22e9bb8ef596f301b" + , "0000000000000000000000000000000000000000000000000000000000000000" + , sigParser + "354b868c757ef0b796003f7c23dd754d2d1726629145be2c7b7794a25fec80a09dab0f6ea6ca0cc46e4314e92b900d7d6b493e4b47b6fb999fd9e841575e602d" ) -- It is used for testing already given message, signature and vKey so that Ver should be sucessful without needing secret key to sign the message for schnorr. -schnorrVerKeyAndSigVerifyTestVectors :: (VerKeyDSIGN SchnorrSecp256k1DSIGN, ByteString, SigDSIGN SchnorrSecp256k1DSIGN) +schnorrVerKeyAndSigVerifyTestVectors :: + (VerKeyDSIGN SchnorrSecp256k1DSIGN, ByteString, SigDSIGN SchnorrSecp256k1DSIGN) schnorrVerKeyAndSigVerifyTestVectors = - ( vKeyParser "599de3e582e2a3779208a210dfeae8f330b9af00a47a7fb22e9bb8ef596f301b", - "0000000000000000000000000000000000000000000000000000000000000000", - sigParser "5a56da88e6fd8419181dec4d3dd6997bab953d2fc71ab65e23cfc9e7e3d1a310613454a60f6703819a39fdac2a410a094442afd1fc083354443e8d8bb4461a9b" + ( vKeyParser "599de3e582e2a3779208a210dfeae8f330b9af00a47a7fb22e9bb8ef596f301b" + , "0000000000000000000000000000000000000000000000000000000000000000" + , sigParser + "5a56da88e6fd8419181dec4d3dd6997bab953d2fc71ab65e23cfc9e7e3d1a310613454a60f6703819a39fdac2a410a094442afd1fc083354443e8d8bb4461a9b" ) -- Wrong length message hash are used to test ecdsa toMessageHash function wrongLengthMessageHashTestVectors :: [ByteString] wrongLengthMessageHashTestVectors = - [ "0", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" + [ "0" + , "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" ] wrongEcdsaVerKeyTestVector :: VerKeyDSIGN EcdsaSecp256k1DSIGN @@ -104,51 +114,57 @@ verKeyNotOnCurveTestVectorRaw = "02EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B97 wrongLengthVerKeyTestVectorsRaw :: [HexStringInCBOR] wrongLengthVerKeyTestVectorsRaw = [ -- Ver key of length 30 bytes - "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B50", - -- Ver key of length 34 bytes + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B50" + , -- Ver key of length 34 bytes "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659FF" ] -- Raw hexstring to be used in invalid length signature parser tests for ecdsa ecdsaWrongLengthSigTestVectorsRaw :: [HexStringInCBOR] ecdsaWrongLengthSigTestVectorsRaw = - [ "354b868c757ef0b796003f7c23dd754d2d1726629145be2c7b7794a25fec80a06254f0915935f33b91bceb16d46ff2814f659e9b6791a4a21ff8764b78d7e1", - "354b868c757ef0b796003f7c23dd754d2d1726629145be2c7b7794a25fec80a06254f0915935f33b91bceb16d46ff2814f659e9b6791a4a21ff8764b78d7e114FF" + [ "354b868c757ef0b796003f7c23dd754d2d1726629145be2c7b7794a25fec80a06254f0915935f33b91bceb16d46ff2814f659e9b6791a4a21ff8764b78d7e1" + , "354b868c757ef0b796003f7c23dd754d2d1726629145be2c7b7794a25fec80a06254f0915935f33b91bceb16d46ff2814f659e9b6791a4a21ff8764b78d7e114FF" ] -- Raw hexstring to be used in invalid length signature parser tests for schnorr schnorrWrongLengthSigTestVectorsRaw :: [HexStringInCBOR] schnorrWrongLengthSigTestVectorsRaw = - [ "5a56da88e6fd8419181dec4d3dd6997bab953d2fc71ab65e23cfc9e7e3d1a310613454a60f6703819a39fdac2a410a094442afd1fc083354443e8d8bb4461a", - "5a56da88e6fd8419181dec4d3dd6997bab953d2fc71ab65e23cfc9e7e3d1a310613454a60f6703819a39fdac2a410a094442afd1fc083354443e8d8bb4461a9bFF" + [ "5a56da88e6fd8419181dec4d3dd6997bab953d2fc71ab65e23cfc9e7e3d1a310613454a60f6703819a39fdac2a410a094442afd1fc083354443e8d8bb4461a" + , "5a56da88e6fd8419181dec4d3dd6997bab953d2fc71ab65e23cfc9e7e3d1a310613454a60f6703819a39fdac2a410a094442afd1fc083354443e8d8bb4461a9bFF" ] -ecdsaMismatchMessageAndSignature :: [(ByteString, VerKeyDSIGN EcdsaSecp256k1DSIGN, SigDSIGN EcdsaSecp256k1DSIGN)] +ecdsaMismatchMessageAndSignature :: + [(ByteString, VerKeyDSIGN EcdsaSecp256k1DSIGN, SigDSIGN EcdsaSecp256k1DSIGN)] ecdsaMismatchMessageAndSignature = map (\(vm, vKey, sig) -> (vm, vKeyParser vKey, sigParser sig)) -- verifyMessage, vKey, signature - [ ( "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", - "0325d1dff95105f5253c4022f628a996ad3a0d95fbf21d468a1b33f8c160d8f517", - "3dccc57be49991e95b112954217e8b4fe884d4d26843dfec794feb370981407b79151d1e5af85aba21721876896957adb2b35bcbb84986dcf82daa520a87a9f9" -- wrong verify message but right signature - ), - ( "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - "0325d1dff95105f5253c4022f628a996ad3a0d95fbf21d468a1b33f8c160d8f517", - "5ef63d477c5d1572550016ccf72a2310c7368beeb843c85b1b5697290872222a09e7519702cb2c9a65bbce92d273080a0193b77588bc2eac6dbcbfc15c6dfefd" -- right verify message but wrong signature + [ + ( "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89" + , "0325d1dff95105f5253c4022f628a996ad3a0d95fbf21d468a1b33f8c160d8f517" + , "3dccc57be49991e95b112954217e8b4fe884d4d26843dfec794feb370981407b79151d1e5af85aba21721876896957adb2b35bcbb84986dcf82daa520a87a9f9" -- wrong verify message but right signature + ) + , + ( "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + , "0325d1dff95105f5253c4022f628a996ad3a0d95fbf21d468a1b33f8c160d8f517" + , "5ef63d477c5d1572550016ccf72a2310c7368beeb843c85b1b5697290872222a09e7519702cb2c9a65bbce92d273080a0193b77588bc2eac6dbcbfc15c6dfefd" -- right verify message but wrong signature ) ] -schnorrMismatchMessageAndSignature :: [(ByteString, VerKeyDSIGN SchnorrSecp256k1DSIGN, SigDSIGN SchnorrSecp256k1DSIGN)] +schnorrMismatchMessageAndSignature :: + [(ByteString, VerKeyDSIGN SchnorrSecp256k1DSIGN, SigDSIGN SchnorrSecp256k1DSIGN)] schnorrMismatchMessageAndSignature = map (\(vm, vKey, sig) -> (vm, vKeyParser vKey, sigParser sig)) -- verifyMessage, vKey, signature - [ ( "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", - "599de3e582e2a3779208a210dfeae8f330b9af00a47a7fb22e9bb8ef596f301b", - "5a56da88e6fd8419181dec4d3dd6997bab953d2fc71ab65e23cfc9e7e3d1a310613454a60f6703819a39fdac2a410a094442afd1fc083354443e8d8bb4461a9b" -- wrong verify message but right signature - ), - ( "0000000000000000000000000000000000000000000000000000000000000000", - "599de3e582e2a3779208a210dfeae8f330b9af00a47a7fb22e9bb8ef596f301b", - "18a66fb829009a9df6312e1d7f4b53af0ac8a6aa17c2b7ff5941b57a27b24c23531f01bd11135dd844318f814241ea41040cc68958a6c47da489a32f0e22b805" -- right verify message but wrong signature + [ + ( "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89" + , "599de3e582e2a3779208a210dfeae8f330b9af00a47a7fb22e9bb8ef596f301b" + , "5a56da88e6fd8419181dec4d3dd6997bab953d2fc71ab65e23cfc9e7e3d1a310613454a60f6703819a39fdac2a410a094442afd1fc083354443e8d8bb4461a9b" -- wrong verify message but right signature + ) + , + ( "0000000000000000000000000000000000000000000000000000000000000000" + , "599de3e582e2a3779208a210dfeae8f330b9af00a47a7fb22e9bb8ef596f301b" + , "18a66fb829009a9df6312e1d7f4b53af0ac8a6aa17c2b7ff5941b57a27b24c23531f01bd11135dd844318f814241ea41040cc68958a6c47da489a32f0e22b805" -- right verify message but wrong signature ) ] diff --git a/cardano-crypto-tests/test/Main.hs b/cardano-crypto-tests/test/Main.hs index 14c10439c..ca5d4f828 100644 --- a/cardano-crypto-tests/test/Main.hs +++ b/cardano-crypto-tests/test/Main.hs @@ -1,5 +1,6 @@ {-# LANGUAGE CPP #-} +{- FOURMOLU_DISABLE -} module Main (main) where import qualified Test.Crypto.DSIGN diff --git a/cardano-git-rev/src/Cardano/Git/Rev.hs b/cardano-git-rev/src/Cardano/Git/Rev.hs index f87a24110..de38941f6 100644 --- a/cardano-git-rev/src/Cardano/Git/Rev.hs +++ b/cardano-git-rev/src/Cardano/Git/Rev.hs @@ -1,7 +1,9 @@ {-# LANGUAGE CPP #-} +{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ForeignFunctionInterface #-} + +{- FOURMOLU_DISABLE -} #if __GLASGOW_HASKELL__ >= 900 {-# LANGUAGE TemplateHaskellQuotes #-} diff --git a/cardano-mempool/app/Main.hs b/cardano-mempool/app/Main.hs index 99c0c3986..89ad4b3e0 100644 --- a/cardano-mempool/app/Main.hs +++ b/cardano-mempool/app/Main.hs @@ -1,5 +1,4 @@ module Main where - main :: IO () main = pure () diff --git a/cardano-mempool/bench/Bench.hs b/cardano-mempool/bench/Bench.hs index 31707c805..aa7727a43 100644 --- a/cardano-mempool/bench/Bench.hs +++ b/cardano-mempool/bench/Bench.hs @@ -22,7 +22,7 @@ instance NFData (Pool n s) where instance NFData (ForeignPtr a) where rnf !_ = () -initHaskellPool :: (KnownNat n) => Int -> IO (Pool n RealWorld) +initHaskellPool :: KnownNat n => Int -> IO (Pool n RealWorld) initHaskellPool n = stToIO $ initPool n (ioToST . mallocForeignPtrBytes) (const (pure ())) cmallocForeignPtr :: Int -> IO (ForeignPtr a) diff --git a/cardano-mempool/src/Cardano/Memory/Pool.hs b/cardano-mempool/src/Cardano/Memory/Pool.hs index 0be97d759..686742a80 100644 --- a/cardano-mempool/src/Cardano/Memory/Pool.hs +++ b/cardano-mempool/src/Cardano/Memory/Pool.hs @@ -94,7 +94,7 @@ data Pool n s = Pool countPages :: Pool n s -> ST s Int countPages pool = go 1 (poolFirstPage pool) where - go n Page{pageNextPage} = do + go n Page {pageNextPage} = do readMutVar pageNextPage >>= \case Nothing -> pure n Just nextPage -> go (n + 1) nextPage @@ -104,23 +104,23 @@ ixBitSize = finiteBitSize (0 :: Word) -- | Initilizes the `Pool` that can be used for further allocation of @`ForeignPtr` -- `Block` n@ with `grabNextBlock`. -initPool - :: forall n s - . KnownNat n - => Int - -- ^ Number of groups per page. Must be a posititve number, otherwise error. One group +initPool :: + forall n s. + KnownNat n => + -- | Number of groups per page. Must be a posititve number, otherwise error. One group -- contains as many blocks as the operating system has bits. A 64bit architecture will -- have 64 blocks per group. For example, if program is compiled on a 64 bit OS and you -- know ahead of time the maximum number of blocks that will be allocated through out -- the program, then the optimal value for this argument will @maxBlockNum/64@ - -> (forall a. Int -> ST s (ForeignPtr a)) - -- ^ Mempool page allocator. Some allocated pages might be immediately discarded, + Int -> + -- | Mempool page allocator. Some allocated pages might be immediately discarded, -- therefore number of pages utilized will not necessesarely match the number of times -- this action will be called. - -> (Ptr (Block n) -> IO ()) - -- ^ Finalizer to use for each block. It is an IO action because it will be executed by + (forall a. Int -> ST s (ForeignPtr a)) -> + -- | Finalizer to use for each block. It is an IO action because it will be executed by -- the Garbage Collector in a separate thread once the `Block` is no longer referenced. - -> ST s (Pool n s) + (Ptr (Block n) -> IO ()) -> + ST s (Pool n s) initPool groupsPerPage memAlloc blockFinalizer = do unless (groupsPerPage > 0) $ error $ @@ -133,7 +133,7 @@ initPool groupsPerPage memAlloc blockFinalizer = do setPrimArray pageBitArray 0 groupsPerPage 0 pageFull <- newPVar 0 pageNextPage <- newMutVar Nothing - pure Page{..} + pure Page {..} firstPage <- pageInit pure Pool @@ -153,10 +153,10 @@ grabNextBlock = grabNextPoolBlockWith grabNextPageForeignPtr -- | This is a helper function that will allocate a `Page` if the current `Page` in the -- `Pool` is full. Whenever there are still block slots are available then supplied -- @grabNext@ function will be used to reserve the slot in that `Page`. -grabNextPoolBlockWith - :: (Page n s -> (Ptr (Block n) -> IO ()) -> ST s (Maybe (ForeignPtr (Block n)))) - -> Pool n s - -> ST s (ForeignPtr (Block n)) +grabNextPoolBlockWith :: + (Page n s -> (Ptr (Block n) -> IO ()) -> ST s (Maybe (ForeignPtr (Block n)))) -> + Pool n s -> + ST s (ForeignPtr (Block n)) grabNextPoolBlockWith grabNext pool = go (poolFirstPage pool) where go page = do @@ -198,14 +198,14 @@ intToBool _ = True -- | This is a helper function that will attempt to find the next available slot for the -- `Block` and create a `ForeignPtr` with the size of `Block` in the `Page`. In case when -- `Page` is full it will return `Nothing`. -grabNextPageForeignPtr - :: forall n s - . KnownNat n - => Page n s - -- ^ Page to grab the block from - -> (Ptr (Block n) -> IO ()) - -- ^ Finalizer to run, once the `ForeignPtr` holding on to `Ptr` `Block` is no longer used - -> ST s (Maybe (ForeignPtr (Block n))) +grabNextPageForeignPtr :: + forall n s. + KnownNat n => + -- | Page to grab the block from + Page n s -> + -- | Finalizer to run, once the `ForeignPtr` holding on to `Ptr` `Block` is no longer used + (Ptr (Block n) -> IO ()) -> + ST s (Maybe (ForeignPtr (Block n))) grabNextPageForeignPtr page finalizer = grabNextPageWithAllocator page $ \blockPtr resetIndex -> do fp <- newForeignPtr_ blockPtr @@ -213,13 +213,13 @@ grabNextPageForeignPtr page finalizer = pure fp {-# INLINE grabNextPageForeignPtr #-} -grabNextPageWithAllocator - :: forall n s - . KnownNat n - => Page n s - -> (Ptr (Block n) -> IO () -> IO (ForeignPtr (Block n))) - -> ST s (Maybe (ForeignPtr (Block n))) -grabNextPageWithAllocator Page{..} allocator = do +grabNextPageWithAllocator :: + forall n s. + KnownNat n => + Page n s -> + (Ptr (Block n) -> IO () -> IO (ForeignPtr (Block n))) -> + ST s (Maybe (ForeignPtr (Block n))) +grabNextPageWithAllocator Page {..} allocator = do setNextZero pageBitArray >>= \case -- There is a slight chance that some Blocks will be cleared before the pageFull is -- set to True. This is not a problem because that memory will be recovered as soon as @@ -284,10 +284,10 @@ setNextZero ma = ifindAtomicMutablePrimArray ma f Just !bitIx -> (setBit w bitIx, Just (ixBitSize * i + bitIx)) {-# INLINE setNextZero #-} -ifindAtomicMutablePrimArray - :: MutablePrimArray s Int - -> (Int -> Int -> (Int, Maybe a)) - -> ST s (Maybe a) +ifindAtomicMutablePrimArray :: + MutablePrimArray s Int -> + (Int -> Int -> (Int, Maybe a)) -> + ST s (Maybe a) ifindAtomicMutablePrimArray ma f = do n <- getSizeofMutablePrimArray ma let go i diff --git a/cardano-mempool/tests/Common.hs b/cardano-mempool/tests/Common.hs index fafcfa039..38fdf1b88 100644 --- a/cardano-mempool/tests/Common.hs +++ b/cardano-mempool/tests/Common.hs @@ -1,6 +1,6 @@ -module Common - ( module X - ) where +module Common ( + module X, +) where import Test.Tasty as X import Test.Tasty.HUnit as X diff --git a/cardano-mempool/tests/Test/Cardano/Memory/PoolTests.hs b/cardano-mempool/tests/Test/Cardano/Memory/PoolTests.hs index d22a72a15..23f2fee58 100644 --- a/cardano-mempool/tests/Test/Cardano/Memory/PoolTests.hs +++ b/cardano-mempool/tests/Test/Cardano/Memory/PoolTests.hs @@ -70,8 +70,8 @@ propFindNextZeroIndex w = monadicIO . run $ ("Expected found index to be different, but got same: " ++ show ix) (ix' /= ix) assertBool - ("Expected the bit under index: " ++ show ix' ++ " to not be set") $ - not (testBit w ix') + ("Expected the bit under index: " ++ show ix' ++ " to not be set") + $ not (testBit w ix') -- We allow one extra page be allocated due to concurrency false positives in block -- reservations @@ -80,20 +80,21 @@ checkNumPages pool n numBlocks = do let estimatedUpperBoundOfPages = 1 + max 1 (numBlocks `div` n `div` 64) numPages <- stToPrim $ countPages pool assertBool - (concat - [ "Number of pages should not exceed the expected amount: " - , show estimatedUpperBoundOfPages - , " but allocated: " - , show numPages - ]) + ( concat + [ "Number of pages should not exceed the expected amount: " + , show estimatedUpperBoundOfPages + , " but allocated: " + , show numPages + ] + ) (numPages <= estimatedUpperBoundOfPages) checkBlockBytes :: - (KnownNat n, Storable a, Eq a, Show a) - => Block n - -> a - -> Ptr b - -> Assertion + (KnownNat n, Storable a, Eq a, Show a) => + Block n -> + a -> + Ptr b -> + Assertion checkBlockBytes block byte ptr = let checkFillByte i = when (i >= 0) $ do @@ -108,7 +109,6 @@ mallocPreFilled preFillByte bc = unsafeIOToPrim $ do withForeignPtr mfp $ \ptr -> setPtr (castPtr ptr) bc preFillByte pure mfp - -- | @ensureAllGCedWith iterations delay expectedCount registerCounter@ waits -- for all items to be GCed by triggering garbage collection @iterations@ -- times, once every @delay@ milliseconds. After @iterations@ attempts, if the @@ -116,18 +116,18 @@ mallocPreFilled preFillByte bc = unsafeIOToPrim $ do -- raised via 'assertFailure'. Garbage collection is tracked via finalizers -- (see below). ensureAllGCedWith :: - Int - -- ^ Number of GC attempts to make before failing - -> Int - -- ^ Delay between attempts, in milliseconds - -> Int - -- ^ Expected number of counter hook firings (in practice: individual + -- | Number of GC attempts to make before failing + Int -> + -- | Delay between attempts, in milliseconds + Int -> + -- | Expected number of counter hook firings (in practice: individual -- garbage collections on 'ForeignPtr's, as per their finalizers). - -> (IO () -> IO a) - -- ^ Function for registering the counter hook. The argument to this + Int -> + -- | Function for registering the counter hook. The argument to this -- function should be attached to each 'ForeignPtr' we're interested in -- as a finalizer. - -> IO a + (IO () -> IO a) -> + IO a ensureAllGCedWith iterations delay expectedCount registerCounter = do countRef <- newPVar (0 :: Int) res <- registerCounter (void $ atomicAddIntPVar countRef 1) @@ -137,29 +137,31 @@ ensureAllGCedWith iterations delay expectedCount registerCounter = do n <- atomicReadIntPVar countRef unless (n == expectedCount) $ do if i <= 1 - then assertFailure $ - "Expected all " ++ - show expectedCount ++ - " pointers to be GCed in " ++ - show (delay * iterations) ++ - "ms, but " ++ show n ++ " where GCed instead" + then + assertFailure $ + "Expected all " + ++ show expectedCount + ++ " pointers to be GCed in " + ++ show (delay * iterations) + ++ "ms, but " + ++ show n + ++ " where GCed instead" else go (i - 1) res <$ go iterations - -- | 'ensureAllGCedWith' with default values: 100 iterations, 10ms delay. ensureAllGCed :: Int -> (IO () -> IO a) -> IO a ensureAllGCed = ensureAllGCedWith 100 10 - propPoolGarbageCollected :: - forall n. KnownNat n - => Block n - -> Positive Int - -> Word16 - -> Word8 - -> Word8 - -> Property + forall n. + KnownNat n => + Block n -> + Positive Int -> + Word16 -> + Word8 -> + Word8 -> + Property propPoolGarbageCollected block (Positive n) numBlocks16 preFillByte fillByte = monadicIO . run $ do let numBlocks = 1 + (fromIntegral numBlocks16 `div` 20) -- make it not too big @@ -187,13 +189,14 @@ propPoolGarbageCollected block (Positive n) numBlocks16 preFillByte fillByte = touch pool propPoolAllocateAndFinalize :: - forall n. KnownNat n - => Block n - -> Positive Int - -> Word16 - -> Word8 - -> Word8 - -> Property + forall n. + KnownNat n => + Block n -> + Positive Int -> + Word16 -> + Word8 -> + Word8 -> + Property propPoolAllocateAndFinalize block (Positive n) numBlocks16 emptyByte fullByte = monadicIO . run $ do let numBlocks = 1 + (fromIntegral numBlocks16 `div` 20) @@ -205,23 +208,26 @@ propPoolAllocateAndFinalize block (Positive n) numBlocks16 emptyByte fullByte = setPtr (castPtr ptr) (blockByteCount block) emptyByte countOneBlockGCed -- allocate and finalize blocks concurrently - pool <$ - concurrently_ - (do replicateConcurrently_ numBlocks $ do + pool + <$ concurrently_ + ( do + replicateConcurrently_ numBlocks $ do fp <- stToPrim $ grabNextBlock pool withForeignPtr fp (checkBlockBytes block emptyByte) writeChan chan (Just fp) -- place Nothing to indicate that we are done allocating blocks - writeChan chan Nothing) - (fix $ \loop -> do - mfp <- readChan chan - forM_ mfp $ \fp -> do - withForeignPtr fp $ \ptr -> - -- fill the newly allocated block - setPtr (castPtr ptr) (blockByteCount block) fullByte - -- manually finalize every other block and let the GC to pick the rest - shouldFinalize <- uniformM globalStdGen - when shouldFinalize $ finalizeForeignPtr fp - loop) + writeChan chan Nothing + ) + ( fix $ \loop -> do + mfp <- readChan chan + forM_ mfp $ \fp -> do + withForeignPtr fp $ \ptr -> + -- fill the newly allocated block + setPtr (castPtr ptr) (blockByteCount block) fullByte + -- manually finalize every other block and let the GC to pick the rest + shouldFinalize <- uniformM globalStdGen + when shouldFinalize $ finalizeForeignPtr fp + loop + ) -- verify number of pages checkNumPages pool n numBlocks diff --git a/cardano-mempool/tests/doctests.hs b/cardano-mempool/tests/doctests.hs index 157a1855f..5ca9ba9d3 100644 --- a/cardano-mempool/tests/doctests.hs +++ b/cardano-mempool/tests/doctests.hs @@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-} + module Main where #if __GLASGOW_HASKELL__ >= 802 && __GLASGOW_HASKELL__ < 810 diff --git a/cardano-slotting/src/Cardano/Slotting/Block.hs b/cardano-slotting/src/Cardano/Slotting/Block.hs index 8bb822fb5..6ead68c41 100644 --- a/cardano-slotting/src/Cardano/Slotting/Block.hs +++ b/cardano-slotting/src/Cardano/Slotting/Block.hs @@ -2,15 +2,15 @@ {-# LANGUAGE DerivingVia #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -module Cardano.Slotting.Block - ( BlockNo (..) - ) +module Cardano.Slotting.Block ( + BlockNo (..), +) where import Cardano.Binary (FromCBOR (..), ToCBOR (..)) import Codec.Serialise (Serialise (..)) import Control.DeepSeq (NFData) -import Data.Aeson (ToJSON, FromJSON) +import Data.Aeson (FromJSON, ToJSON) import Data.Word (Word64) import GHC.Generics (Generic) import NoThunks.Class (NoThunks) @@ -21,7 +21,7 @@ import Quiet (Quiet (..)) -- for every slot where N <= SlotNo. newtype BlockNo = BlockNo {unBlockNo :: Word64} deriving stock (Eq, Ord, Generic) - deriving Show via Quiet BlockNo + deriving (Show) via Quiet BlockNo deriving newtype (Enum, Bounded, Num, Serialise, NoThunks, NFData, ToJSON, FromJSON) instance ToCBOR BlockNo where diff --git a/cardano-slotting/src/Cardano/Slotting/EpochInfo.hs b/cardano-slotting/src/Cardano/Slotting/EpochInfo.hs index bd06ca943..34bd11b7c 100644 --- a/cardano-slotting/src/Cardano/Slotting/EpochInfo.hs +++ b/cardano-slotting/src/Cardano/Slotting/EpochInfo.hs @@ -1,7 +1,7 @@ -module Cardano.Slotting.EpochInfo - ( module Cardano.Slotting.EpochInfo.API, - module Cardano.Slotting.EpochInfo.Impl, - ) +module Cardano.Slotting.EpochInfo ( + module Cardano.Slotting.EpochInfo.API, + module Cardano.Slotting.EpochInfo.Impl, +) where import Cardano.Slotting.EpochInfo.API diff --git a/cardano-slotting/src/Cardano/Slotting/EpochInfo/API.hs b/cardano-slotting/src/Cardano/Slotting/EpochInfo/API.hs index 533c1d3f6..4479c227a 100644 --- a/cardano-slotting/src/Cardano/Slotting/EpochInfo/API.hs +++ b/cardano-slotting/src/Cardano/Slotting/EpochInfo/API.hs @@ -3,24 +3,24 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE RankNTypes #-} -module Cardano.Slotting.EpochInfo.API - ( EpochInfo (..), - epochInfoSize, - epochInfoFirst, - epochInfoEpoch, - epochInfoRange, - epochInfoSlotToRelativeTime, - epochInfoSlotToUTCTime, - epochInfoSlotLength, - - -- * Utility - hoistEpochInfo, - generalizeEpochInfo, - ) +module Cardano.Slotting.EpochInfo.API ( + EpochInfo (..), + epochInfoSize, + epochInfoFirst, + epochInfoEpoch, + epochInfoRange, + epochInfoSlotToRelativeTime, + epochInfoSlotToUTCTime, + epochInfoSlotLength, + + -- * Utility + hoistEpochInfo, + generalizeEpochInfo, +) where import Cardano.Slotting.Slot (EpochNo (..), EpochSize (..), SlotNo (..)) -import Cardano.Slotting.Time (RelativeTime, SystemStart, fromRelativeTime, SlotLength) +import Cardano.Slotting.Time (RelativeTime, SlotLength, SystemStart, fromRelativeTime) import Control.Monad.Morph (generalize) import Data.Functor.Identity import Data.Time.Clock (UTCTime) @@ -38,34 +38,36 @@ import NoThunks.Class (NoThunks, OnlyCheckWhnfNamed (..)) -- query. data EpochInfo m = EpochInfo - { -- | Return the size of the given epoch as a number of slots - -- - -- Note that the number of slots does /not/ bound the number of blocks, - -- since the EBB and a regular block share a slot number. - epochInfoSize_ :: HasCallStack => EpochNo -> m EpochSize, - -- | First slot in the specified epoch - -- - -- See also 'epochInfoRange' - epochInfoFirst_ :: HasCallStack => EpochNo -> m SlotNo, - -- | Epoch containing the given slot - -- - -- We should have the property that - -- - -- > s `inRange` epochInfoRange (epochInfoEpoch s) - epochInfoEpoch_ :: HasCallStack => SlotNo -> m EpochNo, - -- | The 'RelativeTime' of the start of the given slot - -- - -- This calculation depends on the varying slot lengths of the relevant - -- epochs. - -- - -- See also 'epochInfoSlotToUTCTime'. - epochInfoSlotToRelativeTime_ :: - HasCallStack => SlotNo -> m RelativeTime, - -- | Return the length of the specified slot. - epochInfoSlotLength_ :: - HasCallStack => SlotNo -> m SlotLength - } - deriving NoThunks via OnlyCheckWhnfNamed "EpochInfo" (EpochInfo m) + { epochInfoSize_ :: HasCallStack => EpochNo -> m EpochSize + -- ^ Return the size of the given epoch as a number of slots + -- + -- Note that the number of slots does /not/ bound the number of blocks, + -- since the EBB and a regular block share a slot number. + , epochInfoFirst_ :: HasCallStack => EpochNo -> m SlotNo + -- ^ First slot in the specified epoch + -- + -- See also 'epochInfoRange' + , epochInfoEpoch_ :: HasCallStack => SlotNo -> m EpochNo + -- ^ Epoch containing the given slot + -- + -- We should have the property that + -- + -- > s `inRange` epochInfoRange (epochInfoEpoch s) + , epochInfoSlotToRelativeTime_ :: + HasCallStack => + SlotNo -> m RelativeTime + -- ^ The 'RelativeTime' of the start of the given slot + -- + -- This calculation depends on the varying slot lengths of the relevant + -- epochs. + -- + -- See also 'epochInfoSlotToUTCTime'. + , epochInfoSlotLength_ :: + HasCallStack => + SlotNo -> m SlotLength + -- ^ Return the length of the specified slot. + } + deriving (NoThunks) via OnlyCheckWhnfNamed "EpochInfo" (EpochInfo m) -- | Unhelpful instance, but this type occurs in records (eg @Shelley.Globals@) -- that we want to be able to 'show' @@ -74,7 +76,8 @@ instance Show (EpochInfo f) where epochInfoRange :: Monad m => EpochInfo m -> EpochNo -> m (SlotNo, SlotNo) epochInfoRange epochInfo epochNo = - aux <$> epochInfoFirst epochInfo epochNo + aux + <$> epochInfoFirst epochInfo epochNo <*> epochInfoSize epochInfo epochNo where aux :: SlotNo -> EpochSize -> (SlotNo, SlotNo) @@ -82,11 +85,11 @@ epochInfoRange epochInfo epochNo = -- | The start of the given slot epochInfoSlotToUTCTime :: - (HasCallStack, Monad m) - => EpochInfo m - -> SystemStart - -> SlotNo - -> m UTCTime + (HasCallStack, Monad m) => + EpochInfo m -> + SystemStart -> + SlotNo -> + m UTCTime epochInfoSlotToUTCTime ei start sl = fromRelativeTime start <$> epochInfoSlotToRelativeTime ei sl @@ -118,13 +121,14 @@ epochInfoSlotLength = epochInfoSlotLength_ -------------------------------------------------------------------------------} hoistEpochInfo :: (forall a. m a -> n a) -> EpochInfo m -> EpochInfo n -hoistEpochInfo f ei = EpochInfo - { epochInfoSize_ = f . epochInfoSize ei, - epochInfoFirst_ = f . epochInfoFirst ei, - epochInfoEpoch_ = f . epochInfoEpoch ei, - epochInfoSlotToRelativeTime_ = f . epochInfoSlotToRelativeTime ei, - epochInfoSlotLength_ = f . epochInfoSlotLength ei - } +hoistEpochInfo f ei = + EpochInfo + { epochInfoSize_ = f . epochInfoSize ei + , epochInfoFirst_ = f . epochInfoFirst ei + , epochInfoEpoch_ = f . epochInfoEpoch ei + , epochInfoSlotToRelativeTime_ = f . epochInfoSlotToRelativeTime ei + , epochInfoSlotLength_ = f . epochInfoSlotLength ei + } generalizeEpochInfo :: Monad m => EpochInfo Identity -> EpochInfo m generalizeEpochInfo = hoistEpochInfo generalize diff --git a/cardano-slotting/src/Cardano/Slotting/EpochInfo/Extend.hs b/cardano-slotting/src/Cardano/Slotting/EpochInfo/Extend.hs index 7b18559aa..7c3147590 100644 --- a/cardano-slotting/src/Cardano/Slotting/EpochInfo/Extend.hs +++ b/cardano-slotting/src/Cardano/Slotting/EpochInfo/Extend.hs @@ -1,17 +1,17 @@ module Cardano.Slotting.EpochInfo.Extend where import Cardano.Slotting.EpochInfo.API (EpochInfo (..)) -import Cardano.Slotting.Slot - ( EpochNo (EpochNo), - EpochSize (EpochSize), - SlotNo (SlotNo), - binOpEpochNo - ) -import Cardano.Slotting.Time - ( SlotLength (getSlotLength), - addRelativeTime, - multNominalDiffTime, - ) +import Cardano.Slotting.Slot ( + EpochNo (EpochNo), + EpochSize (EpochSize), + SlotNo (SlotNo), + binOpEpochNo, + ) +import Cardano.Slotting.Time ( + SlotLength (getSlotLength), + addRelativeTime, + multNominalDiffTime, + ) -- | Given a basis point, use it and its slot length to impute a linear -- relationship between slots and time in order to extend an 'EpochInfo' to @@ -69,9 +69,9 @@ unsafeLinearExtendEpochInfo basisSlot underlyingEI = then epochInfoSlotLength_ underlyingEI sn else epochInfoSlotLength_ underlyingEI basisSlot in EpochInfo - { epochInfoSize_ = goSize, - epochInfoFirst_ = goFirst, - epochInfoEpoch_ = goEpoch, - epochInfoSlotToRelativeTime_ = goTime, - epochInfoSlotLength_ = goLength + { epochInfoSize_ = goSize + , epochInfoFirst_ = goFirst + , epochInfoEpoch_ = goEpoch + , epochInfoSlotToRelativeTime_ = goTime + , epochInfoSlotLength_ = goLength } diff --git a/cardano-slotting/src/Cardano/Slotting/EpochInfo/Impl.hs b/cardano-slotting/src/Cardano/Slotting/EpochInfo/Impl.hs index 377404be9..fd43dd465 100644 --- a/cardano-slotting/src/Cardano/Slotting/EpochInfo/Impl.hs +++ b/cardano-slotting/src/Cardano/Slotting/EpochInfo/Impl.hs @@ -1,10 +1,11 @@ -- | For use in trivial cases, such as in mocks, tests, etc. -module Cardano.Slotting.EpochInfo.Impl - ( fixedEpochInfo, - -- * Shortcuts - fixedEpochInfoEpoch, - fixedEpochInfoFirst, - ) +module Cardano.Slotting.EpochInfo.Impl ( + fixedEpochInfo, + + -- * Shortcuts + fixedEpochInfoEpoch, + fixedEpochInfoFirst, +) where import Cardano.Slotting.EpochInfo.API @@ -14,15 +15,16 @@ import Cardano.Slotting.Time (RelativeTime (..), SlotLength, getSlotLength) -- | The 'EpochInfo' induced by assuming the epoch size and slot length are -- fixed for the entire system lifetime fixedEpochInfo :: Monad m => EpochSize -> SlotLength -> EpochInfo m -fixedEpochInfo (EpochSize size) slotLength = EpochInfo - { epochInfoSize_ = \_ -> - return $ EpochSize size, - epochInfoFirst_ = \e -> return $ fixedEpochInfoFirst (EpochSize size) e, - epochInfoEpoch_ = \sl -> return $ fixedEpochInfoEpoch (EpochSize size) sl, - epochInfoSlotToRelativeTime_ = \(SlotNo slot) -> - return $ RelativeTime (fromIntegral slot * getSlotLength slotLength), - epochInfoSlotLength_ = const $ pure slotLength - } +fixedEpochInfo (EpochSize size) slotLength = + EpochInfo + { epochInfoSize_ = \_ -> + return $ EpochSize size + , epochInfoFirst_ = \e -> return $ fixedEpochInfoFirst (EpochSize size) e + , epochInfoEpoch_ = \sl -> return $ fixedEpochInfoEpoch (EpochSize size) sl + , epochInfoSlotToRelativeTime_ = \(SlotNo slot) -> + return $ RelativeTime (fromIntegral slot * getSlotLength slotLength) + , epochInfoSlotLength_ = const $ pure slotLength + } -- | The pure computation underlying 'epochInfoFirst' applied to -- 'fixedEpochInfo' diff --git a/cardano-slotting/src/Cardano/Slotting/Slot.hs b/cardano-slotting/src/Cardano/Slotting/Slot.hs index 0f4a34552..27ee5f297 100644 --- a/cardano-slotting/src/Cardano/Slotting/Slot.hs +++ b/cardano-slotting/src/Cardano/Slotting/Slot.hs @@ -6,21 +6,21 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} -module Cardano.Slotting.Slot - ( SlotNo (..), - WithOrigin (..), - at, - origin, - fromWithOrigin, - withOrigin, - withOriginToMaybe, - withOriginFromMaybe, - EpochNo (..), - EpochSize (..), - EpochInterval (..), - binOpEpochNo, - addEpochInterval, - ) +module Cardano.Slotting.Slot ( + SlotNo (..), + WithOrigin (..), + at, + origin, + fromWithOrigin, + withOrigin, + withOriginToMaybe, + withOriginFromMaybe, + EpochNo (..), + EpochSize (..), + EpochInterval (..), + binOpEpochNo, + addEpochInterval, +) where import Cardano.Binary (FromCBOR (..), ToCBOR (..)) @@ -28,15 +28,15 @@ import Codec.Serialise (Serialise (..)) import Control.DeepSeq (NFData (rnf)) import Data.Aeson (FromJSON (..), ToJSON (..), Value (String)) import Data.Typeable (Typeable) -import Data.Word (Word64, Word32) +import Data.Word (Word32, Word64) import GHC.Generics (Generic) -import Quiet (Quiet (..)) import NoThunks.Class (NoThunks) +import Quiet (Quiet (..)) -- | The 0-based index for the Ourboros time slot. newtype SlotNo = SlotNo {unSlotNo :: Word64} deriving stock (Eq, Ord, Generic) - deriving Show via Quiet SlotNo + deriving (Show) via Quiet SlotNo deriving newtype (Enum, Bounded, Num, NFData, Serialise, NoThunks, ToJSON, FromJSON) instance ToCBOR SlotNo where @@ -52,15 +52,15 @@ instance FromCBOR SlotNo where data WithOrigin t = Origin | At !t deriving - ( Eq, - Ord, - Show, - Generic, - Functor, - Foldable, - Traversable, - Serialise, - NoThunks + ( Eq + , Ord + , Show + , Generic + , Functor + , Foldable + , Traversable + , Serialise + , NoThunks ) instance (Serialise t, Typeable t) => ToCBOR (WithOrigin t) where @@ -116,12 +116,12 @@ withOriginFromMaybe (Just t) = At t -- | An epoch, i.e. the number of the epoch. newtype EpochNo = EpochNo {unEpochNo :: Word64} deriving stock (Eq, Ord, Generic) - deriving Show via Quiet EpochNo + deriving (Show) via Quiet EpochNo deriving newtype (Enum, Serialise, ToCBOR, FromCBOR, NoThunks, ToJSON, FromJSON, NFData) newtype EpochSize = EpochSize {unEpochSize :: Word64} deriving stock (Eq, Ord, Generic) - deriving Show via Quiet EpochSize + deriving (Show) via Quiet EpochSize deriving newtype (Enum, ToCBOR, FromCBOR, NoThunks, ToJSON, FromJSON, NFData) newtype EpochInterval = EpochInterval diff --git a/cardano-slotting/src/Cardano/Slotting/Time.hs b/cardano-slotting/src/Cardano/Slotting/Time.hs index 10708cc50..e585c2ee7 100644 --- a/cardano-slotting/src/Cardano/Slotting/Time.hs +++ b/cardano-slotting/src/Cardano/Slotting/Time.hs @@ -1,48 +1,53 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DerivingVia #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingVia #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Cardano.Slotting.Time ( - -- * System time - SystemStart (..) - -- * Relative time - , RelativeTime (..) - , addRelativeTime - , diffRelativeTime - , fromRelativeTime - , multRelativeTime - , toRelativeTime - -- * Nominal diff time - , multNominalDiffTime - -- * Slot length - , getSlotLength - , mkSlotLength - -- ** Conversions - , slotLengthFromMillisec - , slotLengthFromSec - , slotLengthToMillisec - , slotLengthToSec - -- ** opaque - , SlotLength - ) where - -import Cardano.Binary (FromCBOR(..), ToCBOR(..)) -import Codec.Serialise -import Control.Exception (assert) -import Data.Aeson (FromJSON, ToJSON) -import Data.Fixed -import Data.Time - ( NominalDiffTime, - UTCTime, - addUTCTime, - diffUTCTime, - nominalDiffTimeToSeconds, - secondsToNominalDiffTime, - ) -import GHC.Generics (Generic) -import NoThunks.Class (InspectHeap (..), NoThunks) -import Quiet + -- * System time + SystemStart (..), + + -- * Relative time + RelativeTime (..), + addRelativeTime, + diffRelativeTime, + fromRelativeTime, + multRelativeTime, + toRelativeTime, + + -- * Nominal diff time + multNominalDiffTime, + + -- * Slot length + getSlotLength, + mkSlotLength, + + -- ** Conversions + slotLengthFromMillisec, + slotLengthFromSec, + slotLengthToMillisec, + slotLengthToSec, + + -- ** opaque + SlotLength, +) where + +import Cardano.Binary (FromCBOR (..), ToCBOR (..)) +import Codec.Serialise +import Control.Exception (assert) +import Data.Aeson (FromJSON, ToJSON) +import Data.Fixed +import Data.Time ( + NominalDiffTime, + UTCTime, + addUTCTime, + diffUTCTime, + nominalDiffTimeToSeconds, + secondsToNominalDiffTime, + ) +import GHC.Generics (Generic) +import NoThunks.Class (InspectHeap (..), NoThunks) +import Quiet {------------------------------------------------------------------------------- System start @@ -51,11 +56,11 @@ import Quiet -- | System start -- -- Slots are counted from the system start. -newtype SystemStart = SystemStart { getSystemStart :: UTCTime } +newtype SystemStart = SystemStart {getSystemStart :: UTCTime} deriving (Eq, Generic) - deriving NoThunks via InspectHeap SystemStart - deriving Show via Quiet SystemStart - deriving newtype Serialise + deriving (NoThunks) via InspectHeap SystemStart + deriving (Show) via Quiet SystemStart + deriving newtype (Serialise) deriving newtype (ToCBOR, FromCBOR, ToJSON, FromJSON) {------------------------------------------------------------------------------- @@ -65,10 +70,10 @@ newtype SystemStart = SystemStart { getSystemStart :: UTCTime } -- | 'RelativeTime' is time relative to the 'SystemStart' -- -- Precision is in picoseconds -newtype RelativeTime = RelativeTime { getRelativeTime :: NominalDiffTime } - deriving stock (Eq, Ord, Generic) +newtype RelativeTime = RelativeTime {getRelativeTime :: NominalDiffTime} + deriving stock (Eq, Ord, Generic) deriving newtype (NoThunks) - deriving Show via Quiet RelativeTime + deriving (Show) via Quiet RelativeTime deriving newtype (ToJSON, FromJSON) instance ToCBOR RelativeTime where @@ -88,8 +93,9 @@ diffRelativeTime :: RelativeTime -> RelativeTime -> NominalDiffTime diffRelativeTime (RelativeTime t) (RelativeTime t') = t - t' toRelativeTime :: SystemStart -> UTCTime -> RelativeTime -toRelativeTime (SystemStart t) t' = assert (t' >= t) $ - RelativeTime (diffUTCTime t' t) +toRelativeTime (SystemStart t) t' = + assert (t' >= t) $ + RelativeTime (diffUTCTime t' t) fromRelativeTime :: SystemStart -> RelativeTime -> UTCTime fromRelativeTime (SystemStart t) (RelativeTime t') = addUTCTime t' t @@ -103,7 +109,6 @@ multNominalDiffTime t f = secondsToNominalDiffTime $ nominalDiffTimeToSeconds t * fromIntegral f - {------------------------------------------------------------------------------- SlotLength -------------------------------------------------------------------------------} @@ -111,9 +116,9 @@ multNominalDiffTime t f = -- | Slot length -- -- Precision is in milliseconds -newtype SlotLength = SlotLength { getSlotLength :: NominalDiffTime } +newtype SlotLength = SlotLength {getSlotLength :: NominalDiffTime} deriving (Eq, Generic, NoThunks) - deriving Show via Quiet SlotLength + deriving (Show) via Quiet SlotLength instance ToCBOR SlotLength where toCBOR = toCBOR . slotLengthToMillisec @@ -141,9 +146,10 @@ slotLengthFromMillisec = mkSlotLength . conv -- Explicit type annotation here means that /if/ we change the precision, -- we are forced to reconsider this code. conv :: Integer -> NominalDiffTime - conv = (realToFrac :: Pico -> NominalDiffTime) - . (/ 1000) - . (fromInteger :: Integer -> Pico) + conv = + (realToFrac :: Pico -> NominalDiffTime) + . (/ 1000) + . (fromInteger :: Integer -> Pico) slotLengthToMillisec :: SlotLength -> Integer slotLengthToMillisec = conv . getSlotLength @@ -151,7 +157,7 @@ slotLengthToMillisec = conv . getSlotLength -- Explicit type annotation here means that /if/ we change the precision, -- we are forced to reconsider this code. conv :: NominalDiffTime -> Integer - conv = truncate - . (* 1000) - . (realToFrac :: NominalDiffTime -> Pico) - + conv = + truncate + . (* 1000) + . (realToFrac :: NominalDiffTime -> Pico) diff --git a/cardano-slotting/test/Main.hs b/cardano-slotting/test/Main.hs index 2bcc173e4..45fefe80f 100644 --- a/cardano-slotting/test/Main.hs +++ b/cardano-slotting/test/Main.hs @@ -1,5 +1,5 @@ -import Test.Tasty import Test.Cardano.Slotting.EpochInfo (epochInfoTests) +import Test.Tasty main :: IO () main = defaultMain tests diff --git a/cardano-slotting/test/Test/Cardano/Slotting/EpochInfo.hs b/cardano-slotting/test/Test/Cardano/Slotting/EpochInfo.hs index 79b99325c..b6c227a22 100644 --- a/cardano-slotting/test/Test/Cardano/Slotting/EpochInfo.hs +++ b/cardano-slotting/test/Test/Cardano/Slotting/EpochInfo.hs @@ -7,12 +7,12 @@ import Cardano.Slotting.Slot (EpochNo (EpochNo), EpochSize (EpochSize), SlotNo ( import Cardano.Slotting.Time (slotLengthFromSec) import Data.Functor.Identity (Identity) import Test.Tasty (TestTree, testGroup) -import Test.Tasty.QuickCheck as QC - ( Arbitrary (arbitrary), - choose, - testProperty, - (===), - ) +import Test.Tasty.QuickCheck as QC ( + Arbitrary (arbitrary), + choose, + testProperty, + (===), + ) baseEpochInfo :: EpochInfo Identity baseEpochInfo = fixedEpochInfo (EpochSize 10) (slotLengthFromSec 10) @@ -38,12 +38,12 @@ epochInfoTests = testGroup "linearExtend" [ QC.testProperty "epochSize matches" $ \(TestSlotNo basisSlot, TestEpochNo sn) -> - epochInfoSize_ baseEpochInfo sn === epochInfoSize_ (extendedEpochInfo basisSlot) sn, - QC.testProperty "epochFirst matches" $ \(TestSlotNo basisSlot, TestEpochNo sn) -> - epochInfoFirst_ baseEpochInfo sn === epochInfoFirst_ (extendedEpochInfo basisSlot) sn, - QC.testProperty "epochEpoch matches" $ \(TestSlotNo basisSlot, TestSlotNo sn) -> - epochInfoEpoch_ baseEpochInfo sn === epochInfoEpoch_ (extendedEpochInfo basisSlot) sn, - QC.testProperty "epochTime matches" $ \(TestSlotNo basisSlot, TestSlotNo sn) -> + epochInfoSize_ baseEpochInfo sn === epochInfoSize_ (extendedEpochInfo basisSlot) sn + , QC.testProperty "epochFirst matches" $ \(TestSlotNo basisSlot, TestEpochNo sn) -> + epochInfoFirst_ baseEpochInfo sn === epochInfoFirst_ (extendedEpochInfo basisSlot) sn + , QC.testProperty "epochEpoch matches" $ \(TestSlotNo basisSlot, TestSlotNo sn) -> + epochInfoEpoch_ baseEpochInfo sn === epochInfoEpoch_ (extendedEpochInfo basisSlot) sn + , QC.testProperty "epochTime matches" $ \(TestSlotNo basisSlot, TestSlotNo sn) -> epochInfoSlotToRelativeTime_ baseEpochInfo sn === epochInfoSlotToRelativeTime_ (extendedEpochInfo basisSlot) sn ] diff --git a/cardano-slotting/testlib/Test/Cardano/Slotting/Arbitrary.hs b/cardano-slotting/testlib/Test/Cardano/Slotting/Arbitrary.hs index 81e8fff4f..6df6554d1 100644 --- a/cardano-slotting/testlib/Test/Cardano/Slotting/Arbitrary.hs +++ b/cardano-slotting/testlib/Test/Cardano/Slotting/Arbitrary.hs @@ -1,21 +1,22 @@ {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE StandaloneDeriving #-} - {-# OPTIONS_GHC -Wno-orphans #-} module Test.Cardano.Slotting.Arbitrary () where -import Test.QuickCheck import Cardano.Slotting.Slot +import Test.QuickCheck instance Arbitrary SlotNo where - arbitrary = SlotNo <$> - ((getPositive <$> arbitrary) - `suchThat` - (\n -> n < maxBound - 2^(32 :: Int))) - -- need some room, we're assuming we'll never wrap around 64bits + arbitrary = + SlotNo + <$> ( (getPositive <$> arbitrary) + `suchThat` (\n -> n < maxBound - 2 ^ (32 :: Int)) + ) + + -- need some room, we're assuming we'll never wrap around 64bits - shrink (SlotNo n) = [ SlotNo n' | n' <- shrink n, n' > 0 ] + shrink (SlotNo n) = [SlotNo n' | n' <- shrink n, n' > 0] deriving newtype instance Arbitrary EpochNo diff --git a/cardano-slotting/testlib/Test/Cardano/Slotting/Numeric.hs b/cardano-slotting/testlib/Test/Cardano/Slotting/Numeric.hs index 96d3c2494..9eeb9fd04 100644 --- a/cardano-slotting/testlib/Test/Cardano/Slotting/Numeric.hs +++ b/cardano-slotting/testlib/Test/Cardano/Slotting/Numeric.hs @@ -5,10 +5,10 @@ module Test.Cardano.Slotting.Numeric () where -import Cardano.Slotting.Slot - ( EpochSize (EpochSize), - EpochNo (EpochNo), - ) +import Cardano.Slotting.Slot ( + EpochNo (EpochNo), + EpochSize (EpochSize), + ) deriving newtype instance Num EpochNo diff --git a/cardano-slotting/testlib/Test/Cardano/Slotting/TreeDiff.hs b/cardano-slotting/testlib/Test/Cardano/Slotting/TreeDiff.hs index f8282ee6c..6d8acc7fa 100644 --- a/cardano-slotting/testlib/Test/Cardano/Slotting/TreeDiff.hs +++ b/cardano-slotting/testlib/Test/Cardano/Slotting/TreeDiff.hs @@ -2,8 +2,8 @@ module Test.Cardano.Slotting.TreeDiff where -import Cardano.Slotting.Slot import Cardano.Slotting.Block +import Cardano.Slotting.Slot import Data.TreeDiff instance ToExpr x => ToExpr (WithOrigin x) diff --git a/cardano-strict-containers/src/Data/FingerTree/Strict.hs b/cardano-strict-containers/src/Data/FingerTree/Strict.hs index f66a9320e..c01aca8ff 100644 --- a/cardano-strict-containers/src/Data/FingerTree/Strict.hs +++ b/cardano-strict-containers/src/Data/FingerTree/Strict.hs @@ -7,54 +7,54 @@ {-# LANGUAGE StandaloneDeriving #-} -- | Strict variants of 'FingerTree' operations. -module Data.FingerTree.Strict - ( StrictFingerTree, - fromStrict, - forceToStrict, - - -- * Construction - empty, - singleton, - (<|), - (|>), - (><), - fromList, - - -- * Deconstruction - null, - - -- ** Examining the ends - viewl, - viewr, - - -- ** Search - SearchResult (..), - search, - - -- ** Splitting - - -- | These functions are special cases of 'search'. - split, - takeUntil, - dropUntil, - - -- * Transformation - reverse, - - -- ** Maps - fmap', - unsafeFmap, - -- Re-export from "Data.FingerTree" - Measured (..), - ViewL (..), - ViewR (..), - ) +module Data.FingerTree.Strict ( + StrictFingerTree, + fromStrict, + forceToStrict, + + -- * Construction + empty, + singleton, + (<|), + (|>), + (><), + fromList, + + -- * Deconstruction + null, + + -- ** Examining the ends + viewl, + viewr, + + -- ** Search + SearchResult (..), + search, + + -- ** Splitting + + -- | These functions are special cases of 'search'. + split, + takeUntil, + dropUntil, + + -- * Transformation + reverse, + + -- ** Maps + fmap', + unsafeFmap, + -- Re-export from "Data.FingerTree" + Measured (..), + ViewL (..), + ViewR (..), +) where import Data.FingerTree (Measured (..), ViewL (..), ViewR (..)) import qualified Data.FingerTree as FT -import qualified Data.Foldable as F (foldl') import Data.Foldable (toList) +import qualified Data.Foldable as F (foldl') import Data.Unit.Strict (forceElemsToWHNF) import GHC.Generics (Generic) import NoThunks.Class (NoThunks (..), noThunksInValues) @@ -95,22 +95,22 @@ singleton !a = SFT (FT.singleton a) -- | /O(n)/. Create a sequence from a finite list of elements. -- The opposite operation 'toList' is supplied by the 'Foldable' instance. -fromList :: (Measured v a) => [a] -> StrictFingerTree v a +fromList :: Measured v a => [a] -> StrictFingerTree v a fromList !xs = F.foldl' (|>) (SFT FT.empty) xs -- | /O(1)/. Add an element to the left end of a sequence. -- Mnemonic: a triangle with the single element at the pointy end. -(<|) :: (Measured v a) => a -> StrictFingerTree v a -> StrictFingerTree v a +(<|) :: Measured v a => a -> StrictFingerTree v a -> StrictFingerTree v a (!a) <| SFT ft = SFT (a FT.<| ft) -- | /O(1)/. Add an element to the right end of a sequence. -- Mnemonic: a triangle with the single element at the pointy end. -(|>) :: (Measured v a) => StrictFingerTree v a -> a -> StrictFingerTree v a +(|>) :: Measured v a => StrictFingerTree v a -> a -> StrictFingerTree v a SFT ft |> (!a) = SFT (ft FT.|> a) -- | /O(log(min(n1,n2)))/. Concatenate two sequences. (><) :: - (Measured v a) => + Measured v a => StrictFingerTree v a -> StrictFingerTree v a -> StrictFingerTree v a @@ -135,7 +135,7 @@ null (SFT ft) = FT.null ft -- | /O(1)/. Analyse the left end of a sequence. viewl :: - (Measured v a) => + Measured v a => StrictFingerTree v a -> ViewL (StrictFingerTree v) a viewl (SFT ft) = case FT.viewl ft of @@ -144,7 +144,7 @@ viewl (SFT ft) = case FT.viewl ft of -- | /O(1)/. Analyse the right end of a sequence. viewr :: - (Measured v a) => + Measured v a => StrictFingerTree v a -> ViewR (StrictFingerTree v) a viewr (SFT ft) = case FT.viewr ft of @@ -215,7 +215,7 @@ fromOriginalSearchResult FT.Nowhere = Nowhere -- -- @since 0.1.2.0 search :: - (Measured v a) => + Measured v a => (v -> v -> Bool) -> StrictFingerTree v a -> SearchResult v a @@ -231,7 +231,7 @@ search p (SFT ft) = fromOriginalSearchResult (FT.search p ft) -- For predictable results, one should ensure that there is only one such -- point, i.e. that the predicate is /monotonic/. split :: - (Measured v a) => + Measured v a => (v -> Bool) -> StrictFingerTree v a -> (StrictFingerTree v a, StrictFingerTree v a) @@ -245,7 +245,7 @@ split p (SFT ft) = (SFT left, SFT right) -- -- * @'takeUntil' p t = 'fst' ('split' p t)@ takeUntil :: - (Measured v a) => + Measured v a => (v -> Bool) -> StrictFingerTree v a -> StrictFingerTree v a @@ -257,7 +257,7 @@ takeUntil p (SFT ft) = SFT (FT.takeUntil p ft) -- -- * @'dropUntil' p t = 'snd' ('split' p t)@ dropUntil :: - (Measured v a) => + Measured v a => (v -> Bool) -> StrictFingerTree v a -> StrictFingerTree v a @@ -268,7 +268,7 @@ dropUntil p (SFT ft) = SFT (FT.dropUntil p ft) -------------------------------------------------------------------------------} -- | /O(n)/. The reverse of a sequence. -reverse :: (Measured v a) => StrictFingerTree v a -> StrictFingerTree v a +reverse :: Measured v a => StrictFingerTree v a -> StrictFingerTree v a reverse (SFT ft) = SFT (FT.reverse ft) {------------------------------------------------------------------------------- diff --git a/cardano-strict-containers/src/Data/Maybe/Strict.hs b/cardano-strict-containers/src/Data/Maybe/Strict.hs index 26cd8fa91..4b3837bfe 100644 --- a/cardano-strict-containers/src/Data/Maybe/Strict.hs +++ b/cardano-strict-containers/src/Data/Maybe/Strict.hs @@ -3,29 +3,29 @@ {-# LANGUAGE DeriveTraversable #-} -- | Strict version of the 'Maybe' type. -module Data.Maybe.Strict - ( StrictMaybe (SNothing, SJust), - - -- * Conversion: StrictMaybe <--> Maybe - strictMaybeToMaybe, - maybeToStrictMaybe, - - -- * Accessing the underlying value - fromSMaybe, - isSNothing, - isSJust, - strictMaybe, - ) +module Data.Maybe.Strict ( + StrictMaybe (SNothing, SJust), + + -- * Conversion: StrictMaybe <--> Maybe + strictMaybeToMaybe, + maybeToStrictMaybe, + + -- * Accessing the underlying value + fromSMaybe, + isSNothing, + isSJust, + strictMaybe, +) where -import Cardano.Binary - ( FromCBOR (fromCBOR), - ToCBOR (toCBOR), - decodeBreakOr, - decodeListLenOrIndef, - encodeListLen, - ) -import Control.Applicative (Alternative(..)) +import Cardano.Binary ( + FromCBOR (fromCBOR), + ToCBOR (toCBOR), + decodeBreakOr, + decodeListLenOrIndef, + encodeListLen, + ) +import Control.Applicative (Alternative (..)) import Control.DeepSeq (NFData) import Data.Aeson (FromJSON (..), ToJSON (..)) import Data.Default.Class (Default (..)) @@ -36,15 +36,15 @@ data StrictMaybe a = SNothing | SJust !a deriving - ( Eq, - Ord, - Show, - Generic, - Functor, - Foldable, - Traversable, - NoThunks, - NFData + ( Eq + , Ord + , Show + , Generic + , Functor + , Foldable + , Traversable + , NoThunks + , NFData ) instance Applicative StrictMaybe where @@ -109,7 +109,6 @@ fromSMaybe :: a -> StrictMaybe a -> a fromSMaybe d SNothing = d fromSMaybe _ (SJust x) = x - -- | Same as `Data.Maybe.isNothing` isSNothing :: StrictMaybe a -> Bool isSNothing SNothing = True @@ -124,12 +123,9 @@ strictMaybe :: a -> (b -> a) -> StrictMaybe b -> a strictMaybe x _ SNothing = x strictMaybe _ f (SJust y) = f y - instance Default (StrictMaybe t) where def = SNothing - - instance Semigroup a => Semigroup (StrictMaybe a) where SNothing <> x = x x <> SNothing = x @@ -141,4 +137,4 @@ instance Semigroup a => Monoid (StrictMaybe a) where instance Alternative StrictMaybe where empty = SNothing SNothing <|> r = r - l <|> _ = l + l <|> _ = l diff --git a/cardano-strict-containers/src/Data/Sequence/Strict.hs b/cardano-strict-containers/src/Data/Sequence/Strict.hs index ed88f91ca..bafba8157 100644 --- a/cardano-strict-containers/src/Data/Sequence/Strict.hs +++ b/cardano-strict-containers/src/Data/Sequence/Strict.hs @@ -6,89 +6,89 @@ {-# LANGUAGE ViewPatterns #-} -- | Strict variants of 'Seq' operations. -module Data.Sequence.Strict - ( StrictSeq (Empty, (:<|), (:|>)), - fromStrict, - forceToStrict, - - -- * Construction - empty, - singleton, - (<|), - (|>), - (><), - fromList, - - -- * Deconstruction - - -- | Additional functions for deconstructing sequences are available - -- via the 'Foldable' instance of 'Seq'. - - -- ** Queries - null, - length, - - -- * Scans - scanl, - - -- * Sublists - - -- ** Sequential searches - takeWhileL, - takeWhileR, - dropWhileL, - dropWhileR, - spanl, - spanr, - - -- * Indexing - lookup, - (!?), - take, - takeLast, - drop, - dropLast, - splitAt, - splitAtEnd, - - -- * Indexing with predicates - findIndexL, - findIndicesL, - findIndexR, - findIndicesR, - - -- * Zips and unzips - zip, - zipWith, - unzip, - unzipWith, - ) +module Data.Sequence.Strict ( + StrictSeq (Empty, (:<|), (:|>)), + fromStrict, + forceToStrict, + + -- * Construction + empty, + singleton, + (<|), + (|>), + (><), + fromList, + + -- * Deconstruction + + -- | Additional functions for deconstructing sequences are available + -- via the 'Foldable' instance of 'Seq'. + + -- ** Queries + null, + length, + + -- * Scans + scanl, + + -- * Sublists + + -- ** Sequential searches + takeWhileL, + takeWhileR, + dropWhileL, + dropWhileR, + spanl, + spanr, + + -- * Indexing + lookup, + (!?), + take, + takeLast, + drop, + dropLast, + splitAt, + splitAtEnd, + + -- * Indexing with predicates + findIndexL, + findIndicesL, + findIndexR, + findIndicesR, + + -- * Zips and unzips + zip, + zipWith, + unzip, + unzipWith, +) where -import Cardano.Binary (FromCBOR(..), ToCBOR(..)) +import Cardano.Binary (FromCBOR (..), ToCBOR (..)) import Codec.Serialise (Serialise) import Control.Arrow ((***)) import Control.DeepSeq (NFData) -import Data.Aeson (FromJSON(..), ToJSON(..)) -import qualified Data.Foldable as F (foldl') +import Data.Aeson (FromJSON (..), ToJSON (..)) import Data.Foldable (toList) +import qualified Data.Foldable as F (foldl') import Data.Sequence (Seq) import qualified Data.Sequence as Seq import Data.Unit.Strict (forceElemsToWHNF) import qualified GHC.Exts as GHC (IsList (..)) import NoThunks.Class (NoThunks (..), noThunksInValues) -import Prelude hiding - ( drop, - length, - lookup, - null, - scanl, - splitAt, - take, - unzip, - zip, - zipWith, - ) +import Prelude hiding ( + drop, + length, + lookup, + null, + scanl, + splitAt, + take, + unzip, + zip, + zipWith, + ) infixr 5 >< diff --git a/cardano-strict-containers/src/Data/Unit/Strict.hs b/cardano-strict-containers/src/Data/Unit/Strict.hs index 487375488..795be84f1 100644 --- a/cardano-strict-containers/src/Data/Unit/Strict.hs +++ b/cardano-strict-containers/src/Data/Unit/Strict.hs @@ -1,8 +1,8 @@ -- | Helper functions for enforcing strictness. -module Data.Unit.Strict - ( StrictUnit (), - forceElemsToWHNF, - ) +module Data.Unit.Strict ( + StrictUnit (), + forceElemsToWHNF, +) where -- | Force all of the elements of a 'Foldable' to weak head normal form. diff --git a/fourmolu.yaml b/fourmolu.yaml new file mode 100644 index 000000000..2761fa757 --- /dev/null +++ b/fourmolu.yaml @@ -0,0 +1,16 @@ +indentation: 2 +function-arrows: trailing +comma-style: leading +import-export-style: diff-friendly +indent-wheres: true +record-brace-space: true +newlines-between-decls: 1 +haddock-style: single-line +haddock-style-module: +let-style: auto +in-style: right-align +unicode: never +respectful: true +fixities: [] +single-constraint-parens: never +column-limit: 100 diff --git a/heapwords/src/Cardano/HeapWords.hs b/heapwords/src/Cardano/HeapWords.hs index 7da7e8ec2..0bc1525d0 100644 --- a/heapwords/src/Cardano/HeapWords.hs +++ b/heapwords/src/Cardano/HeapWords.hs @@ -2,49 +2,49 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MagicHash #-} -module Cardano.HeapWords - ( HeapWords(..) - , heapSizeMb - , heapSizeKb - , heapWords0 - , heapWords1 - , heapWords2 - , heapWords3 - , heapWords4 - , heapWords5 - , heapWords6 - , heapWords7 - , heapWords8 - , heapWords9 - , heapWords10 - , heapWords11 - , heapWords12 - , heapWords13 - , heapWordsUArray - , heapWordsUVector - , heapWordsUnpacked - ) +module Cardano.HeapWords ( + HeapWords (..), + heapSizeMb, + heapSizeKb, + heapWords0, + heapWords1, + heapWords2, + heapWords3, + heapWords4, + heapWords5, + heapWords6, + heapWords7, + heapWords8, + heapWords9, + heapWords10, + heapWords11, + heapWords12, + heapWords13, + heapWordsUArray, + heapWordsUVector, + heapWordsUnpacked, +) where import qualified Data.Array.Unboxed as A import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS import qualified Data.ByteString.Short as BSS +import Data.Foldable (toList) import qualified Data.IntMap.Strict as IntMap import qualified Data.IntSet as IntSet -import Data.Sequence (Seq) -import Data.Foldable (toList) import Data.Ix import qualified Data.Map.Strict as Map +import Data.Sequence (Seq) import qualified Data.Set as Set -import Data.Word (Word8, Word32, Word64) import Data.Text as Text import Data.Time (Day, UTCTime) import qualified Data.Vector as V import qualified Data.Vector.Unboxed as V.U -import GHC.Natural (Natural(NatS#, NatJ#)) +import Data.Word (Word32, Word64, Word8) +import GHC.Natural (Natural (NatJ#, NatS#)) import GHC.Prim (ByteArray#, sizeofByteArray#) -import GHC.Types (Int(I#)) +import GHC.Types (Int (I#)) #if __GLASGOW_HASKELL__ >= 900 -- Use the GHC version here because this is compiler dependent, and only indirectly lib dependent. @@ -78,199 +78,197 @@ heapWords0 :: Int heapWords1 :: HeapWords a => a -> Int heapWords2 :: (HeapWords a1, HeapWords a) => a -> a1 -> Int heapWords3 :: (HeapWords a2, HeapWords a1, HeapWords a) => a -> a1 -> a2 -> Int -heapWords4 - :: (HeapWords a3, HeapWords a2, HeapWords a1, HeapWords a) - => a - -> a1 - -> a2 - -> a3 - -> Int -heapWords5 - :: (HeapWords a4, HeapWords a3, HeapWords a2, HeapWords a1, HeapWords a) - => a - -> a1 - -> a2 - -> a3 - -> a4 - -> Int -heapWords6 - :: ( HeapWords a5 - , HeapWords a4 - , HeapWords a3 - , HeapWords a2 - , HeapWords a1 - , HeapWords a - ) - => a - -> a1 - -> a2 - -> a3 - -> a4 - -> a5 - -> Int -heapWords7 - :: ( HeapWords a6 - , HeapWords a5 - , HeapWords a4 - , HeapWords a3 - , HeapWords a2 - , HeapWords a1 - , HeapWords a - ) - => a - -> a1 - -> a2 - -> a3 - -> a4 - -> a5 - -> a6 - -> Int -heapWords8 - :: ( HeapWords a7 - , HeapWords a6 - , HeapWords a5 - , HeapWords a4 - , HeapWords a3 - , HeapWords a2 - , HeapWords a1 - , HeapWords a - ) - => a - -> a1 - -> a2 - -> a3 - -> a4 - -> a5 - -> a6 - -> a7 - -> Int -heapWords9 - :: ( HeapWords a8 - , HeapWords a7 - , HeapWords a6 - , HeapWords a5 - , HeapWords a4 - , HeapWords a3 - , HeapWords a2 - , HeapWords a1 - , HeapWords a - ) - => a - -> a1 - -> a2 - -> a3 - -> a4 - -> a5 - -> a6 - -> a7 - -> a8 - -> Int -heapWords10 - :: ( HeapWords a9 - , HeapWords a8 - , HeapWords a7 - , HeapWords a6 - , HeapWords a5 - , HeapWords a4 - , HeapWords a3 - , HeapWords a2 - , HeapWords a1 - , HeapWords a - ) - => a - -> a1 - -> a2 - -> a3 - -> a4 - -> a5 - -> a6 - -> a7 - -> a8 - -> a9 - -> Int -heapWords11 - :: ( HeapWords a10 - , HeapWords a9 - , HeapWords a8 - , HeapWords a7 - , HeapWords a6 - , HeapWords a5 - , HeapWords a4 - , HeapWords a3 - , HeapWords a2 - , HeapWords a1 - , HeapWords a - ) - => a - -> a1 - -> a2 - -> a3 - -> a4 - -> a5 - -> a6 - -> a7 - -> a8 - -> a9 - -> a10 - -> Int -heapWords12 - :: ( HeapWords a11 - , HeapWords a10 - , HeapWords a9 - , HeapWords a8 - , HeapWords a7 - , HeapWords a6 - , HeapWords a5 - , HeapWords a4 - , HeapWords a3 - , HeapWords a2 - , HeapWords a1 - , HeapWords a - ) - => a - -> a1 - -> a2 - -> a3 - -> a4 - -> a5 - -> a6 - -> a7 - -> a8 - -> a9 - -> a10 - -> a11 - -> Int -heapWords13 - :: ( HeapWords a12 - , HeapWords a11 - , HeapWords a10 - , HeapWords a9 - , HeapWords a8 - , HeapWords a7 - , HeapWords a6 - , HeapWords a5 - , HeapWords a4 - , HeapWords a3 - , HeapWords a2 - , HeapWords a1 - , HeapWords a - ) - => a - -> a1 - -> a2 - -> a3 - -> a4 - -> a5 - -> a6 - -> a7 - -> a8 - -> a9 - -> a10 - -> a11 - -> a12 - -> Int - - +heapWords4 :: + (HeapWords a3, HeapWords a2, HeapWords a1, HeapWords a) => + a -> + a1 -> + a2 -> + a3 -> + Int +heapWords5 :: + (HeapWords a4, HeapWords a3, HeapWords a2, HeapWords a1, HeapWords a) => + a -> + a1 -> + a2 -> + a3 -> + a4 -> + Int +heapWords6 :: + ( HeapWords a5 + , HeapWords a4 + , HeapWords a3 + , HeapWords a2 + , HeapWords a1 + , HeapWords a + ) => + a -> + a1 -> + a2 -> + a3 -> + a4 -> + a5 -> + Int +heapWords7 :: + ( HeapWords a6 + , HeapWords a5 + , HeapWords a4 + , HeapWords a3 + , HeapWords a2 + , HeapWords a1 + , HeapWords a + ) => + a -> + a1 -> + a2 -> + a3 -> + a4 -> + a5 -> + a6 -> + Int +heapWords8 :: + ( HeapWords a7 + , HeapWords a6 + , HeapWords a5 + , HeapWords a4 + , HeapWords a3 + , HeapWords a2 + , HeapWords a1 + , HeapWords a + ) => + a -> + a1 -> + a2 -> + a3 -> + a4 -> + a5 -> + a6 -> + a7 -> + Int +heapWords9 :: + ( HeapWords a8 + , HeapWords a7 + , HeapWords a6 + , HeapWords a5 + , HeapWords a4 + , HeapWords a3 + , HeapWords a2 + , HeapWords a1 + , HeapWords a + ) => + a -> + a1 -> + a2 -> + a3 -> + a4 -> + a5 -> + a6 -> + a7 -> + a8 -> + Int +heapWords10 :: + ( HeapWords a9 + , HeapWords a8 + , HeapWords a7 + , HeapWords a6 + , HeapWords a5 + , HeapWords a4 + , HeapWords a3 + , HeapWords a2 + , HeapWords a1 + , HeapWords a + ) => + a -> + a1 -> + a2 -> + a3 -> + a4 -> + a5 -> + a6 -> + a7 -> + a8 -> + a9 -> + Int +heapWords11 :: + ( HeapWords a10 + , HeapWords a9 + , HeapWords a8 + , HeapWords a7 + , HeapWords a6 + , HeapWords a5 + , HeapWords a4 + , HeapWords a3 + , HeapWords a2 + , HeapWords a1 + , HeapWords a + ) => + a -> + a1 -> + a2 -> + a3 -> + a4 -> + a5 -> + a6 -> + a7 -> + a8 -> + a9 -> + a10 -> + Int +heapWords12 :: + ( HeapWords a11 + , HeapWords a10 + , HeapWords a9 + , HeapWords a8 + , HeapWords a7 + , HeapWords a6 + , HeapWords a5 + , HeapWords a4 + , HeapWords a3 + , HeapWords a2 + , HeapWords a1 + , HeapWords a + ) => + a -> + a1 -> + a2 -> + a3 -> + a4 -> + a5 -> + a6 -> + a7 -> + a8 -> + a9 -> + a10 -> + a11 -> + Int +heapWords13 :: + ( HeapWords a12 + , HeapWords a11 + , HeapWords a10 + , HeapWords a9 + , HeapWords a8 + , HeapWords a7 + , HeapWords a6 + , HeapWords a5 + , HeapWords a4 + , HeapWords a3 + , HeapWords a2 + , HeapWords a1 + , HeapWords a + ) => + a -> + a1 -> + a2 -> + a3 -> + a4 -> + a5 -> + a6 -> + a7 -> + a8 -> + a9 -> + a10 -> + a11 -> + a12 -> + Int heapWords0 = 0 heapWords1 a = 2 + heapWords a heapWords2 a b = 3 + heapWords a + heapWords b @@ -371,7 +369,6 @@ heapWords13 a b c d e f g h i j k l m = + heapWords l + heapWords m - instance HeapWords (a -> b) where heapWords _ = 0 @@ -406,6 +403,7 @@ instance HeapWords Bool where -- tends to 0. heapWords _ = 0 +{- FOURMOLU_DISABLE -} instance HeapWords Integer where #if __GLASGOW_HASKELL__ >= 900 heapWords (IS _) = 2 @@ -438,6 +436,7 @@ instance HeapWords Integer where -- └──┴──────┘ -- #endif +{- FOURMOLU_ENABLE -} #if __GLASGOW_HASKELL__ >= 900 heapWords (IP bigNat) = 4 + I# (sizeofByteArray# bigNat) @@ -556,47 +555,48 @@ instance HeapWords Day where heapWords _ = 2 instance HeapWords a => HeapWords [a] where - heapWords [] = heapWords0 - heapWords (x:xs) = heapWords2 x xs + heapWords [] = heapWords0 + heapWords (x : xs) = heapWords2 x xs -instance (HeapWords a, HeapWords b) => HeapWords (a,b) where - heapWords (a,b) = heapWords2 a b +instance (HeapWords a, HeapWords b) => HeapWords (a, b) where + heapWords (a, b) = heapWords2 a b -instance (HeapWords a, HeapWords b, HeapWords c) => HeapWords (a,b,c) where - heapWords (a,b,c) = heapWords3 a b c +instance (HeapWords a, HeapWords b, HeapWords c) => HeapWords (a, b, c) where + heapWords (a, b, c) = heapWords3 a b c -instance (HeapWords a, HeapWords b, HeapWords c, HeapWords d) => HeapWords (a,b,c,d) where - heapWords (a,b,c,d) = heapWords4 a b c d +instance (HeapWords a, HeapWords b, HeapWords c, HeapWords d) => HeapWords (a, b, c, d) where + heapWords (a, b, c, d) = heapWords4 a b c d instance HeapWords a => HeapWords (Maybe a) where - heapWords Nothing = heapWords0 + heapWords Nothing = heapWords0 heapWords (Just a) = heapWords1 a instance (HeapWords a, HeapWords b) => HeapWords (Either a b) where - heapWords (Left a) = heapWords1 a + heapWords (Left a) = heapWords1 a heapWords (Right b) = heapWords1 b instance (HeapWords a, HeapWords b) => HeapWords (Map.Map a b) where - heapWords m = sum [ 6 + heapWords k + heapWords v | (k,v) <- Map.toList m ] + heapWords m = sum [6 + heapWords k + heapWords v | (k, v) <- Map.toList m] instance HeapWords a => HeapWords (IntMap.IntMap a) where - heapWords m = sum [ 8 + heapWords v | v <- IntMap.elems m ] + heapWords m = sum [8 + heapWords v | v <- IntMap.elems m] instance HeapWords a => HeapWords (Set.Set a) where - heapWords m = sum [ 5 + heapWords v | v <- Set.elems m ] + heapWords m = sum [5 + heapWords v | v <- Set.elems m] instance HeapWords IntSet.IntSet where - heapWords s = 4 * IntSet.size s --estimate + heapWords s = 4 * IntSet.size s -- estimate instance HeapWords a => HeapWords (Seq a) where - heapWords s = sum [ 5 + heapWords v | v <- toList s ] --estimate + heapWords s = sum [5 + heapWords v | v <- toList s] -- estimate instance HeapWords BS.ByteString where - heapWords s = let (w,t) = divMod (BS.length s) wordSize - in 5 + w + signum t + heapWords s = + let (w, t) = divMod (BS.length s) wordSize + in 5 + w + signum t instance HeapWords BSS.ShortByteString where - heapWords s + heapWords s = -- We have -- -- > data ShortByteString = SBS ByteArray# @@ -617,15 +617,16 @@ instance HeapWords BSS.ShortByteString where -- │BA#│ sz│ │ │ │ 2 + n Words -- └───┴───┴───┴─┈ ┈─┴───┘ -- - = let (w,t) = divMod (BSS.length s) wordSize - in 4 + w + signum t + let (w, t) = divMod (BSS.length s) wordSize + in 4 + w + signum t instance HeapWords LBS.ByteString where - heapWords s = sum [ 1 + heapWords c | c <- LBS.toChunks s ] + heapWords s = sum [1 + heapWords c | c <- LBS.toChunks s] instance HeapWords Text.Text where - heapWords s = let (w,t) = divMod (Text.length s) (wordSize `div` 2) - in 5 + w + signum t + heapWords s = + let (w, t) = divMod (Text.length s) (wordSize `div` 2) + in 5 + w + signum t heapWordsUArray :: (Ix i, A.IArray a e) => Int -> a i e -> Int heapWordsUArray sz a = 13 + (rangeSize (A.bounds a) * sz) `div` wordSize @@ -637,7 +638,7 @@ heapWordsUVector :: V.U.Unbox e => Int -> V.U.Vector e -> Int heapWordsUVector sz a = 5 + (V.U.length a * sz) `div` wordSize instance HeapWords Natural where - heapWords (NatS# _) + heapWords (NatS# _) = -- We have -- -- > NatS# GmpLimb# @@ -652,8 +653,8 @@ instance HeapWords Natural where -- │NatS#│ Word#'│ -- └─────┴───────┘ -- - = 1 + 1 - heapWords (NatJ# bn) + 1 + 1 + heapWords (NatJ# bn) = -- We have -- -- > NatJ# {-# UNPACK #-} !BigNat @@ -675,7 +676,7 @@ instance HeapWords Natural where -- │BA#│ sz│ │ │ │ 2 + n Words -- └───┴───┴───┴─┈ ┈─┴───┘ -- - = 1 + 1 + heapWordsUnpacked bn + 1 + 1 + heapWordsUnpacked bn instance HeapWords BigNat where heapWords (BN# arr) = @@ -699,21 +700,21 @@ instance HeapWords BigNat where 1 + 1 + heapWordsByteArray# arr -- | Calculate the heap words required to store a 'ByteArray#' object. --- heapWordsByteArray# :: ByteArray# -> Int heapWordsByteArray# ba# = 2 + n - -- We require: - -- - -- - 2 for the 'ByteArray#' heap object (1 for header, and 1 for storing its - -- size) - -- - @n@ for the variable sized part - -- - -- ┌───┬───┬───┬─┈ ┈─┬───┐ - -- │BA#│ sz│ │ │ │ 2 + n Words - -- └───┴───┴───┴─┈ ┈─┴───┘ - where - n = 1 + ((nbytes - 1) `div` wordSize) - nbytes = I# (sizeofByteArray# ba#) + where + -- We require: + -- + -- - 2 for the 'ByteArray#' heap object (1 for header, and 1 for storing its + -- size) + -- - @n@ for the variable sized part + -- + -- ┌───┬───┬───┬─┈ ┈─┬───┐ + -- │BA#│ sz│ │ │ │ 2 + n Words + -- └───┴───┴───┴─┈ ┈─┴───┘ + + n = 1 + ((nbytes - 1) `div` wordSize) + nbytes = I# (sizeofByteArray# ba#) -- | Calculate the number of heap words used by a field unpacked within another -- constructor. @@ -723,6 +724,5 @@ heapWordsByteArray# ba# = 2 + n -- -- - a word for the pointer to the inner structure. -- - a word for the constructor that is being unpacked. --- heapWordsUnpacked :: HeapWords a => a -> Int heapWordsUnpacked x = heapWords x - 2 diff --git a/measures/src/Data/Measure.hs b/measures/src/Data/Measure.hs index 52f254536..5b30f9e6a 100644 --- a/measures/src/Data/Measure.hs +++ b/measures/src/Data/Measure.hs @@ -1,5 +1,5 @@ -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NoImplicitPrelude #-} -- | Combinators for a possibly-multidimensional measurement @@ -14,13 +14,13 @@ -- -- See the 'Measure' class for more. module Data.Measure ( - module Data.Measure.Class - , (<=) - , (>=) - , drop - , splitAt - , take - ) + module Data.Measure.Class, + (<=), + (>=), + drop, + splitAt, + take, +) where import Data.Measure.Class @@ -48,26 +48,26 @@ x >= y = x Prelude.== max x y -- clever like bin-packing etc. splitAt :: Measure a => (e -> a) -> a -> [e] -> ([e], [e]) splitAt measure limit = - go zero [] + go zero [] where go !tot acc = \case - [] -> (Prelude.reverse acc, []) - e:es -> - if tot' <= limit + [] -> (Prelude.reverse acc, []) + e : es -> + if tot' <= limit then go tot' (e : acc) es - else (Prelude.reverse acc, e:es) + else (Prelude.reverse acc, e : es) where tot' = plus tot (measure e) -- | @fst . 'splitAt' measure limit@, but non-strict take :: Measure a => (e -> a) -> a -> [e] -> [e] take measure limit = - go zero + go zero where go !tot = \case - [] -> [] - e:es -> - if tot' <= limit + [] -> [] + e : es -> + if tot' <= limit then e : go tot' es else [] where @@ -76,13 +76,13 @@ take measure limit = -- | @snd . 'splitAt' measure limit@, with a bit less allocation drop :: Measure a => (e -> a) -> a -> [e] -> [e] drop measure limit = - go zero + go zero where go !tot = \case - [] -> [] - e:es -> - if tot' <= limit + [] -> [] + e : es -> + if tot' <= limit then go tot' es - else e:es + else e : es where tot' = plus tot (measure e) diff --git a/measures/src/Data/Measure/Class.hs b/measures/src/Data/Measure/Class.hs index 90a218230..5625486b9 100644 --- a/measures/src/Data/Measure/Class.hs +++ b/measures/src/Data/Measure/Class.hs @@ -1,33 +1,34 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DerivingVia #-} -{-# LANGUAGE EmptyCase #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE CPP #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DerivingVia #-} +{-# LANGUAGE EmptyCase #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE NoImplicitPrelude #-} {-# OPTIONS -Wno-unticked-promoted-constructors #-} -- | See 'Measure' -module Data.Measure.Class - ( BoundedMeasure (..) - , Measure (..) - -- * Exceptions - , DataMeasureClassOverflowException (..) - ) +module Data.Measure.Class ( + BoundedMeasure (..), + Measure (..), + + -- * Exceptions + DataMeasureClassOverflowException (..), +) where import Control.Exception (Exception, throw) import Data.Coerce import Data.DerivingVia -import Data.Word (Word8, Word16, Word32, Word64) +import Data.Word (Word16, Word32, Word64, Word8) import GHC.Generics #if __GLASGOW_HASKELL__ < 900 -- Use the GHC version here because this is compiler dependent, and only indirectly lib dependent. @@ -98,32 +99,49 @@ class Measure a => BoundedMeasure a where instance Measure Natural where zero = 0 plus = (Prelude.+) - min = Prelude.min - max = Prelude.max - -deriving via InstantiatedAt Generic (a, b) - instance (Measure a, Measure b) => Measure (a, b) - -deriving via InstantiatedAt Generic (a, b, c) - instance (Measure a, Measure b, Measure c) => Measure (a, b, c) - -deriving via InstantiatedAt Generic (a, b, c, d) - instance (Measure a, Measure b, Measure c, Measure d) - => Measure (a, b, c, d) - -deriving via InstantiatedAt Generic (a, b, c, d, e) - instance (Measure a, Measure b, Measure c, Measure d, Measure e) - => Measure (a, b, c, d, e) - -deriving via InstantiatedAt Generic (a, b, c, d, e, f) - instance (Measure a, Measure b, Measure c, Measure d, Measure e, Measure f) - => Measure (a, b, c, d, e, f) - -deriving via InstantiatedAt Generic (a, b, c, d, e, f, g) - instance ( Measure a, Measure b, Measure c, Measure d, Measure e, Measure f - , Measure g - ) - => Measure (a, b, c, d, e, f, g) + min = Prelude.min + max = Prelude.max + +deriving via + InstantiatedAt Generic (a, b) + instance + (Measure a, Measure b) => Measure (a, b) + +deriving via + InstantiatedAt Generic (a, b, c) + instance + (Measure a, Measure b, Measure c) => Measure (a, b, c) + +deriving via + InstantiatedAt Generic (a, b, c, d) + instance + (Measure a, Measure b, Measure c, Measure d) => + Measure (a, b, c, d) + +deriving via + InstantiatedAt Generic (a, b, c, d, e) + instance + (Measure a, Measure b, Measure c, Measure d, Measure e) => + Measure (a, b, c, d, e) + +deriving via + InstantiatedAt Generic (a, b, c, d, e, f) + instance + (Measure a, Measure b, Measure c, Measure d, Measure e, Measure f) => + Measure (a, b, c, d, e, f) + +deriving via + InstantiatedAt Generic (a, b, c, d, e, f, g) + instance + ( Measure a + , Measure b + , Measure c + , Measure d + , Measure e + , Measure f + , Measure g + ) => + Measure (a, b, c, d, e, f, g) -- larger tuples unfortunatley do not have Generic instances @@ -131,8 +149,8 @@ deriving via InstantiatedAt Generic (a, b, c, d, e, f, g) instance Measure Word8 where zero = 0 plus = checkedPlus - min = Prelude.min - max = Prelude.max + min = Prelude.min + max = Prelude.max instance BoundedMeasure Word8 where maxBound = Prelude.maxBound @@ -141,8 +159,8 @@ instance BoundedMeasure Word8 where instance Measure Word16 where zero = 0 plus = checkedPlus - min = Prelude.min - max = Prelude.max + min = Prelude.min + max = Prelude.max instance BoundedMeasure Word16 where maxBound = Prelude.maxBound @@ -151,8 +169,8 @@ instance BoundedMeasure Word16 where instance Measure Word32 where zero = 0 plus = checkedPlus - min = Prelude.min - max = Prelude.max + min = Prelude.min + max = Prelude.max instance BoundedMeasure Word32 where maxBound = Prelude.maxBound @@ -161,8 +179,8 @@ instance BoundedMeasure Word32 where instance Measure Word64 where zero = 0 plus = checkedPlus - min = Prelude.min - max = Prelude.max + min = Prelude.min + max = Prelude.max instance BoundedMeasure Word64 where maxBound = Prelude.maxBound @@ -171,10 +189,10 @@ instance BoundedMeasure Word64 where -- -- Throws 'DataMeasureClassOverflowException' checkedPlus :: - (Prelude.Bounded a, Prelude.Integral a) - => a -> a -> a + (Prelude.Bounded a, Prelude.Integral a) => + a -> a -> a checkedPlus x y = - if x Prelude.> Prelude.maxBound Prelude.- y + if x Prelude.> Prelude.maxBound Prelude.- y then throw DataMeasureClassOverflowException else x Prelude.+ y @@ -201,26 +219,34 @@ instance Measure a => Prelude.Semigroup (InstantiatedAt Measure a) where -- DerivingVia instances of these classes -------------------------------------------------------------------------------- -instance (Prelude.Monoid a, Prelude.Ord a) - => Measure (InstantiatedAt Prelude.Ord a) where +instance + (Prelude.Monoid a, Prelude.Ord a) => + Measure (InstantiatedAt Prelude.Ord a) + where zero = coerce $ Prelude.mempty @a - plus = coerce $ (Prelude.<>) @a - min = coerce $ Prelude.min @a - max = coerce $ Prelude.max @a - -instance (Prelude.Bounded a, Prelude.Monoid a, Prelude.Ord a) - => BoundedMeasure (InstantiatedAt Prelude.Ord a) where + plus = coerce $ (Prelude.<>) @a + min = coerce $ Prelude.min @a + max = coerce $ Prelude.max @a + +instance + (Prelude.Bounded a, Prelude.Monoid a, Prelude.Ord a) => + BoundedMeasure (InstantiatedAt Prelude.Ord a) + where maxBound = coerce $ Prelude.maxBound @a -instance (Prelude.Eq a, Generic a, GMeasure (Rep a)) - => Measure (InstantiatedAt Generic a) where - zero = coerce $ to @a gzero +instance + (Prelude.Eq a, Generic a, GMeasure (Rep a)) => + Measure (InstantiatedAt Generic a) + where + zero = coerce $ to @a gzero plus = coerce $ gbinop @a gplus - min = coerce $ gbinop @a gmin - max = coerce $ gbinop @a gmax + min = coerce $ gbinop @a gmin + max = coerce $ gbinop @a gmax -instance (Prelude.Eq a, Generic a, GBoundedMeasure (Rep a), GMeasure (Rep a)) - => BoundedMeasure (InstantiatedAt Generic a) where +instance + (Prelude.Eq a, Generic a, GBoundedMeasure (Rep a), GMeasure (Rep a)) => + BoundedMeasure (InstantiatedAt Generic a) + where maxBound = coerce $ to @a gmaxBound -- not exported @@ -231,49 +257,52 @@ gbinop f l r = to $ f (from l) (from r) class GMeasure rep where gzero :: rep x gplus :: rep x -> rep x -> rep x - gmin :: rep x -> rep x -> rep x - gmax :: rep x -> rep x -> rep x + gmin :: rep x -> rep x -> rep x + gmax :: rep x -> rep x -> rep x instance Measure c => GMeasure (K1 i c) where - gzero = K1 zero + gzero = K1 zero gplus (K1 l) (K1 r) = K1 (plus l r) - gmin (K1 l) (K1 r) = K1 (min l r) - gmax (K1 l) (K1 r) = K1 (max l r) + gmin (K1 l) (K1 r) = K1 (min l r) + gmax (K1 l) (K1 r) = K1 (max l r) instance GMeasure f => GMeasure (M1 i c f) where - gzero = M1 gzero + gzero = M1 gzero gplus (M1 l) (M1 r) = M1 (gplus l r) - gmin (M1 l) (M1 r) = M1 (gmin l r) - gmax (M1 l) (M1 r) = M1 (gmax l r) + gmin (M1 l) (M1 r) = M1 (gmin l r) + gmax (M1 l) (M1 r) = M1 (gmax l r) instance GMeasure V1 where gzero = Prelude.error "GMeasure V1" gplus = \case {} - gmin = \case {} - gmax = \case {} + gmin = \case {} + gmax = \case {} instance GMeasure U1 where - gzero = U1 + gzero = U1 gplus U1 U1 = U1 - gmin U1 U1 = U1 - gmax U1 U1 = U1 + gmin U1 U1 = U1 + gmax U1 U1 = U1 instance (GMeasure l, GMeasure r) => GMeasure (l :*: r) where - gzero = gzero :*: gzero + gzero = gzero :*: gzero gplus (l1 :*: r1) (l2 :*: r2) = gplus l1 l2 :*: gplus r1 r2 - gmin (l1 :*: r1) (l2 :*: r2) = gmin l1 l2 :*: gmin r1 r2 - gmax (l1 :*: r1) (l2 :*: r2) = gmax l1 l2 :*: gmax r1 r2 - -instance TypeError ( Text "No Generics definition of " - :<>: ShowType Measure - :<>: Text " for types with multiple constructors " - :<>: ShowType (l :+: r) - ) - => GMeasure (l :+: r) where + gmin (l1 :*: r1) (l2 :*: r2) = gmin l1 l2 :*: gmin r1 r2 + gmax (l1 :*: r1) (l2 :*: r2) = gmax l1 l2 :*: gmax r1 r2 + +instance + TypeError + ( Text "No Generics definition of " + :<>: ShowType Measure + :<>: Text " for types with multiple constructors " + :<>: ShowType (l :+: r) + ) => + GMeasure (l :+: r) + where gzero = Prelude.error "GMeasure gzero :+:" gplus = Prelude.error "GMeasure gplus :+:" - gmin = Prelude.error "GMeasure gmin :+:" - gmax = Prelude.error "GMeasure gmax :+:" + gmin = Prelude.error "GMeasure gmin :+:" + gmax = Prelude.error "GMeasure gmax :+:" class GBoundedMeasure rep where gmaxBound :: rep x @@ -293,10 +322,13 @@ instance GBoundedMeasure U1 where instance (GBoundedMeasure l, GBoundedMeasure r) => GBoundedMeasure (l :*: r) where gmaxBound = gmaxBound :*: gmaxBound -instance TypeError ( Text "No Generics definition of " - :<>: ShowType BoundedMeasure - :<>: Text " for types with multiple constructors " - :<>: ShowType (l :+: r) - ) - => GBoundedMeasure (l :+: r) where +instance + TypeError + ( Text "No Generics definition of " + :<>: ShowType BoundedMeasure + :<>: Text " for types with multiple constructors " + :<>: ShowType (l :+: r) + ) => + GBoundedMeasure (l :+: r) + where gmaxBound = Prelude.error "GBoundedMeasure :+:" diff --git a/measures/test/Main.hs b/measures/test/Main.hs index 91bb35316..84a488455 100644 --- a/measures/test/Main.hs +++ b/measures/test/Main.hs @@ -1,7 +1,7 @@ -module Main - ( main - , tests - ) +module Main ( + main, + tests, +) where import Test.Tasty @@ -12,6 +12,8 @@ main :: IO () main = defaultMain tests tests :: TestTree -tests = testGroup "measures package" +tests = + testGroup + "measures package" [ Test.Data.Measure.tests ] diff --git a/measures/test/Test/Data/Measure.hs b/measures/test/Test/Data/Measure.hs index c8c5f6fff..21450affa 100644 --- a/measures/test/Test/Data/Measure.hs +++ b/measures/test/Test/Data/Measure.hs @@ -1,8 +1,8 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} -module Test.Data.Measure - ( tests - ) +module Test.Data.Measure ( + tests, +) where import GHC.Natural @@ -12,10 +12,12 @@ import Test.Tasty.QuickCheck import qualified Data.Measure as M tests :: TestTree -tests = testGroup "Data.Measure" - [ testProperty "uncurry (++) undoes splitAt" prop_idAppendSplitAt - , testProperty "take and drop agrees with splitAt" prop_eqTakeDropSplitAt - ] +tests = + testGroup + "Data.Measure" + [ testProperty "uncurry (++) undoes splitAt" prop_idAppendSplitAt + , testProperty "take and drop agrees with splitAt" prop_eqTakeDropSplitAt + ] -------------------------------------------------------------------------------- -- A nice measure to run tests with @@ -32,12 +34,12 @@ itemToInteger (Item n) = naturalToInteger n instance Arbitrary Item where arbitrary = fmap (integerToItem . getSmall) arbitrary - shrink = - fmap (integerToItem . getSmall) - . filter (>= 0) - . shrink - . Small - . itemToInteger + shrink = + fmap (integerToItem . getSmall) + . filter (>= 0) + . shrink + . Small + . itemToInteger -------------------------------------------------------------------------------- -- Required properties @@ -46,12 +48,12 @@ instance Arbitrary Item where -- | @uncurry (++)@ undoes 'M.splitAt' prop_idAppendSplitAt :: Item -> [Item] -> Property prop_idAppendSplitAt limit es = - l ++ r === es + l ++ r === es where (l, r) = M.splitAt id limit es -- | 'M.take' and 'M.drop' are the components of 'M.splitAt' prop_eqTakeDropSplitAt :: Item -> [Item] -> Property prop_eqTakeDropSplitAt limit es = - (M.take id limit es, M.drop id limit es) + (M.take id limit es, M.drop id limit es) === M.splitAt id limit es diff --git a/orphans-deriving-via/src/Data/DerivingVia/DeepSeq.hs b/orphans-deriving-via/src/Data/DerivingVia/DeepSeq.hs index 37d89365b..67f6a9601 100644 --- a/orphans-deriving-via/src/Data/DerivingVia/DeepSeq.hs +++ b/orphans-deriving-via/src/Data/DerivingVia/DeepSeq.hs @@ -1,24 +1,25 @@ -{-# LANGUAGE EmptyCase #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE EmptyCase #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} - {-# OPTIONS_GHC -Wno-orphans #-} -- | "GHC.Generics" definition of 'rnf' -module Data.DerivingVia.DeepSeq - ( - ) +module Data.DerivingVia.DeepSeq ( + +) where import Control.DeepSeq import Data.DerivingVia import GHC.Generics -instance (Generic a, GNFData (Rep a)) - => NFData (InstantiatedAt Generic a) where +instance + (Generic a, GNFData (Rep a)) => + NFData (InstantiatedAt Generic a) + where rnf (InstantiatedAt x) = grnf (from x) class GNFData rep where diff --git a/orphans-deriving-via/src/Data/DerivingVia/NoThunks.hs b/orphans-deriving-via/src/Data/DerivingVia/NoThunks.hs index aec896587..1214a0d40 100644 --- a/orphans-deriving-via/src/Data/DerivingVia/NoThunks.hs +++ b/orphans-deriving-via/src/Data/DerivingVia/NoThunks.hs @@ -1,17 +1,16 @@ -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} {-# LANGUAGE UndecidableInstances #-} - {-# OPTIONS_GHC -Wno-orphans #-} -- | "GHC.Generics" definition of 'NoThunks' -module Data.DerivingVia.NoThunks - ( - ) +module Data.DerivingVia.NoThunks ( + +) where import Data.DerivingVia @@ -20,10 +19,12 @@ import GHC.Generics import NoThunks.Class -- | Copied from the "NoThunks.Class" default method definitions -instance (Generic a, GShowTypeOf (Rep a), GWNoThunks '[] (Rep a)) - => NoThunks (InstantiatedAt Generic a) where +instance + (Generic a, GShowTypeOf (Rep a), GWNoThunks '[] (Rep a)) => + NoThunks (InstantiatedAt Generic a) + where wNoThunks ctxt (InstantiatedAt x) = - gwNoThunks (Proxy @'[]) ctxt fp + gwNoThunks (Proxy @'[]) ctxt fp where !fp = from x diff --git a/scripts/fourmolize.sh b/scripts/fourmolize.sh new file mode 100755 index 000000000..1b712c005 --- /dev/null +++ b/scripts/fourmolize.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [[ $# -gt 0 ]]; then + case "$1" in + --changes) + files=$(git diff --diff-filter=MA --name-only origin/master HEAD -- '*.hs') + if [[ -n "$files" ]]; then + # Run fourmolu on changes compared to `master`. + fourmolu -m inplace $(echo "$files" | grep -v Setup.hs) + fi + ;; + *) + echo "Invalid option: $1" >&2 + exit 1 + ;; + esac +else + fourmolu -m inplace $(git ls-files -- '*.hs' | grep -v Setup.hs) +fi + +git diff --exit-code