csecp256k1

secp256k1 bindings.
Log | Files | Refs | README | LICENSE

commit aa6b4415aadbbec9304528849695c4000c897267
parent d0d57454fc76ecaa554356c9d583345bc49c197f
Author: Jared Tobin <jared@jtobin.io>
Date:   Fri, 23 Feb 2024 17:10:53 +0400

Most basic stuff working.

Diffstat:
Msecp256k1-sys/lib/Crypto/Secp256k1/Internal.hs | 222+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msecp256k1-sys/secp256k1-sys.cabal | 1+
Msecp256k1-sys/test/Main.hs | 63++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
3 files changed, 274 insertions(+), 12 deletions(-)

diff --git a/secp256k1-sys/lib/Crypto/Secp256k1/Internal.hs b/secp256k1-sys/lib/Crypto/Secp256k1/Internal.hs @@ -8,18 +8,37 @@ module Crypto.Secp256k1.Internal ( , secp256k1_context_create , secp256k1_context_destroy , secp256k1_context_randomize + + -- ec + , secp256k1_ec_pubkey_parse + , secp256k1_ec_pubkey_serialize + , secp256k1_ec_pubkey_create + + -- ecdsa + , MsgHash32 + , PubKey64 + , SecKey32 + , Sig64 + , secp256k1_ecdsa_sign + , secp256k1_ecdsa_verify + , secp256k1_ecdsa_signature_parse_der + , secp256k1_ecdsa_signature_serialize_der + + -- ecdh + -- , secp256k1_ecdh ) where import Foreign.Ptr (Ptr) -import Foreign.C.Types (CInt(..), CUInt(..)) +import Foreign.C.Types (CUChar(..), CInt(..), CUInt(..), CSize(..)) +-- context + +-- secp256k1 context data Context -- 32-byte random seed data Seed32 --- context - -- per secp256k1.h: -- -- > The only valid non-deprecated flag in recent library versions is @@ -52,3 +71,200 @@ foreign import capi -> Ptr Seed32 -> IO CInt +-- ec + +-- 64-byte public key +data PubKey64 + +-- 32-byte secret key +data SecKey32 + +foreign import capi + "secp256k1.h haskellsecp256k1_v0_1_0_ec_pubkey_parse" + secp256k1_ec_pubkey_parse + :: Ptr Context + -> Ptr PubKey64 + -> Ptr CUChar + -> CSize + -> IO CInt + +foreign import capi + "secp256k1.h haskellsecp256k1_v0_1_0_ec_pubkey_serialize" + secp256k1_ec_pubkey_serialize + :: Ptr Context + -> Ptr CUChar + -> Ptr CSize + -> Ptr PubKey64 + -> CUInt + -> IO CInt + +foreign import capi + "secp256k1.h haskellsecp256k1_v0_1_0_ec_pubkey_create" + secp256k1_ec_pubkey_create + :: Ptr Context + -> Ptr PubKey64 + -> Ptr SecKey32 + -> IO CInt + +-- ecdsa + +-- 32-byte message hash +data MsgHash32 + +-- 64-byte signature +data Sig64 + +foreign import capi + "secp256k1.h haskellsecp256k1_v0_1_0_ecdsa_sign" + secp256k1_ecdsa_sign + :: Ptr Context + -> Ptr Sig64 + -> Ptr MsgHash32 + -> Ptr SecKey32 + -> Ptr a + -> Ptr b + -> IO CInt + +foreign import capi + "secp256k1.h haskellsecp256k1_v0_1_0_ecdsa_verify" + secp256k1_ecdsa_verify + :: Ptr Context + -> Ptr Sig64 + -> Ptr MsgHash32 + -> Ptr PubKey64 + -> IO CInt + +foreign import capi + "secp256k1.h haskellsecp256k1_v0_1_0_ecdsa_signature_parse_der" + secp256k1_ecdsa_signature_parse_der + :: Ptr Context + -> Ptr Sig64 + -> Ptr CUChar + -> CSize + -> IO CInt + +foreign import capi + "secp256k1.h haskellsecp256k1_v0_1_0_ecdsa_signature_serialize_der" + secp256k1_ecdsa_signature_serialize_der + :: Ptr Context + -> Ptr CUChar + -> Ptr CSize + -> Ptr Sig64 + -> IO CInt + + +-- ecdh + +-- XX seems fine, but GHC bails on call +-- +-- foreign import capi +-- "secp256k1_ecdh.h haskellsecp256k1_v0_1_0_ecdh" +-- secp256k1_ecdh +-- :: Ptr Context +-- -> Ptr CUChar +-- -> Ptr PubKey64 +-- -> Ptr SecKey32 +-- -> Ptr a +-- -> Ptr b +-- -> IO CInt + +-- schnorr + +-- foreign import capi +-- "secp256k1_schnorrsig.h haskellsecp256k1_v0_1_0_schnorrsig_sign32" +-- secp256k1_schnorrsig_sign32 +-- :: Ptr Context +-- -> Ptr CUChar +-- -> Ptr CUChar +-- -> Ptr KeyPair +-- -> Ptr CUChar +-- -> IO CInt + +-- foreign import capi +-- "secp256k1_schnorrsig.h haskellsecp256k1_v0_1_0_schnorrsig_verify" +-- secp256k1_schnorrsig_verify +-- :: Ptr Context +-- -> Ptr CUChar +-- -> Ptr CUChar +-- -> CSize +-- -> Ptr XOnlyPublicKey +-- -> IO CInt +-- +-- -- foreign import capi +-- -- "secp256k1_extrakeys.h haskellsecp256k1_v0_1_0_keypair_create" +-- -- secp256k1_keypair_create +-- -- :: Ptr Context +-- -- -> Ptr KeyPair +-- -- -> Ptr CUChar +-- -- -> IO CInt +-- -- +-- -- foreign import capi +-- -- "secp256k1_extrakeys.h haskellsecp256k1_v0_1_0_xonly_pubkey_parse" +-- -- secp256k1_xonly_pubkey_parse +-- -- :: Ptr Context +-- -- -> Ptr XOnlyPublicKey +-- -- -> Ptr CUChar +-- -- -> IO CInt +-- -- +-- -- foreign import capi +-- -- "secp256k1_extrakeys.h haskellsecp256k1_v0_1_0_xonly_pubkey_serialize" +-- -- secp256k1_xonly_pubkey_serialize +-- -- :: Ptr Context +-- -- -> Ptr CUChar +-- -- -> Ptr XOnlyPublicKey +-- -- -> IO CInt +-- -- +-- -- foreign import capi +-- -- "secp256k1_extrakeys.h haskellsecp256k1_v0_1_0_xonly_pubkey_from_pubkey" +-- -- secp256k1_xonly_pubkey_from_pubkey +-- -- :: Ptr Context +-- -- -> Ptr XOnlyPublicKey +-- -- -> Ptr CInt +-- -- -> Ptr PublicKey +-- -- -> IO CInt +-- -- +-- -- foreign import capi +-- -- "secp256k1_extrakeys.h haskellsecp256k1_v0_1_0_xonly_pubkey_cmp" +-- -- secp256k1_xonly_pubkey_cmp +-- -- :: Ptr Context +-- -- -> Ptr XOnlyPublicKey +-- -- -> Ptr XOnlyPublicKey +-- -- -> IO CInt +-- -- +-- -- foreign import capi +-- -- "secp256k1_extrakeys.h haskellsecp256k1_v0_1_0_xonly_pubkey_tweak_add" +-- -- secp256k1_xonly_pubkey_tweak_add +-- -- :: Ptr Context +-- -- -> Ptr PublicKey +-- -- -> Ptr XOnlyPublicKey +-- -- -> Ptr CUChar +-- -- -> IO CInt +-- -- +-- -- foreign import capi +-- -- "secp256k1_extrakeys.h haskellsecp256k1_v0_1_0_keypair_xonly_pub" +-- -- secp256k1_keypair_xonly_pub +-- -- :: Ptr Context +-- -- -> Ptr XOnlyPublicKey +-- -- -> Ptr CInt +-- -- -> Ptr KeyPair +-- -- -> IO CInt +-- -- +-- -- foreign import capi +-- -- "secp256k1_extrakeys.h haskellsecp256k1_v0_1_0_keypair_xonly_tweak_add" +-- -- secp256k1_keypair_xonly_tweak_add +-- -- :: Ptr Context +-- -- -> Ptr KeyPair +-- -- -> Ptr CUChar +-- -- -> IO CInt +-- -- +-- -- foreign import capi +-- -- "secp256k1_extrakeys.h haskellsecp256k1_v0_1_0_xonly_pubkey_tweak_add_check" +-- -- secp256k1_xonly_pubkey_tweak_add_check +-- -- :: Ptr Context +-- -- -> Ptr CUChar +-- -- -> CInt +-- -- -> Ptr XOnlyPublicKey +-- -- -> Ptr CUChar +-- -- -> IO CInt +-- -- +-- -- diff --git a/secp256k1-sys/secp256k1-sys.cabal b/secp256k1-sys/secp256k1-sys.cabal @@ -35,6 +35,7 @@ library , depend/secp256k1/src/secp256k1.c cpp-options: + -DENABLE_MODULE_ECDH -DENABLE_MODULE_SCHNORRSIG -DENABLE_MODULE_EXTRAKEYS -DENABLE_MODULE_ELLSWIFT diff --git a/secp256k1-sys/test/Main.hs b/secp256k1-sys/test/Main.hs @@ -34,6 +34,9 @@ _PUB_BYTES_UNCOMPRESSED = 65 _PUB_BYTES_INTERNAL :: Int _PUB_BYTES_INTERNAL = 64 +_SEC_BYTES :: Int +_SEC_BYTES = 32 + _SIG_BYTES :: Int _SIG_BYTES = 64 @@ -53,11 +56,13 @@ units = testGroup "unit tests" [ , ec_pubkey_parse , ec_pubkey_serialize_compressed , ec_pubkey_serialize_uncompressed + , ec_pubkey_create , ecdsa_signature_parse_der , ecdsa_signature_serialize_der , ecdsa_sign , ecdsa_verify_compressed , ecdsa_verify_uncompressed + -- , ecdh_test ] wcontext :: (Ptr Context -> IO a) -> IO a @@ -108,6 +113,13 @@ ec_pubkey_serialize_uncompressed = pub <- serialize_pubkey_uncompressed tex par assertEqual "success" pub _PUB_UNCOMPRESSED +ec_pubkey_create :: TestTree +ec_pubkey_create = + testCase "secp256k1_ec_pubkey_create (success)" $ + wcontext $ \tex -> do + _ <- create_pubkey tex _SEC + assertBool "success" True + -- ecdsa ecdsa_signature_parse_der :: TestTree @@ -147,6 +159,17 @@ ecdsa_verify_uncompressed = suc <- verify_ecdsa tex _PUB_UNCOMPRESSED _HAS _DER assertBool "success" suc +-- ecdh + +-- XX getting dyld error when trying to run +-- +-- ecdh_test :: TestTree +-- ecdh_test = testCase "secp256k1_ecdh (success)" $ +-- wcontext $ \tex -> do +-- -- throws on failure, so any return implies success +-- _ <- ecdh tex _PUB_COMPRESSED _SEC +-- assertBool "success" True + -- wrappers parse_der :: Ptr Context -> BS.ByteString -> IO BS.ByteString @@ -158,15 +181,6 @@ parse_der tex bs = let par = F.castPtr out BS.packCStringLen (par, _SIG_BYTES) -parse_pubkey :: Ptr Context -> BS.ByteString -> IO BS.ByteString -parse_pubkey tex bs = - BS.useAsCStringLen bs $ \(F.castPtr -> pub, fromIntegral -> len) -> - A.allocaBytes _PUB_BYTES_INTERNAL $ \out -> do - suc <- secp256k1_ec_pubkey_parse tex out pub len - when (suc /= 1) $ throwIO Secp256k1Error - let par = F.castPtr out - BS.packCStringLen (par, _PUB_BYTES_INTERNAL) - serialize_der :: Ptr Context -> BS.ByteString -> IO BS.ByteString serialize_der tex bs = A.alloca $ \len -> A.allocaBytes _DER_BYTES $ \out -> @@ -180,6 +194,24 @@ serialize_der tex bs = A.alloca $ \len -> nel = fromIntegral pek BS.packCStringLen (enc, nel) +parse_pubkey :: Ptr Context -> BS.ByteString -> IO BS.ByteString +parse_pubkey tex bs = + BS.useAsCStringLen bs $ \(F.castPtr -> pub, fromIntegral -> len) -> + A.allocaBytes _PUB_BYTES_INTERNAL $ \out -> do + suc <- secp256k1_ec_pubkey_parse tex out pub len + when (suc /= 1) $ throwIO Secp256k1Error + let par = F.castPtr out + BS.packCStringLen (par, _PUB_BYTES_INTERNAL) + +create_pubkey :: Ptr Context -> BS.ByteString -> IO BS.ByteString +create_pubkey tex bs = + BS.useAsCString bs $ \(F.castPtr -> sec) -> + A.allocaBytes _PUB_BYTES_INTERNAL $ \out -> do + suc <- secp256k1_ec_pubkey_create tex out sec + when (suc /= 1) $ throwIO Secp256k1Error + let pub = F.castPtr out + BS.packCStringLen (pub, _PUB_BYTES_INTERNAL) + serialize_pubkey_compressed :: Ptr Context -> BS.ByteString -> IO BS.ByteString serialize_pubkey_compressed tex bs = BS.useAsCString bs $ \(F.castPtr -> pub) -> @@ -236,6 +268,19 @@ verify_ecdsa tex key msg der = do secp256k1_ecdsa_verify tex sip has kep pure (suc == 1) +-- XX resurrect when ecdh problems solved +-- +-- ecdh :: Ptr Context -> BS.ByteString -> BS.ByteString -> IO BS.ByteString +-- ecdh tex pub sec = +-- A.allocaBytes _SEC_BYTES $ \out -> do +-- par <- parse_pubkey tex pub +-- BS.useAsCString par $ \(F.castPtr -> pab) -> +-- BS.useAsCString sec $ \(F.castPtr -> sep) -> do +-- suc <- secp256k1_ecdh tex out pab sep F.nullPtr F.nullPtr +-- when (suc /= 1) $ throwIO Secp256k1Error +-- let key = F.castPtr out +-- BS.packCStringLen (key, _SEC_BYTES) + -- test inputs -- a DER-encoded signature