mirror of
https://github.com/ilyakooo0/secp256k1-haskell.git
synced 2024-09-11 12:25:38 +03:00
Remove non-standard support
I removed support for all non-standard features: - ECDH - Schnorr Signatures - Signature Recovery These features are rarely compiled in shared libraries avaliable from distribution repositories. Also, they are not needed for any Haskoin project, so there is little incentive for me to continue maintaining them, especially when I have no good way to test this code. Please make your own fork of this library if you wish to add these back.
This commit is contained in:
parent
f8e9dfbed5
commit
0f862c2198
41
.travis.yml
Normal file
41
.travis.yml
Normal file
@ -0,0 +1,41 @@
|
||||
# This is the simple Travis configuration, which is intended for use
|
||||
# on applications which do not require cross-platform and
|
||||
# multiple-GHC-version support. For more information and other
|
||||
# options, see:
|
||||
#
|
||||
# https://docs.haskellstack.org/en/stable/travis_ci/
|
||||
#
|
||||
# Copy these contents into the root directory of your Github project in a file
|
||||
# named .travis.yml
|
||||
|
||||
# Choose a build environment
|
||||
dist: xenial
|
||||
|
||||
# Do not choose a language; we provide our own build tools.
|
||||
language: generic
|
||||
|
||||
# Caching so the next build will be fast too.
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.stack
|
||||
|
||||
# Ensure necessary system libraries are present
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libgmp-dev
|
||||
- secp256k1
|
||||
|
||||
before_install:
|
||||
# Download and unpack the stack executable
|
||||
- mkdir -p ~/.local/bin
|
||||
- export PATH=$HOME/.local/bin:$PATH
|
||||
- travis_retry curl -L https://get.haskellstack.org/stable/linux-x86_64.tar.gz | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'
|
||||
|
||||
install:
|
||||
# Build dependencies
|
||||
- stack --no-terminal --install-ghc test --only-dependencies
|
||||
|
||||
script:
|
||||
# Build the package, its tests, and its docs and run the tests
|
||||
- stack --no-terminal test --haddock --no-haddock-deps
|
15
CHANGELOG.md
15
CHANGELOG.md
@ -4,11 +4,26 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.6
|
||||
### Fixed
|
||||
- Compiles with all flags now.
|
||||
|
||||
### Added
|
||||
- Script to compile with all flags.
|
||||
|
||||
### Removed
|
||||
- Remove ECDH support.
|
||||
- Remove Schnorr support.
|
||||
- Remove Recovery support.
|
||||
|
||||
## 0.2.5
|
||||
### Changed
|
||||
- Reuse context aggressively.
|
||||
- Generate context in a single thread.
|
||||
|
||||
### Fixed
|
||||
- Memory deallocation bug.
|
||||
|
||||
## 0.2.4
|
||||
### Changed
|
||||
- Update Cabal and package version.
|
||||
|
28
package.yaml
28
package.yaml
@ -1,5 +1,5 @@
|
||||
name: secp256k1-haskell
|
||||
version: 0.2.5
|
||||
version: 0.3.0
|
||||
synopsis: Bindings for secp256k1
|
||||
description: Sign and verify signatures using the secp256k1 library.
|
||||
category: Crypto
|
||||
@ -23,15 +23,6 @@ dependencies:
|
||||
- hashable
|
||||
- QuickCheck
|
||||
- string-conversions
|
||||
when:
|
||||
- condition: flag(ecdh)
|
||||
cpp-options: -DECDH
|
||||
- condition: flag(schnorr)
|
||||
cpp-options: -DSCHNORR
|
||||
- condition: flag(recovery)
|
||||
cpp-options: -DRECOVERY
|
||||
- condition: flag(negate)
|
||||
cpp-options: -DNEGATE
|
||||
library:
|
||||
source-dirs: src
|
||||
generated-exposed-modules:
|
||||
@ -55,20 +46,3 @@ tests:
|
||||
- monad-par
|
||||
- mtl
|
||||
- HUnit
|
||||
flags:
|
||||
negate:
|
||||
description: "Enable tweak negate"
|
||||
manual: true
|
||||
default: false
|
||||
ecdh:
|
||||
description: "Enable (experimental) ECDH APIs"
|
||||
manual: true
|
||||
default: false
|
||||
schnorr:
|
||||
description: "Enable BIP-340 (Schnorr) APIs"
|
||||
manual: true
|
||||
default: false
|
||||
recovery:
|
||||
description: "Enable signature key recovery APIs"
|
||||
manual: true
|
||||
default: false
|
||||
|
@ -4,10 +4,10 @@ cabal-version: 2.0
|
||||
--
|
||||
-- see: https://github.com/sol/hpack
|
||||
--
|
||||
-- hash: f64a6c7d68d58fab5fc141dd7bda78089fe9403dc39525641eba1ca0fd92593c
|
||||
-- hash: d55c31829652e236145323f89ee1ec9c61e4f18712778a13011c688d36db8b19
|
||||
|
||||
name: secp256k1-haskell
|
||||
version: 0.2.5
|
||||
version: 0.3.0
|
||||
synopsis: Bindings for secp256k1
|
||||
description: Sign and verify signatures using the secp256k1 library.
|
||||
category: Crypto
|
||||
@ -27,26 +27,6 @@ source-repository head
|
||||
type: git
|
||||
location: https://github.com/haskoin/secp256k1-haskell.git
|
||||
|
||||
flag ecdh
|
||||
description: Enable (experimental) ECDH APIs
|
||||
manual: True
|
||||
default: False
|
||||
|
||||
flag negate
|
||||
description: Enable tweak negate
|
||||
manual: True
|
||||
default: False
|
||||
|
||||
flag recovery
|
||||
description: Enable signature key recovery APIs
|
||||
manual: True
|
||||
default: False
|
||||
|
||||
flag schnorr
|
||||
description: Enable BIP-340 (Schnorr) APIs
|
||||
manual: True
|
||||
default: False
|
||||
|
||||
library
|
||||
exposed-modules:
|
||||
Crypto.Secp256k1
|
||||
@ -68,14 +48,6 @@ library
|
||||
, entropy
|
||||
, hashable
|
||||
, string-conversions
|
||||
if flag(ecdh)
|
||||
cpp-options: -DECDH
|
||||
if flag(schnorr)
|
||||
cpp-options: -DSCHNORR
|
||||
if flag(recovery)
|
||||
cpp-options: -DRECOVERY
|
||||
if flag(negate)
|
||||
cpp-options: -DNEGATE
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite spec
|
||||
@ -103,13 +75,5 @@ test-suite spec
|
||||
, mtl
|
||||
, secp256k1-haskell
|
||||
, string-conversions
|
||||
if flag(ecdh)
|
||||
cpp-options: -DECDH
|
||||
if flag(schnorr)
|
||||
cpp-options: -DSCHNORR
|
||||
if flag(recovery)
|
||||
cpp-options: -DRECOVERY
|
||||
if flag(negate)
|
||||
cpp-options: -DNEGATE
|
||||
default-language: Haskell2010
|
||||
build-tool-depends: hspec-discover:hspec-discover
|
||||
|
@ -39,16 +39,6 @@ module Crypto.Secp256k1
|
||||
, CompactSig(..)
|
||||
, exportCompactSig
|
||||
, importCompactSig
|
||||
#ifdef RECOVERY
|
||||
-- ** Recovery
|
||||
, RecSig
|
||||
, CompactRecSig(..)
|
||||
, importCompactRecSig
|
||||
, exportCompactRecSig
|
||||
, convertRecSig
|
||||
, signRecMsg
|
||||
, recover
|
||||
#endif
|
||||
|
||||
-- * Addition & Multiplication
|
||||
, Tweak
|
||||
@ -59,29 +49,7 @@ module Crypto.Secp256k1
|
||||
, tweakAddPubKey
|
||||
, tweakMulPubKey
|
||||
, combinePubKeys
|
||||
#ifdef NEGATE
|
||||
, tweakNegate
|
||||
#endif
|
||||
|
||||
#ifdef ECDH
|
||||
-- * Diffie Hellman
|
||||
, ecdh
|
||||
#endif
|
||||
|
||||
#ifdef SCHNORR
|
||||
, XOnlyPubKey
|
||||
, SchnorrSig
|
||||
, signMsgSchnorr
|
||||
, exportSchnorrSig
|
||||
, importSchnorrSig
|
||||
, exportXOnlyPubKey
|
||||
, importXOnlyPubKey
|
||||
, verifyMsgSchnorr
|
||||
, deriveXOnlyPubKey
|
||||
, schnorrTweakAddPubKey
|
||||
, schnorrTweakAddSecKey
|
||||
, testTweakXOnlyPubKey
|
||||
#endif
|
||||
) where
|
||||
|
||||
import Control.Monad (replicateM, unless, (<=<))
|
||||
@ -93,9 +61,8 @@ import Data.Hashable (Hashable (..))
|
||||
import Data.Maybe (fromJust, fromMaybe, isJust)
|
||||
import Data.String (IsString (..))
|
||||
import Data.String.Conversions (ConvertibleStrings, cs)
|
||||
import Foreign (ForeignPtr, alloca,
|
||||
allocaArray, allocaBytes,
|
||||
mallocForeignPtr,
|
||||
import Foreign (ForeignPtr, alloca, allocaArray,
|
||||
allocaBytes, mallocForeignPtr,
|
||||
nullPtr, peek, poke, pokeArray,
|
||||
withForeignPtr)
|
||||
import System.IO.Unsafe (unsafePerformIO)
|
||||
@ -113,10 +80,6 @@ newtype Sig = Sig (ForeignPtr Sig64)
|
||||
newtype SecKey = SecKey (ForeignPtr SecKey32)
|
||||
newtype Tweak = Tweak (ForeignPtr Tweak32)
|
||||
newtype RecSig = RecSig (ForeignPtr RecSig65)
|
||||
#ifdef SCHNORR
|
||||
newtype XOnlyPubKey = XOnlyPubKey (ForeignPtr XOnlyPubKey64)
|
||||
newtype SchnorrSig = SchnorrSig (ForeignPtr SchnorrSig64)
|
||||
#endif
|
||||
|
||||
instance NFData PubKey where
|
||||
rnf (PubKey p) = p `seq` ()
|
||||
@ -185,30 +148,6 @@ instance Hashable Sig where
|
||||
instance Show Sig where
|
||||
showsPrec _ = shows . B16.encode . exportSig
|
||||
|
||||
#ifdef RECOVERY
|
||||
recSigFromString :: String -> Maybe RecSig
|
||||
recSigFromString str = do
|
||||
bs <- decodeHex str
|
||||
rs <- either (const Nothing) Just $ decode bs
|
||||
importCompactRecSig rs
|
||||
|
||||
instance Hashable RecSig where
|
||||
i `hashWithSalt` s = i `hashWithSalt` encode (exportCompactRecSig s)
|
||||
|
||||
instance Read RecSig where
|
||||
readPrec = parens $ do
|
||||
String str <- lexP
|
||||
maybe pfail return $ recSigFromString str
|
||||
|
||||
instance IsString RecSig where
|
||||
fromString = fromMaybe e . recSigFromString
|
||||
where
|
||||
e = error "Could not decode signature from hex string"
|
||||
|
||||
instance Show RecSig where
|
||||
showsPrec _ = shows . B16.encode . encode . exportCompactRecSig
|
||||
#endif
|
||||
|
||||
instance Read SecKey where
|
||||
readPrec = parens $ do
|
||||
String str <- lexP
|
||||
@ -248,61 +187,12 @@ instance Eq Msg where
|
||||
instance Eq Sig where
|
||||
fg1 == fg2 = exportCompactSig fg1 == exportCompactSig fg2
|
||||
|
||||
#ifdef RECOVERY
|
||||
instance Eq RecSig where
|
||||
fg1 == fg2 = exportCompactRecSig fg1 == exportCompactRecSig fg2
|
||||
#endif
|
||||
|
||||
instance Eq SecKey where
|
||||
fk1 == fk2 = getSecKey fk1 == getSecKey fk2
|
||||
|
||||
instance Eq Tweak where
|
||||
ft1 == ft2 = getTweak ft1 == getTweak ft2
|
||||
|
||||
#ifdef SCHNORR
|
||||
instance NFData SchnorrSig where
|
||||
rnf (SchnorrSig p) = p `seq` ()
|
||||
|
||||
instance Show SchnorrSig where
|
||||
showsPrec _ = shows . B16.encode . exportSchnorrSig
|
||||
|
||||
instance Read SchnorrSig where
|
||||
readPrec = parens $ do
|
||||
String str <- lexP
|
||||
maybe pfail return $ importSchnorrSig =<< decodeHex str
|
||||
|
||||
instance Eq SchnorrSig where
|
||||
fg1 == fg2 = exportSchnorrSig fg1 == exportSchnorrSig fg2
|
||||
|
||||
instance IsString SchnorrSig where
|
||||
fromString = fromMaybe e . (importSchnorrSig <=< decodeHex) where
|
||||
e = error "Could not decode Schnorr signature from hex string"
|
||||
|
||||
instance Hashable SchnorrSig where
|
||||
i `hashWithSalt` s = i `hashWithSalt` exportSchnorrSig s
|
||||
|
||||
instance NFData XOnlyPubKey where
|
||||
rnf (XOnlyPubKey p) = p `seq` ()
|
||||
|
||||
instance Show XOnlyPubKey where
|
||||
showsPrec _ = shows . B16.encode . exportXOnlyPubKey
|
||||
|
||||
instance Read XOnlyPubKey where
|
||||
readPrec = do
|
||||
String str <- lexP
|
||||
maybe pfail return $ importXOnlyPubKey =<< decodeHex str
|
||||
|
||||
instance Eq XOnlyPubKey where
|
||||
fp1 == fp2 = getXOnlyPubKey fp1 == getXOnlyPubKey fp2
|
||||
|
||||
instance IsString XOnlyPubKey where
|
||||
fromString = fromMaybe e . (importXOnlyPubKey <=< decodeHex) where
|
||||
e = error "Could not decode public key from hex string"
|
||||
|
||||
instance Hashable XOnlyPubKey where
|
||||
i `hashWithSalt` k = i `hashWithSalt` exportXOnlyPubKey k
|
||||
#endif
|
||||
|
||||
-- | Import 32-byte 'ByteString' as 'Msg'.
|
||||
msg :: ByteString -> Maybe Msg
|
||||
msg bs
|
||||
@ -500,65 +390,8 @@ combinePubKeys pubs = unsafePerformIO $ pointers [] pubs $ \ps ->
|
||||
pointers ps (PubKey fp : pubs') f =
|
||||
withForeignPtr fp $ \p -> pointers (p:ps) pubs' f
|
||||
|
||||
#ifdef RECOVERY
|
||||
-- | Parse a compact ECDSA signature (64 bytes + recovery id).
|
||||
importCompactRecSig :: CompactRecSig -> Maybe RecSig
|
||||
importCompactRecSig cr =
|
||||
if getCompactRecSigV cr `notElem` [0,1,2,3]
|
||||
then Nothing
|
||||
else withContext $ \ctx -> alloca $ \pc -> do
|
||||
let
|
||||
c = CompactSig (getCompactRecSigR cr) (getCompactRecSigS cr)
|
||||
recid = fromIntegral $ getCompactRecSigV cr
|
||||
poke pc c
|
||||
fg <- mallocForeignPtr
|
||||
ret <- withForeignPtr fg $ \pg ->
|
||||
ecdsaRecoverableSignatureParseCompact ctx pg pc recid
|
||||
if isSuccess ret then return $ Just $ RecSig fg else return Nothing
|
||||
|
||||
-- | Serialize an ECDSA signature in compact format (64 bytes + recovery id).
|
||||
exportCompactRecSig :: RecSig -> CompactRecSig
|
||||
exportCompactRecSig (RecSig fg) = withContext $ \ctx ->
|
||||
withForeignPtr fg $ \pg -> alloca $ \pc -> alloca $ \pr -> do
|
||||
ret <- ecdsaRecoverableSignatureSerializeCompact ctx pc pr pg
|
||||
unless (isSuccess ret) $ error "Could not obtain compact signature"
|
||||
CompactSig r s <- peek pc
|
||||
v <- fromIntegral <$> peek pr
|
||||
return $ CompactRecSig r s v
|
||||
|
||||
-- | Convert a recoverable signature into a normal signature.
|
||||
convertRecSig :: RecSig -> Sig
|
||||
convertRecSig (RecSig frg) = withContext $ \ctx ->
|
||||
withForeignPtr frg $ \prg -> do
|
||||
fg <- mallocForeignPtr
|
||||
ret <- withForeignPtr fg $ \pg ->
|
||||
ecdsaRecoverableSignatureConvert ctx pg prg
|
||||
unless (isSuccess ret) $
|
||||
error "Could not convert a recoverable signature"
|
||||
return $ Sig fg
|
||||
|
||||
-- | Create a recoverable ECDSA signature.
|
||||
signRecMsg :: SecKey -> Msg -> RecSig
|
||||
signRecMsg (SecKey fk) (Msg fm) = withContext $ \ctx ->
|
||||
withForeignPtr fk $ \k -> withForeignPtr fm $ \m -> do
|
||||
fg <- mallocForeignPtr
|
||||
ret <- withForeignPtr fg $ \g ->
|
||||
ecdsaSignRecoverable ctx g m k nullPtr nullPtr
|
||||
unless (isSuccess ret) $ error "could not sign message"
|
||||
return $ RecSig fg
|
||||
|
||||
-- | Recover an ECDSA public key from a signature.
|
||||
recover :: RecSig -> Msg -> Maybe PubKey
|
||||
recover (RecSig frg) (Msg fm) = withContext $ \ctx ->
|
||||
withForeignPtr frg $ \prg -> withForeignPtr fm $ \pm -> do
|
||||
fp <- mallocForeignPtr
|
||||
ret <- withForeignPtr fp $ \pp -> ecdsaRecover ctx pp prg pm
|
||||
if isSuccess ret then return $ Just $ PubKey fp else return Nothing
|
||||
#endif
|
||||
|
||||
#ifdef NEGATE
|
||||
tweakNegate :: Tweak -> Maybe Tweak
|
||||
tweakNegate (Tweak fk) = withContext $ \ctx -> do
|
||||
tweakNegate (Tweak fk) = unsafePerformIO $ do
|
||||
fnew <- mallocForeignPtr
|
||||
peeked <- withForeignPtr fk peek
|
||||
ret <- withForeignPtr fnew $ \n -> do
|
||||
@ -568,121 +401,6 @@ tweakNegate (Tweak fk) = withContext $ \ctx -> do
|
||||
if isSuccess ret
|
||||
then Just (Tweak fnew)
|
||||
else Nothing
|
||||
#endif
|
||||
|
||||
#ifdef ECDH
|
||||
-- | Compute Diffie-Hellman secret.
|
||||
ecdh :: PubKey -> SecKey -> ByteString
|
||||
ecdh (PubKey pk) (SecKey sk) = withContext $ \ctx ->
|
||||
withForeignPtr pk $ \pkPtr -> withForeignPtr sk $ \skPtr ->
|
||||
allocaBytes size $ \o -> do
|
||||
ret <- ecEcdh ctx o pkPtr skPtr nullPtr nullPtr
|
||||
unless (isSuccess ret) $ error "ecdh failed"
|
||||
packByteString (o, size)
|
||||
where
|
||||
size :: Integral a => a
|
||||
size = 32
|
||||
#endif
|
||||
|
||||
#ifdef SCHNORR
|
||||
-- Get 64-byte x-only public key.
|
||||
getXOnlyPubKey :: XOnlyPubKey -> ByteString
|
||||
getXOnlyPubKey (XOnlyPubKey fp) =
|
||||
fromShort $ getXOnlyPubKey64 $ unsafePerformIO $ withForeignPtr fp peek
|
||||
|
||||
-- | Add tweak to public key. Tweak is multiplied first by G to obtain a point.
|
||||
schnorrTweakAddPubKey :: XOnlyPubKey -> Tweak -> Maybe (XOnlyPubKey, CInt)
|
||||
schnorrTweakAddPubKey (XOnlyPubKey fp) (Tweak ft) = withContext $ \ctx ->
|
||||
withForeignPtr fp $ \p -> withForeignPtr ft $ \t -> alloca $ \is_negated -> do
|
||||
fp' <- mallocForeignPtr
|
||||
ret <- withForeignPtr fp' $ \p' -> do
|
||||
pub <- peek p
|
||||
poke p' pub
|
||||
schnorrPubKeyTweakAdd ctx p' is_negated t
|
||||
peeked_is_negated <- peek is_negated
|
||||
if isSuccess ret then return $ Just $ (XOnlyPubKey fp', peeked_is_negated) else return Nothing
|
||||
|
||||
-- | Add tweak to secret key.
|
||||
schnorrTweakAddSecKey :: SecKey -> Tweak -> Maybe SecKey
|
||||
schnorrTweakAddSecKey (SecKey fk) (Tweak ft) = withContext $ \ctx ->
|
||||
withForeignPtr fk $ \k -> withForeignPtr ft $ \t -> do
|
||||
fk' <- mallocForeignPtr
|
||||
ret <- withForeignPtr fk' $ \k' -> do
|
||||
key <- peek k
|
||||
poke k' key
|
||||
schnorrSecKeyTweakAdd ctx k' t
|
||||
if isSuccess ret then return $ Just $ SecKey fk' else return Nothing
|
||||
|
||||
signMsgSchnorr :: SecKey -> Msg -> SchnorrSig
|
||||
signMsgSchnorr (SecKey fk) (Msg fm) =
|
||||
withContext $ \ctx ->
|
||||
withForeignPtr fk $ \k ->
|
||||
withForeignPtr fm $ \m -> do
|
||||
fg <- mallocForeignPtr
|
||||
ret <-
|
||||
withForeignPtr fg $ \g ->
|
||||
schnorrSign ctx g m k nullPtr nullPtr
|
||||
unless (isSuccess ret) $ error "could not schnorr-sign message"
|
||||
return $ SchnorrSig fg
|
||||
|
||||
exportSchnorrSig :: SchnorrSig -> ByteString
|
||||
exportSchnorrSig (SchnorrSig fg) = withContext $ \ctx ->
|
||||
withForeignPtr fg $ \g -> allocaBytes 64 $ \o -> do
|
||||
ret <- signatureSerializeSchnorr ctx o g
|
||||
unless (isSuccess ret) $ error "could not serialize schnorr signature"
|
||||
packByteString (o, 64)
|
||||
|
||||
importXOnlyPubKey :: ByteString -> Maybe XOnlyPubKey
|
||||
importXOnlyPubKey bs
|
||||
| BS.length bs == 32 = withContext $ \ctx -> do
|
||||
fp <- mallocForeignPtr
|
||||
ret <- withForeignPtr fp $ \pfp -> useByteString bs $ \(inp, _) ->
|
||||
schnorrXOnlyPubKeyParse ctx pfp inp
|
||||
if isSuccess ret
|
||||
then return $ Just $ XOnlyPubKey fp
|
||||
else return Nothing
|
||||
| otherwise = Nothing
|
||||
|
||||
importSchnorrSig :: ByteString -> Maybe SchnorrSig
|
||||
importSchnorrSig bs
|
||||
| BS.length bs == 64 = withContext $ \ctx -> do
|
||||
fp <- mallocForeignPtr
|
||||
ret <- withForeignPtr fp $ \pfp -> useByteString bs $ \(inp, _) ->
|
||||
schnorrSignatureParse ctx pfp inp
|
||||
if isSuccess ret
|
||||
then return $ Just $ SchnorrSig fp
|
||||
else return Nothing
|
||||
| otherwise = Nothing
|
||||
|
||||
verifyMsgSchnorr :: XOnlyPubKey -> SchnorrSig -> Msg -> Bool
|
||||
verifyMsgSchnorr (XOnlyPubKey fp) (SchnorrSig fg) (Msg fm) = withContext $ \ctx ->
|
||||
withForeignPtr fp $ \p -> withForeignPtr fg $ \g ->
|
||||
withForeignPtr fm $ \m -> isSuccess <$> schnorrSignatureVerify ctx g m p
|
||||
|
||||
exportXOnlyPubKey :: XOnlyPubKey -> ByteString
|
||||
exportXOnlyPubKey (XOnlyPubKey pub) = withContext $ \ctx ->
|
||||
withForeignPtr pub $ \p -> allocaBytes 32 $ \o -> do
|
||||
ret <- schnorrPubKeySerialize ctx o p
|
||||
unless (isSuccess ret) $ error "could not serialize x-only public key"
|
||||
packByteString (o, 32)
|
||||
|
||||
deriveXOnlyPubKey :: SecKey -> XOnlyPubKey
|
||||
deriveXOnlyPubKey (SecKey fk) = withContext $ \ctx -> withForeignPtr fk $ \k -> do
|
||||
fp <- mallocForeignPtr
|
||||
ret <- withForeignPtr fp $ \p -> schnorrXOnlyPubKeyCreate ctx p k
|
||||
unless (isSuccess ret) $ error "could not derive x-only public key"
|
||||
return $ XOnlyPubKey fp
|
||||
|
||||
testTweakXOnlyPubKey :: XOnlyPubKey -> CInt -> XOnlyPubKey -> Tweak -> Bool
|
||||
testTweakXOnlyPubKey (XOnlyPubKey fp) is_negated (XOnlyPubKey internal) (Tweak ft) =
|
||||
withContext $ \ctx ->
|
||||
withForeignPtr fp $ \p ->
|
||||
withForeignPtr internal $ \internalp ->
|
||||
withForeignPtr ft $ \t -> do
|
||||
ret <- xOnlyPubKeyTweakTest ctx p is_negated internalp t
|
||||
return $ isSuccess ret
|
||||
-- End of Schnorr block
|
||||
#endif
|
||||
|
||||
instance Arbitrary Msg where
|
||||
arbitrary = gen_msg
|
||||
@ -699,10 +417,3 @@ instance Arbitrary SecKey where
|
||||
|
||||
instance Arbitrary PubKey where
|
||||
arbitrary = derivePubKey <$> arbitrary
|
||||
|
||||
#ifdef SCHNORR
|
||||
instance Arbitrary XOnlyPubKey where
|
||||
arbitrary = do
|
||||
key <- arbitrary
|
||||
return $ deriveXOnlyPubKey key
|
||||
#endif
|
||||
|
@ -23,8 +23,8 @@ import Data.Serialize (Serialize (..))
|
||||
import qualified Data.Serialize.Get as Get
|
||||
import qualified Data.Serialize.Put as Put
|
||||
import Data.Void (Void)
|
||||
import Foreign (FunPtr, Ptr, Storable (..),
|
||||
alloca, castPtr, copyArray)
|
||||
import Foreign (FunPtr, Ptr, Storable (..), alloca,
|
||||
castPtr, copyArray)
|
||||
import Foreign.C (CInt (..), CSize (..), CString, CUChar,
|
||||
CUInt (..))
|
||||
import GHC.Generics (Generic)
|
||||
@ -52,16 +52,6 @@ data CompactSig =
|
||||
newtype RecSig65 = RecSig65 { getRecSig65 :: ShortByteString }
|
||||
deriving (Read, Show, Eq, Ord, Generic, NFData)
|
||||
|
||||
#ifdef RECOVERY
|
||||
data CompactRecSig =
|
||||
CompactRecSig
|
||||
{ getCompactRecSigR :: !ShortByteString
|
||||
, getCompactRecSigS :: !ShortByteString
|
||||
, getCompactRecSigV :: !Word8
|
||||
}
|
||||
deriving (Show, Eq, Ord, Generic, NFData)
|
||||
#endif
|
||||
|
||||
newtype Seed32 = Seed32 { getSeed32 :: ShortByteString }
|
||||
deriving (Read, Show, Eq, Ord, Generic, NFData)
|
||||
|
||||
@ -86,14 +76,6 @@ newtype SerFlags = SerFlags { getSerFlags :: CUInt }
|
||||
newtype Ret = Ret { getRet :: CInt }
|
||||
deriving (Read, Show, Eq, Ord, Generic, NFData)
|
||||
|
||||
#ifdef SCHNORR
|
||||
newtype XOnlyPubKey64 = XOnlyPubKey64 { getXOnlyPubKey64 :: ShortByteString }
|
||||
deriving (Read, Show, Eq, Ord, Generic, NFData)
|
||||
|
||||
newtype SchnorrSig64 = SchnorrSig64 { getSchnorrSig64 :: ShortByteString }
|
||||
deriving (Read, Show, Eq, Ord, Generic, NFData)
|
||||
#endif
|
||||
|
||||
verify :: CtxFlags
|
||||
verify = CtxFlags 0x0101
|
||||
|
||||
@ -116,22 +98,6 @@ useByteString bs f =
|
||||
packByteString :: (Ptr CUChar, CSize) -> IO ByteString
|
||||
packByteString (b, l) = BS.packCStringLen (castPtr b, fromIntegral l)
|
||||
|
||||
#if SCHNORR
|
||||
instance Storable XOnlyPubKey64 where
|
||||
sizeOf _ = 64
|
||||
alignment _ = 1
|
||||
peek p = XOnlyPubKey64 . toShort <$> packByteString (castPtr p, 64)
|
||||
poke p (XOnlyPubKey64 k) = useByteString (fromShort k) $
|
||||
\(b, _) -> copyArray (castPtr p) b 64
|
||||
|
||||
instance Storable SchnorrSig64 where
|
||||
sizeOf _ = 64
|
||||
alignment _ = 1
|
||||
peek p = SchnorrSig64 . toShort <$> packByteString (castPtr p, 64)
|
||||
poke p (SchnorrSig64 k) = useByteString (fromShort k) $
|
||||
\(b, _) -> copyArray (castPtr p) b 64
|
||||
#endif
|
||||
|
||||
instance Storable PubKey64 where
|
||||
sizeOf _ = 64
|
||||
alignment _ = 1
|
||||
@ -173,47 +139,6 @@ instance Serialize CompactSig where
|
||||
Put.putShortByteString r
|
||||
Put.putShortByteString s
|
||||
|
||||
#ifdef RECOVERY
|
||||
instance Storable RecSig65 where
|
||||
sizeOf _ = 65
|
||||
alignment _ = 1
|
||||
peek p = RecSig65 . toShort <$> packByteString (castPtr p, 65)
|
||||
poke p (RecSig65 k) = useByteString (fromShort k) $
|
||||
\(b, _) -> copyArray (castPtr p) b 65
|
||||
|
||||
instance Storable CompactRecSig where
|
||||
sizeOf _ = 65
|
||||
alignment _ = 1
|
||||
peek p = do
|
||||
bs <- BS.packCStringLen (castPtr p, 65)
|
||||
let (r, s) = BS.splitAt 32 $ BS.take 64 bs
|
||||
v = BS.last bs
|
||||
return CompactRecSig { getCompactRecSigR = toShort r
|
||||
, getCompactRecSigS = toShort s
|
||||
, getCompactRecSigV = v
|
||||
}
|
||||
poke p CompactRecSig{..} =
|
||||
useByteString bs $ \(b, _) -> copyArray (castPtr p) b 65
|
||||
where
|
||||
bs = fromShort getCompactRecSigR `BS.append`
|
||||
fromShort getCompactRecSigS `BS.snoc`
|
||||
getCompactRecSigV
|
||||
|
||||
instance Serialize CompactRecSig where
|
||||
get = do
|
||||
r <- Get.getByteString 32
|
||||
s <- Get.getByteString 32
|
||||
v <- Get.getWord8
|
||||
return CompactRecSig { getCompactRecSigR = toShort r
|
||||
, getCompactRecSigS = toShort s
|
||||
, getCompactRecSigV = v
|
||||
}
|
||||
put (CompactRecSig r s v) = do
|
||||
Put.putShortByteString r
|
||||
Put.putShortByteString s
|
||||
Put.putWord8 v
|
||||
#endif
|
||||
|
||||
instance Storable Msg32 where
|
||||
sizeOf _ = 32
|
||||
alignment _ = 1
|
||||
@ -410,14 +335,12 @@ foreign import ccall
|
||||
-> Ptr Tweak32
|
||||
-> IO Ret
|
||||
|
||||
#ifdef NEGATE
|
||||
foreign import ccall
|
||||
"secp256k1.h secp256k1_ec_privkey_negate"
|
||||
ecTweakNegate
|
||||
:: Ptr Ctx
|
||||
-> Ptr Tweak32
|
||||
-> IO Ret
|
||||
#endif
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1.h secp256k1_ec_pubkey_tweak_add"
|
||||
@ -458,156 +381,3 @@ foreign import ccall
|
||||
-> Ptr (Ptr PubKey64) -- ^ pointer to array of public keys
|
||||
-> CInt -- ^ number of public keys
|
||||
-> IO Ret
|
||||
|
||||
#ifdef RECOVERY
|
||||
foreign import ccall
|
||||
"secp256k1_recovery.h secp256k1_ecdsa_recoverable_signature_parse_compact"
|
||||
ecdsaRecoverableSignatureParseCompact
|
||||
:: Ptr Ctx
|
||||
-> Ptr RecSig65
|
||||
-> Ptr CompactSig
|
||||
-> CInt
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1_recovery.h secp256k1_ecdsa_recoverable_signature_convert"
|
||||
ecdsaRecoverableSignatureConvert
|
||||
:: Ptr Ctx
|
||||
-> Ptr Sig64
|
||||
-> Ptr RecSig65
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1_recovery.h secp256k1_ecdsa_recoverable_signature_serialize_compact"
|
||||
ecdsaRecoverableSignatureSerializeCompact
|
||||
:: Ptr Ctx
|
||||
-> Ptr CompactSig
|
||||
-> Ptr CInt
|
||||
-> Ptr RecSig65
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1_recovery.h secp256k1_ecdsa_sign_recoverable"
|
||||
ecdsaSignRecoverable
|
||||
:: Ptr Ctx
|
||||
-> Ptr RecSig65
|
||||
-> Ptr Msg32
|
||||
-> Ptr SecKey32
|
||||
-> Ptr Void
|
||||
-> Ptr a -- ^ nonce data
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1_recovery.h secp256k1_ecdsa_recover"
|
||||
ecdsaRecover
|
||||
:: Ptr Ctx
|
||||
-> Ptr PubKey64
|
||||
-> Ptr RecSig65
|
||||
-> Ptr Msg32
|
||||
-> IO Ret
|
||||
#endif
|
||||
|
||||
#ifdef SCHNORR
|
||||
foreign import ccall
|
||||
"secp256k1.h secp256k1_xonly_pubkey_tweak_add"
|
||||
schnorrPubKeyTweakAdd
|
||||
:: Ptr Ctx
|
||||
-> Ptr XOnlyPubKey64
|
||||
-> Ptr CInt
|
||||
-> Ptr Tweak32
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1.h secp256k1_xonly_seckey_tweak_add"
|
||||
schnorrSecKeyTweakAdd
|
||||
:: Ptr Ctx
|
||||
-> Ptr SecKey32
|
||||
-> Ptr Tweak32
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1.h secp256k1_schnorrsig_serialize"
|
||||
signatureSerializeSchnorr
|
||||
:: Ptr Ctx
|
||||
-> Ptr CUChar -- ^ array for encoded signature, must be large enough
|
||||
-> Ptr SchnorrSig64
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1.h secp256k1_schnorrsig_sign"
|
||||
schnorrSign
|
||||
:: Ptr Ctx
|
||||
-> Ptr SchnorrSig64
|
||||
-> Ptr Msg32
|
||||
-> Ptr SecKey32
|
||||
-- TODO
|
||||
-- This is actually an "extended nonce function" in the C code. So this signature is broken,
|
||||
-- but we pass a nullFunPtr (and this module is Internal), so it doesn't matter right now.
|
||||
-> Ptr Void
|
||||
-> Ptr a -- ^ nonce data
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1.h secp256k1_xonly_pubkey_tweak_test"
|
||||
xOnlyPubKeyTweakTest
|
||||
:: Ptr Ctx
|
||||
-> Ptr XOnlyPubKey64 -- output_pubkey
|
||||
-> CInt -- is_negated
|
||||
-> Ptr XOnlyPubKey64 -- internal_pubkey
|
||||
-> Ptr Tweak32
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1.h secp256k1_xonly_pubkey_serialize"
|
||||
schnorrPubKeySerialize
|
||||
:: Ptr Ctx
|
||||
-> Ptr CUChar -- 32 bytes output buffer
|
||||
-> Ptr XOnlyPubKey64
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1.h secp256k1_schnorrsig_verify"
|
||||
schnorrSignatureVerify
|
||||
:: Ptr Ctx
|
||||
-> Ptr SchnorrSig64
|
||||
-> Ptr Msg32
|
||||
-> Ptr XOnlyPubKey64
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1.h secp256k1_schnorrsig_parse"
|
||||
schnorrSignatureParse
|
||||
:: Ptr Ctx
|
||||
-> Ptr SchnorrSig64 -- out
|
||||
-> Ptr CUChar -- in
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1.h secp256k1_xonly_pubkey_parse"
|
||||
schnorrXOnlyPubKeyParse
|
||||
:: Ptr Ctx
|
||||
-> Ptr XOnlyPubKey64 -- out
|
||||
-> Ptr CUChar -- in
|
||||
-> IO Ret
|
||||
|
||||
foreign import ccall
|
||||
"secp256k1.h secp256k1_xonly_pubkey_create"
|
||||
schnorrXOnlyPubKeyCreate
|
||||
:: Ptr Ctx
|
||||
-> Ptr XOnlyPubKey64
|
||||
-> Ptr SecKey32
|
||||
-> IO Ret
|
||||
#endif
|
||||
|
||||
#ifdef ECDH
|
||||
foreign import ccall
|
||||
"secp256k1_ecdh.h secp256k1_ecdh"
|
||||
ecEcdh
|
||||
:: Ptr Ctx
|
||||
-> Ptr CUChar
|
||||
-> Ptr PubKey64
|
||||
-> Ptr SecKey32
|
||||
-> Ptr a
|
||||
-> Ptr b
|
||||
-> IO Ret
|
||||
#endif
|
||||
|
@ -61,53 +61,7 @@ spec = do
|
||||
it "multiply public key" $ property tweakMulPubKeyTest
|
||||
it "combine public keys" $ property combinePubKeyTest
|
||||
it "can't combine 0 public keys" $ property combinePubKeyEmptyListTest
|
||||
#ifdef RECOVERY
|
||||
describe "recovery" $ do
|
||||
it "recovers public keys" $
|
||||
property recoverTest
|
||||
it "recovers key from signed message" $
|
||||
property signRecMsgTest
|
||||
it "does not recover bad public keys" $
|
||||
property badRecoverTest
|
||||
it "detects bad recoverable signature" $
|
||||
property badRecSignatureTest
|
||||
it "serializes compact recoverable signature" $
|
||||
property serializeCompactRecSigTest
|
||||
it "shows and reads recoverable signature" $
|
||||
property (showReadRecSig :: (SecKey, Msg) -> Bool)
|
||||
it "reads recoverable signature from string" $ property $ isStringRecSig
|
||||
#endif
|
||||
#ifdef NEGATE
|
||||
describe "negate" $
|
||||
it "negates tweak" $ property negateTweakTest
|
||||
#endif
|
||||
#ifdef ECDH
|
||||
describe "ecdh" $ do
|
||||
it "computes dh secret" $ property computeDhSecret
|
||||
#endif
|
||||
#ifdef SCHNORR
|
||||
describe "schnorr (bip-340)" $ do
|
||||
it "validates test vector 0" $
|
||||
property bip340Vector0
|
||||
it "rejects test vector 5" $
|
||||
property $
|
||||
failingVectorToAssertion InvalidPubKey
|
||||
(
|
||||
hexToBytes "eefdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34",
|
||||
hexToBytes "243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89",
|
||||
hexToBytes "667c2f778e0616e611bd0c14b8a600c5884551701a949ef0ebfd72d452d64e844160bcfc3f466ecb8facd19ade57d8699d74e7207d78c6aedc3799b52a8e0598"
|
||||
)
|
||||
it "rejects test vector 6" $
|
||||
property $
|
||||
failingVectorToAssertion InvalidSig
|
||||
(
|
||||
hexToBytes "dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659",
|
||||
hexToBytes "243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89",
|
||||
hexToBytes "f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9935554d1aa5f0374e5cdaacb3925035c7c169b27c4426df0a6b19af3baeab138"
|
||||
)
|
||||
it "makes a valid taproot key spend signature" $
|
||||
property taprootKeySpend
|
||||
#endif
|
||||
|
||||
hexToBytes :: String -> BS.ByteString
|
||||
hexToBytes = fst . B16.decode . B8.pack
|
||||
@ -121,13 +75,6 @@ isStringSig (k, m) = g == fromString (cs hex) where
|
||||
g = signMsg k m
|
||||
hex = B16.encode $ exportSig g
|
||||
|
||||
#ifdef RECOVERY
|
||||
isStringRecSig :: (SecKey, Msg) -> Bool
|
||||
isStringRecSig (k, m) = g == fromString (cs hex) where
|
||||
g = signRecMsg k m
|
||||
hex = B16.encode . S.encode $ exportCompactRecSig g
|
||||
#endif
|
||||
|
||||
isStringMsg :: Msg -> Bool
|
||||
isStringMsg m = m == fromString (cs m') where
|
||||
m' = B16.encode $ getMsg m
|
||||
@ -150,12 +97,6 @@ showReadSig :: (SecKey, Msg) -> Bool
|
||||
showReadSig (k, m) = showRead sig where
|
||||
sig = signMsg k m
|
||||
|
||||
#ifdef RECOVERY
|
||||
showReadRecSig :: (SecKey, Msg) -> Bool
|
||||
showReadRecSig (k, m) = showRead recSig where
|
||||
recSig = signRecMsg k m
|
||||
#endif
|
||||
|
||||
showRead :: (Show a, Read a, Eq a) => a -> Bool
|
||||
showRead x = read (show x) == x
|
||||
|
||||
@ -169,36 +110,10 @@ signMsgParTest xs = P.runPar $ do
|
||||
ys <- mapM (P.spawnP . signMsgTest) xs
|
||||
and <$> mapM P.get ys
|
||||
|
||||
#ifdef RECOVERY
|
||||
signRecMsgTest :: (Msg, SecKey) -> Bool
|
||||
signRecMsgTest (fm, fk) = verifySig fp fg fm where
|
||||
fp = derivePubKey fk
|
||||
fg = convertRecSig $ signRecMsg fk fm
|
||||
|
||||
recoverTest :: (Msg, SecKey) -> Bool
|
||||
recoverTest (fm, fk) = recover fg fm == Just fp where
|
||||
fp = derivePubKey fk
|
||||
fg = signRecMsg fk fm
|
||||
|
||||
badRecoverTest :: (Msg, SecKey, Msg) -> Property
|
||||
badRecoverTest (fm, fk, fm') =
|
||||
fm' /= fm ==> fp' /= Nothing ==> fp' /= Just fp
|
||||
where
|
||||
fg = signRecMsg fk fm
|
||||
fp = derivePubKey fk
|
||||
fp' = recover fg fm'
|
||||
#endif
|
||||
|
||||
badSignatureTest :: (Msg, SecKey, PubKey) -> Bool
|
||||
badSignatureTest (fm, fk, fp) = not $ verifySig fp fg fm where
|
||||
fg = signMsg fk fm
|
||||
|
||||
#ifdef RECOVERY
|
||||
badRecSignatureTest :: (Msg, SecKey, PubKey) -> Bool
|
||||
badRecSignatureTest (fm, fk, fp) = not $ verifySig fp fg fm where
|
||||
fg = convertRecSig $ signRecMsg fk fm
|
||||
#endif
|
||||
|
||||
normalizeSigTest :: (Msg, SecKey) -> Bool
|
||||
normalizeSigTest (fm, fk) = not norm && sig == fg where
|
||||
fg = signMsg fk fm
|
||||
@ -226,16 +141,6 @@ serializeCompactSigTest (fm, fk) =
|
||||
where
|
||||
fg = signMsg fk fm
|
||||
|
||||
#ifdef RECOVERY
|
||||
serializeCompactRecSigTest :: (Msg, SecKey) -> Bool
|
||||
serializeCompactRecSigTest (fm, fk) =
|
||||
case importCompactRecSig $ exportCompactRecSig fg of
|
||||
Just fg' -> fg == fg'
|
||||
Nothing -> False
|
||||
where
|
||||
fg = signRecMsg fk fm
|
||||
#endif
|
||||
|
||||
serializeSecKeyTest :: SecKey -> Bool
|
||||
serializeSecKeyTest fk =
|
||||
case secKey $ getSecKey fk of
|
||||
@ -316,7 +221,6 @@ combinePubKeyEmptyListTest =
|
||||
expected = Nothing
|
||||
combined = combinePubKeys []
|
||||
|
||||
#ifdef NEGATE
|
||||
negateTweakTest :: Assertion
|
||||
negateTweakTest =
|
||||
assertEqual "can recover secret key 1 after adding tweak 1" oneKey subtracted
|
||||
@ -328,85 +232,3 @@ negateTweakTest =
|
||||
Just minusOneTwk = tweakNegate oneTwk
|
||||
Just twoKey = tweakAddSecKey oneKey oneTwk
|
||||
Just subtracted = tweakAddSecKey twoKey minusOneTwk
|
||||
#endif
|
||||
|
||||
#ifdef ECDH
|
||||
computeDhSecret :: Assertion
|
||||
computeDhSecret =
|
||||
assertEqual "ecdh computes known secret" expected computed
|
||||
where
|
||||
computed = do
|
||||
pub <- importPubKey $ hexToBytes
|
||||
"028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7"
|
||||
sec <- secKey $ hexToBytes
|
||||
"1212121212121212121212121212121212121212121212121212121212121212"
|
||||
pure $ ecdh pub sec
|
||||
expected = Just $ hexToBytes
|
||||
"1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3"
|
||||
#endif
|
||||
|
||||
#ifdef SCHNORR
|
||||
data VectorError = InvalidPubKey | InvalidSig | InvalidMsg | InvalidSigFormat
|
||||
deriving (Eq, Show)
|
||||
|
||||
failingVectorToAssertion :: VectorError -> (BS.ByteString, BS.ByteString, BS.ByteString) -> Assertion
|
||||
failingVectorToAssertion expectedFailure (pubBytes, msgBytes, sigBytes) =
|
||||
assertEqual ("expected error " <> show expectedFailure <> " occurs") (Left expectedFailure) computed
|
||||
where
|
||||
computed :: Either VectorError ()
|
||||
computed =
|
||||
let
|
||||
pubM = importXOnlyPubKey pubBytes
|
||||
sigM = importSchnorrSig sigBytes
|
||||
msgM = msg $ msgBytes
|
||||
in
|
||||
case (pubM, sigM, msgM) of
|
||||
(Nothing, _, _) -> Left InvalidPubKey
|
||||
(_, Nothing, _) -> Left InvalidSigFormat
|
||||
(_, _, Nothing) -> Left InvalidMsg
|
||||
(Just pub, Just sig, Just msg) ->
|
||||
if verifyMsgSchnorr pub sig msg
|
||||
then Right ()
|
||||
else Left InvalidSig
|
||||
|
||||
bip340Vector0 :: Assertion
|
||||
bip340Vector0 =
|
||||
passingVectorToAssertion 0
|
||||
(
|
||||
BS.replicate 31 0 <> B8.pack ['\x01']
|
||||
, BS.replicate 32 0
|
||||
, hexToBytes "db46b5cdc554edbd7765611b75d7bdbc639cf538fb6e9ef04a61884b765343aae148954f27eb69291a9045862f8ae4fa53436c117e9397c70275d5398066d44b"
|
||||
)
|
||||
|
||||
-- Integer is BIP-340 vector test number
|
||||
passingVectorToAssertion :: Integer -> (BS.ByteString, BS.ByteString, BS.ByteString) -> Assertion
|
||||
passingVectorToAssertion idx (secBytes, msgBytes, sigBytes) =
|
||||
assertEqual ("BIP-340 test vector " <> show idx <> " signature matches") expectedSig computedSig
|
||||
where
|
||||
expectedSig :: Maybe SchnorrSig
|
||||
expectedSig = importSchnorrSig $ sigBytes
|
||||
computedSig :: Maybe SchnorrSig
|
||||
computedSig = do
|
||||
sec <- secKey secBytes
|
||||
msg <- msg $ msgBytes
|
||||
pure $ signMsgSchnorr sec msg
|
||||
|
||||
-- This test is ported from the C code, it is called 'test_schnorrsig_taproot'.
|
||||
-- But this version was modified to use fixed keys and messages.
|
||||
taprootKeySpend :: Assertion
|
||||
taprootKeySpend =
|
||||
assertEqual "derivation succeded and resulting signature is valid" (Just True) computed
|
||||
where
|
||||
computed = do
|
||||
sec <- secKey $ BS.replicate 32 32
|
||||
msgToSign <- msg $ BS.replicate 32 00
|
||||
|
||||
let internalPub = deriveXOnlyPubKey sec
|
||||
twea <- tweak $ exportXOnlyPubKey internalPub
|
||||
(outputPub, isNegated) <- schnorrTweakAddPubKey internalPub twea
|
||||
|
||||
-- This is a 'key spend' in Taproot terminology:
|
||||
tweakSec <- schnorrTweakAddSecKey sec twea
|
||||
let sig = signMsgSchnorr tweakSec msgToSign
|
||||
pure $ verifyMsgSchnorr outputPub sig msgToSign
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user