module Crypto.Secp256k1
(
Msg, msg, getMsg
, SecKey, secKey, getSecKey, importSecKey, exportSecKey, pubKey
, PubKey, importPubKey, exportPubKey
, Sig, importSig, exportSig
, signMsg, verifySig
, Tweak, tweak, getTweak
, tweakAddSecKey, tweakMulSecKey
, tweakAddPubKey, tweakMulPubKey
, combinePubKeys
) where
import Control.Monad.Reader
import Crypto.Secp256k1.Internal
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Foreign
import System.IO.Unsafe
newtype PubKey = PubKey (ForeignPtr PubKey64)
newtype Msg = Msg (ForeignPtr Msg32)
newtype Sig = Sig (ForeignPtr Sig64)
newtype SecKey = SecKey (ForeignPtr SecKey32)
newtype Tweak = Tweak (ForeignPtr Tweak32)
instance Show PubKey where
show = show . exportPubKey True
instance Show Msg where
show = show . getMsg
instance Show Sig where
show = show . exportSig
instance Show SecKey where
show = show . getSecKey
instance Show Tweak where
show = show . getTweak
instance Eq PubKey where
fp1 == fp2 = getPubKey fp1 == getPubKey fp2
instance Eq Msg where
fm1 == fm2 = getMsg fm1 == getMsg fm2
instance Eq Sig where
fg1 == fg2 = getSig fg1 == getSig fg2
instance Eq SecKey where
fk1 == fk2 = getSecKey fk1 == getSecKey fk2
instance Eq Tweak where
ft1 == ft2 = getTweak ft1 == getTweak ft2
msg :: ByteString -> Maybe Msg
msg bs
| BS.length bs == 32 = unsafePerformIO $ do
fp <- mallocForeignPtr
withForeignPtr fp $ flip poke (Msg32 bs)
return $ Just $ Msg fp
| otherwise = Nothing
secKey :: ByteString -> Maybe SecKey
secKey bs
| BS.length bs == 32 = unsafePerformIO $ do
fp <- mallocForeignPtr
ret <- withForeignPtr fp $ \p -> do
poke p (SecKey32 bs)
ec_seckey_verify ctx p
if isSuccess ret
then return $ Just $ SecKey fp
else return $ Nothing
| otherwise = Nothing
tweak :: ByteString -> Maybe Tweak
tweak bs
| BS.length bs == 32 = unsafePerformIO $ do
fp <- mallocForeignPtr
withForeignPtr fp $ flip poke (Tweak32 bs)
return $ Just $ Tweak fp
| otherwise = Nothing
getSecKey :: SecKey -> ByteString
getSecKey (SecKey fk) = getSecKey32 $ unsafePerformIO $ withForeignPtr fk peek
getPubKey :: PubKey -> ByteString
getPubKey (PubKey fp) = getPubKey64 $ unsafePerformIO $ withForeignPtr fp peek
getSig :: Sig -> ByteString
getSig (Sig fg) = getSig64 $ unsafePerformIO $ withForeignPtr fg peek
getMsg :: Msg -> ByteString
getMsg (Msg fm) = getMsg32 $ unsafePerformIO $ withForeignPtr fm $ peek
getTweak :: Tweak -> ByteString
getTweak (Tweak ft) = getTweak32 $ unsafePerformIO $ withForeignPtr ft $ peek
importPubKey :: ByteString -> Maybe PubKey
importPubKey bs = unsafePerformIO $ do
useByteString bs $ \(b, l) -> do
fp <- mallocForeignPtr
ret <- withForeignPtr fp $ \p -> ec_pubkey_parse ctx p b l
if isSuccess ret then return $ Just $ PubKey fp else return Nothing
exportPubKey :: Bool -> PubKey -> ByteString
exportPubKey compress (PubKey pub) = unsafePerformIO $
withForeignPtr pub $ \p -> alloca $ \l -> allocaBytes 65 $ \o -> do
poke l 65
ret <- ec_pubkey_serialize ctx o l p c
unless (isSuccess ret) $ error "could not serialize public key"
n <- peek l
packByteString (o, n)
where
c = if compress then compressed else uncompressed
importSig :: ByteString -> Maybe Sig
importSig bs = unsafePerformIO $
useByteString bs $ \(b, l) -> do
fg <- mallocForeignPtr
ret <- withForeignPtr fg $ \g -> ecdsa_signature_parse_der ctx g b l
if isSuccess ret then return $ Just $ Sig fg else return Nothing
exportSig :: Sig -> ByteString
exportSig (Sig fg) = unsafePerformIO $
withForeignPtr fg $ \g -> alloca $ \l -> allocaBytes 72 $ \o -> do
poke l 72
ret <- ecdsa_signature_serialize_der ctx o l g
unless (isSuccess ret) $ error "could not serialize signature"
n <- peek l
packByteString (o, n)
verifySig :: PubKey -> Sig -> Msg -> Bool
verifySig (PubKey fp) (Sig fg) (Msg fm) = unsafePerformIO $
withForeignPtr fp $ \p -> withForeignPtr fg $ \g ->
withForeignPtr fm $ \m -> isSuccess <$> ecdsa_verify ctx g m p
signMsg :: SecKey -> Msg -> Sig
signMsg (SecKey fk) (Msg fm) = unsafePerformIO $
withForeignPtr fk $ \k -> withForeignPtr fm $ \m -> do
fg <- mallocForeignPtr
ret <- withForeignPtr fg $ \g -> ecdsa_sign ctx g m k nullFunPtr nullPtr
unless (isSuccess ret) $ error "could not sign message"
return $ Sig fg
pubKey :: SecKey -> PubKey
pubKey (SecKey fk) = unsafePerformIO $
withForeignPtr fk $ \k -> do
fp <- mallocForeignPtr
ret <- withForeignPtr fp $ \p -> ec_pubkey_create ctx p k
unless (isSuccess ret) $ error "could not compute public key"
return $ PubKey fp
importSecKey :: ByteString -> Maybe SecKey
importSecKey bs = unsafePerformIO $
useByteString bs $ \(b, l) -> do
fk <- mallocForeignPtr
ret <- withForeignPtr fk $ \k -> ec_privkey_import ctx k b l
if isSuccess ret then return $ Just $ SecKey fk else return Nothing
exportSecKey :: Bool -> SecKey -> ByteString
exportSecKey compress (SecKey fk) = unsafePerformIO $
withForeignPtr fk $ \k -> alloca $ \l -> allocaBytes 279 $ \o -> do
poke l 279
ret <- ec_privkey_export ctx o l k c
unless (isSuccess ret) $ error "could not export secret key"
n <- peek l
packByteString (o, n)
where
c = if compress then compressed else uncompressed
tweakAddSecKey :: SecKey -> Tweak -> Maybe SecKey
tweakAddSecKey (SecKey fk) (Tweak ft) = unsafePerformIO $
withForeignPtr fk $ \k -> withForeignPtr ft $ \t -> do
fk' <- mallocForeignPtr
ret <- withForeignPtr fk' $ \k' -> do
key <- peek k
poke k' key
ec_privkey_tweak_add ctx k' t
if isSuccess ret then return $ Just $ SecKey fk' else return Nothing
tweakMulSecKey :: SecKey -> Tweak -> Maybe SecKey
tweakMulSecKey (SecKey fk) (Tweak ft) = unsafePerformIO $
withForeignPtr fk $ \k -> withForeignPtr ft $ \t -> do
fk' <- mallocForeignPtr
ret <- withForeignPtr fk' $ \k' -> do
key <- peek k
poke k' key
ec_privkey_tweak_mul ctx k' t
if isSuccess ret then return $ Just $ SecKey fk' else return Nothing
tweakAddPubKey :: PubKey -> Tweak -> Maybe PubKey
tweakAddPubKey (PubKey fp) (Tweak ft) = unsafePerformIO $
withForeignPtr fp $ \p -> withForeignPtr ft $ \t -> do
fp' <- mallocForeignPtr
ret <- withForeignPtr fp' $ \p' -> do
pub <- peek p
poke p' pub
ec_pubkey_tweak_add ctx p' t
if isSuccess ret then return $ Just $ PubKey fp' else return Nothing
tweakMulPubKey :: PubKey -> Tweak -> Maybe PubKey
tweakMulPubKey (PubKey fp) (Tweak ft) = unsafePerformIO $
withForeignPtr fp $ \p -> withForeignPtr ft $ \t -> do
fp' <- mallocForeignPtr
ret <- withForeignPtr fp' $ \p' -> do
pub <- peek p
poke p' pub
ec_pubkey_tweak_mul ctx p' t
if isSuccess ret then return $ Just $ PubKey fp' else return Nothing
combinePubKeys :: [PubKey] -> Maybe PubKey
combinePubKeys pubs = unsafePerformIO $ pointers [] pubs $ \ps ->
allocaArray (length ps) $ \a -> do
pokeArray a ps
fp <- mallocForeignPtr
ret <- withForeignPtr fp $ \p ->
ec_pubkey_combine ctx p a (fromIntegral $ length ps)
if isSuccess ret
then return $ Just $ PubKey fp
else return Nothing
where
pointers ps [] f = f ps
pointers ps (PubKey fp : pubs') f =
withForeignPtr fp $ \p -> pointers (p:ps) pubs' f