{-|
Module      : Crypto.Secp256k1.Internal
License     : UNLICENSE
Maintainer  : Jean-Pierre Rupp <jprupp@protonmail.ch>
Stability   : experimental
Portability : POSIX

The API for this module may change at any time. This is an internal module only
exposed for hacking and experimentation.
-}
module Crypto.Secp256k1.Internal where

import           Data.ByteString        (ByteString)
import qualified Data.ByteString        as BS
import qualified Data.ByteString.Unsafe as BU
import           Foreign                (FunPtr, Ptr, castPtr)
import           Foreign.C              (CInt (..), CSize (..), CString, CUChar,
                                         CUInt (..))
import           System.IO.Unsafe       (unsafePerformIO)

data LCtx
data PubKey64
data Msg32
data Sig64
data Compact64
data Seed32
data SecKey32
data Tweak32

type CtxFlags = CUInt
type SerFlags = CUInt
type Ret = CInt

type NonceFun a =
    Ptr CUChar ->
    Ptr CUChar ->
    Ptr CUChar ->
    Ptr CUChar ->
    Ptr a ->
    CInt ->
    IO CInt

type Ctx = Ptr LCtx

verify :: CtxFlags
verify :: CtxFlags
verify = CtxFlags
0x0101

sign :: CtxFlags
sign :: CtxFlags
sign = CtxFlags
0x0201

signVerify :: CtxFlags
signVerify :: CtxFlags
signVerify = CtxFlags
0x0301

compressed :: SerFlags
compressed :: CtxFlags
compressed = CtxFlags
0x0102

uncompressed :: SerFlags
uncompressed :: CtxFlags
uncompressed = CtxFlags
0x0002

isSuccess :: Ret -> Bool
isSuccess :: Ret -> Bool
isSuccess Ret
0 = Bool
False
isSuccess Ret
1 = Bool
True
isSuccess Ret
n = [Char] -> Bool
forall a. HasCallStack => [Char] -> a
error ([Char] -> Bool) -> [Char] -> Bool
forall a b. (a -> b) -> a -> b
$ [Char]
"isSuccess expected 0 or 1 but got " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Ret -> [Char]
forall a. Show a => a -> [Char]
show Ret
n

unsafeUseByteString :: ByteString -> ((Ptr a, CSize) -> IO b) -> IO b
unsafeUseByteString :: ByteString -> ((Ptr a, CSize) -> IO b) -> IO b
unsafeUseByteString ByteString
bs (Ptr a, CSize) -> IO b
f =
    ByteString -> (CStringLen -> IO b) -> IO b
forall a. ByteString -> (CStringLen -> IO a) -> IO a
BU.unsafeUseAsCStringLen ByteString
bs ((CStringLen -> IO b) -> IO b) -> (CStringLen -> IO b) -> IO b
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
b, Int
l) ->
    (Ptr a, CSize) -> IO b
f (Ptr CChar -> Ptr a
forall a b. Ptr a -> Ptr b
castPtr Ptr CChar
b, Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
l)

useByteString :: ByteString -> ((Ptr a, CSize) -> IO b) -> IO b
useByteString :: ByteString -> ((Ptr a, CSize) -> IO b) -> IO b
useByteString ByteString
bs (Ptr a, CSize) -> IO b
f =
    ByteString -> (CStringLen -> IO b) -> IO b
forall a. ByteString -> (CStringLen -> IO a) -> IO a
BS.useAsCStringLen ByteString
bs ((CStringLen -> IO b) -> IO b) -> (CStringLen -> IO b) -> IO b
forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
b, Int
l) ->
    (Ptr a, CSize) -> IO b
f (Ptr CChar -> Ptr a
forall a b. Ptr a -> Ptr b
castPtr Ptr CChar
b, Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
l)

unsafePackByteString :: (Ptr a, CSize) -> IO ByteString
unsafePackByteString :: (Ptr a, CSize) -> IO ByteString
unsafePackByteString (Ptr a
b, CSize
l) =
    CStringLen -> IO ByteString
BU.unsafePackMallocCStringLen (Ptr a -> Ptr CChar
forall a b. Ptr a -> Ptr b
castPtr Ptr a
b, CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
l)

packByteString :: (Ptr a, CSize) -> IO ByteString
packByteString :: (Ptr a, CSize) -> IO ByteString
packByteString (Ptr a
b, CSize
l) =
    CStringLen -> IO ByteString
BS.packCStringLen (Ptr a -> Ptr CChar
forall a b. Ptr a -> Ptr b
castPtr Ptr a
b, CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
l)

