morley-1.3.0: src/Tezos/Crypto/P256.hs
-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ
-- | P256 cryptographic primitives.
--
-- This module is mostly a stub, it doesn't implement actual crypto.
-- TODO (#18) implement crypto properly.
module Tezos.Crypto.P256
( -- * Cryptographic primitive types
PublicKey (..)
, SecretKey
, Signature (..)
, detSecretKey
, toPublic
-- * Raw bytes (no checksums, tags or anything)
, publicKeyToBytes
, mkPublicKey
, publicKeyLengthBytes
, signatureToBytes
, mkSignature
, signatureLengthBytes
-- * Formatting and parsing
, formatPublicKey
, mformatPublicKey
, parsePublicKey
, formatSignature
, mformatSignature
, parseSignature
-- * Signing
, checkSignature
) where
import Crypto.Random (getRandomBytes)
import Data.ByteArray (ByteArray, ByteArrayAccess)
import qualified Data.ByteArray as BA
import qualified Data.ByteString as BS
import Fmt (Buildable, build)
import Test.QuickCheck (Arbitrary(..), vector)
import Michelson.Text
import Tezos.Crypto.Util
----------------------------------------------------------------------------
-- Types, instances, conversions
----------------------------------------------------------------------------
-- | P256 public cryptographic key.
newtype PublicKey = PublicKey
{ unPublicKey :: ByteString
} deriving stock (Show, Eq, Generic)
instance Arbitrary PublicKey where
arbitrary = toPublic <$> arbitrary
instance NFData PublicKey
-- | P256 secret cryptographic key.
newtype SecretKey = SecretKey
{ unSecretKey :: ByteString
} deriving stock (Show, Eq, Generic)
instance NFData SecretKey
-- | Deterministicaly generate a secret key from seed.
detSecretKey :: ByteString -> SecretKey
detSecretKey seed =
SecretKey $ deterministic seed $ getRandomBytes publicKeyLengthBytes
instance Arbitrary SecretKey where
arbitrary = detSecretKey . BS.pack <$> vector 32
-- | Create a public key from a secret key.
toPublic :: SecretKey -> PublicKey
toPublic = PublicKey . unSecretKey
-- | P256 cryptographic signature.
newtype Signature = Signature
{ unSignature :: ByteString
} deriving stock (Show, Eq, Generic)
instance Arbitrary Signature where
arbitrary = Signature . BS.pack <$> replicateM signatureLengthBytes arbitrary
instance NFData Signature
----------------------------------------------------------------------------
-- Conversion to/from raw bytes (no checksums, tags or anything)
----------------------------------------------------------------------------
-- | Convert a 'PublicKey' to raw bytes.
--
-- TODO (#18): implement properly.
publicKeyToBytes :: forall ba. ByteArray ba => PublicKey -> ba
publicKeyToBytes = BA.convert . unPublicKey
-- | Make a 'PublicKey' from raw bytes.
--
-- TODO (#18): implement properly.
mkPublicKey :: ByteArrayAccess ba => ba -> Either CryptoParseError PublicKey
mkPublicKey ba
| l == publicKeyLengthBytes =
Right $ PublicKey (BA.convert ba)
| otherwise =
Left $ CryptoParseUnexpectedLength "public key" l
where
l = BA.length ba
publicKeyLengthBytes :: Integral n => n
publicKeyLengthBytes = 33
-- | Convert a 'PublicKey' to raw bytes.
--
-- TODO (#18): implement properly.
signatureToBytes :: ByteArray ba => Signature -> ba
signatureToBytes = BA.convert . unSignature
-- | Make a 'Signature' from raw bytes.
--
-- TODO (#18): implement properly.
mkSignature :: ByteArray ba => ba -> Either CryptoParseError Signature
mkSignature ba
| l == signatureLengthBytes =
Right $ Signature (BA.convert ba)
| otherwise =
Left $ CryptoParseUnexpectedLength "signature" l
where
l = BA.length ba
signatureLengthBytes :: Integral n => n
signatureLengthBytes = 64
----------------------------------------------------------------------------
-- Magic bytes
----------------------------------------------------------------------------
publicKeyTag :: ByteString
publicKeyTag = "\003\178\139\127"
signatureTag :: ByteString
signatureTag = "\054\240\044\052"
----------------------------------------------------------------------------
-- Formatting
----------------------------------------------------------------------------
formatPublicKey :: PublicKey -> Text
formatPublicKey = formatImpl @ByteString publicKeyTag . publicKeyToBytes
mformatPublicKey :: PublicKey -> MText
mformatPublicKey = mkMTextUnsafe . formatPublicKey
instance Buildable PublicKey where
build = build . formatPublicKey
parsePublicKey :: Text -> Either CryptoParseError PublicKey
parsePublicKey = parseImpl publicKeyTag mkPublicKey
formatSignature :: Signature -> Text
formatSignature = formatImpl @ByteString signatureTag . signatureToBytes
mformatSignature :: Signature -> MText
mformatSignature = mkMTextUnsafe . formatSignature
instance Buildable Signature where
build = build . formatSignature
parseSignature :: Text -> Either CryptoParseError Signature
parseSignature = parseImpl signatureTag mkSignature
----------------------------------------------------------------------------
-- Signing
----------------------------------------------------------------------------
-- | Check that a sequence of bytes has been signed with a given key.
checkSignature :: PublicKey -> Signature -> ByteString -> Bool
checkSignature _ _ _ = False