README.md (9173B)
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 51.22 μs (51.02 μs .. 51.36 μs) 80 1.000 R² (1.000 R² .. 1.000 R²) 81 mean 51.08 μs (50.95 μs .. 51.19 μs) 82 std dev 403.3 ns (344.5 ns .. 507.5 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 52.34 μs (52.22 μs .. 52.49 μs) 152 1.000 R² (1.000 R² .. 1.000 R²) 153 mean 52.35 μs (52.30 μs .. 52.42 μs) 154 std dev 205.9 ns (159.2 ns .. 281.1 ns) 155 156 benchmarking ecdsa/sign_ecdsa' (large) 157 time 52.40 μs (52.31 μs .. 52.55 μs) 158 1.000 R² (1.000 R² .. 1.000 R²) 159 mean 52.66 μs (52.47 μs .. 52.99 μs) 160 std dev 813.7 ns (427.9 ns .. 1.244 μs) 161 variance introduced by outliers: 10% (moderately inflated) 162 163 benchmarking ecdh/ecdh (small) 164 time 143.6 μs (143.4 μs .. 143.7 μs) 165 1.000 R² (1.000 R² .. 1.000 R²) 166 mean 143.7 μs (143.3 μs .. 144.6 μs) 167 std dev 2.022 μs (846.9 ns .. 3.402 μs) 168 169 benchmarking ecdh/ecdh (large) 170 time 143.8 μs (143.7 μs .. 143.9 μs) 171 1.000 R² (1.000 R² .. 1.000 R²) 172 mean 143.8 μs (143.7 μs .. 143.9 μs) 173 std dev 385.2 ns (265.9 ns .. 544.5 ns) 174 ``` 175 176 Note also that care has been taken to ensure that allocation is held 177 constant across input sizes for all sensitive operations: 178 179 ``` 180 derive_pub 181 182 Case Allocated GCs 183 wnaf, sk = 2 304 0 184 wnaf, sk = 2 ^ 255 - 19 304 0 185 186 schnorr 187 188 Case Allocated GCs 189 sign_schnorr' (small) 27,104 0 190 sign_schnorr' (large) 27,104 0 191 192 ecdsa 193 194 Case Allocated GCs 195 sign_ecdsa' (small) 61,592 0 196 sign_ecdsa' (large) 61,592 0 197 198 ecdh 199 200 Case Allocated GCs 201 ecdh (small) 1,880 0 202 ecdh (large) 1,880 0 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