README.md (9278B)
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, highly-auditable Haskell 61 code. 62 63 Current benchmark figures on an M4 MacBook Air look like (use `cabal 64 bench` to run the benchmark suite): 65 66 ``` 67 benchmarking schnorr/sign_schnorr' (large) 68 time 1.400 ms (1.399 ms .. 1.402 ms) 69 1.000 R² (1.000 R² .. 1.000 R²) 70 mean 1.406 ms (1.404 ms .. 1.408 ms) 71 std dev 5.989 μs (5.225 μs .. 7.317 μs) 72 73 benchmarking schnorr/verify_schnorr' 74 time 720.2 μs (716.7 μs .. 724.8 μs) 75 1.000 R² (1.000 R² .. 1.000 R²) 76 mean 724.6 μs (722.0 μs .. 730.4 μs) 77 std dev 12.68 μs (6.334 μs .. 26.31 μs) 78 79 benchmarking ecdsa/sign_ecdsa' (large) 80 time 115.3 μs (115.1 μs .. 115.7 μs) 81 1.000 R² (1.000 R² .. 1.000 R²) 82 mean 116.0 μs (115.6 μs .. 116.4 μs) 83 std dev 1.367 μs (1.039 μs .. 1.839 μs) 84 85 benchmarking ecdsa/verify_ecdsa' 86 time 702.3 μs (699.9 μs .. 704.9 μs) 87 1.000 R² (1.000 R² .. 1.000 R²) 88 mean 704.9 μs (702.7 μs .. 708.4 μs) 89 std dev 9.641 μs (6.638 μs .. 14.04 μs) 90 ``` 91 92 In terms of allocations, we get: 93 94 ``` 95 schnorr 96 97 Case Allocated GCs 98 sign_schnorr' 3,273,824 0 99 verify_schnorr' 1,667,360 0 100 101 ecdsa 102 103 Case Allocated GCs 104 sign_ecdsa' 324,672 0 105 verify_ecdsa' 3,796,328 0 106 107 ecdh 108 109 Case Allocated GCs 110 ecdh (small) 2,141,736 0 111 ecdh (large) 2,145,464 0 112 ``` 113 114 ## Security 115 116 This library aims at the maximum security achievable in a 117 garbage-collected language under an optimizing compiler such as GHC, in 118 which strict constant-timeness can be [challenging to achieve][const]. 119 120 The Schnorr implementation within has been tested against the [official 121 BIP0340 vectors][ut340], and ECDSA and ECDH have been tested against the 122 relevant [Wycheproof vectors][wyche] (with the former also being tested 123 against [noble-secp256k1's][noble] vectors), so their implementations 124 are likely to be accurate and safe from attacks targeting e.g. 125 faulty nonce generation or malicious inputs for signature or public 126 key parameters. Timing-sensitive operations, e.g. elliptic curve 127 scalar multiplication, have been explicitly written so as to execute 128 *algorithmically* in time constant with respect to secret data, and 129 evidence from benchmarks supports this: 130 131 ``` 132 benchmarking derive_pub/wnaf, sk = 2 133 time 76.20 μs (75.62 μs .. 77.33 μs) 134 0.999 R² (0.998 R² .. 1.000 R²) 135 mean 75.87 μs (75.61 μs .. 76.48 μs) 136 std dev 1.218 μs (614.3 ns .. 2.291 μs) 137 variance introduced by outliers: 11% (moderately inflated) 138 139 benchmarking derive_pub/wnaf, sk = 2 ^ 255 - 19 140 time 76.50 μs (75.88 μs .. 77.37 μs) 141 0.999 R² (0.998 R² .. 1.000 R²) 142 mean 76.26 μs (75.99 μs .. 76.93 μs) 143 std dev 1.317 μs (570.7 ns .. 2.583 μs) 144 variance introduced by outliers: 12% (moderately inflated) 145 146 benchmarking schnorr/sign_schnorr' (small) 147 time 1.430 ms (1.424 ms .. 1.438 ms) 148 1.000 R² (1.000 R² .. 1.000 R²) 149 mean 1.429 ms (1.425 ms .. 1.433 ms) 150 std dev 13.71 μs (10.48 μs .. 18.85 μs) 151 152 benchmarking schnorr/sign_schnorr' (large) 153 time 1.400 ms (1.399 ms .. 1.402 ms) 154 1.000 R² (1.000 R² .. 1.000 R²) 155 mean 1.406 ms (1.404 ms .. 1.408 ms) 156 std dev 5.989 μs (5.225 μs .. 7.317 μs) 157 158 benchmarking ecdsa/sign_ecdsa' (small) 159 time 114.5 μs (114.0 μs .. 115.3 μs) 160 1.000 R² (0.999 R² .. 1.000 R²) 161 mean 115.2 μs (114.8 μs .. 115.8 μs) 162 std dev 1.650 μs (1.338 μs .. 2.062 μs) 163 164 benchmarking ecdsa/sign_ecdsa' (large) 165 time 115.3 μs (115.1 μs .. 115.7 μs) 166 1.000 R² (1.000 R² .. 1.000 R²) 167 mean 116.0 μs (115.6 μs .. 116.4 μs) 168 std dev 1.367 μs (1.039 μs .. 1.839 μs) 169 170 benchmarking ecdh/ecdh (small) 171 time 907.0 μs (902.8 μs .. 912.0 μs) 172 1.000 R² (0.999 R² .. 1.000 R²) 173 mean 909.5 μs (907.0 μs .. 913.0 μs) 174 std dev 10.05 μs (6.943 μs .. 17.11 μs) 175 176 benchmarking ecdh/ecdh (large) 177 time 922.9 μs (911.0 μs .. 937.4 μs) 178 0.999 R² (0.998 R² .. 1.000 R²) 179 mean 915.8 μs (911.9 μs .. 922.5 μs) 180 std dev 16.84 μs (9.830 μs .. 26.48 μs) 181 ``` 182 183 Due to the use of arbitrary-precision integers, integer division modulo 184 the elliptic curve group order does display persistent substantial 185 timing differences on the order of 1-2 nanoseconds when the inputs 186 differ dramatically in size (here 2 bits vs 255 bits): 187 188 ``` 189 benchmarking remQ (remainder modulo _CURVE_Q)/remQ 2 190 time 11.13 ns (11.12 ns .. 11.14 ns) 191 1.000 R² (1.000 R² .. 1.000 R²) 192 mean 11.10 ns (11.09 ns .. 11.11 ns) 193 std dev 33.75 ps (30.27 ps .. 38.31 ps) 194 195 benchmarking remQ (remainder modulo _CURVE_Q)/remQ (2 ^ 255 - 19) 196 time 12.50 ns (12.49 ns .. 12.51 ns) 197 1.000 R² (1.000 R² .. 1.000 R²) 198 mean 12.51 ns (12.51 ns .. 12.52 ns) 199 std dev 26.72 ps (14.45 ps .. 45.87 ps) 200 ``` 201 202 This represents the worst-case scenario (real-world private keys will 203 never differ so extraordinarily) and is likely to be well within 204 acceptable limits for all but the most extreme security requirements. 205 But because we don't make "hard" guarantees of constant-time execution, 206 take reasonable security precautions as appropriate. You shouldn't 207 deploy the implementations within in any situation where they could 208 easily be used as an oracle to construct a [timing attack][timea], 209 and you shouldn't give sophisticated malicious actors [access to your 210 computer][flurl]. 211 212 If you discover any vulnerabilities, please disclose them via 213 security@ppad.tech. 214 215 ## Development 216 217 You'll require [Nix][nixos] with [flake][flake] support enabled. Enter a 218 development shell with: 219 220 ``` 221 $ nix develop 222 ``` 223 224 Then do e.g.: 225 226 ``` 227 $ cabal repl ppad-secp256k1 228 ``` 229 230 to get a REPL for the main library. 231 232 [bp340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki 233 [ut340]: https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv 234 [bp146]: https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki 235 [r6979]: https://www.rfc-editor.org/rfc/rfc6979 236 [nixos]: https://nixos.org/ 237 [flake]: https://nixos.org/manual/nix/unstable/command-ref/new-cli/nix3-flake.html 238 [hadoc]: https://docs.ppad.tech/secp256k1 239 [wyche]: https://github.com/C2SP/wycheproof 240 [timea]: https://en.wikipedia.org/wiki/Timing_attack 241 [flurl]: https://eprint.iacr.org/2014/140.pdf 242 [const]: https://www.chosenplaintext.ca/articles/beginners-guide-constant-time-cryptography.html 243 [csecp]: https://git.ppad.tech/csecp256k1 244 [noble]: https://github.com/paulmillr/noble-secp256k1