module Tezos.Crypto.Ed25519
(
PublicKey (..)
, SecretKey
, Signature (..)
, detSecretKey
, toPublic
, publicKeyToBytes
, mkPublicKey
, publicKeyLengthBytes
, signatureToBytes
, mkSignature
, signatureLengthBytes
, formatPublicKey
, mformatPublicKey
, parsePublicKey
, formatSecretKey
, parseSecretKey
, formatSignature
, mformatSignature
, parseSignature
, sign
, checkSignature
) where
import Crypto.Error (onCryptoFailure)
import qualified Crypto.PubKey.Ed25519 as Ed25519
import Data.ByteArray (ByteArray, ByteArrayAccess, convert)
import qualified Data.ByteString as BS
import Fmt (Buildable, build)
import Test.QuickCheck (Arbitrary(..), vector)
import Michelson.Text
import Tezos.Crypto.Hash
import Tezos.Crypto.Util
newtype PublicKey = PublicKey
{ unPublicKey :: Ed25519.PublicKey
} deriving stock (Show, Eq)
instance Arbitrary PublicKey where
arbitrary = toPublic <$> arbitrary
newtype SecretKey = SecretKey
{ unSecretKey :: Ed25519.SecretKey
} deriving stock (Show, Eq)
detSecretKey :: ByteString -> SecretKey
detSecretKey seed = SecretKey $ deterministic seed Ed25519.generateSecretKey
instance Arbitrary SecretKey where
arbitrary = detSecretKey . BS.pack <$> vector 32
toPublic :: SecretKey -> PublicKey
toPublic = PublicKey . Ed25519.toPublic . unSecretKey
newtype Signature = Signature
{ unSignature :: Ed25519.Signature
} deriving stock (Show, Eq)
instance Arbitrary Signature where
arbitrary = sign <$> arbitrary <*> (encodeUtf8 @String <$> arbitrary)
publicKeyToBytes :: ByteArray ba => PublicKey -> ba
publicKeyToBytes = convert . unPublicKey
mkPublicKey :: ByteArrayAccess ba => ba -> Either CryptoParseError PublicKey
mkPublicKey =
onCryptoFailure (Left . CryptoParseCryptoError) (Right . PublicKey) .
Ed25519.publicKey
publicKeyLengthBytes :: Integral n => n
publicKeyLengthBytes = fromIntegral Ed25519.publicKeySize
signatureToBytes :: ByteArray ba => Signature -> ba
signatureToBytes = convert . unSignature
mkSignature :: ByteArrayAccess ba => ba -> Either CryptoParseError Signature
mkSignature =
onCryptoFailure (Left . CryptoParseCryptoError) (Right . Signature) .
Ed25519.signature
signatureLengthBytes :: Integral n => n
signatureLengthBytes = fromIntegral Ed25519.signatureSize
mkSecretKey :: ByteArrayAccess ba => ba -> Either CryptoParseError SecretKey
mkSecretKey = onCryptoFailure (Left . CryptoParseCryptoError) (Right . SecretKey) .
Ed25519.secretKey
publicKeyTag :: ByteString
publicKeyTag = "\13\15\37\217"
secretKeyTag :: ByteString
secretKeyTag = "\13\15\58\7"
signatureTag :: ByteString
signatureTag = "\9\245\205\134\18"
formatPublicKey :: PublicKey -> Text
formatPublicKey = formatImpl publicKeyTag . unPublicKey
mformatPublicKey :: PublicKey -> MText
mformatPublicKey = mkMTextUnsafe . formatPublicKey
instance Buildable PublicKey where
build = build . formatPublicKey
parsePublicKey :: Text -> Either CryptoParseError PublicKey
parsePublicKey = parseImpl publicKeyTag mkPublicKey
formatSecretKey :: SecretKey -> Text
formatSecretKey = formatImpl secretKeyTag . unSecretKey
instance Buildable SecretKey where
build = build . formatSecretKey
parseSecretKey :: Text -> Either CryptoParseError SecretKey
parseSecretKey = parseImpl secretKeyTag mkSecretKey
formatSignature :: Signature -> Text
formatSignature = formatImpl signatureTag . unSignature
mformatSignature :: Signature -> MText
mformatSignature = mkMTextUnsafe . formatSignature
instance Buildable Signature where
build = build . formatSignature
parseSignature :: Text -> Either CryptoParseError Signature
parseSignature = parseImpl signatureTag mkSignature
sign :: SecretKey -> ByteString -> Signature
sign sk =
Signature .
Ed25519.sign (unSecretKey sk) (unPublicKey (toPublic sk)) . blake2b
checkSignature :: PublicKey -> Signature -> ByteString -> Bool
checkSignature (PublicKey pk) (Signature sig) bytes =
Ed25519.verify pk (blake2b bytes) sig