Skip to content

Commit 2cf0de7

Browse files
committed
Build haskell-bitcoin/libsecp256k1-haskell with haskell-bitcoin/bitcoin
1 parent 773d363 commit 2cf0de7

File tree

19 files changed

+123
-99
lines changed

19 files changed

+123
-99
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ cabal.project.local~
2222
.ghc.environment.*
2323
TAGS
2424
tags
25+
.vscode

bitcoin.cabal

+1-1
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,12 @@ benchmark benchmark
211211
, entropy >=0.4.1.5
212212
, hashable >=1.3.0.0
213213
, hspec >=2.7.1
214+
, libsecp256k1 >=0.1.0
214215
, memory >=0.15.0
215216
, murmur3 >=1.0.3
216217
, network >=3.1.1.1
217218
, safe >=0.3.18
218219
, scientific >=0.3.6.2
219-
, secp256k1-haskell >=0.4.0
220220
, split >=0.2.3.3
221221
, string-conversions >=0.4.0.1
222222
, text >=1.2.3.0

src/Bitcoin/Crypto/Signature.hs

+10-9
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import Crypto.Secp256k1
2222
import Data.Binary (Binary (..))
2323
import Data.ByteString (ByteString)
2424
import qualified Data.ByteString as BS
25+
import Data.ByteString.Short (fromShort)
2526
import Data.Bytes.Get
2627
import Data.Bytes.Put
2728
import Data.Bytes.Serial
@@ -31,15 +32,15 @@ import Numeric (showHex)
3132

3233

3334
-- | Sign a 256-bit hash using secp256k1 elliptic curve.
34-
signHash :: SecKey -> Hash256 -> Signature
35+
signHash :: SecKey -> Hash256 -> Maybe Signature
3536
signHash k = ecdsaSign k . fromShort . getHash256
3637

3738

3839
-- | Verify an ECDSA signature for a 256-bit hash.
3940
verifyHashSig :: Hash256 -> Signature -> PubKeyXY -> Bool
40-
verifyHashSig h s p = verifySig p norm (hashToMsg h)
41+
verifyHashSig h s p = ecdsaVerify (fromShort $ getHash256 h) p norm
4142
where
42-
norm = fromMaybe s (normalizeSig s)
43+
norm = fromMaybe s (normalizeSignature s)
4344

4445

4546
-- | Deserialize an ECDSA signature as commonly encoded in Bitcoin.
@@ -64,23 +65,23 @@ getSig = do
6465

6566
-- | Serialize an ECDSA signature for Bitcoin use.
6667
putSig :: MonadPut m => Signature -> m ()
67-
putSig s = putByteString $ exportSig s
68+
putSig s = putByteString $ exportSignatureDer s
6869

6970

7071
-- | Is canonical half order.
7172
isCanonicalHalfOrder :: Signature -> Bool
72-
isCanonicalHalfOrder = isNothing . normalizeSig
73+
isCanonicalHalfOrder = isNothing . normalizeSignature
7374

7475

7576
-- | Decode signature strictly.
7677
decodeStrictSig :: ByteString -> Maybe Signature
7778
decodeStrictSig bs = do
78-
g <- importSig bs
79+
g <- importSignatureDer bs
7980
-- <http://www.secg.org/sec1-v2.pdf Section 4.1.4>
8081
-- 4.1.4.1 (r and s can not be zero)
81-
let compact = exportCompactSig g
82+
let compact = exportSignatureCompact g
8283
let zero = BS.replicate 32 0
83-
guard $ BS.take 32 (getCompactSig compact) /= zero
84-
guard $ BS.take 32 (BS.drop 32 (getCompactSig compact)) /= zero
84+
guard $ BS.take 32 compact /= zero
85+
guard $ BS.take 32 (BS.drop 32 compact) /= zero
8586
guard $ isCanonicalHalfOrder g
8687
return g

src/Bitcoin/Keys/Common.hs

