README.md (9112B)
1 # secp256k1 2 3 [](https://hackage.haskell.org/package/ppad-secp256k1) 4  5 [](https://docs.ppad.tech/secp256k1) 6 7 A pure Haskell implementation of [BIP0340][bp340] Schnorr signatures, 8 deterministic [RFC6979][r6979] ECDSA (with [BIP0146][bp146]-style 9 "low-S" signatures), ECDH, and various primitives on the elliptic curve 10 secp256k1. 11 12 (See also [ppad-csecp256k1][csecp] for FFI bindings to 13 bitcoin-core/secp256k1.) 14 15 ## Usage 16 17 A sample GHCi session: 18 19 ``` 20 > -- pragmas and b16 import for illustration only; not required 21 > :set -XOverloadedStrings 22 > :set -XBangPatterns 23 > import qualified Data.ByteString.Base16 as B16 24 > 25 > -- import qualified 26 > import qualified Crypto.Curve.Secp256k1 as Secp256k1 27 > 28 > -- secret, public keys 29 > let sec = 0xB7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF 30 :{ 31 ghci| let Just pub = Secp256k1.parse_point . B16.decodeLenient $ 32 ghci| "DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659" 33 ghci| :} 34 > 35 > let msg = "i approve of this message" 36 > 37 > -- create and verify a schnorr signature for the message 38 > let Just sig0 = Secp256k1.sign_schnorr sec msg mempty 39 > Secp256k1.verify_schnorr msg pub sig0 40 True 41 > 42 > -- create and verify a low-S ECDSA signature for the message 43 > let Just sig1 = Secp256k1.sign_ecdsa sec msg 44 > Secp256k1.verify_ecdsa msg pub sig1 45 True 46 > 47 > -- for faster signs (especially w/ECDSA) and verifies, use a context 48 > let !tex = Secp256k1.precompute 49 > Secp256k1.verify_schnorr' tex msg pub sig0 50 True 51 ``` 52 53 ## Documentation 54 55 Haddocks (API documentation, etc.) are hosted at 56 [docs.ppad.tech/secp256k1][hadoc]. 57 58 ## Performance 59 60 The aim is best-in-class performance for pure Haskell code. 61 62 Current benchmark figures on an M4 MacBook Air look like (use `cabal 63 bench` to run the benchmark suite): 64 65 ``` 66 benchmarking schnorr/sign_schnorr' (large) 67 time 76.57 μs (76.46 μs .. 76.73 μs) 68 1.000 R² (0.999 R² .. 1.000 R²) 69 mean 77.81 μs (77.23 μs .. 79.13 μs) 70 std dev 2.732 μs (1.296 μs .. 5.251 μs) 71 72 benchmarking schnorr/verify_schnorr' 73 time 112.8 μs (112.4 μs .. 113.1 μs) 74 1.000 R² (1.000 R² .. 1.000 R²) 75 mean 112.4 μs (112.0 μs .. 112.8 μs) 76 std dev 1.246 μs (1.023 μs .. 1.554 μs) 77 78 benchmarking ecdsa/sign_ecdsa' (large) 79 time 44.02 μs (44.00 μs .. 44.03 μs) 80 1.000 R² (1.000 R² .. 1.000 R²) 81 mean 43.99 μs (43.97 μs .. 44.01 μs) 82 std dev 58.86 ns (46.66 ns .. 72.16 ns) 83 84 benchmarking ecdsa/verify_ecdsa' 85 time 105.1 μs (104.8 μs .. 105.4 μs) 86 1.000 R² (1.000 R² .. 1.000 R²) 87 mean 104.8 μs (104.4 μs .. 105.8 μs) 88 std dev 2.037 μs (1.170 μs .. 3.692 μs) 89 90 benchmarking ecdh/ecdh (large) 91 time 138.5 μs (137.8 μs .. 139.4 μs) 92 1.000 R² (0.999 R² .. 1.000 R²) 93 mean 137.8 μs (137.4 μs .. 138.4 μs) 94 std dev 1.584 μs (1.119 μs .. 2.541 μs) 95 ``` 96 97 Ensure you compile with the 'llvm' flag (and that [ppad-fixed][fixed] 98 and [ppad-sha256][sha256] have been compiled with the 'llvm' flag) for 99 maximum performance. 100 101 ## Security 102 103 This library aims at the maximum security achievable in a 104 garbage-collected language under an optimizing compiler such as GHC, in 105 which strict constant-timeness can be [challenging to achieve][const]. 106 107 The Schnorr implementation within has been tested against the [official 108 BIP0340 vectors][ut340], and ECDSA and ECDH have been tested against the 109 relevant [Wycheproof vectors][wyche] (with the former also being tested 110 against [noble-secp256k1's][noble] vectors), so their implementations 111 are likely to be accurate and safe from attacks targeting e.g. 112 faulty nonce generation or malicious inputs for signature or public 113 key parameters. 114 115 Timing-sensitive operations, e.g. elliptic curve scalar multiplication, 116 have been explicitly written so as to execute in time constant with 117 respect to secret data. Moreover, fixed-size (256-bit) wide words with 118 constant-time operations provided by [ppad-fixed][fixed] are used 119 exclusively internally, avoiding timing variations incurred by use of 120 GHC's variable-size Integer type. 121 122 Criterion benchmarks attest that any timing variation between cases with 123 differing inputs is attributable to noise: 124 125 ``` 126 benchmarking derive_pub/wnaf, sk = 2 127 time 29.67 μs (29.64 μs .. 29.71 μs) 128 1.000 R² (1.000 R² .. 1.000 R²) 129 mean 29.68 μs (29.64 μs .. 29.71 μs) 130 std dev 121.1 ns (83.80 ns .. 177.2 ns) 131 132 benchmarking derive_pub/wnaf, sk = 2 ^ 255 - 19 133 time 29.68 μs (29.65 μs .. 29.72 μs) 134 1.000 R² (1.000 R² .. 1.000 R²) 135 mean 29.71 μs (29.68 μs .. 29.75 μs) 136 std dev 106.7 ns (71.74 ns .. 174.7 ns) 137 138 benchmarking schnorr/sign_schnorr' (small) 139 time 76.27 μs (76.21 μs .. 76.32 μs) 140 1.000 R² (1.000 R² .. 1.000 R²) 141 mean 76.44 μs (76.40 μs .. 76.50 μs) 142 std dev 162.3 ns (123.1 ns .. 246.7 ns) 143 144 benchmarking schnorr/sign_schnorr' (large) 145 time 76.35 μs (76.31 μs .. 76.38 μs) 146 1.000 R² (1.000 R² .. 1.000 R²) 147 mean 76.37 μs (76.35 μs .. 76.40 μs) 148 std dev 84.10 ns (67.03 ns .. 112.7 ns) 149 150 benchmarking ecdsa/sign_ecdsa' (small) 151 time 43.95 μs (43.89 μs .. 44.02 μs) 152 1.000 R² (1.000 R² .. 1.000 R²) 153 mean 44.04 μs (43.96 μs .. 44.15 μs) 154 std dev 310.2 ns (259.9 ns .. 384.6 ns) 155 156 benchmarking ecdsa/sign_ecdsa' (large) 157 time 44.02 μs (44.00 μs .. 44.03 μs) 158 1.000 R² (1.000 R² .. 1.000 R²) 159 mean 43.99 μs (43.97 μs .. 44.01 μs) 160 std dev 58.86 ns (46.66 ns .. 72.16 ns) 161 162 benchmarking ecdh/ecdh (small) 163 time 143.6 μs (143.4 μs .. 143.7 μs) 164 1.000 R² (1.000 R² .. 1.000 R²) 165 mean 143.7 μs (143.3 μs .. 144.6 μs) 166 std dev 2.022 μs (846.9 ns .. 3.402 μs) 167 168 benchmarking ecdh/ecdh (large) 169 time 143.8 μs (143.7 μs .. 143.9 μs) 170 1.000 R² (1.000 R² .. 1.000 R²) 171 mean 143.8 μs (143.7 μs .. 143.9 μs) 172 std dev 385.2 ns (265.9 ns .. 544.5 ns) 173 ``` 174 175 Note also that care has been taken to ensure that allocation is held 176 constant across input sizes for all sensitive operations: 177 178 ``` 179 derive_pub 180 181 Case Allocated GCs 182 wnaf, sk = 2 312 0 183 wnaf, sk = 2 ^ 255 - 19 312 0 184 185 schnorr 186 187 Case Allocated GCs 188 sign_schnorr' (small) 14,416 0 189 sign_schnorr' (large) 14,416 0 190 191 ecdsa 192 193 Case Allocated GCs 194 sign_ecdsa' (small) 1,560 0 195 sign_ecdsa' (large) 1,560 0 196 197 ecdh 198 199 Case Allocated GCs 200 ecdh (small) 616 0 201 ecdh (large) 616 0 202 203 ``` 204 205 Though constant-resource execution is enforced rigorously, take 206 reasonable security precautions as appropriate. You shouldn't deploy the 207 implementations within in any situation where they could easily be used 208 as an oracle to construct a [timing attack][timea], and you shouldn't 209 give sophisticated malicious actors [access to your computer][flurl]. 210 211 If you discover any vulnerabilities, please disclose them via 212 security@ppad.tech. 213 214 ## Development 215 216 You'll require [Nix][nixos] with [flake][flake] support enabled. Enter a 217 development shell with: 218 219 ``` 220 $ nix develop 221 ``` 222 223 Then do e.g.: 224 225 ``` 226 $ cabal repl ppad-secp256k1 227 ``` 228 229 to get a REPL for the main library. 230 231 [bp340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki 232 [ut340]: https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv 233 [bp146]: https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki 234 [r6979]: https://www.rfc-editor.org/rfc/rfc6979 235 [nixos]: https://nixos.org/ 236 [flake]: https://nixos.org/manual/nix/unstable/command-ref/new-cli/nix3-flake.html 237 [hadoc]: https://docs.ppad.tech/secp256k1 238 [wyche]: https://github.com/C2SP/wycheproof 239 [timea]: https://en.wikipedia.org/wiki/Timing_attack 240 [flurl]: https://eprint.iacr.org/2014/140.pdf 241 [const]: https://www.chosenplaintext.ca/articles/beginners-guide-constant-time-cryptography.html 242 [csecp]: https://git.ppad.tech/csecp256k1 243 [noble]: https://github.com/paulmillr/noble-secp256k1 244 [fixed]: https://git.ppad.tech/fixed 245 [sha256]: https://git.ppad.tech/sha256