1
1
{-# LANGUAGE DataKinds #-}
2
- {-# LANGUAGE DeriveGeneric #-}
3
2
{-# LANGUAGE FlexibleContexts #-}
4
3
{-# LANGUAGE GADTs #-}
5
- {-# LANGUAGE GeneralizedNewtypeDeriving #-}
6
4
{-# LANGUAGE MultiParamTypeClasses #-}
7
5
{-# LANGUAGE MultiWayIf #-}
8
6
{-# LANGUAGE RankNTypes #-}
@@ -32,6 +30,7 @@ module Crypto.Secp256k1 (
32
30
33
31
-- * Parsing and Serialization
34
32
importSecKey ,
33
+ exportSecKey ,
35
34
importPubKeyXY ,
36
35
exportPubKeyXY ,
37
36
importPubKeyXO ,
@@ -86,6 +85,7 @@ import Control.Monad.Trans.Cont (ContT (..), evalContT)
86
85
import Crypto.Secp256k1.Internal
87
86
import Crypto.Secp256k1.Prim (flagsEcUncompressed )
88
87
import qualified Crypto.Secp256k1.Prim as Prim
88
+ import qualified Data.ByteArray.Encoding as BA
89
89
import Data.ByteArray.Sized
90
90
import Data.ByteString (ByteString )
91
91
import qualified Data.ByteString as BS
@@ -100,6 +100,7 @@ import Data.String (IsString (..))
100
100
101
101
-- import Data.String.Conversions (ConvertibleStrings, cs)
102
102
103
+ import qualified Data.ByteString.Char8 as B8
103
104
import Data.Foldable (for_ )
104
105
import Data.Memory.PtrMethods (memCompare )
105
106
import Foreign (
@@ -147,7 +148,16 @@ import Text.Read (
147
148
)
148
149
149
150
151
+ -- | Secret Key
150
152
newtype SecKey = SecKey { secKeyFPtr :: ForeignPtr Prim. Seckey32}
153
+
154
+
155
+ instance Show SecKey where
156
+ show SecKey {.. } = unsafePerformIO . evalContT $ do
157
+ secKeyPtr <- ContT (withForeignPtr secKeyFPtr)
158
+ -- avoid allocating a new bytestring because we are only reading from this pointer
159
+ bs <- lift (Data.ByteString.Unsafe. unsafePackCStringLen (castPtr secKeyPtr, 32 ))
160
+ pure $ " 0x" <> B8. unpack (BA. convertToBase BA. Base16 bs)
151
161
instance Eq SecKey where
152
162
sk == sk' = unsafePerformIO . evalContT $ do
153
163
skp <- ContT $ withForeignPtr (secKeyFPtr sk)
@@ -160,7 +170,14 @@ instance Ord SecKey where
160
170
lift (memCompare (castPtr skp) (castPtr skp') 32 )
161
171
162
172
173
+ -- | Public Key with both X and Y coordinates
163
174
newtype PubKeyXY = PubKeyXY { pubKeyXYFPtr :: ForeignPtr Prim. Pubkey64}
175
+
176
+
177
+ instance Show PubKeyXY where
178
+ show pk = " 0x" <> B8. unpack (BA. convertToBase BA. Base16 (exportPubKeyXY True pk))
179
+
180
+
164
181
instance Eq PubKeyXY where
165
182
pk == pk' = unsafePerformIO . evalContT $ do
166
183
pkp <- ContT . withForeignPtr . pubKeyXYFPtr $ pk
@@ -175,7 +192,14 @@ instance Ord PubKeyXY where
175
192
pure $ compare res 0
176
193
177
194
195
+ -- | Public Key with only an X coordinate.
178
196
newtype PubKeyXO = PubKeyXO { pubKeyXOFPtr :: ForeignPtr Prim. XonlyPubkey64}
197
+
198
+
199
+ instance Show PubKeyXO where
200
+ show pk = " 0x" <> B8. unpack (BA. convertToBase BA. Base16 (exportPubKeyXO pk))
201
+
202
+
179
203
instance Eq PubKeyXO where
180
204
pk == pk' = unsafePerformIO . evalContT $ do
181
205
pkp <- ContT . withForeignPtr . pubKeyXOFPtr $ pk
@@ -190,31 +214,45 @@ instance Ord PubKeyXO where
190
214
pure $ compare res 0
191
215
192
216
217
+ -- | Structure containing information equivalent to 'SecKey' and 'PubKeyXY'
193
218
newtype KeyPair = KeyPair { keyPairFPtr :: ForeignPtr Prim. Keypair96}
219
+
220
+
194
221
instance Eq KeyPair where
195
222
kp == kp' = unsafePerformIO . evalContT $ do
196
223
kpp <- ContT $ withForeignPtr (keyPairFPtr kp)
197
224
kpp' <- ContT $ withForeignPtr (keyPairFPtr kp')
198
225
(EQ == ) <$> lift (memCompare (castPtr kpp) (castPtr kpp') 32 )
199
226
200
227
228
+ -- | Structure containing Signature (R,S) data.
201
229
newtype Signature = Signature { signatureFPtr :: ForeignPtr Prim. Sig64}
230
+
231
+
232
+ instance Show Signature where
233
+ show sig = " 0x" <> B8. unpack (BA. convertToBase BA. Base16 (exportSignatureCompact sig))
202
234
instance Eq Signature where
203
235
sig == sig' = unsafePerformIO . evalContT $ do
204
236
sigp <- ContT $ withForeignPtr (signatureFPtr sig)
205
237
sigp' <- ContT $ withForeignPtr (signatureFPtr sig')
206
238
(EQ == ) <$> lift (memCompare (castPtr sigp) (castPtr sigp') 32 )
207
239
208
240
241
+ -- | Structure containing Signature AND recovery ID
209
242
newtype RecoverableSignature = RecoverableSignature { recoverableSignatureFPtr :: ForeignPtr Prim. RecSig65}
243
+
244
+
210
245
instance Eq RecoverableSignature where
211
246
rs == rs' = unsafePerformIO . evalContT $ do
212
247
rsp <- ContT $ withForeignPtr (recoverableSignatureFPtr rs)
213
248
rsp' <- ContT $ withForeignPtr (recoverableSignatureFPtr rs')
214
249
(EQ == ) <$> lift (memCompare (castPtr rsp) (castPtr rsp') 32 )
215
250
216
251
252
+ -- | Isomorphic to 'SecKey' but specifically used for tweaking (EC Group operations) other keys
217
253
newtype Tweak = Tweak { tweakFPtr :: ForeignPtr Prim. Tweak32}
254
+
255
+
218
256
instance Eq Tweak where
219
257
sk == sk' = unsafePerformIO . evalContT $ do
220
258
skp <- ContT $ withForeignPtr (tweakFPtr sk)
@@ -248,29 +286,39 @@ importSecKey bs
248
286
else pure Nothing
249
287
250
288
289
+ exportSecKey :: SecKey -> ByteString
290
+ exportSecKey SecKey {.. } = unsafePerformIO . evalContT $ do
291
+ secKeyPtr <- ContT (withForeignPtr secKeyFPtr)
292
+ lift $ packByteString (secKeyPtr, 32 )
293
+
294
+
251
295
-- | Parses a 33 or 65 byte 'PubKeyXY', all other lengths will result in @Nothing@
252
296
importPubKeyXY :: ByteString -> Maybe PubKeyXY
253
- importPubKeyXY bs = unsafePerformIO $
254
- unsafeUseByteString bs $ \ (input, len) -> do
255
- pubkeyOutputBuf <- mallocBytes 64
297
+ importPubKeyXY bs = unsafePerformIO . evalContT $ do
298
+ (input, len) <- ContT (unsafeUseByteString bs)
299
+ lift $ do
256
300
if len == 33 || len == 65
257
301
then do
258
- ret <- Prim. ecPubkeyParse ctx (castPtr pubkeyOutputBuf) input len
302
+ pubkeyOutputBuf <- mallocBytes 64
303
+ ret <- Prim. ecPubkeyParse ctx pubkeyOutputBuf input len
259
304
if isSuccess ret
260
- then Just . PubKeyXY <$> newForeignPtr finalizerFree (castPtr pubkeyOutputBuf)
305
+ then Just . PubKeyXY <$> newForeignPtr finalizerFree pubkeyOutputBuf
261
306
else free pubkeyOutputBuf $> Nothing
262
307
else pure Nothing
263
308
264
309
265
310
-- | Serialize 'PubKeyXY'. First argument @True@ for compressed output (33 bytes), @False@ for uncompressed (65 bytes).
266
311
exportPubKeyXY :: Bool -> PubKeyXY -> ByteString
267
- exportPubKeyXY compress ( PubKeyXY fptr) = unsafePerformIO $ do
312
+ exportPubKeyXY compress PubKeyXY { .. } = unsafePerformIO . evalContT $ do
268
313
let flags = if compress then Prim. flagsEcCompressed else Prim. flagsEcUncompressed
269
314
let sz = if compress then 33 else 65
270
- buf <- mallocBytes sz
271
- alloca $ \ written -> do
315
+ ptr <- ContT (withForeignPtr pubKeyXYFPtr)
316
+ written <- ContT alloca
317
+ lift $ do
318
+ poke written (fromIntegral sz)
319
+ buf <- mallocBytes sz
272
320
-- always succeeds so we don't need to check
273
- _ret <- withForeignPtr fptr $ \ ptr -> Prim. ecPubkeySerialize ctx buf written ptr flags
321
+ _ret <- Prim. ecPubkeySerialize ctx buf written ptr flags
274
322
len <- peek written
275
323
unsafePackMallocCStringLen (castPtr buf, fromIntegral len)
276
324
@@ -286,7 +334,7 @@ importPubKeyXO bs
286
334
ret <- Prim. xonlyPubkeyParse ctx outBuf ptr
287
335
if isSuccess ret
288
336
then Just . PubKeyXO <$> newForeignPtr finalizerFree outBuf
289
- else pure Nothing
337
+ else free outBuf $> Nothing
290
338
291
339
292
340
-- | Serializes 'PubKeyXO' to 32 byte @ByteString@
@@ -307,11 +355,11 @@ importSignature bs = unsafePerformIO $
307
355
-- compact
308
356
| len == 64 -> Prim. ecdsaSignatureParseCompact ctx outBuf inBuf
309
357
-- der
310
- | len >= 71 && len <= 73 -> Prim. ecdsaSignatureParseDer ctx outBuf inBuf len
358
+ | len >= 69 && len <= 73 -> Prim. ecdsaSignatureParseDer ctx outBuf inBuf len
311
359
-- invalid
312
360
| otherwise -> pure 0
313
361
if isSuccess ret
314
- then Just . Signature <$> newForeignPtr finalizerFree (castPtr outBuf)
362
+ then Just . Signature <$> newForeignPtr finalizerFree outBuf
315
363
else free outBuf $> Nothing
316
364
317
365
@@ -330,6 +378,7 @@ exportSignatureDer (Signature fptr) = unsafePerformIO $ do
330
378
-- as of Q4'2015 73 byte sigs became nonstandard so we will never create one that big
331
379
outBuf <- mallocBytes 72
332
380
alloca $ \ written -> do
381
+ poke written 72
333
382
-- always succeeds
334
383
_ret <- withForeignPtr fptr $ Prim. ecdsaSignatureSerializeDer ctx outBuf written
335
384
len <- peek written
@@ -383,16 +432,16 @@ ecdsaVerify msgHash (PubKeyXY pkFPtr) (Signature sigFPtr) = unsafePerformIO $
383
432
ecdsaSign :: SecKey -> ByteString -> Maybe Signature
384
433
ecdsaSign (SecKey skFPtr) msgHash
385
434
| BS. length msgHash /= 32 = Nothing
386
- | otherwise = unsafePerformIO $
387
- evalContT $ do
388
- skPtr <- ContT (withForeignPtr skFPtr )
389
- (msgHashPtr, _) <- ContT (unsafeUseByteString msgHash)
390
- sigBuf <- lift $ mallocBytes 64
391
- ret <- lift $ Prim. ecdsaSign ctx sigBuf msgHashPtr skPtr Prim. nonceFunctionDefault nullPtr
392
- lift $
393
- if isSuccess ret
394
- then Just . Signature <$> newForeignPtr finalizerFree sigBuf
395
- else free sigBuf $> Nothing
435
+ | otherwise = unsafePerformIO . evalContT $ do
436
+ skPtr <- ContT (withForeignPtr skFPtr)
437
+ (msgHashPtr, _) <- ContT (unsafeUseByteString msgHash )
438
+ lift $ do
439
+ sigBuf <- mallocBytes 64
440
+ entropy <- mallocBytes 32
441
+ ret <- Prim. ecdsaSign ctx sigBuf msgHashPtr skPtr Prim. nonceFunctionRfc6979 entropy
442
+ if isSuccess ret
443
+ then Just . Signature <$> newForeignPtr finalizerFree sigBuf
444
+ else free sigBuf $> Nothing
396
445
397
446
398
447
-- | Signs @ByteString@ with 'SecKey' only if @ByteString@ is 32 bytes. Retains ability to compute 'PubKeyXY' from the
@@ -553,8 +602,8 @@ keyPairPubKeyXOTweakAdd KeyPair{..} Tweak{..} = unsafePerformIO . evalContT $ do
553
602
keyPairPtr <- ContT (withForeignPtr keyPairFPtr)
554
603
tweakPtr <- ContT (withForeignPtr tweakFPtr)
555
604
lift $ do
556
- keyPairOut <- ( mallocBytes 96 )
557
- _ <- ( memcpy keyPairOut keyPairPtr 96 )
605
+ keyPairOut <- mallocBytes 96
606
+ _ <- memcpy keyPairOut keyPairPtr 96
558
607
ret <- Prim. keypairXonlyTweakAdd ctx keyPairOut tweakPtr
559
608
if isSuccess ret
560
609
then Just . KeyPair <$> newForeignPtr finalizerFree keyPairOut
0 commit comments