+17-17
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ module Bitcoin.Keys.Common (
1515
-- * Public & Private Keys
1616
PubKeyI (..),
1717
SecKeyI (..),
18-
exportPubKey,
19-
importPubKey,
18+
exportPubKeyXY,
19+
importPubKeyXY,
2020
wrapPubKey,
2121
derivePubKeyI,
2222
wrapSecKey,
2323
fromMiniKey,
2424
tweakPubKey,
2525
tweakSecKey,
26-
getSecKey,
27-
secKey,
26+
exportSecKey,
27+
importSecKey,
2828

2929
-- ** Private Key Wallet Import Format (WIF)
3030
fromWif,
@@ -55,7 +55,7 @@ import GHC.Generics (Generic)
5555

5656
-- | Elliptic curve public key type with expected serialized compression flag.
5757
data PubKeyI = PubKeyI
58-
{ pubKeyPoint :: !PubKey
58+
{ pubKeyPoint :: !PubKeyXY
5959
, pubKeyCompressed :: !Bool
6060
}
6161
deriving (Generic, Eq, Show, Read, Hashable, NFData)
@@ -84,14 +84,14 @@ instance Serial PubKeyI where
8484
c = do
8585
bs <- getByteString 33
8686
maybe (fail "Could not decode public key") return $
87-
PubKeyI <$> importPubKey bs <*> pure True
87+
PubKeyI <$> importPubKeyXY bs <*> pure True
8888
u = do
8989
bs <- getByteString 65
9090
maybe (fail "Could not decode public key") return $
91-
PubKeyI <$> importPubKey bs <*> pure False
91+
PubKeyI <$> importPubKeyXY bs <*> pure False
9292

9393

94-
serialize pk = putByteString $ exportPubKey (pubKeyCompressed pk) (pubKeyPoint pk)
94+
serialize pk = putByteString $ exportPubKeyXY (pubKeyCompressed pk) (pubKeyPoint pk)
9595

9696

9797
instance Serialize PubKeyI where
@@ -105,7 +105,7 @@ instance Binary PubKeyI where
105105

106106

107107
-- | Wrap a public key from secp256k1 library adding information about compression.
108-
wrapPubKey :: Bool -> PubKey -> PubKeyI
108+
wrapPubKey :: Bool -> PubKeyXY -> PubKeyI
109109
wrapPubKey c p = PubKeyI p c
110110

111111

@@ -116,8 +116,8 @@ derivePubKeyI (SecKeyI d c) = PubKeyI (derivePubKey d) c
116116

117117

118118
-- | Tweak a public key.
119-
tweakPubKey :: PubKey -> Hash256 -> Maybe PubKey
120-
tweakPubKey p h = tweakAddPubKey p =<< tweak (runPutS (serialize h))
119+
tweakPubKey :: PubKeyXY -> Hash256 -> Maybe PubKeyXY
120+
tweakPubKey p h = pubKeyTweakAdd p =<< importTweak (runPutS (serialize h))
121121

122122

123123
-- | Elliptic curve private key type with expected public key compression
@@ -138,14 +138,14 @@ wrapSecKey c d = SecKeyI d c
138138

139139
-- | Tweak a private key.
140140
tweakSecKey :: SecKey -> Hash256 -> Maybe SecKey
141-
tweakSecKey key h = tweakAddSecKey key =<< tweak (runPutS (serialize h))
141+
tweakSecKey key h = secKeyTweakAdd key =<< importTweak (runPutS (serialize h))
142142

143143

144144
-- | Decode Casascius mini private keys (22 or 30 characters).
145145
fromMiniKey :: ByteString -> Maybe SecKeyI
146146
fromMiniKey bs = do
147147
guard checkShortKey
148-
wrapSecKey False <$> secKey (runPutS (serialize (sha256 bs)))
148+
wrapSecKey False <$> importSecKey (runPutS (serialize (sha256 bs)))
149149
where
150150
checkHash = runPutS $ serialize $ sha256 $ bs `BS.append` "?"
151151
checkShortKey = BS.length bs `elem` [22, 30] && BS.head checkHash == 0x00
@@ -159,11 +159,11 @@ fromWif net wif = do
159159
guard (BS.head bs == getSecretPrefix net)
160160
case BS.length bs of
161161
-- Uncompressed format
162-
33 -> wrapSecKey False <$> secKey (BS.tail bs)
162+
33 -> wrapSecKey False <$> importSecKey (BS.tail bs)
163163
-- Compressed format
164164
34 -> do
165165
guard $ BS.last bs == 0x01
166-
wrapSecKey True <$> secKey (BS.tail $ BS.init bs)
166+
wrapSecKey True <$> importSecKey (BS.tail $ BS.init bs)
167167
-- Bad length
168168
_ -> Nothing
169169

@@ -173,5 +173,5 @@ toWif :: Network -> SecKeyI -> Base58
173173
toWif net (SecKeyI k c) =
174174
encodeBase58Check . BS.cons (getSecretPrefix net) $
175175
if c
176-
then getSecKey k `BS.snoc` 0x01
177-
else getSecKey k
176+
then exportSecKey k `BS.snoc` 0x01
177+
else exportSecKey k

src/Bitcoin/Keys/Extended.hs

+13-13
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ data XPubKey = XPubKey
205205
-- ^ derivation index
206206
, xPubChain :: !ChainCode
207207
-- ^ chain code
208-
, xPubKey :: !PubKey
208+
, xPubKey :: !PubKeyXY
209209
-- ^ public key of this node
210210
}
211211
deriving (Generic, Eq, Show, Read, NFData, Hashable)
@@ -244,7 +244,7 @@ makeXPrvKey bs =
244244
XPrvKey 0 (Fingerprint 0) 0 c k
245245
where
246246
(p, c) = split512 $ hmac512 "Bitcoin seed" bs
247-
k = fromMaybe err (secKey (runPutS (serialize p)))
247+
k = fromMaybe err (importSecKey (runPutS (serialize p)))
248248
err = throw $ DerivationException "Invalid seed"
249249

250250

@@ -277,7 +277,7 @@ prvSubKey xkey child
277277
| otherwise = error "Invalid child derivation index"
278278
where
279279
pK = xPubKey $ deriveXPubKey xkey
280-
m = B.append (exportPubKey True pK) (runPutS (serialize child))
280+
m = B.append (exportPubKeyXY True pK) (runPutS (serialize child))
281281
(a, c) = split512 $ hmac512 (runPutS $ serialize $ xPrvChain xkey) m
282282
k = fromMaybe err $ tweakSecKey (xPrvKey xkey) a
283283
err = throw $ DerivationException "Invalid prvSubKey derivation"
@@ -297,7 +297,7 @@ pubSubKey xKey child
297297
XPubKey (xPubDepth xKey + 1) (xPubFP xKey) child c pK
298298
| otherwise = error "Invalid child derivation index"
299299
where
300-
m = B.append (exportPubKey True (xPubKey xKey)) (runPutS $ serialize child)
300+
m = B.append (exportPubKeyXY True (xPubKey xKey)) (runPutS $ serialize child)
301301
(a, c) = split512 $ hmac512 (runPutS $ serialize $ xPubChain xKey) m
302302
pK = fromMaybe err $ tweakPubKey (xPubKey xKey) a
303303
err = throw $ DerivationException "Invalid pubSubKey derivation"
@@ -359,7 +359,7 @@ xPrvID = xPubID . deriveXPubKey
359359

360360
-- | Computes the key identifier of an extended public key.
361361
xPubID :: XPubKey -> Hash160
362-
xPubID = ripemd160 . runPutS . serialize . sha256 . exportPubKey True . xPubKey
362+
xPubID = ripemd160 . runPutS . serialize . sha256 . exportPubKeyXY True . xPubKey
363363

364364

365365
-- | Computes the key fingerprint of an extended private key.
@@ -477,15 +477,15 @@ hardSubKeys k = map (\i -> (hardSubKey k i, i)) . cycleIndex
477477

478478

479479
-- | Derive a standard address from an extended public key and an index.
480-
deriveAddr :: XPubKey -> KeyIndex -> (Address, PubKey)
480+
deriveAddr :: XPubKey -> KeyIndex -> (Address, PubKeyXY)
481481
deriveAddr k i =
482482
(xPubAddr key, xPubKey key)
483483
where
484484
key = pubSubKey k i
485485

486486

487487
-- | Derive a SegWit P2WPKH address from an extended public key and an index.
488-
deriveWitnessAddr :: XPubKey -> KeyIndex -> (Address, PubKey)
488+
deriveWitnessAddr :: XPubKey -> KeyIndex -> (Address, PubKeyXY)
489489
deriveWitnessAddr k i =
490490
(xPubWitnessAddr key, xPubKey key)
491491
where
@@ -494,7 +494,7 @@ deriveWitnessAddr k i =
494494

495495
-- | Derive a backwards-compatible SegWit P2SH-P2WPKH address from an extended
496496
-- public key and an index.
497-
deriveCompatWitnessAddr :: XPubKey -> KeyIndex -> (Address, PubKey)
497+
deriveCompatWitnessAddr :: XPubKey -> KeyIndex -> (Address, PubKeyXY)
498498
deriveCompatWitnessAddr k i =
499499
(xPubCompatWitnessAddr key, xPubKey key)
500500
where
@@ -503,7 +503,7 @@ deriveCompatWitnessAddr k i =
503503

504504
-- | Cyclic list of all addresses derived from a public key starting from an
505505
-- offset index.
506-
deriveAddrs :: XPubKey -> KeyIndex -> [(Address, PubKey, KeyIndex)]
506+
deriveAddrs :: XPubKey -> KeyIndex -> [(Address, PubKeyXY, KeyIndex)]
507507
deriveAddrs k =
508508
map f . cycleIndex
509509
where
@@ -512,7 +512,7 @@ deriveAddrs k =
512512

513513
-- | Cyclic list of all SegWit P2WPKH addresses derived from a public key
514514
-- starting from an offset index.
515-
deriveWitnessAddrs :: XPubKey -> KeyIndex -> [(Address, PubKey, KeyIndex)]
515+
deriveWitnessAddrs :: XPubKey -> KeyIndex -> [(Address, PubKeyXY, KeyIndex)]
516516
deriveWitnessAddrs k =
517517
map f . cycleIndex
518518
where
@@ -521,7 +521,7 @@ deriveWitnessAddrs k =
521521

522522
-- | Cyclic list of all backwards-compatible SegWit P2SH-P2WPKH addresses
523523
-- derived from a public key starting from an offset index.
524-
deriveCompatWitnessAddrs :: XPubKey -> KeyIndex -> [(Address, PubKey, KeyIndex)]
524+
deriveCompatWitnessAddrs :: XPubKey -> KeyIndex -> [(Address, PubKeyXY, KeyIndex)]
525525
deriveCompatWitnessAddrs k =
526526
map f . cycleIndex
527527
where
@@ -1026,14 +1026,14 @@ applyPath path key =
10261026
{- Helpers for derivation paths and addresses -}
10271027

10281028
-- | Derive an address from a given parent path.
1029-
derivePathAddr :: XPubKey -> SoftPath -> KeyIndex -> (Address, PubKey)
1029+
derivePathAddr :: XPubKey -> SoftPath -> KeyIndex -> (Address, PubKeyXY)
10301030
derivePathAddr key path = deriveAddr (derivePubPath path key)
10311031

10321032

10331033
-- | Cyclic list of all addresses derived from a given parent path and starting
10341034
-- from the given offset index.
10351035
derivePathAddrs ::
1036-
XPubKey -> SoftPath -> KeyIndex -> [(Address, PubKey, KeyIndex)]
1036+
XPubKey -> SoftPath -> KeyIndex -> [(Address, PubKeyXY, KeyIndex)]
10371037
derivePathAddrs key path = deriveAddrs (derivePubPath path key)
10381038

10391039

src/Bitcoin/Script/SigHash.hs

+2-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import Data.Bytes.Serial
4444
import Data.Hashable
4545
import Data.Maybe
4646
import Data.Scientific
47+
import qualified Data.Text as T
4748
import Data.Word
4849
import GHC.Generics (Generic)
4950

@@ -276,7 +277,7 @@ txSigHashSegwitV0 _ tx out v i sh =
276277
-- transaction inputs are of type 'TxSignature'.
277278
data TxSignature
278279
= TxSignature
279-
{ txSignature :: !Sig
280+
{ txSignature :: !Signature
280281
, txSignatureSigHash :: !SigHash
281282
}
282283
| TxSignatureEmpty

src/Bitcoin/Transaction/Builder.hs

+2-2
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ countMulSig ::
311311
Script ->
312312
Word64 ->
313313
Int ->
314-
[PubKey] ->
314+
[PubKeyXY] ->
315315
[TxSignature] ->
316316
Int
317317
countMulSig net tx out val i =
@@ -320,7 +320,7 @@ countMulSig net tx out val i =
320320
h = txSigHash net tx out val i
321321

322322

323-
countMulSig' :: (SigHash -> Hash256) -> [PubKey] -> [TxSignature] -> Int
323+
countMulSig' :: (SigHash -> Hash256) -> [PubKeyXY] -> [TxSignature] -> Int
324324
countMulSig' _ [] _ = 0
325325
countMulSig' _ _ [] = 0
326326
countMulSig' h (_ : pubs) (TxSignatureEmpty : sigs) = countMulSig' h pubs sigs

src/Bitcoin/Transaction/Builder/Sign.hs

+3-3
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ signInput ::
108108
SecKeyI ->
109109
Either String Tx
110110
signInput net tx i (sigIn@(SigInput so val _ _ rdmM), nest) key = do
111-
let sig = makeSignature net tx i sigIn key
111+
sig <- maybe (Left "cannot sign input") return $ makeSignature net tx i sigIn key
112112
si <- buildInput net tx i so val rdmM sig $ derivePubKeyI key
113113
w <- updatedWitnessData tx i so si
114114
return
@@ -246,9 +246,9 @@ parseExistingSigs net tx so i = insSigs <> witSigs
246246

247247

248248
-- | Produce a structured representation of a deterministic (RFC-6979) signature over an input.
249-
makeSignature :: Network -> Tx -> Int -> SigInput -> SecKeyI -> TxSignature
249+
makeSignature :: Network -> Tx -> Int -> SigInput -> SecKeyI -> Maybe TxSignature
250250
makeSignature net tx i (SigInput so val _ sh rdmM) key =
251-
TxSignature (signHash (secKeyData key) m) sh
251+
TxSignature <$> signHash (secKeyData key) m <*> pure sh
252252
where
253253
m = makeSigHash net tx i so val sh rdmM
254254

src/Bitcoin/Transaction/Partial.hs

+7-3
Original file line numberDiff line numberDiff line change
@@ -358,10 +358,14 @@ onPrevTxOut net signer tx ix input prevTxData =
358358
{ partialSigs = newSigs <> partialSigs input
359359
}
360360
where
361-
newSigs = HM.mapWithKey sigForInput sigKeys
361+
newSigs = HM.foldMapWithKey sigForInput sigKeys
362362
sigForInput thePubKey theSecKey =
363-
encodeTxSig . makeSignature net tx ix theSigInput $
364-
SecKeyI theSecKey (pubKeyCompressed thePubKey)
363+
maybe
364+
mempty
365+
(HM.singleton thePubKey . encodeTxSig)
366+
( makeSignature net tx ix theSigInput $
367+
SecKeyI theSecKey (pubKeyCompressed thePubKey)
368+
)
365369

366370
theSigInput =
367371
SigInput

0 commit comments

Comments
 (0)