secp256k1-0.1.0: src/Crypto/Secp256k1/Internal.hs
{-|
Module : Crypto.Secp256k1.Internal
Description : Internal SECP256K1 cryptographic functions
License : PublicDomain
Maintainer : root@haskoin.com
Stability : experimental
Portability : POSIX
The API in this module may change at any time. This is an internal module
only exposed for hacking and experimentation.
-}
module Crypto.Secp256k1.Internal where
import Control.Monad
import Data.ByteString (ByteString, packCStringLen)
import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
import Foreign
import Foreign.C
import System.Entropy
import System.IO.Unsafe
data Ctx = Ctx
newtype PubKey64 = PubKey64 { getPubKey64 :: ByteString }
deriving (Read, Show, Eq, Ord)
newtype Msg32 = Msg32 { getMsg32 :: ByteString }
deriving (Read, Show, Eq, Ord)
newtype Sig64 = Sig64 { getSig64 :: ByteString }
deriving (Read, Show, Eq, Ord)
newtype Seed32 = Seed32 { getSeed32 :: ByteString }
deriving (Read, Show, Eq, Ord)
newtype SecKey32 = SecKey32 { getSecKey32 :: ByteString }
deriving (Read, Show, Eq, Ord)
newtype Tweak32 = Tweak32 { getTweak32 :: ByteString }
deriving (Read, Show, Eq, Ord)
newtype Nonce32 = Nonce32 { getNonce32 :: ByteString }
deriving (Read, Show, Eq, Ord)
newtype Algo16 = Algo16 { getAlgo16 :: ByteString }
deriving (Read, Show, Eq, Ord)
newtype CtxFlags = CtxFlags { getCtxFlags :: CUInt }
deriving (Read, Show, Eq, Ord)
newtype SerFlags = SerFlags { getSerFlags :: CUInt }
deriving (Read, Show, Eq, Ord)
newtype Ret = Ret { getRet :: CInt }
deriving (Read, Show, Eq, Ord)
-- | Nonce32-generating function
type NonceFunction a
= Ptr Nonce32
-> Ptr Msg32
-> Ptr SecKey32
-> Ptr Algo16
-> Ptr a -- ^ extra data
-> CUInt -- ^ attempt
-> Ret
verify :: CtxFlags
verify = CtxFlags 1
sign :: CtxFlags
sign = CtxFlags 2
signVerify :: CtxFlags
signVerify = CtxFlags 3
compressed :: SerFlags
compressed = SerFlags 1
uncompressed :: SerFlags
uncompressed = SerFlags 0
useByteString :: ByteString -> ((Ptr CUChar, CSize) -> IO a) -> IO a
useByteString bs f =
unsafeUseAsCStringLen bs $ \(b, l) -> f (castPtr b, fromIntegral l)
packByteString :: (Ptr CUChar, CSize) -> IO ByteString
packByteString (b, l) = packCStringLen (castPtr b, fromIntegral l)
instance Storable PubKey64 where
sizeOf _ = 64
alignment _ = 1
peek p = PubKey64 <$> packByteString (castPtr p, 64)
poke p (PubKey64 k) = useByteString k $
\(b, _) -> copyArray (castPtr p) b 64
instance Storable Sig64 where
sizeOf _ = 64
alignment _ = 1
peek p = Sig64 <$> packByteString (castPtr p, 64)
poke p (Sig64 k) = useByteString k $
\(b, _) -> copyArray (castPtr p) b 64
instance Storable Msg32 where
sizeOf _ = 32
alignment _ = 1
peek p = Msg32 <$> packByteString (castPtr p, 32)
poke p (Msg32 k) = useByteString k $
\(b, _) -> copyArray (castPtr p) b 32
instance Storable Seed32 where
sizeOf _ = 32
alignment _ = 1
peek p = Seed32 <$> packByteString (castPtr p, 32)
poke p (Seed32 k) = useByteString k $
\(b, _) -> copyArray (castPtr p) b 32
instance Storable SecKey32 where
sizeOf _ = 32
alignment _ = 1
peek p = SecKey32 <$> packByteString (castPtr p, 32)
poke p (SecKey32 k) = useByteString k $
\(b, _) -> copyArray (castPtr p) b 32
instance Storable Tweak32 where
sizeOf _ = 32
alignment _ = 1
peek p = Tweak32 <$> packByteString (castPtr p, 32)
poke p (Tweak32 k) = useByteString k $
\(b, _) -> copyArray (castPtr p) b 32
instance Storable Nonce32 where
sizeOf _ = 32
alignment _ = 1
peek p = Nonce32 <$> packByteString (castPtr p, 32)
poke p (Nonce32 k) = useByteString k $
\(b, _) -> copyArray (castPtr p) b 32
instance Storable Algo16 where
sizeOf _ = 16
alignment _ = 1
peek p = Algo16 <$> packByteString (castPtr p, 16)
poke p (Algo16 k) = useByteString k $
\(b, _) -> copyArray (castPtr p) b 16
isSuccess :: Ret -> Bool
isSuccess (Ret 0) = False
isSuccess (Ret 1) = True
isSuccess _ = undefined
{-# NOINLINE ctx #-}
ctx :: Ptr Ctx
ctx = unsafePerformIO $ do
x <- context_create signVerify
e <- getEntropy 32
ret <- alloca $ \s -> poke s (Seed32 e) >> context_randomize x s
unless (isSuccess ret) $ error "failed to randomize context"
return x
foreign import ccall
"secp256k1.h secp256k1_context_create"
context_create
:: CtxFlags
-> IO (Ptr Ctx)
foreign import ccall
"secp256k1.h secp256k1_context_clone"
context_clone
:: Ptr Ctx
-> IO (Ptr Ctx)
foreign import ccall
"secp256k1.h &secp256k1_context_destroy"
context_destroy
:: FunPtr (Ptr Ctx -> IO ())
foreign import ccall
"secp256k1.h secp256k1_context_set_illegal_callback"
set_illegal_callback
:: Ptr Ctx
-> FunPtr (CString -> Ptr a -> IO ()) -- ^ message, data
-> Ptr a -- ^ data
-> IO ()
foreign import ccall
"secp256k1.h secp256k1_context_set_error_callback"
set_error_callback
:: Ptr Ctx
-> FunPtr (CString -> Ptr a -> IO ()) -- ^ message, data
-> Ptr a -- ^ data
-> IO ()
foreign import ccall
"secp256k1.h secp256k1_ec_pubkey_parse"
ec_pubkey_parse
:: Ptr Ctx
-> Ptr PubKey64
-> Ptr CUChar -- ^ encoded public key array
-> CSize -- ^ size of encoded public key array
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ec_pubkey_serialize"
ec_pubkey_serialize
:: Ptr Ctx
-> Ptr CUChar -- ^ array for encoded public key, must be large enough
-> Ptr CSize -- ^ size of encoded public key, will be updated
-> Ptr PubKey64
-> SerFlags
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ecdsa_signature_parse_der"
ecdsa_signature_parse_der
:: Ptr Ctx
-> Ptr Sig64
-> Ptr CUChar -- ^ encoded DER signature
-> CSize -- ^ size of encoded signature
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ecdsa_signature_serialize_der"
ecdsa_signature_serialize_der
:: Ptr Ctx
-> Ptr CUChar -- ^ array for encoded signature, must be large enough
-> Ptr CSize -- ^ size of encoded signature, will be updated
-> Ptr Sig64
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ecdsa_verify"
ecdsa_verify
:: Ptr Ctx
-> Ptr Sig64
-> Ptr Msg32
-> Ptr PubKey64
-> IO Ret
-- TODO:
-- foreign import ccall
-- "secp256k1.h &secp256k1_nonce_function_rfc6979"
-- nonce_function_rfc6979
-- :: FunPtr (NonceFunction Seed32)
--
-- TODO:
-- foreign import ccall
-- "secp256k1.h &secp256k1_nonce_function_default"
-- nonce_function_default
-- :: FunPtr (NonceFunction Seed32)
foreign import ccall
"secp256k1.h secp256k1_ecdsa_sign"
ecdsa_sign
:: Ptr Ctx
-> Ptr Sig64
-> Ptr Msg32
-> Ptr SecKey32
-> FunPtr (NonceFunction a)
-> Ptr a -- ^ nonce data
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ec_seckey_verify"
ec_seckey_verify
:: Ptr Ctx
-> Ptr SecKey32
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ec_pubkey_create"
ec_pubkey_create
:: Ptr Ctx
-> Ptr PubKey64
-> Ptr SecKey32
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ec_privkey_export"
ec_privkey_export
:: Ptr Ctx
-> Ptr CUChar -- ^ array to store BER-encoded key (allocate 279 bytes)
-> Ptr CSize -- ^ size of previous array, will be updated
-> Ptr SecKey32
-> SerFlags
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ec_privkey_import"
ec_privkey_import
:: Ptr Ctx
-> Ptr SecKey32
-> Ptr CUChar -- ^ BER-encoded private key
-> CSize
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ec_privkey_tweak_add"
ec_privkey_tweak_add
:: Ptr Ctx
-> Ptr SecKey32
-> Ptr Tweak32
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ec_pubkey_tweak_add"
ec_pubkey_tweak_add
:: Ptr Ctx
-> Ptr PubKey64
-> Ptr Tweak32
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ec_privkey_tweak_mul"
ec_privkey_tweak_mul
:: Ptr Ctx
-> Ptr SecKey32
-> Ptr Tweak32
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ec_pubkey_tweak_mul"
ec_pubkey_tweak_mul
:: Ptr Ctx
-> Ptr PubKey64
-> Ptr Tweak32
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_context_randomize"
context_randomize
:: Ptr Ctx
-> Ptr Seed32
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ec_pubkey_combine"
ec_pubkey_combine
:: Ptr Ctx
-> Ptr PubKey64 -- ^ pointer to public key storage
-> Ptr (Ptr PubKey64) -- ^ pointer to array of public keys
-> CInt -- ^ number of public keys
-> IO Ret