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)
type NonceFunction a
= Ptr Nonce32
-> Ptr Msg32
-> Ptr SecKey32
-> Ptr Algo16
-> Ptr a
-> CUInt
-> 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
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 ())
-> Ptr a
-> IO ()
foreign import ccall
"secp256k1.h secp256k1_context_set_error_callback"
set_error_callback
:: Ptr Ctx
-> FunPtr (CString -> Ptr a -> IO ())
-> Ptr a
-> IO ()
foreign import ccall
"secp256k1.h secp256k1_ec_pubkey_parse"
ec_pubkey_parse
:: Ptr Ctx
-> Ptr PubKey64
-> Ptr CUChar
-> CSize
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ec_pubkey_serialize"
ec_pubkey_serialize
:: Ptr Ctx
-> Ptr CUChar
-> Ptr CSize
-> 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
-> CSize
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ecdsa_signature_serialize_der"
ecdsa_signature_serialize_der
:: Ptr Ctx
-> Ptr CUChar
-> Ptr CSize
-> Ptr Sig64
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ecdsa_verify"
ecdsa_verify
:: Ptr Ctx
-> Ptr Sig64
-> Ptr Msg32
-> Ptr PubKey64
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ecdsa_sign"
ecdsa_sign
:: Ptr Ctx
-> Ptr Sig64
-> Ptr Msg32
-> Ptr SecKey32
-> FunPtr (NonceFunction a)
-> Ptr a
-> 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
-> Ptr CSize
-> Ptr SecKey32
-> SerFlags
-> IO Ret
foreign import ccall
"secp256k1.h secp256k1_ec_privkey_import"
ec_privkey_import
:: Ptr Ctx
-> Ptr SecKey32
-> Ptr CUChar
-> 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
-> Ptr (Ptr PubKey64)
-> CInt
-> IO Ret