{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}

-- |
-- Module      : Crypto.Secp256k1.Prim
-- License     : UNLICENSE
-- Maintainer  : Keagan McClelland <keagan.mcclelland@gmail.com>
-- 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.Prim 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 GHC.TypeNats (Nat)
import System.IO.Unsafe (unsafePerformIO)


data LCtx
data Pubkey64
data XonlyPubkey64
data Keypair96
data Msg32
data RecSig65
data Sig64
data Compact64
data Seed32
data Seckey32
data Tweak32
data SchnorrExtra
data Scratch
data Bytes (n :: Nat)


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 NonceFunHardened a =
    Ptr CUChar ->
    Ptr CUChar ->
    CSize ->
    Ptr CUChar ->
    Ptr CUChar ->
    Ptr CUChar ->
    CSize ->
    Ptr a ->
    IO CInt


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


type Ctx = Ptr LCtx


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


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


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


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


uncompressed :: SerFlags
uncompressed :: SerFlags
uncompressed = SerFlags
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 :: forall a b. 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 :: forall a b. 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 :: forall a. (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 :: forall a. (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
$ SerFlags -> IO Ctx
contextCreate SerFlags
signVerify
{-# NOINLINE ctx #-}


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


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


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


-- secp256k1_context_no_precomp
foreign import ccall safe "secp256k1.h secp256k1_context_no_precomp"
    contextNoPrecomp :: Ctx


-- secp256k1_context_preallocated_clone
foreign import ccall safe "secp256k1.h secp256k1_context_preallocated_clone"
    contextPreallocatedClone :: Ctx -> Ptr (Bytes n) -> IO Ctx


-- secp256k1_context_preallocated_clone_size
foreign import ccall safe "secp256k1.h secp256k1_context_preallocated_clone_size"
    contextPreallocatedCloneSize :: Ctx -> IO CSize


-- secp256k1_context_preallocated_create
foreign import ccall safe "secp256k1.h secp256k1_context_preallocated_create"
    contextPreallocatedCreate :: Ptr (Bytes n) -> CUInt -> IO Ctx


-- secp256k1_context_preallocated_destroy
foreign import ccall safe "secp256k1.h secp256k1_context_preallocated_destroy"
    contextPreallocatedDestroy :: Ctx -> IO ()


-- secp256k1_context_preallocated_size
foreign import ccall safe "secp256k1.h secp256k1_context_preallocated_size"
    contextPreallocatedSize :: CUInt -> IO CSize


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


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


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


-- secp256k1_ecdh
foreign import ccall safe "secp256k1.h secp256k1_ecdh"
    ecdh :: Ctx -> Ptr (Bytes n) -> Ptr Pubkey64 -> Ptr Seckey32 -> FunPtr (EcdhHashFun a) -> Ptr a -> IO Ret


-- secp256k1_ecdh_hash_function_default
foreign import ccall safe "secp256k1.h &secp256k1_ecdh_hash_function_default"
    ecdhHashFunctionDefault :: FunPtr (EcdhHashFun a)


-- secp256k1_ecdh_hash_function_sha256
foreign import ccall safe "secp256k1.h &secp256k1_ecdh_hash_sha256"
    ecdhHashSha256 :: FunPtr (EcdhHashFun a)


-- secp256k1_ecdsa_recover
foreign import ccall safe "secp256k1.h secp256k1_ecdsa_recover"
    ecdsaRecover :: Ctx -> Ptr Pubkey64 -> Ptr RecSig65 -> Ptr Msg32 -> IO Ret


-- secp256k1_ecdsa_recoverable_signature_convert
foreign import ccall safe "secp256k1.h secp256k1_ecdsa_recoverable_signature_convert"
    ecdsaRecoverableSignatureConvert :: Ctx -> Ptr Sig64 -> Ptr RecSig65 -> IO Ret


-- secp256k1_ecdsa_recoverable_signature_parse_compact
foreign import ccall safe "secp256k1.h secp256k1_ecdsa_recoverable_signature_parse_compact"
    ecdsaRecoverableSignatureParseCompact :: Ctx -> Ptr RecSig65 -> Ptr (Bytes 64) -> CInt -> IO Ret


-- secp256k1_ecdsa_recoverable_signature_serialize_compact
foreign import ccall safe "secp256k1.h secp256k1_ecdsa_recoverable_signature_serialize_compact"
    ecdsaRecoverableSignatureSerializeCompact :: Ctx -> Ptr (Bytes 64) -> Ptr CInt -> Ptr RecSig65 -> IO Ret


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


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


-- secp256k1_ecdsa_signature_parse_compact
foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_parse_compact"
    ecdsaSignatureParseCompact ::
        Ctx ->
        Ptr Sig64 ->
        Ptr Compact64 ->
        IO Ret


-- secp256k1_ecdsa_signature_parse_der
foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_parse_der"
    ecdsaSignatureParseDer ::
        Ctx ->
        Ptr Sig64 ->
        -- | encoded DER signature
        Ptr (Bytes n) ->
        -- | size of encoded signature
        CSize ->
        IO Ret


-- secp256k1_ecdsa_signature_serialize_compact
foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_serialize_compact"
    ecdsaSignatureSerializeCompact ::
        Ctx ->
        Ptr Compact64 ->
        Ptr Sig64 ->
        IO Ret


-- secp256k1_ecdsa_signature_serialize_der
foreign import ccall safe "secp256k1.h secp256k1_ecdsa_signature_serialize_der"
    ecdsaSignatureSerializeDer ::
        Ctx ->
        -- | array for encoded signature, must be large enough
        Ptr (Bytes n) ->
        -- | size of encoded signature, will be updated
        Ptr CSize ->
        Ptr Sig64 ->
        IO Ret


-- secp256k1_ecdsa_sign_recoverable
foreign import ccall safe "secp256k1.h secp256k1_ecdsa_sign_recoverable"
    ecdsaSignRecoverable ::
        Ctx -> Ptr RecSig65 -> Ptr Msg32 -> Ptr Seckey32 -> FunPtr (NonceFun a) -> Ptr a -> IO Ret


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


-- secp256k1_ec_privkey_negate
{-# DEPRECATED ecPrivkeyNegate "use ecSeckeyNegate instead" #-}
foreign import ccall safe "secp256k1.h secp256k1_ec_privkey_negate"
    ecPrivkeyNegate ::
        Ctx ->
        Ptr Tweak32 ->
        IO Ret


-- secp256k1_ec_privkey_tweak_add
{-# DEPRECATED ecPrivkeyTweakAdd "use ecSeckeyTweakAdd instead" #-}
foreign import ccall safe "secp256k1.h secp256k1_ec_privkey_tweak_add"
    ecPrivkeyTweakAdd ::
        Ctx ->
        Ptr Seckey32 ->
        Ptr Tweak32 ->
        IO Ret


-- secp256k1_ec_privkey_tweak_mul
{-# DEPRECATED ecPrivkeyTweakMul "use ecSeckeyTweakMul instead" #-}
foreign import ccall safe "secp256k1.h secp256k1_ec_privkey_tweak_mul"
    ecPrivkeyTweakMul ::
        Ctx ->
        Ptr Seckey32 ->
        Ptr Tweak32 ->
        IO Ret


-- secp256k1_ec_pubkey_cmp
foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_cmp"
    ecPubkeyCmp ::
        Ctx ->
        Ptr Pubkey64 ->
        Ptr Pubkey64


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


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


-- secp256k1_ec_pubkey_negate
foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_negate"
    ecPubkeyNegate :: Ctx -> Ptr Pubkey64 -> IO Ret


-- secp256k1_ec_pubkey_parse
foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_parse"
    ecPubkeyParse ::
        Ctx ->
        Ptr Pubkey64 ->
        -- | encoded public key array
        Ptr (Bytes n) ->
        -- | size of encoded public key array
        CSize ->
        IO Ret


-- secp256k1_ec_pubkey_serialize
foreign import ccall safe "secp256k1.h secp256k1_ec_pubkey_serialize"
    ecPubKeySerialize ::
        Ctx ->
        -- | array for encoded public key, must be large enough
        Ptr (Bytes n) ->
        -- | size of encoded public key, will be updated
        Ptr CSize ->
        Ptr Pubkey64 ->
        SerFlags ->
        IO Ret


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


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


-- secp256k1_ec_seckey_negate
foreign import ccall safe "secp256k1.h secp256k1_ec_seckey_negate"
    ecSeckeyNegate :: Ctx -> Ptr Seckey32 -> IO Ret


-- secp256k1_ec_seckey_tweak_add
foreign import ccall safe "secp256k1.h secp256k1_ec_seckey_tweak_add"
    ecSeckeyTweakAdd :: Ctx -> Ptr Seckey32 -> Ptr Tweak32 -> IO Ret


-- secp256k1_ec_seckey_tweak_mul
foreign import ccall safe "secp256k1.h secp256k1_ec_seckey_tweak_mul"
    ecSeckeyTweakMul :: Ctx -> Ptr Seckey32 -> Ptr Tweak32 -> IO Ret


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


-- secp256k1_keypair_create
foreign import ccall safe "secp256k1.h secp256k1_keypair_create"
    keypairCreate :: Ctx -> Ptr Keypair96 -> Ptr Seckey32 -> IO Ret


-- secp256k1_keypair_pub
foreign import ccall safe "secp256k1.h secp256k1_keypair_pub"
    keypairPub :: Ctx -> Ptr Pubkey64 -> Ptr Keypair96 -> IO Ret


-- secp256k1_keypair_sec
foreign import ccall safe "secp256k1.h secp256k1_keypair_sec"
    keypairSec :: Ctx -> Ptr Seckey32 -> Ptr Keypair96 -> IO Ret


-- secp256k1_keypair_xonly_pub
foreign import ccall safe "secp256k1.h secp256k1_keypair_xonly_pub"
    keypairXonlyPub :: Ctx -> Ptr XonlyPubkey64 -> Ptr CInt -> Ptr Keypair96 -> IO Ret


-- secp256k1_keypair_xonly_tweak_add
foreign import ccall safe "secp256k1.h secp256k1_keypair_xonly_tweak_add"
    keypairXonlyTweakAdd :: Ctx -> Ptr Keypair96 -> Ptr Tweak32 -> IO Ret


-- secp256k1_nonce_function_bip340
foreign import ccall safe "secp256k1.h &secp256k1_nonce_function_bip340"
    nonceFunctionBip340 :: FunPtr (NonceFunHardened a)


-- secp256k1_nonce_function_default
foreign import ccall safe "secp256k1.h &secp256k1_nonce_function_default"
    nonceFunctionDefault :: FunPtr (NonceFun a)


-- secp256k1_nonce_function_rfc6979
foreign import ccall safe "secp256k1.h &secp256k1_nonce_function_rfc6979"
    nonceFunctionRfc6979 :: FunPtr (NonceFun a)


-- secp256k1_schnorrsig_sign
foreign import ccall safe "secp256k1.h secp256k1_schnorrsig_sign"
    schnorrsigSign :: Ctx -> Ptr Sig64 -> Ptr Msg32 -> Ptr Keypair96 -> Ptr (Bytes 32) -> IO Ret


-- secp256k1_schnorrsig_sign_custom
foreign import ccall safe "secp256k1.h secp256k1_schnorrsig_sign_custom"
    schnorrsigSignCustom :: Ctx -> Ptr Sig64 -> Ptr (Bytes n) -> CSize -> Ptr Keypair96 -> Ptr SchnorrExtra -> IO Ret


-- secp256k1_schnorrsig_verify
foreign import ccall safe "secp256k1.h secp256k1_schnorrsig_verify"
    schnorrSigSignVerify :: Ctx -> Ptr Sig64 -> Ptr (Bytes n) -> CSize -> Ptr XonlyPubkey64 -> IO Ret


-- secp256k1_scratch_space_create
foreign import ccall safe "secp256k1.h secp256k1_scratch_space_create"
    scratchSpaceCreate :: Ctx -> CSize -> IO (Ptr Scratch)


-- secp256k1_scratch_space_destroy
foreign import ccall safe "secp256k1.h secp256k1_scratch_space_destroy"
    scratchSpaceDestroy :: Ctx -> Ptr Scratch -> IO ()


-- secp256k1_tagged_sha256
foreign import ccall safe "secp256k1.h secp256k1_tagged_sha256"
    taggedSha256 :: Ctx -> Ptr (Bytes 32) -> Ptr (Bytes n) -> CSize -> Ptr (Bytes n) -> CSize -> IO Ret


-- secp256k1_xonly_pubkey_cmp
foreign import ccall safe "secp256k1.h secp256k1_xonly_pubkey_cmp"
    xonlyPubkeyCmp :: Ctx -> Ptr XonlyPubkey64 -> Ptr XonlyPubkey64 -> IO Ret


-- secp256k1_xonly_pubkey_from_pubkey
foreign import ccall safe "secp256k1.h secp256k1_xonly_pubkey_from_pubkey"
    xonlyPubkeyFromPubkey :: Ctx -> Ptr XonlyPubkey64 -> Ptr CInt -> Ptr Pubkey64 -> IO Ret


-- secp256k1_xonly_pubkey_parse
foreign import ccall safe "secp256k1.h secp256k1_xonly_pubkey_parse"
    xonlyPubkeyParse :: Ctx -> Ptr XonlyPubkey64 -> Ptr (Bytes 32) -> IO Ret


-- secp256k1_xonly_pubkey_serialize
foreign import ccall safe "secp256k1.h secp256k1_xonly_pubkey_serialize"
    xonlyPubkeySerialize :: Ctx -> Ptr (Bytes 32) -> Ptr XonlyPubkey64 -> IO Ret


-- secp256k1_xonly_pubkey_tweak_add
foreign import ccall safe "secp256k1.h secp256k1_xonly_pubkey_tweak_add"
    xonlyPubkeyTweakAdd :: Ctx -> Ptr Pubkey64 -> Ptr XonlyPubkey64 -> Ptr Tweak32 -> IO Ret


-- secp256k1_xonly_pubkey_tweak_add_check
foreign import ccall safe "secp256k1.h secp256k1_xonly_pubkey_tweak_add_check"
    xonlyPubkeyTweakAddCheck :: Ctx -> Ptr (Bytes 32) -> CInt -> Ptr XonlyPubkey64 -> Ptr Tweak32 -> IO Ret