{-# LANGUAGE DerivingStrategies #-} -- | 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) instance Arbitrary PublicKey where arbitrary = toPublic <$> arbitrary -- | P256 secret cryptographic key. newtype SecretKey = SecretKey { unSecretKey :: ByteString } deriving stock (Show, Eq) -- | 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) instance Arbitrary Signature where arbitrary = Signature . BS.pack <$> replicateM signatureLengthBytes arbitrary ---------------------------------------------------------------------------- -- 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