git.iko.soy/haskell-nix-1459-repro
on master help sign in
initial commit
commit5bc04a082312b7a50852d7118965cb410a6ce7f5 authoriko <ilyakooo0@gmail.com> dateSun 1 May 2022, 10:53 (4 years ago)
20 files changed+2168
unifiedsplit
extra-deps/secp256k1-haskell/.gitignore+19 extra-deps/secp256k1-haskell/.travis.yml+41 extra-deps/secp256k1-haskell/CHANGELOG.md+123 extra-deps/secp256k1-haskell/LICENSE+19 extra-deps/secp256k1-haskell/README.md+6 extra-deps/secp256k1-haskell/Setup.hs+2 extra-deps/secp256k1-haskell/package.yaml+49 extra-deps/secp256k1-haskell/secp256k1-haskell.cabal+79 extra-deps/secp256k1-haskell/src/Crypto/Secp256k1.hs+443 extra-deps/secp256k1-haskell/src/Crypto/Secp256k1/Internal.hs+270 extra-deps/secp256k1-haskell/stack.yaml+5 extra-deps/secp256k1-haskell/test/Crypto/Secp256k1/InternalSpec.hs+378 extra-deps/secp256k1-haskell/test/Crypto/Secp256k1Spec.hs+248 extra-deps/secp256k1-haskell/test/Spec.hs+1 flake.lock+419 flake.nix+24 foo.cabal+20 package.yaml+9 src/Main.hs+4 stack.yaml+9
extra-deps/secp256k1-haskell/.gitignorenew file+19
@@ -0,0 +1,19 @@
1+dist
2+dist-newstyle
3+cabal-dev
4+*.o
5+*.hi
6+*.chi
7+*.chs.h
8+*.dyn_o
9+*.dyn_hi
10+.virtualenv
11+.hpc
12+.hsenv
13+.cabal-sandbox/
14+cabal.sandbox.config
15+*.prof
16+*.aux
17+*.hp
18+.stack-work
19+TAGS
extra-deps/secp256k1-haskell/.travis.ymlnew file+41
@@ -0,0 +1,41 @@
1+# This is the simple Travis configuration, which is intended for use
2+# on applications which do not require cross-platform and
3+# multiple-GHC-version support. For more information and other
4+# options, see:
5+#
6+# https://docs.haskellstack.org/en/stable/travis_ci/
7+#
8+# Copy these contents into the root directory of your Github project in a file
9+# named .travis.yml
10+
11+# Choose a build environment
12+dist: bionic
13+
14+# Do not choose a language; we provide our own build tools.
15+language: generic
16+
17+# Caching so the next build will be fast too.
18+cache:
19+ directories:
20+ - $HOME/.stack
21+
22+# Ensure necessary system libraries are present
23+addons:
24+ apt:
25+ packages:
26+ - libgmp-dev
27+ - libsecp256k1-dev
28+
29+before_install:
30+# Download and unpack the stack executable
31+- mkdir -p ~/.local/bin
32+- export PATH=$HOME/.local/bin:$PATH
33+- travis_retry curl -L https://get.haskellstack.org/stable/linux-x86_64.tar.gz | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'
34+
35+install:
36+# Build dependencies
37+- stack --no-terminal --install-ghc test --only-dependencies
38+
39+script:
40+# Build the package, its tests, and its docs and run the tests
41+- stack --no-terminal test --haddock --no-haddock-deps
extra-deps/secp256k1-haskell/CHANGELOG.mdnew file+123
@@ -0,0 +1,123 @@
1+# Changelog
2+All notable changes to this project will be documented in this file.
3+
4+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6+
7+## 0.6.1
8+### Changed
9+- Bump version and LTS Haskell.
10+- Update dependencies.
11+
12+## 0.6.0
13+### Changed
14+- Remove all use of CPP.
15+- Depend on base16 instead of the old base16-bytestring package.
16+- Target ghc-9.0.1 compiler.
17+
18+### Fixed
19+- Do not crash on bytestrings that are backed by null C pointers.
20+
21+## 0.5.0
22+### Changed
23+- Include version boundaries and other changes submitted by Emily Pillmore.
24+
25+## 0.4.0
26+### Changed
27+- Remove fragile ForeignPtr implementation in favor of just storing ByteStrings.
28+- Reuse memory instead of copying when possible.
29+
30+## 0.3.1
31+### Fixed
32+- Use unsafe calls in FFI.
33+
34+## 0.3.0
35+### Fixed
36+- Compiles with all flags now.
37+
38+### Added
39+- Script to compile with all flags.
40+
41+### Removed
42+- Remove ECDH support.
43+- Remove Schnorr support.
44+- Remove Recovery support.
45+
46+## 0.2.5
47+### Changed
48+- Reuse context aggressively.
49+- Generate context in a single thread.
50+
51+### Fixed
52+- Memory deallocation bug.
53+
54+## 0.2.4
55+### Changed
56+- Update Cabal and package version.
57+
58+## 0.2.3
59+### Changed
60+- Return meaningful error upon encountering weird ret status from upstream code.
61+
62+### Added
63+- Test parallel signature creation and verification.
64+
65+## 0.2.2
66+### Removed
67+- Hide tweak negation behind a flag for compatibilidy with Debian 9.
68+
69+### Fixed
70+- Correct code that was not compiling with some flags enabled.
71+
72+## 0.2.1
73+### Changed
74+- Do not depend on hardcoded DER signatures in tests.
75+
76+## 0.2.0
77+### Added
78+- Support for ECDH APIs.
79+- Support for Schnorr APIs.
80+
81+### Removed
82+- Enabling key recovery APIs need a flag.
83+
84+## 0.1.8
85+### Added
86+- Add missing `NFData` instances for some types.
87+
88+## 0.1.7
89+### Added
90+- Add `NFData` instances for all types.
91+
92+## 0.1.6
93+### Added
94+- Use `pkgconfig` for C library dependency.
95+
96+## 0.1.5
97+### Added
98+- Flag for ECDH bindings.
99+
100+## 0.1.4
101+### Changed
102+- Constrain imports to avoid clashes with a QuickCheck function.
103+
104+## 0.1.3
105+### Added
106+- Hashable instances for various types.
107+
108+## 0.1.2
109+### Changed
110+- Separate dependencies between library and tests.
111+- Remove `hspec` default to prevent problems with Nix.
112+
113+### Removed
114+- Dependency to `cryptohash` not needed.
115+
116+## 0.1.1
117+### Changed
118+- Update changelog to reflect name and version change.
119+- Update to LTS Haskell 12.9.
120+
121+## 0.1.0
122+### Changed
123+- Name of package change from `secp256k1` to `secp256k1-haskell` to avoid Nix conflicts.
extra-deps/secp256k1-haskell/LICENSEnew file+19
@@ -0,0 +1,19 @@
1+Copyright 2020 Haskoin Developers
2+
3+Permission is hereby granted, free of charge, to any person obtaining a copy of
4+this software and associated documentation files (the "Software"), to deal in
5+the Software without restriction, including without limitation the rights to
6+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7+the Software, and to permit persons to whom the Software is furnished to do so,
8+subject to the following conditions:
9+
10+The above copyright notice and this permission notice shall be included in all
11+copies or substantial portions of the Software.
12+
13+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19+
extra-deps/secp256k1-haskell/README.mdnew file+6
@@ -0,0 +1,6 @@
1+[![Build Status](https://travis-ci.org/haskoin/secp256k1-haskell.svg?branch=master)](https://travis-ci.org/haskoin/secp256k1-haskell)
2+
3+# Haskell bindings for secp256k1
4+
5+This project contains Haskell bindings for the
6+[secp256k1](https://github.com/bitcoin-core/secp256k1) library.
extra-deps/secp256k1-haskell/Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
extra-deps/secp256k1-haskell/package.yamlnew file+49
@@ -0,0 +1,49 @@
1+name: secp256k1-haskell
2+version: 0.6.1
3+synopsis: Bindings for secp256k1
4+description: Sign and verify signatures using the secp256k1 library.
5+category: Crypto
6+author: Jean-Pierre Rupp
7+maintainer: jprupp@protonmail.ch
8+copyright: (c) 2017 Jean-Pierre Rupp
9+license: MIT
10+license-file: LICENSE
11+github: haskoin/secp256k1-haskell.git
12+homepage: http://github.com/haskoin/secp256k1-haskell#readme
13+extra-source-files:
14+ - CHANGELOG.md
15+ - README.md
16+dependencies:
17+ - base >=4.9 && <5
18+ - base16 >=0.3.0.1
19+ - bytestring >=0.10.8 && <0.12
20+ - cereal >=0.5.4 && <0.6
21+ - entropy >=0.3.8 && <0.5
22+ - deepseq >=1.4.2 && <1.5
23+ - hashable >=1.2.6 && <1.5
24+ - QuickCheck >=2.9.2 && <2.15
25+ - string-conversions >=0.4 && <0.5
26+ - unliftio-core >=0.1.0 && <0.3
27+library:
28+ source-dirs: src
29+ generated-exposed-modules:
30+ - Paths_secp256k1_haskell
31+ pkg-config-dependencies:
32+ - libsecp256k1
33+tests:
34+ spec:
35+ main: Spec.hs
36+ source-dirs: test
37+ ghc-options:
38+ - -threaded
39+ - -rtsopts
40+ - -with-rtsopts=-N
41+ verbatim:
42+ build-tool-depends:
43+ hspec-discover:hspec-discover
44+ dependencies:
45+ - hspec
46+ - secp256k1-haskell
47+ - monad-par
48+ - mtl
49+ - HUnit
extra-deps/secp256k1-haskell/secp256k1-haskell.cabalnew file+79
@@ -0,0 +1,79 @@
1+cabal-version: 2.0
2+
3+-- This file has been generated from package.yaml by hpack version 0.34.4.
4+--
5+-- see: https://github.com/sol/hpack
6+
7+name: secp256k1-haskell
8+version: 0.6.1
9+synopsis: Bindings for secp256k1
10+description: Sign and verify signatures using the secp256k1 library.
11+category: Crypto
12+homepage: http://github.com/haskoin/secp256k1-haskell#readme
13+bug-reports: https://github.com/haskoin/secp256k1-haskell.git/issues
14+author: Jean-Pierre Rupp
15+maintainer: jprupp@protonmail.ch
16+copyright: (c) 2017 Jean-Pierre Rupp
17+license: MIT
18+license-file: LICENSE
19+build-type: Simple
20+extra-source-files:
21+ CHANGELOG.md
22+ README.md
23+
24+source-repository head
25+ type: git
26+ location: https://github.com/haskoin/secp256k1-haskell.git
27+
28+library
29+ exposed-modules:
30+ Crypto.Secp256k1
31+ Crypto.Secp256k1.Internal
32+ Paths_secp256k1_haskell
33+ autogen-modules:
34+ Paths_secp256k1_haskell
35+ hs-source-dirs:
36+ src
37+ pkgconfig-depends:
38+ libsecp256k1
39+ build-depends:
40+ QuickCheck >=2.9.2 && <2.15
41+ , base >=4.9 && <5
42+ , base16 >=0.3.0.1
43+ , bytestring >=0.10.8 && <0.12
44+ , cereal >=0.5.4 && <0.6
45+ , deepseq >=1.4.2 && <1.5
46+ , entropy >=0.3.8 && <0.5
47+ , hashable >=1.2.6 && <1.5
48+ , string-conversions ==0.4.*
49+ , unliftio-core >=0.1.0 && <0.3
50+ default-language: Haskell2010
51+
52+test-suite spec
53+ type: exitcode-stdio-1.0
54+ main-is: Spec.hs
55+ other-modules:
56+ Crypto.Secp256k1.InternalSpec
57+ Crypto.Secp256k1Spec
58+ Paths_secp256k1_haskell
59+ hs-source-dirs:
60+ test
61+ ghc-options: -threaded -rtsopts -with-rtsopts=-N
62+ build-depends:
63+ HUnit
64+ , QuickCheck >=2.9.2 && <2.15
65+ , base >=4.9 && <5
66+ , base16 >=0.3.0.1
67+ , bytestring >=0.10.8 && <0.12
68+ , cereal >=0.5.4 && <0.6
69+ , deepseq >=1.4.2 && <1.5
70+ , entropy >=0.3.8 && <0.5
71+ , hashable >=1.2.6 && <1.5
72+ , hspec
73+ , monad-par
74+ , mtl
75+ , secp256k1-haskell
76+ , string-conversions ==0.4.*
77+ , unliftio-core >=0.1.0 && <0.3
78+ default-language: Haskell2010
79+ build-tool-depends: hspec-discover:hspec-discover
extra-deps/secp256k1-haskell/src/Crypto/Secp256k1.hsnew file+443
@@ -0,0 +1,443 @@
1+{-# LANGUAGE DeriveGeneric #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-|
6+Module : Crypto.Secp256k1
7+License : UNLICENSE
8+Maintainer : Jean-Pierre Rupp <jprupp@protonmail.ch>
9+Stability : experimental
10+Portability : POSIX
11+
12+Crytpographic functions from Bitcoin’s secp256k1 library.
13+-}
14+module Crypto.Secp256k1
15+ ( -- * Messages
16+ Msg
17+ , msg
18+ , getMsg
19+
20+ -- * Secret Keys
21+ , SecKey
22+ , secKey
23+ , getSecKey
24+ , derivePubKey
25+
26+ -- * Public Keys
27+ , PubKey
28+ , importPubKey
29+ , exportPubKey
30+
31+ -- * Signatures
32+ , Sig
33+ , signMsg
34+ , verifySig
35+ , normalizeSig
36+ -- ** DER
37+ , importSig
38+ , exportSig
39+ -- ** Compact
40+ , CompactSig
41+ , getCompactSig
42+ , compactSig
43+ , exportCompactSig
44+ , importCompactSig
45+
46+ -- * Addition & Multiplication
47+ , Tweak
48+ , tweak
49+ , getTweak
50+ , tweakAddSecKey
51+ , tweakMulSecKey
52+ , tweakAddPubKey
53+ , tweakMulPubKey
54+ , combinePubKeys
55+ , tweakNegate
56+ ) where
57+
58+import Control.DeepSeq (NFData)
59+import Control.Monad (replicateM, unless, (<=<))
60+import Crypto.Secp256k1.Internal
61+import Data.ByteString (ByteString)
62+import qualified Data.ByteString as BS
63+import qualified Data.ByteString.Base16 as B16
64+import Data.Hashable (Hashable (..))
65+import Data.Maybe (fromJust, fromMaybe, isJust)
66+import Data.Serialize (Serialize (..), getByteString,
67+ putByteString)
68+import Data.String (IsString (..))
69+import Data.String.Conversions (ConvertibleStrings, cs)
70+import Foreign (alloca, allocaArray, allocaBytes,
71+ free, mallocBytes, nullFunPtr,
72+ nullPtr, peek, poke, pokeArray)
73+import GHC.Generics (Generic)
74+import System.IO.Unsafe (unsafePerformIO)
75+import Test.QuickCheck (Arbitrary (..),
76+ arbitraryBoundedRandom, suchThat)
77+import Text.Read (Lexeme (String), lexP, parens,
78+ pfail, readPrec)
79+
80+newtype PubKey = PubKey { getPubKey :: ByteString }
81+ deriving (Eq, Generic, NFData)
82+newtype Msg = Msg { getMsg :: ByteString }
83+ deriving (Eq, Generic, NFData)
84+newtype Sig = Sig { getSig :: ByteString }
85+ deriving (Eq, Generic, NFData)
86+newtype SecKey = SecKey { getSecKey :: ByteString }
87+ deriving (Eq, Generic, NFData)
88+newtype Tweak = Tweak { getTweak :: ByteString }
89+ deriving (Eq, Generic, NFData)
90+newtype CompactSig = CompactSig { getCompactSig :: ByteString }
91+ deriving (Eq, Generic, NFData)
92+
93+instance Serialize PubKey where
94+ put (PubKey bs) = putByteString bs
95+ get = PubKey <$> getByteString 64
96+
97+instance Serialize Msg where
98+ put (Msg m) = putByteString m
99+ get = Msg <$> getByteString 32
100+
101+instance Serialize Sig where
102+ put (Sig bs) = putByteString bs
103+ get = Sig <$> getByteString 64
104+
105+instance Serialize SecKey where
106+ put (SecKey bs) = putByteString bs
107+ get = SecKey <$> getByteString 32
108+
109+instance Serialize Tweak where
110+ put (Tweak bs) = putByteString bs
111+ get = Tweak <$> getByteString 32
112+
113+instance Serialize CompactSig where
114+ put (CompactSig bs) = putByteString bs
115+ get = CompactSig <$> getByteString 64
116+
117+decodeHex :: ConvertibleStrings a ByteString => a -> Maybe ByteString
118+decodeHex str = case B16.decodeBase16 $ cs str of
119+ Right bs -> Just bs
120+ Left _ -> Nothing
121+
122+instance Read PubKey where
123+ readPrec = do
124+ String str <- lexP
125+ maybe pfail return $ importPubKey =<< decodeHex str
126+
127+instance Hashable PubKey where
128+ i `hashWithSalt` k = i `hashWithSalt` exportPubKey True k
129+
130+instance IsString PubKey where
131+ fromString = fromMaybe e . (importPubKey <=< decodeHex) where
132+ e = error "Could not decode public key from hex string"
133+
134+instance Show PubKey where
135+ showsPrec _ = shows . B16.encodeBase16 . exportPubKey True
136+
137+instance Read Msg where
138+ readPrec = parens $ do
139+ String str <- lexP
140+ maybe pfail return $ msg =<< decodeHex str
141+
142+instance Hashable Msg where
143+ i `hashWithSalt` m = i `hashWithSalt` getMsg m
144+
145+instance IsString Msg where
146+ fromString = fromMaybe e . (msg <=< decodeHex) where
147+ e = error "Could not decode message from hex string"
148+
149+instance Show Msg where
150+ showsPrec _ = shows . B16.encodeBase16 . getMsg
151+
152+instance Read Sig where
153+ readPrec = parens $ do
154+ String str <- lexP
155+ maybe pfail return $ importSig =<< decodeHex str
156+
157+instance IsString Sig where
158+ fromString = fromMaybe e . (importSig <=< decodeHex) where
159+ e = error "Could not decode signature from hex string"
160+
161+instance Hashable Sig where
162+ i `hashWithSalt` s = i `hashWithSalt` exportSig s
163+
164+instance Show Sig where
165+ showsPrec _ = shows . B16.encodeBase16 . exportSig
166+
167+instance Read SecKey where
168+ readPrec = parens $ do
169+ String str <- lexP
170+ maybe pfail return $ secKey =<< decodeHex str
171+
172+instance Hashable SecKey where
173+ i `hashWithSalt` k = i `hashWithSalt` getSecKey k
174+
175+instance IsString SecKey where
176+ fromString = fromMaybe e . (secKey <=< decodeHex) where
177+ e = error "Colud not decode secret key from hex string"
178+
179+instance Show SecKey where
180+ showsPrec _ = shows . B16.encodeBase16 . getSecKey
181+
182+instance Hashable Tweak where
183+ i `hashWithSalt` t = i `hashWithSalt` getTweak t
184+
185+instance Read Tweak where
186+ readPrec = parens $ do
187+ String str <- lexP
188+ maybe pfail return $ tweak =<< decodeHex str
189+
190+instance IsString Tweak where
191+ fromString = fromMaybe e . (tweak <=< decodeHex) where
192+ e = error "Could not decode tweak from hex string"
193+
194+instance Show Tweak where
195+ showsPrec _ = shows . B16.encodeBase16 . getTweak
196+
197+-- | Import 32-byte 'ByteString' as 'Msg'.
198+msg :: ByteString -> Maybe Msg
199+msg bs
200+ | BS.length bs == 32 = Just (Msg bs)
201+ | otherwise = Nothing
202+
203+-- | Import 32-byte 'ByteString' as 'SecKey'.
204+secKey :: ByteString -> Maybe SecKey
205+secKey bs
206+ | BS.length bs == 32 = Just (SecKey bs)
207+ | otherwise = Nothing
208+
209+compactSig :: ByteString -> Maybe CompactSig
210+compactSig bs
211+ | BS.length bs == 64 = Just (CompactSig bs)
212+ | otherwise = Nothing
213+
214+-- | Convert signature to a normalized lower-S form. 'Nothing' indicates that it
215+-- was already normal.
216+normalizeSig :: Sig -> Maybe Sig
217+normalizeSig (Sig sig) = unsafePerformIO $
218+ unsafeUseByteString sig $ \(sig_in, _) -> do
219+ sig_out <- mallocBytes 64
220+ ret <- ecdsaSignatureNormalize ctx sig_out sig_in
221+ if isSuccess ret
222+ then do
223+ bs <- unsafePackByteString (sig_out, 64)
224+ return (Just (Sig bs))
225+ else do
226+ free sig_out
227+ return Nothing
228+
229+-- | 32-Byte 'ByteString' as 'Tweak'.
230+tweak :: ByteString -> Maybe Tweak
231+tweak bs
232+ | BS.length bs == 32 = Just (Tweak bs)
233+ | otherwise = Nothing
234+
235+-- | Import DER-encoded public key.
236+importPubKey :: ByteString -> Maybe PubKey
237+importPubKey bs
238+ | BS.null bs = Nothing
239+ | otherwise = unsafePerformIO $
240+ unsafeUseByteString bs $ \(input, len) -> do
241+ pub_key <- mallocBytes 64
242+ ret <- ecPubKeyParse ctx pub_key input len
243+ if isSuccess ret
244+ then do
245+ out <- unsafePackByteString (pub_key, 64)
246+ return (Just (PubKey out))
247+ else do
248+ free pub_key
249+ return Nothing
250+
251+-- | Encode public key as DER. First argument 'True' for compressed output.
252+exportPubKey :: Bool -> PubKey -> ByteString
253+exportPubKey compress (PubKey in_bs) = unsafePerformIO $
254+ unsafeUseByteString in_bs $ \(in_ptr, _) ->
255+ alloca $ \len_ptr ->
256+ allocaBytes len $ \out_ptr -> do
257+ poke len_ptr $ fromIntegral len
258+ ret <- ecPubKeySerialize ctx out_ptr len_ptr in_ptr flags
259+ unless (isSuccess ret) $ error "could not serialize public key"
260+ final_len <- peek len_ptr
261+ packByteString (out_ptr, final_len)
262+ where
263+ len = if compress then 33 else 65
264+ flags = if compress then compressed else uncompressed
265+
266+exportCompactSig :: Sig -> CompactSig
267+exportCompactSig (Sig sig_bs) = unsafePerformIO $
268+ unsafeUseByteString sig_bs $ \(sig_ptr, _) -> do
269+ out_ptr <- mallocBytes 64
270+ ret <- ecdsaSignatureSerializeCompact ctx out_ptr sig_ptr
271+ unless (isSuccess ret) $ do
272+ free out_ptr
273+ error "Could not obtain compact signature"
274+ out_bs <- unsafePackByteString (out_ptr, 64)
275+ return $ CompactSig out_bs
276+
277+importCompactSig :: CompactSig -> Maybe Sig
278+importCompactSig (CompactSig compact_sig) = unsafePerformIO $
279+ unsafeUseByteString compact_sig $ \(compact_ptr, _) -> do
280+ out_sig <- mallocBytes 64
281+ ret <- ecdsaSignatureParseCompact ctx out_sig compact_ptr
282+ if isSuccess ret
283+ then do
284+ out_bs <- unsafePackByteString (out_sig, 64)
285+ return (Just (Sig out_bs))
286+ else do
287+ free out_sig
288+ return Nothing
289+
290+-- | Import DER-encoded signature.
291+importSig :: ByteString -> Maybe Sig
292+importSig bs
293+ | BS.null bs = Nothing
294+ | otherwise = unsafePerformIO $
295+ unsafeUseByteString bs $ \(in_ptr, in_len) -> do
296+ out_sig <- mallocBytes 64
297+ ret <- ecdsaSignatureParseDer ctx out_sig in_ptr in_len
298+ if isSuccess ret
299+ then do
300+ out_bs <- unsafePackByteString (out_sig, 64)
301+ return (Just (Sig out_bs))
302+ else do
303+ free out_sig
304+ return Nothing
305+
306+-- | Encode signature as strict DER.
307+exportSig :: Sig -> ByteString
308+exportSig (Sig in_sig) = unsafePerformIO $
309+ unsafeUseByteString in_sig $ \(in_ptr, _) ->
310+ alloca $ \out_len ->
311+ allocaBytes 72 $ \out_ptr -> do
312+ poke out_len 72
313+ ret <- ecdsaSignatureSerializeDer ctx out_ptr out_len in_ptr
314+ unless (isSuccess ret) $ error "could not serialize signature"
315+ final_len <- peek out_len
316+ packByteString (out_ptr, final_len)
317+
318+-- | Verify message signature. 'True' means that the signature is correct.
319+verifySig :: PubKey -> Sig -> Msg -> Bool
320+verifySig (PubKey pub_key) (Sig sig) (Msg m) = unsafePerformIO $
321+ unsafeUseByteString pub_key $ \(pub_key_ptr, _) ->
322+ unsafeUseByteString sig $ \(sig_ptr, _) ->
323+ unsafeUseByteString m $ \(msg_ptr, _) ->
324+ isSuccess <$> ecdsaVerify ctx sig_ptr msg_ptr pub_key_ptr
325+
326+signMsg :: SecKey -> Msg -> Sig
327+signMsg (SecKey sec_key) (Msg m) = unsafePerformIO $
328+ unsafeUseByteString sec_key $ \(sec_key_ptr, _) ->
329+ unsafeUseByteString m $ \(msg_ptr, _) -> do
330+ sig_ptr <- mallocBytes 64
331+ ret <- ecdsaSign ctx sig_ptr msg_ptr sec_key_ptr nullFunPtr nullPtr
332+ unless (isSuccess ret) $ do
333+ free sig_ptr
334+ error "could not sign message"
335+ Sig <$> unsafePackByteString (sig_ptr, 64)
336+
337+derivePubKey :: SecKey -> PubKey
338+derivePubKey (SecKey sec_key) = unsafePerformIO $
339+ unsafeUseByteString sec_key $ \(sec_key_ptr, _) -> do
340+ pub_key_ptr <- mallocBytes 64
341+ ret <- ecPubKeyCreate ctx pub_key_ptr sec_key_ptr
342+ unless (isSuccess ret) $ do
343+ free pub_key_ptr
344+ error "could not compute public key"
345+ PubKey <$> unsafePackByteString (pub_key_ptr, 64)
346+
347+
348+-- | Add tweak to secret key.
349+tweakAddSecKey :: SecKey -> Tweak -> Maybe SecKey
350+tweakAddSecKey (SecKey sec_key) (Tweak t) = unsafePerformIO $
351+ unsafeUseByteString new_bs $ \(sec_key_ptr, _) ->
352+ unsafeUseByteString t $ \(tweak_ptr, _) -> do
353+ ret <- ecSecKeyTweakAdd ctx sec_key_ptr tweak_ptr
354+ if isSuccess ret
355+ then return (Just (SecKey new_bs))
356+ else return Nothing
357+ where
358+ new_bs = BS.copy sec_key
359+
360+-- | Multiply secret key by tweak.
361+tweakMulSecKey :: SecKey -> Tweak -> Maybe SecKey
362+tweakMulSecKey (SecKey sec_key) (Tweak t) = unsafePerformIO $
363+ unsafeUseByteString new_bs $ \(sec_key_ptr, _) ->
364+ unsafeUseByteString t $ \(tweak_ptr, _) -> do
365+ ret <- ecSecKeyTweakMul ctx sec_key_ptr tweak_ptr
366+ if isSuccess ret
367+ then return (Just (SecKey new_bs))
368+ else return Nothing
369+ where
370+ new_bs = BS.copy sec_key
371+
372+-- | Add tweak to public key. Tweak is multiplied first by G to obtain a point.
373+tweakAddPubKey :: PubKey -> Tweak -> Maybe PubKey
374+tweakAddPubKey (PubKey pub_key) (Tweak t) = unsafePerformIO $
375+ unsafeUseByteString new_bs $ \(pub_key_ptr, _) ->
376+ unsafeUseByteString t $ \(tweak_ptr, _) -> do
377+ ret <- ecPubKeyTweakAdd ctx pub_key_ptr tweak_ptr
378+ if isSuccess ret
379+ then return (Just (PubKey new_bs))
380+ else return Nothing
381+ where
382+ new_bs = BS.copy pub_key
383+
384+-- | Multiply public key by tweak. Tweak is multiplied first by G to obtain a
385+-- point.
386+tweakMulPubKey :: PubKey -> Tweak -> Maybe PubKey
387+tweakMulPubKey (PubKey pub_key) (Tweak t) = unsafePerformIO $
388+ unsafeUseByteString new_bs $ \(pub_key_ptr, _) ->
389+ unsafeUseByteString t $ \(tweak_ptr, _) -> do
390+ ret <- ecPubKeyTweakMul ctx pub_key_ptr tweak_ptr
391+ if isSuccess ret
392+ then return (Just (PubKey new_bs))
393+ else return Nothing
394+ where
395+ new_bs = BS.copy pub_key
396+
397+-- | Add multiple public keys together.
398+combinePubKeys :: [PubKey] -> Maybe PubKey
399+combinePubKeys [] = Nothing
400+combinePubKeys pubs = unsafePerformIO $
401+ pointers [] pubs $ \ps ->
402+ allocaArray (length ps) $ \a -> do
403+ out <- mallocBytes 64
404+ pokeArray a ps
405+ ret <- ecPubKeyCombine ctx out a (fromIntegral $ length ps)
406+ if isSuccess ret
407+ then do
408+ bs <- unsafePackByteString (out, 64)
409+ return (Just (PubKey bs))
410+ else do
411+ free out
412+ return Nothing
413+ where
414+ pointers ps [] f = f ps
415+ pointers ps (PubKey pub_key : pub_keys) f =
416+ unsafeUseByteString pub_key $ \(p, _) ->
417+ pointers (p : ps) pub_keys f
418+
419+tweakNegate :: Tweak -> Maybe Tweak
420+tweakNegate (Tweak t) = unsafePerformIO $
421+ unsafeUseByteString new $ \(out, _) -> do
422+ ret <- ecTweakNegate ctx out
423+ if isSuccess ret
424+ then return (Just (Tweak new))
425+ else return Nothing
426+ where
427+ new = BS.copy t
428+
429+instance Arbitrary Msg where
430+ arbitrary = gen_msg
431+ where
432+ valid_bs = bs_gen `suchThat` isJust
433+ bs_gen = msg . BS.pack <$> replicateM 32 arbitraryBoundedRandom
434+ gen_msg = fromJust <$> valid_bs
435+
436+instance Arbitrary SecKey where
437+ arbitrary = gen_key where
438+ valid_bs = bs_gen `suchThat` isJust
439+ bs_gen = secKey . BS.pack <$> replicateM 32 arbitraryBoundedRandom
440+ gen_key = fromJust <$> valid_bs
441+
442+instance Arbitrary PubKey where
443+ arbitrary = derivePubKey <$> arbitrary
extra-deps/secp256k1-haskell/src/Crypto/Secp256k1/Internal.hsnew file+270
@@ -0,0 +1,270 @@
1+{-|
2+Module : Crypto.Secp256k1.Internal
3+License : UNLICENSE
4+Maintainer : Jean-Pierre Rupp <jprupp@protonmail.ch>
5+Stability : experimental
6+Portability : POSIX
7+
8+The API for this module may change at any time. This is an internal module only
9+exposed for hacking and experimentation.
10+-}
11+module Crypto.Secp256k1.Internal where
12+
13+import Data.ByteString (ByteString)
14+import qualified Data.ByteString as BS
15+import qualified Data.ByteString.Unsafe as BU
16+import Foreign (FunPtr, Ptr, castPtr)
17+import Foreign.C (CInt (..), CSize (..), CString, CUChar,
18+ CUInt (..))
19+import System.IO.Unsafe (unsafePerformIO)
20+
21+data LCtx
22+data PubKey64
23+data Msg32
24+data Sig64
25+data Compact64
26+data Seed32
27+data SecKey32
28+data Tweak32
29+
30+type CtxFlags = CUInt
31+type SerFlags = CUInt
32+type Ret = CInt
33+
34+type NonceFun a =
35+ Ptr CUChar ->
36+ Ptr CUChar ->
37+ Ptr CUChar ->
38+ Ptr CUChar ->
39+ Ptr a ->
40+ CInt ->
41+ IO CInt
42+
43+type Ctx = Ptr LCtx
44+
45+verify :: CtxFlags
46+verify = 0x0101
47+
48+sign :: CtxFlags
49+sign = 0x0201
50+
51+signVerify :: CtxFlags
52+signVerify = 0x0301
53+
54+compressed :: SerFlags
55+compressed = 0x0102
56+
57+uncompressed :: SerFlags
58+uncompressed = 0x0002
59+
60+isSuccess :: Ret -> Bool
61+isSuccess 0 = False
62+isSuccess 1 = True
63+isSuccess n = error $ "isSuccess expected 0 or 1 but got " ++ show n
64+
65+unsafeUseByteString :: ByteString -> ((Ptr a, CSize) -> IO b) -> IO b
66+unsafeUseByteString bs f =
67+ BU.unsafeUseAsCStringLen bs $ \(b, l) ->
68+ f (castPtr b, fromIntegral l)
69+
70+useByteString :: ByteString -> ((Ptr a, CSize) -> IO b) -> IO b
71+useByteString bs f =
72+ BS.useAsCStringLen bs $ \(b, l) ->
73+ f (castPtr b, fromIntegral l)
74+
75+unsafePackByteString :: (Ptr a, CSize) -> IO ByteString
76+unsafePackByteString (b, l) =
77+ BU.unsafePackMallocCStringLen (castPtr b, fromIntegral l)
78+
79+packByteString :: (Ptr a, CSize) -> IO ByteString
80+packByteString (b, l) =
81+ BS.packCStringLen (castPtr b, fromIntegral l)
82+
83+ctx :: Ctx
84+ctx = unsafePerformIO $ contextCreate signVerify
85+{-# NOINLINE ctx #-}
86+
87+foreign import ccall safe
88+ "secp256k1.h secp256k1_context_create"
89+ contextCreate
90+ :: CtxFlags
91+ -> IO Ctx
92+
93+foreign import ccall safe
94+ "secp256k1.h secp256k1_context_clone"
95+ contextClone
96+ :: Ctx
97+ -> IO Ctx
98+
99+foreign import ccall safe
100+ "secp256k1.h &secp256k1_context_destroy"
101+ contextDestroy
102+ :: FunPtr (Ctx -> IO ())
103+
104+foreign import ccall safe
105+ "secp256k1.h secp256k1_context_set_illegal_callback"
106+ setIllegalCallback
107+ :: Ctx
108+ -> FunPtr (CString -> Ptr a -> IO ()) -- ^ message, data
109+ -> Ptr a -- ^ data
110+ -> IO ()
111+
112+foreign import ccall safe
113+ "secp256k1.h secp256k1_context_set_error_callback"
114+ setErrorCallback
115+ :: Ctx
116+ -> FunPtr (CString -> Ptr a -> IO ()) -- ^ message, data
117+ -> Ptr a -- ^ data
118+ -> IO ()
119+
120+foreign import ccall safe
121+ "secp256k1.h secp256k1_ec_pubkey_parse"
122+ ecPubKeyParse
123+ :: Ctx
124+ -> Ptr PubKey64
125+ -> Ptr CUChar -- ^ encoded public key array
126+ -> CSize -- ^ size of encoded public key array
127+ -> IO Ret
128+
129+foreign import ccall safe
130+ "secp256k1.h secp256k1_ec_pubkey_serialize"
131+ ecPubKeySerialize
132+ :: Ctx
133+ -> Ptr CUChar -- ^ array for encoded public key, must be large enough
134+ -> Ptr CSize -- ^ size of encoded public key, will be updated
135+ -> Ptr PubKey64
136+ -> SerFlags
137+ -> IO Ret
138+
139+foreign import ccall safe
140+ "secp256k1.h secp256k1_ecdsa_signature_parse_compact"
141+ ecdsaSignatureParseCompact
142+ :: Ctx
143+ -> Ptr Sig64
144+ -> Ptr Compact64
145+ -> IO Ret
146+
147+
148+foreign import ccall safe
149+ "secp256k1.h secp256k1_ecdsa_signature_parse_der"
150+ ecdsaSignatureParseDer
151+ :: Ctx
152+ -> Ptr Sig64
153+ -> Ptr CUChar -- ^ encoded DER signature
154+ -> CSize -- ^ size of encoded signature
155+ -> IO Ret
156+
157+foreign import ccall safe
158+ "secp256k1.h secp256k1_ecdsa_signature_serialize_der"
159+ ecdsaSignatureSerializeDer
160+ :: Ctx
161+ -> Ptr CUChar -- ^ array for encoded signature, must be large enough
162+ -> Ptr CSize -- ^ size of encoded signature, will be updated
163+ -> Ptr Sig64
164+ -> IO Ret
165+
166+foreign import ccall safe
167+ "secp256k1.h secp256k1_ecdsa_signature_serialize_compact"
168+ ecdsaSignatureSerializeCompact
169+ :: Ctx
170+ -> Ptr Compact64
171+ -> Ptr Sig64
172+ -> IO Ret
173+
174+foreign import ccall safe
175+ "secp256k1.h secp256k1_ecdsa_verify"
176+ ecdsaVerify
177+ :: Ctx
178+ -> Ptr Sig64
179+ -> Ptr Msg32
180+ -> Ptr PubKey64
181+ -> IO Ret
182+
183+foreign import ccall safe
184+ "secp256k1.h secp256k1_ecdsa_signature_normalize"
185+ ecdsaSignatureNormalize
186+ :: Ctx
187+ -> Ptr Sig64 -- ^ output
188+ -> Ptr Sig64 -- ^ input
189+ -> IO Ret
190+
191+foreign import ccall safe
192+ "secp256k1.h secp256k1_ecdsa_sign"
193+ ecdsaSign
194+ :: Ctx
195+ -> Ptr Sig64
196+ -> Ptr Msg32
197+ -> Ptr SecKey32
198+ -> FunPtr (NonceFun a)
199+ -> Ptr a -- ^ nonce data
200+ -> IO Ret
201+
202+foreign import ccall safe
203+ "secp256k1.h secp256k1_ec_seckey_verify"
204+ ecSecKeyVerify
205+ :: Ctx
206+ -> Ptr SecKey32
207+ -> IO Ret
208+
209+foreign import ccall safe
210+ "secp256k1.h secp256k1_ec_pubkey_create"
211+ ecPubKeyCreate
212+ :: Ctx
213+ -> Ptr PubKey64
214+ -> Ptr SecKey32
215+ -> IO Ret
216+
217+foreign import ccall safe
218+ "secp256k1.h secp256k1_ec_privkey_tweak_add"
219+ ecSecKeyTweakAdd
220+ :: Ctx
221+ -> Ptr SecKey32
222+ -> Ptr Tweak32
223+ -> IO Ret
224+
225+foreign import ccall safe
226+ "secp256k1.h secp256k1_ec_privkey_negate"
227+ ecTweakNegate
228+ :: Ctx
229+ -> Ptr Tweak32
230+ -> IO Ret
231+
232+foreign import ccall unsafe
233+ "secp256k1.h secp256k1_ec_pubkey_tweak_add"
234+ ecPubKeyTweakAdd
235+ :: Ctx
236+ -> Ptr PubKey64
237+ -> Ptr Tweak32
238+ -> IO Ret
239+
240+foreign import ccall safe
241+ "secp256k1.h secp256k1_ec_privkey_tweak_mul"
242+ ecSecKeyTweakMul
243+ :: Ctx
244+ -> Ptr SecKey32
245+ -> Ptr Tweak32
246+ -> IO Ret
247+
248+foreign import ccall safe
249+ "secp256k1.h secp256k1_ec_pubkey_tweak_mul"
250+ ecPubKeyTweakMul
251+ :: Ctx
252+ -> Ptr PubKey64
253+ -> Ptr Tweak32
254+ -> IO Ret
255+
256+foreign import ccall safe
257+ "secp256k1.h secp256k1_context_randomize"
258+ contextRandomize
259+ :: Ctx
260+ -> Ptr Seed32
261+ -> IO Ret
262+
263+foreign import ccall safe
264+ "secp256k1.h secp256k1_ec_pubkey_combine"
265+ ecPubKeyCombine
266+ :: Ctx
267+ -> Ptr PubKey64 -- ^ pointer to public key storage
268+ -> Ptr (Ptr PubKey64) -- ^ pointer to array of public keys
269+ -> CInt -- ^ number of public keys
270+ -> IO Ret
extra-deps/secp256k1-haskell/stack.yamlnew file+5
@@ -0,0 +1,5 @@
1+resolver: lts-18.28
2+nix:
3+ packages:
4+ - secp256k1
5+ - pkg-config
extra-deps/secp256k1-haskell/test/Crypto/Secp256k1/InternalSpec.hsnew file+378
@@ -0,0 +1,378 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Crypto.Secp256k1.InternalSpec (spec) where
3+
4+import Control.Monad
5+import Control.Monad.Trans
6+import Crypto.Secp256k1.Internal
7+import Data.ByteString (ByteString, copy, packCStringLen,
8+ useAsCStringLen)
9+import qualified Data.ByteString.Base16 as B16
10+import Data.Either (fromRight)
11+import Foreign
12+import System.Entropy
13+import Test.HUnit (Assertion, assertBool, assertEqual)
14+import Test.Hspec
15+
16+spec :: Spec
17+spec = do
18+ describe "housekeeping" $ do
19+ it "creates context" createContextTest
20+ it "randomizes context" randomizeContextTest
21+ it "clones context" cloneContextTest
22+ describe "serialization" $ do
23+ it "parses public key" ecPubkeyParseTest
24+ it "serializes public key" ecPubKeySerializeTest
25+ it "parses DER signature" ecdsaSignatureParseDerTest
26+ it "serializes DER signature" ecdsaSignatureSerializeDerTest
27+ describe "signatures" $ do
28+ it "verifies signature" ecdsaVerifyTest
29+ -- TODO:
30+ -- , testCase "RFC6979 nonce function" nonce_function_rfc6979_test
31+ it "signs message" ecdsaSignTest
32+ describe "secret keys" $ do
33+ it "verifies secret key" ecSecKeyVerifyTest
34+ it "creates public key" ecPubkeyCreateTest
35+ it "adds secret key" ecSecKeyTweakAddTest
36+ it "multiplies secret key" ecSecKeyTweakMulTest
37+ describe "public keys" $ do
38+ it "adds public key" ecPubKeyTweakAddTest
39+ it "multiplies public key" ecPubKeyTweakMulTest
40+ it "combines public keys" ecPubKeyCombineTest
41+
42+withEntropy :: (Ptr Seed32 -> IO a) -> IO a
43+withEntropy f =
44+ getEntropy 32 >>= \e ->
45+ useByteString e $ \(s, _) -> f s
46+
47+createContextTest :: Assertion
48+createContextTest = do
49+ context_ptr <- liftIO $ contextCreate signVerify
50+ assertBool "context not null" $ context_ptr /= nullPtr
51+
52+randomizeContextTest :: Assertion
53+randomizeContextTest = do
54+ ret <- liftIO $ contextCreate sign >>= \x ->
55+ withEntropy (contextRandomize x)
56+ assertBool "context randomized" $ isSuccess ret
57+
58+cloneContextTest :: Assertion
59+cloneContextTest = do
60+ (x1, x2) <- liftIO $ do
61+ x1 <- contextCreate signVerify
62+ ret <- withEntropy $ contextRandomize x1
63+ unless (isSuccess ret) $ error "failed to randomize context"
64+ x2 <- contextClone x1
65+ return (x1, x2)
66+ assertBool "original context not null" $ x1 /= nullPtr
67+ assertBool "cloned context not null" $ x2 /= nullPtr
68+ assertBool "context ptrs different" $ x1 /= x2
69+
70+ecPubkeyParseTest :: Assertion
71+ecPubkeyParseTest = do
72+ ret <- liftIO $ useAsCStringLen der $ \(i, il) -> do
73+ x <- contextCreate verify
74+ allocaBytes 64 $ \pubkey ->
75+ ecPubKeyParse x pubkey (castPtr i) (fromIntegral il)
76+ assertBool "parsed public key" (isSuccess ret)
77+ where
78+ der = fromRight undefined $ B16.decodeBase16
79+ "03dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd44705"
80+
81+ecPubKeySerializeTest :: Assertion
82+ecPubKeySerializeTest = do
83+ (ret, dec) <- liftIO $
84+ useByteString der $ \(i, il) ->
85+ allocaBytes 64 $ \k ->
86+ alloca $ \ol ->
87+ allocaBytes 72 $ \o -> do
88+ poke ol 72
89+ x <- contextCreate verify
90+ ret1 <- ecPubKeyParse x k i il
91+ unless (isSuccess ret1) $ error "failed to parse pubkey"
92+ ret2 <- ecPubKeySerialize x o ol k compressed
93+ len <- fromIntegral <$> peek ol
94+ decoded <- packCStringLen (castPtr o, len)
95+ return (ret2, decoded)
96+ assertBool "serialized public key successfully" $ isSuccess ret
97+ assertEqual "public key matches" der dec
98+ where
99+ der = fromRight undefined $ B16.decodeBase16
100+ "03dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd44705"
101+
102+ecdsaSignatureParseDerTest :: Assertion
103+ecdsaSignatureParseDerTest = do
104+ ret <- liftIO $ useAsCStringLen der $ \(d, dl) -> allocaBytes 64 $ \s -> do
105+ x <- contextCreate verify
106+ ecdsaSignatureParseDer x s (castPtr d) (fromIntegral dl)
107+ assertBool "parsed signature successfully" $ isSuccess ret
108+ where
109+ der = fromRight undefined $ B16.decodeBase16
110+ "3045022100f502bfa07af43e7ef265618b0d929a7619ee01d6150e37eb6eaaf2c8bd37\
111+ \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\
112+ \45"
113+
114+parseDer :: Ctx -> ByteString -> IO ByteString
115+parseDer x bs =
116+ useAsCStringLen bs $ \(d, dl) ->
117+ allocaBytes 64 $ \s -> do
118+ ret <- ecdsaSignatureParseDer x s (castPtr d) (fromIntegral dl)
119+ unless (isSuccess ret) $ error "could not parse DER"
120+ packByteString (s, 64)
121+
122+ecdsaSignatureSerializeDerTest :: Assertion
123+ecdsaSignatureSerializeDerTest = do
124+ (ret, enc) <- liftIO $ do
125+ x <- contextCreate verify
126+ sig <- parseDer x der
127+ alloca $ \ol ->
128+ allocaBytes 72 $ \o ->
129+ useByteString sig $ \(s, _) -> do
130+ poke ol 72
131+ ret <- ecdsaSignatureSerializeDer x o ol s
132+ len <- fromIntegral <$> peek ol
133+ enc <- packCStringLen (castPtr o, len)
134+ return (ret, enc)
135+ assertBool "serialization successful" $ isSuccess ret
136+ assertEqual "signatures match" der enc
137+ where
138+ der = fromRight undefined $ B16.decodeBase16
139+ "3045022100f502bfa07af43e7ef265618b0d929a7619ee01d6150e37eb6eaaf2c8bd37\
140+ \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\
141+ \45"
142+
143+ecdsaVerifyTest :: Assertion
144+ecdsaVerifyTest = do
145+ ret <- liftIO $ do
146+ x <- contextCreate verify
147+ sig <- parseDer x der
148+ pk <- useByteString pub $ \(p, pl) ->
149+ allocaBytes 64 $ \k -> do
150+ ret <- ecPubKeyParse x k p (fromIntegral pl)
151+ unless (isSuccess ret) $ error "could not parse public key"
152+ packByteString (k, 64)
153+ useByteString msg $ \(m, _) ->
154+ useByteString pk $ \(k, _) ->
155+ useByteString sig $ \(s, _) ->
156+ ecdsaVerify x s m k
157+ assertBool "signature valid" $ isSuccess ret
158+ where
159+ der = fromRight undefined $ B16.decodeBase16
160+ "3045022100f502bfa07af43e7ef265618b0d929a7619ee01d6150e37eb6eaaf2c8bd37\
161+ \fb2202206f0415ab0e9a977afd78b2c26ef39b3952096d319fd4b101c768ad6c132e30\
162+ \45"
163+ pub = fromRight undefined $ B16.decodeBase16
164+ "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\
165+ \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
166+ msg = fromRight undefined $ B16.decodeBase16
167+ "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"
168+
169+signCtx :: IO Ctx
170+signCtx = contextCreate sign >>= \c ->
171+ withEntropy (contextRandomize c) >>= \r ->
172+ unless (isSuccess r) (error "failed to randomize context") >> return c
173+
174+createPubKey :: Ctx -> Ptr SecKey32 -> Ptr PubKey64 -> IO ()
175+createPubKey x k p = do
176+ ret <- ecPubKeyCreate x p k
177+ unless (isSuccess ret) $ error "failed to create public key"
178+
179+ecdsaSignTest :: Assertion
180+ecdsaSignTest = do
181+ der <- liftIO $ do
182+ x <- signCtx
183+ allocaBytes 64 $ \s ->
184+ useByteString msg $ \(m, _) ->
185+ useByteString key $ \(k, _) ->
186+ alloca $ \ol ->
187+ allocaBytes 72 $ \o -> do
188+ poke ol 72
189+ ret1 <- ecdsaSign x s m k nullFunPtr nullPtr
190+ unless (isSuccess ret1) $ error "could not sign message"
191+ ret2 <- ecdsaSignatureSerializeDer x o ol s
192+ unless (isSuccess ret2) $ error "could not serialize signature"
193+ len <- peek ol
194+ packCStringLen (castPtr o, fromIntegral len)
195+ ret <- liftIO $ do
196+ pub <- allocaBytes 64 $ \p ->
197+ useByteString key $ \(s, _) -> do
198+ x <- signCtx
199+ createPubKey x s p
200+ packByteString (p, 64)
201+ useByteString msg $ \(m, _) ->
202+ useByteString pub $ \(p, _) -> do
203+ x <- contextCreate verify
204+ s' <- parseDer x der
205+ useByteString s' $ \(s, _) -> ecdsaVerify x s m p
206+ assertBool "signature matches" (isSuccess ret)
207+ where
208+ msg = fromRight undefined $ B16.decodeBase16
209+ "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"
210+ key = fromRight undefined $ B16.decodeBase16
211+ "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"
212+
213+
214+ecSecKeyVerifyTest :: Assertion
215+ecSecKeyVerifyTest = do
216+ ret <- liftIO $ useByteString key $ \(k, _) -> do
217+ x <- signCtx
218+ ecSecKeyVerify x k
219+ assertBool "valid secret key" $ isSuccess ret
220+ where
221+ key = fromRight undefined $ B16.decodeBase16
222+ "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"
223+
224+ecPubkeyCreateTest :: Assertion
225+ecPubkeyCreateTest = do
226+ pk <- liftIO $
227+ useByteString key $ \(s, _) ->
228+ allocaBytes 64 $ \k -> do
229+ x <- signCtx
230+ createPubKey x s k
231+ allocaBytes 65 $ \o ->
232+ alloca $ \ol -> do
233+ poke ol 65
234+ rets <- ecPubKeySerialize x o ol k uncompressed
235+ unless (isSuccess rets) $ error "failed to serialize public key"
236+ len <- fromIntegral <$> peek ol
237+ packCStringLen (castPtr o, len)
238+ assertEqual "public key matches" pub pk
239+ where
240+ key = fromRight undefined $ B16.decodeBase16
241+ "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"
242+ pub = fromRight undefined $ B16.decodeBase16
243+ "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\
244+ \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
245+
246+ecSecKeyTweakAddTest :: Assertion
247+ecSecKeyTweakAddTest = do
248+ (ret, tweaked) <- liftIO $
249+ signCtx >>= \x ->
250+ useByteString tweak $ \(w, _) ->
251+ useByteString key $ \(k, _) -> do
252+ ret <- ecSecKeyTweakAdd x k w
253+ tweaked <- packByteString (k, 32)
254+ return (ret, tweaked)
255+ assertBool "successful secret key tweak" $ isSuccess ret
256+ assertEqual "tweaked keys match" expected tweaked
257+ where
258+ key = fromRight undefined $ B16.decodeBase16
259+ "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"
260+ tweak = fromRight undefined $ B16.decodeBase16
261+ "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"
262+ expected = fromRight undefined $ B16.decodeBase16
263+ "ec1e3ce1cefa18a671d51125e2b249688d934b0e28f5d1665384d9b02f929059"
264+
265+ecSecKeyTweakMulTest :: Assertion
266+ecSecKeyTweakMulTest = do
267+ (ret, tweaked) <- liftIO $ do
268+ x <- contextCreate sign
269+ retr <- withEntropy $ contextRandomize x
270+ unless (isSuccess retr) $ error "failed to randomize context"
271+ useByteString tweak $ \(w, _) -> useByteString key $ \(k, _) -> do
272+ ret <- ecSecKeyTweakMul x k w
273+ tweaked <- packByteString (k, 32)
274+ return (ret, tweaked)
275+ assertBool "successful secret key tweak" $ isSuccess ret
276+ assertEqual "tweaked keys match" expected tweaked
277+ where
278+ key = fromRight undefined $ B16.decodeBase16
279+ "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"
280+ tweak = fromRight undefined $ B16.decodeBase16
281+ "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"
282+ expected = fromRight undefined $ B16.decodeBase16
283+ "a96f5962493acb179f60a86a9785fc7a30e0c39b64c09d24fe064d9aef15e4c0"
284+
285+serializeKey :: Ctx -> Ptr PubKey64 -> IO ByteString
286+serializeKey x p = allocaBytes 72 $ \d -> alloca $ \dl -> do
287+ poke dl 72
288+ ret <- ecPubKeySerialize x d dl p uncompressed
289+ unless (isSuccess ret) $ error "could not serialize public key"
290+ len <- peek dl
291+ packCStringLen (castPtr d, fromIntegral len)
292+
293+parseKey :: Ctx -> ByteString -> IO ByteString
294+parseKey x bs =
295+ allocaBytes 64 $ \p ->
296+ useByteString bs $ \(d, dl) -> do
297+ ret <- ecPubKeyParse x p d dl
298+ unless (isSuccess ret) $ error "could not parse public key"
299+ packByteString (p, 64)
300+
301+ecPubKeyTweakAddTest :: Assertion
302+ecPubKeyTweakAddTest = do
303+ (ret, tweaked) <- liftIO $ do
304+ x <- contextCreate verify
305+ pk <- copy <$> parseKey x pub
306+ useByteString tweak $ \(w, _) ->
307+ useByteString pk $ \(p, _) -> do
308+ ret <- ecPubKeyTweakAdd x p w
309+ tweaked <- serializeKey x p
310+ return (ret, tweaked)
311+ assertBool "successful secret key tweak" $ isSuccess ret
312+ assertEqual "tweaked keys match" expected tweaked
313+ where
314+ pub = fromRight undefined $ B16.decodeBase16
315+ "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\
316+ \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
317+ tweak = fromRight undefined $ B16.decodeBase16
318+ "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"
319+ expected = fromRight undefined $ B16.decodeBase16
320+ "04441c3982b97576646e0df0c96736063df6b42f2ee566d13b9f6424302d1379e518fd\
321+ \c87a14c5435bff7a5db4552042cb4120c6b86a4bbd3d0643f3c14ad01368"
322+
323+ecPubKeyTweakMulTest :: Assertion
324+ecPubKeyTweakMulTest = do
325+ (ret, tweaked) <- liftIO $ do
326+ x <- contextCreate verify
327+ pk <- copy <$> parseKey x pub
328+ useByteString tweak $ \(w, _) ->
329+ useByteString pk $ \(p, _) -> do
330+ ret <- ecPubKeyTweakMul x p w
331+ tweaked <- serializeKey x p
332+ return (ret, tweaked)
333+ assertBool "successful secret key tweak" $ isSuccess ret
334+ assertEqual "tweaked keys match" expected tweaked
335+ where
336+ pub = fromRight undefined $ B16.decodeBase16
337+ "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\
338+ \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
339+ tweak = fromRight undefined $ B16.decodeBase16
340+ "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"
341+ expected = fromRight undefined $ B16.decodeBase16
342+ "04f379dc99cdf5c83e433defa267fbb3377d61d6b779c06a0e4ce29ae3ff5353b12ae4\
343+ \9c9d07e7368f2ba5a446c203255ce912322991a2d6a9d5d5761c61ed1845"
344+
345+ecPubKeyCombineTest :: Assertion
346+ecPubKeyCombineTest = do
347+ (ret, com) <- liftIO $
348+ allocaBytes 64 $ \p1 ->
349+ allocaBytes 64 $ \p2 ->
350+ allocaBytes 64 $ \p3 ->
351+ allocaArray 3 $ \a ->
352+ allocaBytes 64 $ \p -> do
353+ x <- contextCreate verify
354+ parse x pub1 p1
355+ parse x pub2 p2
356+ parse x pub3 p3
357+ pokeArray a [p1, p2, p3]
358+ ret <- ecPubKeyCombine x p a 3
359+ com <- serializeKey x p
360+ return (ret, com)
361+ assertBool "successful key combination" $ isSuccess ret
362+ assertEqual "combined keys match" expected com
363+ where
364+ parse x pub p = useByteString pub $ \(d, dl) -> do
365+ ret <- ecPubKeyParse x p d dl
366+ unless (isSuccess ret) $ error "could not parse public key"
367+ pub1 = fromRight undefined $ B16.decodeBase16
368+ "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd447051221\
369+ \3d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
370+ pub2 = fromRight undefined $ B16.decodeBase16
371+ "0487d82042d93447008dfe2af762068a1e53ff394a5bf8f68a045fa642b99ea5d153f5\
372+ \77dd2dba6c7ae4cfd7b6622409d7edd2d76dd13a8092cd3af97b77bd2c77"
373+ pub3 = fromRight undefined $ B16.decodeBase16
374+ "049b101edcbe1ee37ff6b2318526a425b629e823d7d8d9154417880595a28000ee3feb\
375+ \d908754b8ce4e491aa6fe488b41fb5d4bb3788e33c9ff95a7a9229166d59"
376+ expected = fromRight undefined $ B16.decodeBase16
377+ "043d9a7ec70011efc23c33a7e62d2ea73cca87797e3b659d93bea6aa871aebde56c3bc\
378+ \6134ca82e324b0ab9c0e601a6d2933afe7fb5d9f3aae900f5c5dc6e362c8"
extra-deps/secp256k1-haskell/test/Crypto/Secp256k1Spec.hsnew file+248
@@ -0,0 +1,248 @@
1+module Crypto.Secp256k1Spec (spec) where
2+
3+import Control.Monad.Par
4+import qualified Control.Monad.Par as P
5+import Crypto.Secp256k1
6+import qualified Data.ByteString as BS
7+import qualified Data.ByteString.Base16 as B16
8+import qualified Data.ByteString.Char8 as B8
9+import Data.Either (fromRight)
10+import Data.Maybe (fromMaybe, isNothing)
11+import Data.String (fromString)
12+import Data.String.Conversions (cs)
13+import Test.HUnit (Assertion, assertEqual)
14+import Test.Hspec
15+import Test.QuickCheck
16+
17+spec :: Spec
18+spec = do
19+ describe "signatures" $ do
20+ it "signs message" $
21+ property signMsgTest
22+ it "signs messages in parallel" $
23+ property signMsgParTest
24+ it "detects bad signature" $
25+ property badSignatureTest
26+ it "normalizes signatures" $
27+ property normalizeSigTest
28+ describe "serialization" $ do
29+ it "serializes public key" $
30+ property serializePubKeyTest
31+ it "serializes public keys in parallel" $
32+ property parSerializePubKeyTest
33+ it "serializes DER signature" $
34+ property serializeSigTest
35+ it "serializes DER signatures in parallel" $
36+ property parSerializeSigTest
37+ it "serializes compact signature" $
38+ property serializeCompactSigTest
39+ it "serialize secret key" $
40+ property serializeSecKeyTest
41+ it "shows and reads public key" $
42+ property (showRead :: PubKey -> Bool)
43+ it "shows and reads secret key" $
44+ property (showRead :: SecKey -> Bool)
45+ it "shows and reads tweak" $
46+ property (showReadTweak :: SecKey -> Bool)
47+ it "shows and reads signature" $
48+ property (showReadSig :: (SecKey, Msg) -> Bool)
49+ it "shows and reads message" $
50+ property (showRead :: Msg -> Bool)
51+ it "reads public key from string" $
52+ property isStringPubKey
53+ it "reads secret key from string" $
54+ property isStringSecKey
55+ it "reads signature from string" $
56+ property isStringSig
57+ it "reads message from string" $
58+ property isStringMsg
59+ it "reads tweak from string" $
60+ property isStringTweak
61+ describe "tweaks" $ do
62+ it "add secret key" $ property tweakAddSecKeyTest
63+ it "multiply secret key" $ property tweakMulSecKeyTest
64+ it "add public key" $ property tweakAddPubKeyTest
65+ it "multiply public key" $ property tweakMulPubKeyTest
66+ it "combine public keys" $ property combinePubKeyTest
67+ it "can't combine 0 public keys" $ property combinePubKeyEmptyListTest
68+ it "negates tweak" $ property negateTweakTest
69+
70+hexToBytes :: String -> BS.ByteString
71+hexToBytes = fromRight undefined . B16.decodeBase16 . B8.pack
72+
73+isStringPubKey :: (PubKey, Bool) -> Bool
74+isStringPubKey (k, c) = k == fromString (cs hex) where
75+ hex = B16.encodeBase16 $ exportPubKey c k
76+
77+isStringSig :: (SecKey, Msg) -> Bool
78+isStringSig (k, m) = g == fromString (cs hex) where
79+ g = signMsg k m
80+ hex = B16.encodeBase16 $ exportSig g
81+
82+isStringMsg :: Msg -> Bool
83+isStringMsg m = m == fromString (cs m') where
84+ m' = B16.encodeBase16 $ getMsg m
85+
86+isStringSecKey :: SecKey -> Bool
87+isStringSecKey k = k == fromString (cs hex) where
88+ hex = B16.encodeBase16 $ getSecKey k
89+
90+isStringTweak :: SecKey -> Bool
91+isStringTweak k = t == fromString (cs hex) where
92+ t = fromMaybe e . tweak $ getSecKey k
93+ hex = B16.encodeBase16 $ getTweak t
94+ e = error "Could not extract tweak from secret key"
95+
96+showReadTweak :: SecKey -> Bool
97+showReadTweak k = showRead t where
98+ t = tweak $ getSecKey k
99+
100+showReadSig :: (SecKey, Msg) -> Bool
101+showReadSig (k, m) = showRead sig where
102+ sig = signMsg k m
103+
104+showRead :: (Show a, Read a, Eq a) => a -> Bool
105+showRead x = read (show x) == x
106+
107+signMsgTest :: (Msg, SecKey) -> Bool
108+signMsgTest (fm, fk) = verifySig fp fg fm where
109+ fp = derivePubKey fk
110+ fg = signMsg fk fm
111+
112+signMsgParTest :: [(Msg, SecKey)] -> Bool
113+signMsgParTest xs = P.runPar $ do
114+ ys <- mapM (P.spawnP . signMsgTest) xs
115+ and <$> mapM P.get ys
116+
117+badSignatureTest :: (Msg, SecKey, PubKey) -> Bool
118+badSignatureTest (fm, fk, fp) = not $ verifySig fp fg fm where
119+ fg = signMsg fk fm
120+
121+normalizeSigTest :: (Msg, SecKey) -> Bool
122+normalizeSigTest (fm, fk) = isNothing sig where
123+ fg = signMsg fk fm
124+ sig = normalizeSig fg
125+
126+serializePubKeyTest :: (PubKey, Bool) -> Bool
127+serializePubKeyTest (fp, b) =
128+ case importPubKey $ exportPubKey b fp of
129+ Just fp' -> fp == fp'
130+ Nothing -> False
131+
132+parSerializePubKeyTest :: [(PubKey, Bool)] -> Bool
133+parSerializePubKeyTest ps = runPar $ do
134+ as <- mapM (spawnP . serializePubKeyTest) ps
135+ and <$> mapM get as
136+
137+serializeSigTest :: (Msg, SecKey) -> Bool
138+serializeSigTest (fm, fk) =
139+ case importSig $ exportSig fg of
140+ Just fg' -> fg == fg'
141+ Nothing -> False
142+ where
143+ fg = signMsg fk fm
144+
145+parSerializeSigTest :: [(Msg, SecKey)] -> Bool
146+parSerializeSigTest ms = runPar $ do
147+ as <- mapM (spawnP . serializeSigTest) ms
148+ and <$> mapM get as
149+
150+serializeCompactSigTest :: (Msg, SecKey) -> Bool
151+serializeCompactSigTest (fm, fk) =
152+ case importCompactSig $ exportCompactSig fg of
153+ Just fg' -> fg == fg'
154+ Nothing -> False
155+ where
156+ fg = signMsg fk fm
157+
158+serializeSecKeyTest :: SecKey -> Bool
159+serializeSecKeyTest fk =
160+ case secKey $ getSecKey fk of
161+ Just fk' -> fk == fk'
162+ Nothing -> False
163+
164+tweakAddSecKeyTest :: Assertion
165+tweakAddSecKeyTest =
166+ assertEqual "tweaked keys match" expected tweaked
167+ where
168+ tweaked = do
169+ key <- secKey $ hexToBytes
170+ "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"
171+ twk <- tweak $ hexToBytes
172+ "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"
173+ tweakAddSecKey key twk
174+ expected = secKey $ hexToBytes
175+ "ec1e3ce1cefa18a671d51125e2b249688d934b0e28f5d1665384d9b02f929059"
176+
177+tweakMulSecKeyTest :: Assertion
178+tweakMulSecKeyTest =
179+ assertEqual "tweaked keys match" expected tweaked
180+ where
181+ tweaked = do
182+ key <- secKey $ hexToBytes
183+ "f65255094d7773ed8dd417badc9fc045c1f80fdc5b2d25172b031ce6933e039a"
184+ twk <- tweak $ hexToBytes
185+ "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"
186+ tweakMulSecKey key twk
187+ expected = secKey $ hexToBytes
188+ "a96f5962493acb179f60a86a9785fc7a30e0c39b64c09d24fe064d9aef15e4c0"
189+
190+tweakAddPubKeyTest :: Assertion
191+tweakAddPubKeyTest =
192+ assertEqual "tweaked keys match" expected tweaked
193+ where
194+ tweaked = do
195+ pub <- importPubKey $ hexToBytes
196+ "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
197+ twk <- tweak $ hexToBytes
198+ "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"
199+ tweakAddPubKey pub twk
200+ expected = importPubKey $ hexToBytes
201+ "04441c3982b97576646e0df0c96736063df6b42f2ee566d13b9f6424302d1379e518fdc87a14c5435bff7a5db4552042cb4120c6b86a4bbd3d0643f3c14ad01368"
202+
203+tweakMulPubKeyTest :: Assertion
204+tweakMulPubKeyTest =
205+ assertEqual "tweaked keys match" expected tweaked
206+ where
207+ tweaked = do
208+ pub <- importPubKey $ hexToBytes
209+ "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
210+ twk <- tweak $ hexToBytes
211+ "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"
212+ tweakMulPubKey pub twk
213+ expected = importPubKey $ hexToBytes
214+ "04f379dc99cdf5c83e433defa267fbb3377d61d6b779c06a0e4ce29ae3ff5353b12ae49c9d07e7368f2ba5a446c203255ce912322991a2d6a9d5d5761c61ed1845"
215+
216+combinePubKeyTest :: Assertion
217+combinePubKeyTest =
218+ assertEqual "combined keys match" expected combined
219+ where
220+ combined = do
221+ pub1 <- importPubKey $ hexToBytes
222+ "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
223+ pub2 <- importPubKey $ hexToBytes
224+ "0487d82042d93447008dfe2af762068a1e53ff394a5bf8f68a045fa642b99ea5d153f577dd2dba6c7ae4cfd7b6622409d7edd2d76dd13a8092cd3af97b77bd2c77"
225+ pub3 <- importPubKey $ hexToBytes
226+ "049b101edcbe1ee37ff6b2318526a425b629e823d7d8d9154417880595a28000ee3febd908754b8ce4e491aa6fe488b41fb5d4bb3788e33c9ff95a7a9229166d59"
227+ combinePubKeys [pub1, pub2, pub3]
228+ expected = importPubKey $ hexToBytes
229+ "043d9a7ec70011efc23c33a7e62d2ea73cca87797e3b659d93bea6aa871aebde56c3bc6134ca82e324b0ab9c0e601a6d2933afe7fb5d9f3aae900f5c5dc6e362c8"
230+
231+combinePubKeyEmptyListTest :: Assertion
232+combinePubKeyEmptyListTest =
233+ assertEqual "empty pubkey list must return Nothing" expected combined
234+ where
235+ expected = Nothing
236+ combined = combinePubKeys []
237+
238+negateTweakTest :: Assertion
239+negateTweakTest =
240+ assertEqual "can recover secret key 1 after adding tweak 1" oneKey subtracted
241+ where
242+ Just oneKey = secKey $ fromRight undefined $ B16.decodeBase16 $ B8.pack
243+ "0000000000000000000000000000000000000000000000000000000000000001"
244+ Just oneTwk = tweak $ fromRight undefined $ B16.decodeBase16 $ B8.pack
245+ "0000000000000000000000000000000000000000000000000000000000000001"
246+ Just minusOneTwk = tweakNegate oneTwk
247+ Just twoKey = tweakAddSecKey oneKey oneTwk
248+ Just subtracted = tweakAddSecKey twoKey minusOneTwk
extra-deps/secp256k1-haskell/test/Spec.hsnew file+1
@@ -0,0 +1 @@
1+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
flake.locknew file+419
@@ -0,0 +1,419 @@
1+{
2+ "nodes": {
3+ "HTTP": {
4+ "flake": false,
5+ "locked": {
6+ "lastModified": 1451647621,
7+ "narHash": "sha256-oHIyw3x0iKBexEo49YeUDV1k74ZtyYKGR2gNJXXRxts=",
8+ "owner": "phadej",
9+ "repo": "HTTP",
10+ "rev": "9bc0996d412fef1787449d841277ef663ad9a915",
11+ "type": "github"
12+ },
13+ "original": {
14+ "owner": "phadej",
15+ "repo": "HTTP",
16+ "type": "github"
17+ }
18+ },
19+ "cabal-32": {
20+ "flake": false,
21+ "locked": {
22+ "lastModified": 1603716527,
23+ "narHash": "sha256-X0TFfdD4KZpwl0Zr6x+PLxUt/VyKQfX7ylXHdmZIL+w=",
24+ "owner": "haskell",
25+ "repo": "cabal",
26+ "rev": "48bf10787e27364730dd37a42b603cee8d6af7ee",
27+ "type": "github"
28+ },
29+ "original": {
30+ "owner": "haskell",
31+ "ref": "3.2",
32+ "repo": "cabal",
33+ "type": "github"
34+ }
35+ },
36+ "cabal-34": {
37+ "flake": false,
38+ "locked": {
39+ "lastModified": 1640353650,
40+ "narHash": "sha256-N1t6M3/wqj90AEdRkeC8i923gQYUpzSr8b40qVOZ1Rk=",
41+ "owner": "haskell",
42+ "repo": "cabal",
43+ "rev": "942639c18c0cd8ec53e0a6f8d120091af35312cd",
44+ "type": "github"
45+ },
46+ "original": {
47+ "owner": "haskell",
48+ "ref": "3.4",
49+ "repo": "cabal",
50+ "type": "github"
51+ }
52+ },
53+ "cabal-36": {
54+ "flake": false,
55+ "locked": {
56+ "lastModified": 1641652457,
57+ "narHash": "sha256-BlFPKP4C4HRUJeAbdembX1Rms1LD380q9s0qVDeoAak=",
58+ "owner": "haskell",
59+ "repo": "cabal",
60+ "rev": "f27667f8ec360c475027dcaee0138c937477b070",
61+ "type": "github"
62+ },
63+ "original": {
64+ "owner": "haskell",
65+ "ref": "3.6",
66+ "repo": "cabal",
67+ "type": "github"
68+ }
69+ },
70+ "cardano-shell": {
71+ "flake": false,
72+ "locked": {
73+ "lastModified": 1608537748,
74+ "narHash": "sha256-PulY1GfiMgKVnBci3ex4ptk2UNYMXqGjJOxcPy2KYT4=",
75+ "owner": "input-output-hk",
76+ "repo": "cardano-shell",
77+ "rev": "9392c75087cb9a3d453998f4230930dea3a95725",
78+ "type": "github"
79+ },
80+ "original": {
81+ "owner": "input-output-hk",
82+ "repo": "cardano-shell",
83+ "type": "github"
84+ }
85+ },
86+ "flake-utils": {
87+ "locked": {
88+ "lastModified": 1649676176,
89+ "narHash": "sha256-OWKJratjt2RW151VUlJPRALb7OU2S5s+f0vLj4o1bHM=",
90+ "owner": "numtide",
91+ "repo": "flake-utils",
92+ "rev": "a4b154ebbdc88c8498a5c7b01589addc9e9cb678",
93+ "type": "github"
94+ },
95+ "original": {
96+ "owner": "numtide",
97+ "repo": "flake-utils",
98+ "type": "github"
99+ }
100+ },
101+ "flake-utils_2": {
102+ "locked": {
103+ "lastModified": 1644229661,
104+ "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
105+ "owner": "numtide",
106+ "repo": "flake-utils",
107+ "rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797",
108+ "type": "github"
109+ },
110+ "original": {
111+ "owner": "numtide",
112+ "repo": "flake-utils",
113+ "type": "github"
114+ }
115+ },
116+ "ghc-8.6.5-iohk": {
117+ "flake": false,
118+ "locked": {
119+ "lastModified": 1600920045,
120+ "narHash": "sha256-DO6kxJz248djebZLpSzTGD6s8WRpNI9BTwUeOf5RwY8=",
121+ "owner": "input-output-hk",
122+ "repo": "ghc",
123+ "rev": "95713a6ecce4551240da7c96b6176f980af75cae",
124+ "type": "github"
125+ },
126+ "original": {
127+ "owner": "input-output-hk",
128+ "ref": "release/8.6.5-iohk",
129+ "repo": "ghc",
130+ "type": "github"
131+ }
132+ },
133+ "hackage": {
134+ "flake": false,
135+ "locked": {
136+ "lastModified": 1651367596,
137+ "narHash": "sha256-kQlMkMP2XX9JVApaF3NmPcL8yABzW/BdufMzzNaxa9c=",
138+ "owner": "input-output-hk",
139+ "repo": "hackage.nix",
140+ "rev": "4d8c31ef957c8b0972b23a01e7d5ab7bf38770de",
141+ "type": "github"
142+ },
143+ "original": {
144+ "owner": "input-output-hk",
145+ "repo": "hackage.nix",
146+ "type": "github"
147+ }
148+ },
149+ "haskellNix": {
150+ "inputs": {
151+ "HTTP": "HTTP",
152+ "cabal-32": "cabal-32",
153+ "cabal-34": "cabal-34",
154+ "cabal-36": "cabal-36",
155+ "cardano-shell": "cardano-shell",
156+ "flake-utils": "flake-utils_2",
157+ "ghc-8.6.5-iohk": "ghc-8.6.5-iohk",
158+ "hackage": "hackage",
159+ "hpc-coveralls": "hpc-coveralls",
160+ "hydra": "hydra",
161+ "nix-tools": "nix-tools",
162+ "nixpkgs": [
163+ "haskellNix",
164+ "nixpkgs-unstable"
165+ ],
166+ "nixpkgs-2003": "nixpkgs-2003",
167+ "nixpkgs-2105": "nixpkgs-2105",
168+ "nixpkgs-2111": "nixpkgs-2111",
169+ "nixpkgs-unstable": "nixpkgs-unstable",
170+ "old-ghc-nix": "old-ghc-nix",
171+ "stackage": "stackage"
172+ },
173+ "locked": {
174+ "lastModified": 1651367700,
175+ "narHash": "sha256-JTSIwNL986NRipZyV++GQ4QoiVoqE2oY0DWhn+LJno0=",
176+ "owner": "input-output-hk",
177+ "repo": "haskell.nix",
178+ "rev": "801310c927bbaab9f83dd0aee75ce959c5f06529",
179+ "type": "github"
180+ },
181+ "original": {
182+ "owner": "input-output-hk",
183+ "repo": "haskell.nix",
184+ "type": "github"
185+ }
186+ },
187+ "hpc-coveralls": {
188+ "flake": false,
189+ "locked": {
190+ "lastModified": 1607498076,
191+ "narHash": "sha256-8uqsEtivphgZWYeUo5RDUhp6bO9j2vaaProQxHBltQk=",
192+ "owner": "sevanspowell",
193+ "repo": "hpc-coveralls",
194+ "rev": "14df0f7d229f4cd2e79f8eabb1a740097fdfa430",
195+ "type": "github"
196+ },
197+ "original": {
198+ "owner": "sevanspowell",
199+ "repo": "hpc-coveralls",
200+ "type": "github"
201+ }
202+ },
203+ "hydra": {
204+ "inputs": {
205+ "nix": "nix",
206+ "nixpkgs": [
207+ "haskellNix",
208+ "hydra",
209+ "nix",
210+ "nixpkgs"
211+ ]
212+ },
213+ "locked": {
214+ "lastModified": 1646878427,
215+ "narHash": "sha256-KtbrofMtN8GlM7D+n90kixr7QpSlVmdN+vK5CA/aRzc=",
216+ "owner": "NixOS",
217+ "repo": "hydra",
218+ "rev": "28b682b85b7efc5cf7974065792a1f22203a5927",
219+ "type": "github"
220+ },
221+ "original": {
222+ "id": "hydra",
223+ "type": "indirect"
224+ }
225+ },
226+ "lowdown-src": {
227+ "flake": false,
228+ "locked": {
229+ "lastModified": 1633514407,
230+ "narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
231+ "owner": "kristapsdz",
232+ "repo": "lowdown",
233+ "rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
234+ "type": "github"
235+ },
236+ "original": {
237+ "owner": "kristapsdz",
238+ "repo": "lowdown",
239+ "type": "github"
240+ }
241+ },
242+ "nix": {
243+ "inputs": {
244+ "lowdown-src": "lowdown-src",
245+ "nixpkgs": "nixpkgs",
246+ "nixpkgs-regression": "nixpkgs-regression"
247+ },
248+ "locked": {
249+ "lastModified": 1643066034,
250+ "narHash": "sha256-xEPeMcNJVOeZtoN+d+aRwolpW8mFSEQx76HTRdlhPhg=",
251+ "owner": "NixOS",
252+ "repo": "nix",
253+ "rev": "a1cd7e58606a41fcf62bf8637804cf8306f17f62",
254+ "type": "github"
255+ },
256+ "original": {
257+ "owner": "NixOS",
258+ "ref": "2.6.0",
259+ "repo": "nix",
260+ "type": "github"
261+ }
262+ },
263+ "nix-tools": {
264+ "flake": false,
265+ "locked": {
266+ "lastModified": 1649424170,
267+ "narHash": "sha256-XgKXWispvv5RCvZzPb+p7e6Hy3LMuRjafKMl7kXzxGw=",
268+ "owner": "input-output-hk",
269+ "repo": "nix-tools",
270+ "rev": "e109c94016e3b6e0db7ed413c793e2d4bdb24aa7",
271+ "type": "github"
272+ },
273+ "original": {
274+ "owner": "input-output-hk",
275+ "repo": "nix-tools",
276+ "type": "github"
277+ }
278+ },
279+ "nixpkgs": {
280+ "locked": {
281+ "lastModified": 1632864508,
282+ "narHash": "sha256-d127FIvGR41XbVRDPVvozUPQ/uRHbHwvfyKHwEt5xFM=",
283+ "owner": "NixOS",
284+ "repo": "nixpkgs",
285+ "rev": "82891b5e2c2359d7e58d08849e4c89511ab94234",
286+ "type": "github"
287+ },
288+ "original": {
289+ "id": "nixpkgs",
290+ "ref": "nixos-21.05-small",
291+ "type": "indirect"
292+ }
293+ },
294+ "nixpkgs-2003": {
295+ "locked": {
296+ "lastModified": 1620055814,
297+ "narHash": "sha256-8LEHoYSJiL901bTMVatq+rf8y7QtWuZhwwpKE2fyaRY=",
298+ "owner": "NixOS",
299+ "repo": "nixpkgs",
300+ "rev": "1db42b7fe3878f3f5f7a4f2dc210772fd080e205",
301+ "type": "github"
302+ },
303+ "original": {
304+ "owner": "NixOS",
305+ "ref": "nixpkgs-20.03-darwin",
306+ "repo": "nixpkgs",
307+ "type": "github"
308+ }
309+ },
310+ "nixpkgs-2105": {
311+ "locked": {
312+ "lastModified": 1645296114,
313+ "narHash": "sha256-y53N7TyIkXsjMpOG7RhvqJFGDacLs9HlyHeSTBioqYU=",
314+ "owner": "NixOS",
315+ "repo": "nixpkgs",
316+ "rev": "530a53dcbc9437363471167a5e4762c5fcfa34a1",
317+ "type": "github"
318+ },
319+ "original": {
320+ "owner": "NixOS",
321+ "ref": "nixpkgs-21.05-darwin",
322+ "repo": "nixpkgs",
323+ "type": "github"
324+ }
325+ },
326+ "nixpkgs-2111": {
327+ "locked": {
328+ "lastModified": 1648744337,
329+ "narHash": "sha256-bYe1dFJAXovjqiaPKrmAbSBEK5KUkgwVaZcTbSoJ7hg=",
330+ "owner": "NixOS",
331+ "repo": "nixpkgs",
332+ "rev": "0a58eebd8ec65ffdef2ce9562784123a73922052",
333+ "type": "github"
334+ },
335+ "original": {
336+ "owner": "NixOS",
337+ "ref": "nixpkgs-21.11-darwin",
338+ "repo": "nixpkgs",
339+ "type": "github"
340+ }
341+ },
342+ "nixpkgs-regression": {
343+ "locked": {
344+ "lastModified": 1643052045,
345+ "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
346+ "owner": "NixOS",
347+ "repo": "nixpkgs",
348+ "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
349+ "type": "github"
350+ },
351+ "original": {
352+ "id": "nixpkgs",
353+ "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
354+ "type": "indirect"
355+ }
356+ },
357+ "nixpkgs-unstable": {
358+ "locked": {
359+ "lastModified": 1648219316,
360+ "narHash": "sha256-Ctij+dOi0ZZIfX5eMhgwugfvB+WZSrvVNAyAuANOsnQ=",
361+ "owner": "NixOS",
362+ "repo": "nixpkgs",
363+ "rev": "30d3d79b7d3607d56546dd2a6b49e156ba0ec634",
364+ "type": "github"
365+ },
366+ "original": {
367+ "owner": "NixOS",
368+ "ref": "nixpkgs-unstable",
369+ "repo": "nixpkgs",
370+ "type": "github"
371+ }
372+ },
373+ "old-ghc-nix": {
374+ "flake": false,
375+ "locked": {
376+ "lastModified": 1631092763,
377+ "narHash": "sha256-sIKgO+z7tj4lw3u6oBZxqIhDrzSkvpHtv0Kki+lh9Fg=",
378+ "owner": "angerman",
379+ "repo": "old-ghc-nix",
380+ "rev": "af48a7a7353e418119b6dfe3cd1463a657f342b8",
381+ "type": "github"
382+ },
383+ "original": {
384+ "owner": "angerman",
385+ "ref": "master",
386+ "repo": "old-ghc-nix",
387+ "type": "github"
388+ }
389+ },
390+ "root": {
391+ "inputs": {
392+ "flake-utils": "flake-utils",
393+ "haskellNix": "haskellNix",
394+ "nixpkgs": [
395+ "haskellNix",
396+ "nixpkgs-unstable"
397+ ]
398+ }
399+ },
400+ "stackage": {
401+ "flake": false,
402+ "locked": {
403+ "lastModified": 1651194938,
404+ "narHash": "sha256-2pDyInnRI7JLZ4QYpx02o0eqE/lR+nouPD/uVCI+yZw=",
405+ "owner": "input-output-hk",
406+ "repo": "stackage.nix",
407+ "rev": "893d8518231919df7e894d350508e930d24fd401",
408+ "type": "github"
409+ },
410+ "original": {
411+ "owner": "input-output-hk",
412+ "repo": "stackage.nix",
413+ "type": "github"
414+ }
415+ }
416+ },
417+ "root": "root",
418+ "version": 7
419+}
flake.nixnew file+24
@@ -0,0 +1,24 @@
1+{
2+ description = "A very basic flake";
3+
4+ inputs = {
5+ haskellNix.url = "github:input-output-hk/haskell.nix";
6+ nixpkgs.follows = "haskellNix/nixpkgs-unstable";
7+ flake-utils.url = "github:numtide/flake-utils";
8+ };
9+
10+ outputs = { self, nixpkgs, flake-utils, haskellNix }:
11+ flake-utils.lib.eachSystem [ "x86_64-linux" "x86_64-darwin" ] (system:
12+ let
13+ overlays = [ haskellNix.overlay ];
14+ pkgs = import nixpkgs { inherit system overlays; inherit (haskellNix) config; };
15+ in
16+ {
17+ defaultPackage =
18+ ((pkgs.haskell-nix.stackProject {
19+ src = ./.;
20+ # modules = [{ reinstallableLibGhc = true; }];
21+ }).flake { }).packages."foo:exe:foo";
22+ }
23+ );
24+}
foo.cabalnew file+20
@@ -0,0 +1,20 @@
1+cabal-version: 1.12
2+
3+-- This file has been generated from package.yaml by hpack version 0.34.5.
4+--
5+-- see: https://github.com/sol/hpack
6+
7+name: foo
8+version: 0.0.0
9+build-type: Simple
10+
11+executable foo
12+ main-is: Main.hs
13+ other-modules:
14+ Paths_foo
15+ hs-source-dirs:
16+ src
17+ build-depends:
18+ base
19+ , haskoin-core
20+ default-language: Haskell2010
package.yamlnew file+9
@@ -0,0 +1,9 @@
1+name: foo
2+
3+dependencies:
4+ - base
5+ - haskoin-core
6+
7+executable:
8+ main: Main.hs
9+ source-dirs: src
src/Main.hsnew file+4
@@ -0,0 +1,4 @@
1+module Main (main) where
2+
3+main :: IO ()
4+main = pure ()
stack.yamlnew file+9
@@ -0,0 +1,9 @@
1+
2+resolver: nightly-2022-04-28
3+
4+packages:
5+ - .
6+
7+extra-deps:
8+ - extra-deps/secp256k1-haskell
9+ - haskoin-core-0.21.2