README.md (9321B)
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 (See both a [security analysis](https://ppad.tech/security-analysis-secp256k1) 104 and follow-up [assembly analysis](https://ppad.tech/static-assembly-analysis) 105 of the library at [ppad.tech](https://ppad.tech).) 106 107 This library aims at the maximum security achievable in a 108 garbage-collected language under an optimizing compiler such as GHC, in 109 which strict constant-timeness can be [challenging to achieve][const]. 110 111 The Schnorr implementation within has been tested against the [official 112 BIP0340 vectors][ut340], and ECDSA and ECDH have been tested against the 113 relevant [Wycheproof vectors][wyche] (with the former also being tested 114 against [noble-secp256k1's][noble] vectors), so their implementations 115 are likely to be accurate and safe from attacks targeting e.g. 116 faulty nonce generation or malicious inputs for signature or public 117 key parameters. 118 119 Timing-sensitive operations, e.g. elliptic curve scalar multiplication, 120 have been explicitly written so as to execute in time constant with 121 respect to secret data. Moreover, fixed-size (256-bit) wide words with 122 constant-time operations provided by [ppad-fixed][fixed] are used 123 exclusively internally, avoiding timing variations incurred by use of 124 GHC's variable-size Integer type. 125 126 Criterion benchmarks attest that any timing variation between cases with 127 differing inputs is attributable to noise: 128 129 ``` 130 benchmarking derive_pub/wnaf, sk = 2 131 time 29.67 μs (29.64 μs .. 29.71 μs) 132 1.000 R² (1.000 R² .. 1.000 R²) 133 mean 29.68 μs (29.64 μs .. 29.71 μs) 134 std dev 121.1 ns (83.80 ns .. 177.2 ns) 135 136 benchmarking derive_pub/wnaf, sk = 2 ^ 255 - 19 137 time 29.68 μs (29.65 μs .. 29.72 μs) 138 1.000 R² (1.000 R² .. 1.000 R²) 139 mean 29.71 μs (29.68 μs .. 29.75 μs) 140 std dev 106.7 ns (71.74 ns .. 174.7 ns) 141 142 benchmarking schnorr/sign_schnorr' (small) 143 time 76.27 μs (76.21 μs .. 76.32 μs) 144 1.000 R² (1.000 R² .. 1.000 R²) 145 mean 76.44 μs (76.40 μs .. 76.50 μs) 146 std dev 162.3 ns (123.1 ns .. 246.7 ns) 147 148 benchmarking schnorr/sign_schnorr' (large) 149 time 76.35 μs (76.31 μs .. 76.38 μs) 150 1.000 R² (1.000 R² .. 1.000 R²) 151 mean 76.37 μs (76.35 μs .. 76.40 μs) 152 std dev 84.10 ns (67.03 ns .. 112.7 ns) 153 154 benchmarking ecdsa/sign_ecdsa' (small) 155 time 43.95 μs (43.89 μs .. 44.02 μs) 156 1.000 R² (1.000 R² .. 1.000 R²) 157 mean 44.04 μs (43.96 μs .. 44.15 μs) 158 std dev 310.2 ns (259.9 ns .. 384.6 ns) 159 160 benchmarking ecdsa/sign_ecdsa' (large) 161 time 44.02 μs (44.00 μs .. 44.03 μs) 162 1.000 R² (1.000 R² .. 1.000 R²) 163 mean 43.99 μs (43.97 μs .. 44.01 μs) 164 std dev 58.86 ns (46.66 ns .. 72.16 ns) 165 166 benchmarking ecdh/ecdh (small) 167 time 143.6 μs (143.4 μs .. 143.7 μs) 168 1.000 R² (1.000 R² .. 1.000 R²) 169 mean 143.7 μs (143.3 μs .. 144.6 μs) 170 std dev 2.022 μs (846.9 ns .. 3.402 μs) 171 172 benchmarking ecdh/ecdh (large) 173 time 143.8 μs (143.7 μs .. 143.9 μs) 174 1.000 R² (1.000 R² .. 1.000 R²) 175 mean 143.8 μs (143.7 μs .. 143.9 μs) 176 std dev 385.2 ns (265.9 ns .. 544.5 ns) 177 ``` 178 179 Note also that care has been taken to ensure that allocation is held 180 constant across input sizes for all sensitive operations: 181 182 ``` 183 derive_pub 184 185 Case Allocated GCs 186 wnaf, sk = 2 312 0 187 wnaf, sk = 2 ^ 255 - 19 312 0 188 189 schnorr 190 191 Case Allocated GCs 192 sign_schnorr' (small) 14,416 0 193 sign_schnorr' (large) 14,416 0 194 195 ecdsa 196 197 Case Allocated GCs 198 sign_ecdsa' (small) 1,560 0 199 sign_ecdsa' (large) 1,560 0 200 201 ecdh 202 203 Case Allocated GCs 204 ecdh (small) 616 0 205 ecdh (large) 616 0 206 207 ``` 208 209 Though constant-resource execution is enforced rigorously, take 210 reasonable security precautions as appropriate. You shouldn't deploy the 211 implementations within in any situation where they could easily be used 212 as an oracle to construct a [timing attack][timea], and you shouldn't 213 give sophisticated malicious actors [access to your computer][flurl]. 214 215 If you discover any vulnerabilities, please disclose them via 216 security@ppad.tech. 217 218 ## Development 219 220 You'll require [Nix][nixos] with [flake][flake] support enabled. Enter a 221 development shell with: 222 223 ``` 224 $ nix develop 225 ``` 226 227 Then do e.g.: 228 229 ``` 230 $ cabal repl ppad-secp256k1 231 ``` 232 233 to get a REPL for the main library. 234 235 [bp340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki 236 [ut340]: https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv 237 [bp146]: https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki 238 [r6979]: https://www.rfc-editor.org/rfc/rfc6979 239 [nixos]: https://nixos.org/ 240 [flake]: https://nixos.org/manual/nix/unstable/command-ref/new-cli/nix3-flake.html 241 [hadoc]: https://docs.ppad.tech/secp256k1 242 [wyche]: https://github.com/C2SP/wycheproof 243 [timea]: https://en.wikipedia.org/wiki/Timing_attack 244 [flurl]: https://eprint.iacr.org/2014/140.pdf 245 [const]: https://www.chosenplaintext.ca/articles/beginners-guide-constant-time-cryptography.html 246 [csecp]: https://git.ppad.tech/csecp256k1 247 [noble]: https://github.com/paulmillr/noble-secp256k1 248 [fixed]: https://git.ppad.tech/fixed 249 [sha256]: https://git.ppad.tech/sha256