ctx :: Ctx
ctx :: Ctx
ctx = IO Ctx -> Ctx
forall a. IO a -> a
unsafePerformIO (IO Ctx -> Ctx) -> IO Ctx -> Ctx
forall a b. (a -> b) -> a -> b
$ CtxFlags -> IO Ctx
contextCreate CtxFlags
signVerify
{-# NOINLINE ctx #-}

foreign import ccall safe
    "secp256k1.h secp256k1_context_create"
    contextCreate
    :: CtxFlags
    -> IO Ctx

foreign import ccall safe
    "secp256k1.h secp256k1_context_clone"
    contextClone
    :: Ctx
    -> IO Ctx

foreign import ccall safe
    "secp256k1.h &secp256k1_context_destroy"
    contextDestroy
    :: FunPtr (Ctx -> IO ())

foreign import ccall safe
    "secp256k1.h secp256k1_context_set_illegal_callback"
    setIllegalCallback
    :: Ctx
    -> FunPtr (CString -> Ptr a -> IO ()) -- ^ message, data
    -> Ptr a                              -- ^ data
    -> IO ()

foreign import ccall safe
    "secp256k1.h secp256k1_context_set_error_callback"
    setErrorCallback
    :: Ctx
    -> FunPtr (CString -> Ptr a -> IO ()) -- ^ message, data
    -> Ptr a                              -- ^ data
    -> IO ()

foreign import ccall safe
    "secp256k1.h secp256k1_ec_pubkey_parse"
    ecPubKeyParse
    :: Ctx
    -> Ptr PubKey64
    -> Ptr CUChar -- ^ encoded public key array
    -> CSize      -- ^ size of encoded public key array
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_ec_pubkey_serialize"
    ecPubKeySerialize
    :: 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 safe
    "secp256k1.h secp256k1_ecdsa_signature_parse_compact"
    ecdsaSignatureParseCompact
    :: Ctx
    -> Ptr Sig64
    -> Ptr Compact64
    -> IO Ret


foreign import ccall safe
    "secp256k1.h secp256k1_ecdsa_signature_parse_der"
    ecdsaSignatureParseDer
    :: Ctx
    -> Ptr Sig64
    -> Ptr CUChar -- ^ encoded DER signature
    -> CSize      -- ^ size of encoded signature
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_ecdsa_signature_serialize_der"
    ecdsaSignatureSerializeDer
    :: 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 safe
    "secp256k1.h secp256k1_ecdsa_signature_serialize_compact"
    ecdsaSignatureSerializeCompact
    :: Ctx
    -> Ptr Compact64
    -> Ptr Sig64
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_ecdsa_verify"
    ecdsaVerify
    :: Ctx
    -> Ptr Sig64
    -> Ptr Msg32
    -> Ptr PubKey64
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_ecdsa_signature_normalize"
    ecdsaSignatureNormalize
    :: Ctx
    -> Ptr Sig64 -- ^ output
    -> Ptr Sig64 -- ^ input
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_ecdsa_sign"
    ecdsaSign
    :: Ctx
    -> Ptr Sig64
    -> Ptr Msg32
    -> Ptr SecKey32
    -> FunPtr (NonceFun a)
    -> Ptr a -- ^ nonce data
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_ec_seckey_verify"
    ecSecKeyVerify
    :: Ctx
    -> Ptr SecKey32
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_ec_pubkey_create"
    ecPubKeyCreate
    :: Ctx
    -> Ptr PubKey64
    -> Ptr SecKey32
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_ec_privkey_tweak_add"
    ecSecKeyTweakAdd
    :: Ctx
    -> Ptr SecKey32
    -> Ptr Tweak32
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_ec_privkey_negate"
    ecTweakNegate
    :: Ctx
    -> Ptr Tweak32
    -> IO Ret

foreign import ccall unsafe
    "secp256k1.h secp256k1_ec_pubkey_tweak_add"
    ecPubKeyTweakAdd
    :: Ctx
    -> Ptr PubKey64
    -> Ptr Tweak32
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_ec_privkey_tweak_mul"
    ecSecKeyTweakMul
    :: Ctx
    -> Ptr SecKey32
    -> Ptr Tweak32
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_ec_pubkey_tweak_mul"
    ecPubKeyTweakMul
    :: Ctx
    -> Ptr PubKey64
    -> Ptr Tweak32
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_context_randomize"
    contextRandomize
    :: Ctx
    -> Ptr Seed32
    -> IO Ret

foreign import ccall safe
    "secp256k1.h secp256k1_ec_pubkey_combine"
    ecPubKeyCombine
    :: Ctx
    -> Ptr PubKey64       -- ^ pointer to public key storage
    -> Ptr (Ptr PubKey64) -- ^ pointer to array of public keys
    -> CInt               -- ^ number of public keys
    -> IO Ret