1// Copyright (c) 2013-2017 The btcsuite developers 2// Use of this source code is governed by an ISC 3// license that can be found in the LICENSE file. 4 5package btcec 6 7import ( 8 "bytes" 9 "crypto/rand" 10 "crypto/sha256" 11 "encoding/hex" 12 "fmt" 13 "math/big" 14 "reflect" 15 "testing" 16) 17 18type signatureTest struct { 19 name string 20 sig []byte 21 der bool 22 isValid bool 23} 24 25// decodeHex decodes the passed hex string and returns the resulting bytes. It 26// panics if an error occurs. This is only used in the tests as a helper since 27// the only way it can fail is if there is an error in the test source code. 28func decodeHex(hexStr string) []byte { 29 b, err := hex.DecodeString(hexStr) 30 if err != nil { 31 panic("invalid hex string in test source: err " + err.Error() + 32 ", hex: " + hexStr) 33 } 34 35 return b 36} 37 38var signatureTests = []signatureTest{ 39 // signatures from bitcoin blockchain tx 40 // 0437cd7f8525ceed2324359c2d0ba26006d92d85 41 { 42 name: "valid signature.", 43 sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 44 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 45 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 46 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 47 0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 48 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 49 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 50 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 51 }, 52 der: true, 53 isValid: true, 54 }, 55 { 56 name: "empty.", 57 sig: []byte{}, 58 isValid: false, 59 }, 60 { 61 name: "bad magic.", 62 sig: []byte{0x31, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 63 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 64 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 65 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 66 0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 67 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 68 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 69 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 70 }, 71 der: true, 72 isValid: false, 73 }, 74 { 75 name: "bad 1st int marker magic.", 76 sig: []byte{0x30, 0x44, 0x03, 0x20, 0x4e, 0x45, 0xe1, 0x69, 77 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 78 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 79 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 80 0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 81 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 82 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 83 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 84 }, 85 der: true, 86 isValid: false, 87 }, 88 { 89 name: "bad 2nd int marker.", 90 sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 91 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 92 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 93 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 94 0x41, 0x03, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 95 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 96 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 97 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 98 }, 99 der: true, 100 isValid: false, 101 }, 102 { 103 name: "short len", 104 sig: []byte{0x30, 0x43, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 105 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 106 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 107 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 108 0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 109 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 110 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 111 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 112 }, 113 der: true, 114 isValid: false, 115 }, 116 { 117 name: "invalid message length", 118 sig: []byte{0x30, 0x00, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00}, 119 der: false, 120 isValid: false, 121 }, 122 { 123 name: "long len", 124 sig: []byte{0x30, 0x45, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 125 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 126 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 127 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 128 0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 129 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 130 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 131 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 132 }, 133 der: true, 134 isValid: false, 135 }, 136 { 137 name: "long X", 138 sig: []byte{0x30, 0x44, 0x02, 0x42, 0x4e, 0x45, 0xe1, 0x69, 139 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 140 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 141 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 142 0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 143 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 144 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 145 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 146 }, 147 der: true, 148 isValid: false, 149 }, 150 { 151 name: "long Y", 152 sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 153 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 154 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 155 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 156 0x41, 0x02, 0x21, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 157 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 158 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 159 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 160 }, 161 der: true, 162 isValid: false, 163 }, 164 { 165 name: "short Y", 166 sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 167 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 168 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 169 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 170 0x41, 0x02, 0x19, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 171 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 172 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 173 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 174 }, 175 der: true, 176 isValid: false, 177 }, 178 { 179 name: "trailing crap.", 180 sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 181 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 182 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 183 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 184 0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 185 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 186 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 187 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 0x01, 188 }, 189 der: true, 190 191 // This test is now passing (used to be failing) because there 192 // are signatures in the blockchain that have trailing zero 193 // bytes before the hashtype. So ParseSignature was fixed to 194 // permit buffers with trailing nonsense after the actual 195 // signature. 196 isValid: true, 197 }, 198 { 199 name: "X == N ", 200 sig: []byte{0x30, 0x44, 0x02, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 201 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 202 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 203 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 204 0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 205 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 206 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 207 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 208 }, 209 der: true, 210 isValid: false, 211 }, 212 { 213 name: "X == N ", 214 sig: []byte{0x30, 0x44, 0x02, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 215 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 216 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 217 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 218 0x42, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 219 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 220 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 221 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 222 }, 223 der: false, 224 isValid: false, 225 }, 226 { 227 name: "Y == N", 228 sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 229 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 230 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 231 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 232 0x41, 0x02, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 233 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 234 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 235 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41, 236 }, 237 der: true, 238 isValid: false, 239 }, 240 { 241 name: "Y > N", 242 sig: []byte{0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 243 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 244 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 245 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 246 0x41, 0x02, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 247 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 248 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 249 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x42, 250 }, 251 der: false, 252 isValid: false, 253 }, 254 { 255 name: "0 len X.", 256 sig: []byte{0x30, 0x24, 0x02, 0x00, 0x02, 0x20, 0x18, 0x15, 257 0x22, 0xec, 0x8e, 0xca, 0x07, 0xde, 0x48, 0x60, 0xa4, 258 0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 259 0xbb, 0xac, 0x46, 0x22, 0x08, 0x22, 0x21, 0xa8, 0x76, 260 0x8d, 0x1d, 0x09, 261 }, 262 der: true, 263 isValid: false, 264 }, 265 { 266 name: "0 len Y.", 267 sig: []byte{0x30, 0x24, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 268 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 269 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 270 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 271 0x41, 0x02, 0x00, 272 }, 273 der: true, 274 isValid: false, 275 }, 276 { 277 name: "extra R padding.", 278 sig: []byte{0x30, 0x45, 0x02, 0x21, 0x00, 0x4e, 0x45, 0xe1, 0x69, 279 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 280 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 281 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 282 0x41, 0x02, 0x20, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 283 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 284 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 285 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 286 }, 287 der: true, 288 isValid: false, 289 }, 290 { 291 name: "extra S padding.", 292 sig: []byte{0x30, 0x45, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 293 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 294 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 295 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 296 0x41, 0x02, 0x21, 0x00, 0x18, 0x15, 0x22, 0xec, 0x8e, 0xca, 297 0x07, 0xde, 0x48, 0x60, 0xa4, 0xac, 0xdd, 0x12, 0x90, 298 0x9d, 0x83, 0x1c, 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 299 0x08, 0x22, 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 300 }, 301 der: true, 302 isValid: false, 303 }, 304 // Standard checks (in BER format, without checking for 'canonical' DER 305 // signatures) don't test for negative numbers here because there isn't 306 // a way that is the same between openssl and go that will mark a number 307 // as negative. The Go ASN.1 parser marks numbers as negative when 308 // openssl does not (it doesn't handle negative numbers that I can tell 309 // at all. When not parsing DER signatures, which is done by by bitcoind 310 // when accepting transactions into its mempool, we otherwise only check 311 // for the coordinates being zero. 312 { 313 name: "X == 0", 314 sig: []byte{0x30, 0x25, 0x02, 0x01, 0x00, 0x02, 0x20, 0x18, 315 0x15, 0x22, 0xec, 0x8e, 0xca, 0x07, 0xde, 0x48, 0x60, 316 0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c, 0xc5, 317 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, 0x22, 0x21, 0xa8, 318 0x76, 0x8d, 0x1d, 0x09, 319 }, 320 der: false, 321 isValid: false, 322 }, 323 { 324 name: "Y == 0.", 325 sig: []byte{0x30, 0x25, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 326 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 0xa1, 327 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 0xe9, 0xd6, 328 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 0x5f, 0xb8, 0xcd, 329 0x41, 0x02, 0x01, 0x00, 330 }, 331 der: false, 332 isValid: false, 333 }, 334} 335 336func TestSignatures(t *testing.T) { 337 for _, test := range signatureTests { 338 var err error 339 if test.der { 340 _, err = ParseDERSignature(test.sig, S256()) 341 } else { 342 _, err = ParseSignature(test.sig, S256()) 343 } 344 if err != nil { 345 if test.isValid { 346 t.Errorf("%s signature failed when shouldn't %v", 347 test.name, err) 348 } /* else { 349 t.Errorf("%s got error %v", test.name, err) 350 } */ 351 continue 352 } 353 if !test.isValid { 354 t.Errorf("%s counted as valid when it should fail", 355 test.name) 356 } 357 } 358} 359 360// TestSignatureSerialize ensures that serializing signatures works as expected. 361func TestSignatureSerialize(t *testing.T) { 362 tests := []struct { 363 name string 364 ecsig *Signature 365 expected []byte 366 }{ 367 // signature from bitcoin blockchain tx 368 // 0437cd7f8525ceed2324359c2d0ba26006d92d85 369 { 370 "valid 1 - r and s most significant bits are zero", 371 &Signature{ 372 R: fromHex("4e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41"), 373 S: fromHex("181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09"), 374 }, 375 []byte{ 376 0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69, 377 0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3, 378 0xa1, 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32, 379 0xe9, 0xd6, 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab, 380 0x5f, 0xb8, 0xcd, 0x41, 0x02, 0x20, 0x18, 0x15, 381 0x22, 0xec, 0x8e, 0xca, 0x07, 0xde, 0x48, 0x60, 382 0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c, 383 0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, 0x22, 384 0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09, 385 }, 386 }, 387 // signature from bitcoin blockchain tx 388 // cb00f8a0573b18faa8c4f467b049f5d202bf1101d9ef2633bc611be70376a4b4 389 { 390 "valid 2 - r most significant bit is one", 391 &Signature{ 392 R: fromHex("0082235e21a2300022738dabb8e1bbd9d19cfb1e7ab8c30a23b0afbb8d178abcf3"), 393 S: fromHex("24bf68e256c534ddfaf966bf908deb944305596f7bdcc38d69acad7f9c868724"), 394 }, 395 []byte{ 396 0x30, 0x45, 0x02, 0x21, 0x00, 0x82, 0x23, 0x5e, 397 0x21, 0xa2, 0x30, 0x00, 0x22, 0x73, 0x8d, 0xab, 398 0xb8, 0xe1, 0xbb, 0xd9, 0xd1, 0x9c, 0xfb, 0x1e, 399 0x7a, 0xb8, 0xc3, 0x0a, 0x23, 0xb0, 0xaf, 0xbb, 400 0x8d, 0x17, 0x8a, 0xbc, 0xf3, 0x02, 0x20, 0x24, 401 0xbf, 0x68, 0xe2, 0x56, 0xc5, 0x34, 0xdd, 0xfa, 402 0xf9, 0x66, 0xbf, 0x90, 0x8d, 0xeb, 0x94, 0x43, 403 0x05, 0x59, 0x6f, 0x7b, 0xdc, 0xc3, 0x8d, 0x69, 404 0xac, 0xad, 0x7f, 0x9c, 0x86, 0x87, 0x24, 405 }, 406 }, 407 // signature from bitcoin blockchain tx 408 // fda204502a3345e08afd6af27377c052e77f1fefeaeb31bdd45f1e1237ca5470 409 { 410 "valid 3 - s most significant bit is one", 411 &Signature{ 412 R: fromHex("1cadddc2838598fee7dc35a12b340c6bde8b389f7bfd19a1252a17c4b5ed2d71"), 413 S: new(big.Int).Add(fromHex("00c1a251bbecb14b058a8bd77f65de87e51c47e95904f4c0e9d52eddc21c1415ac"), S256().N), 414 }, 415 []byte{ 416 0x30, 0x45, 0x02, 0x20, 0x1c, 0xad, 0xdd, 0xc2, 417 0x83, 0x85, 0x98, 0xfe, 0xe7, 0xdc, 0x35, 0xa1, 418 0x2b, 0x34, 0x0c, 0x6b, 0xde, 0x8b, 0x38, 0x9f, 419 0x7b, 0xfd, 0x19, 0xa1, 0x25, 0x2a, 0x17, 0xc4, 420 0xb5, 0xed, 0x2d, 0x71, 0x02, 0x21, 0x00, 0xc1, 421 0xa2, 0x51, 0xbb, 0xec, 0xb1, 0x4b, 0x05, 0x8a, 422 0x8b, 0xd7, 0x7f, 0x65, 0xde, 0x87, 0xe5, 0x1c, 423 0x47, 0xe9, 0x59, 0x04, 0xf4, 0xc0, 0xe9, 0xd5, 424 0x2e, 0xdd, 0xc2, 0x1c, 0x14, 0x15, 0xac, 425 }, 426 }, 427 { 428 "valid 4 - s is bigger than half order", 429 &Signature{ 430 R: fromHex("a196ed0e7ebcbe7b63fe1d8eecbdbde03a67ceba4fc8f6482bdcb9606a911404"), 431 S: fromHex("971729c7fa944b465b35250c6570a2f31acbb14b13d1565fab7330dcb2b3dfb1"), 432 }, 433 []byte{ 434 0x30, 0x45, 0x02, 0x21, 0x00, 0xa1, 0x96, 0xed, 435 0x0e, 0x7e, 0xbc, 0xbe, 0x7b, 0x63, 0xfe, 0x1d, 436 0x8e, 0xec, 0xbd, 0xbd, 0xe0, 0x3a, 0x67, 0xce, 437 0xba, 0x4f, 0xc8, 0xf6, 0x48, 0x2b, 0xdc, 0xb9, 438 0x60, 0x6a, 0x91, 0x14, 0x04, 0x02, 0x20, 0x68, 439 0xe8, 0xd6, 0x38, 0x05, 0x6b, 0xb4, 0xb9, 0xa4, 440 0xca, 0xda, 0xf3, 0x9a, 0x8f, 0x5d, 0x0b, 0x9f, 441 0xe3, 0x2b, 0x9b, 0x9b, 0x77, 0x49, 0xdc, 0x14, 442 0x5f, 0x2d, 0xb0, 0x1d, 0x82, 0x61, 0x90, 443 }, 444 }, 445 { 446 "zero signature", 447 &Signature{ 448 R: big.NewInt(0), 449 S: big.NewInt(0), 450 }, 451 []byte{0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00}, 452 }, 453 } 454 455 for i, test := range tests { 456 result := test.ecsig.Serialize() 457 if !bytes.Equal(result, test.expected) { 458 t.Errorf("Serialize #%d (%s) unexpected result:\n"+ 459 "got: %x\nwant: %x", i, test.name, result, 460 test.expected) 461 } 462 } 463} 464 465func testSignCompact(t *testing.T, tag string, curve *KoblitzCurve, 466 data []byte, isCompressed bool) { 467 tmp, _ := NewPrivateKey(curve) 468 priv := (*PrivateKey)(tmp) 469 470 hashed := []byte("testing") 471 sig, err := SignCompact(curve, priv, hashed, isCompressed) 472 if err != nil { 473 t.Errorf("%s: error signing: %s", tag, err) 474 return 475 } 476 477 pk, wasCompressed, err := RecoverCompact(curve, sig, hashed) 478 if err != nil { 479 t.Errorf("%s: error recovering: %s", tag, err) 480 return 481 } 482 if pk.X.Cmp(priv.X) != 0 || pk.Y.Cmp(priv.Y) != 0 { 483 t.Errorf("%s: recovered pubkey doesn't match original "+ 484 "(%v,%v) vs (%v,%v) ", tag, pk.X, pk.Y, priv.X, priv.Y) 485 return 486 } 487 if wasCompressed != isCompressed { 488 t.Errorf("%s: recovered pubkey doesn't match compressed state "+ 489 "(%v vs %v)", tag, isCompressed, wasCompressed) 490 return 491 } 492 493 // If we change the compressed bit we should get the same key back, 494 // but the compressed flag should be reversed. 495 if isCompressed { 496 sig[0] -= 4 497 } else { 498 sig[0] += 4 499 } 500 501 pk, wasCompressed, err = RecoverCompact(curve, sig, hashed) 502 if err != nil { 503 t.Errorf("%s: error recovering (2): %s", tag, err) 504 return 505 } 506 if pk.X.Cmp(priv.X) != 0 || pk.Y.Cmp(priv.Y) != 0 { 507 t.Errorf("%s: recovered pubkey (2) doesn't match original "+ 508 "(%v,%v) vs (%v,%v) ", tag, pk.X, pk.Y, priv.X, priv.Y) 509 return 510 } 511 if wasCompressed == isCompressed { 512 t.Errorf("%s: recovered pubkey doesn't match reversed "+ 513 "compressed state (%v vs %v)", tag, isCompressed, 514 wasCompressed) 515 return 516 } 517} 518 519func TestSignCompact(t *testing.T) { 520 for i := 0; i < 256; i++ { 521 name := fmt.Sprintf("test %d", i) 522 data := make([]byte, 32) 523 _, err := rand.Read(data) 524 if err != nil { 525 t.Errorf("failed to read random data for %s", name) 526 continue 527 } 528 compressed := i%2 != 0 529 testSignCompact(t, name, S256(), data, compressed) 530 } 531} 532 533// recoveryTests assert basic tests for public key recovery from signatures. 534// The cases are borrowed from github.com/fjl/btcec-issue. 535var recoveryTests = []struct { 536 msg string 537 sig string 538 pub string 539 err error 540}{ 541 { 542 // Valid curve point recovered. 543 msg: "ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008", 544 sig: "0190f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc93", 545 pub: "04E32DF42865E97135ACFB65F3BAE71BDC86F4D49150AD6A440B6F15878109880A0A2B2667F7E725CEEA70C673093BF67663E0312623C8E091B13CF2C0F11EF652", 546 }, 547 { 548 // Invalid curve point recovered. 549 msg: "00c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c", 550 sig: "0100b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549", 551 err: fmt.Errorf("invalid square root"), 552 }, 553 { 554 // Low R and S values. 555 msg: "ba09edc1275a285fb27bfe82c4eea240a907a0dbaf9e55764b8f318c37d5974f", 556 sig: "00000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000004", 557 pub: "04A7640409AA2083FDAD38B2D8DE1263B2251799591D840653FB02DBBA503D7745FCB83D80E08A1E02896BE691EA6AFFB8A35939A646F1FC79052A744B1C82EDC3", 558 }, 559} 560 561func TestRecoverCompact(t *testing.T) { 562 for i, test := range recoveryTests { 563 msg := decodeHex(test.msg) 564 sig := decodeHex(test.sig) 565 566 // Magic DER constant. 567 sig[0] += 27 568 569 pub, _, err := RecoverCompact(S256(), sig, msg) 570 571 // Verify that returned error matches as expected. 572 if !reflect.DeepEqual(test.err, err) { 573 t.Errorf("unexpected error returned from pubkey "+ 574 "recovery #%d: wanted %v, got %v", 575 i, test.err, err) 576 continue 577 } 578 579 // If check succeeded because a proper error was returned, we 580 // ignore the returned pubkey. 581 if err != nil { 582 continue 583 } 584 585 // Otherwise, ensure the correct public key was recovered. 586 exPub, _ := ParsePubKey(decodeHex(test.pub), S256()) 587 if !exPub.IsEqual(pub) { 588 t.Errorf("unexpected recovered public key #%d: "+ 589 "want %v, got %v", i, exPub, pub) 590 } 591 } 592} 593 594func TestRFC6979(t *testing.T) { 595 // Test vectors matching Trezor and CoreBitcoin implementations. 596 // - https://github.com/trezor/trezor-crypto/blob/9fea8f8ab377dc514e40c6fd1f7c89a74c1d8dc6/tests.c#L432-L453 597 // - https://github.com/oleganza/CoreBitcoin/blob/e93dd71207861b5bf044415db5fa72405e7d8fbc/CoreBitcoin/BTCKey%2BTests.m#L23-L49 598 tests := []struct { 599 key string 600 msg string 601 nonce string 602 signature string 603 }{ 604 { 605 "cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", 606 "sample", 607 "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3", 608 "3045022100af340daf02cc15c8d5d08d7735dfe6b98a474ed373bdb5fbecf7571be52b384202205009fb27f37034a9b24b707b7c6b79ca23ddef9e25f7282e8a797efe53a8f124", 609 }, 610 { 611 // This signature hits the case when S is higher than halforder. 612 // If S is not canonicalized (lowered by halforder), this test will fail. 613 "0000000000000000000000000000000000000000000000000000000000000001", 614 "Satoshi Nakamoto", 615 "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15", 616 "3045022100934b1ea10a4b3c1757e2b0c017d0b6143ce3c9a7e6a4a49860d7a6ab210ee3d802202442ce9d2b916064108014783e923ec36b49743e2ffa1c4496f01a512aafd9e5", 617 }, 618 { 619 "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", 620 "Satoshi Nakamoto", 621 "33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90", 622 "3045022100fd567d121db66e382991534ada77a6bd3106f0a1098c231e47993447cd6af2d002206b39cd0eb1bc8603e159ef5c20a5c8ad685a45b06ce9bebed3f153d10d93bed5", 623 }, 624 { 625 "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181", 626 "Alan Turing", 627 "525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1", 628 "304402207063ae83e7f62bbb171798131b4a0564b956930092b33b07b395615d9ec7e15c022058dfcc1e00a35e1572f366ffe34ba0fc47db1e7189759b9fb233c5b05ab388ea", 629 }, 630 { 631 "0000000000000000000000000000000000000000000000000000000000000001", 632 "All those moments will be lost in time, like tears in rain. Time to die...", 633 "38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3", 634 "30450221008600dbd41e348fe5c9465ab92d23e3db8b98b873beecd930736488696438cb6b0220547fe64427496db33bf66019dacbf0039c04199abb0122918601db38a72cfc21", 635 }, 636 { 637 "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2", 638 "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!", 639 "1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d", 640 "3045022100b552edd27580141f3b2a5463048cb7cd3e047b97c9f98076c32dbdf85a68718b0220279fa72dd19bfae05577e06c7c0c1900c371fcd5893f7e1d56a37d30174671f6", 641 }, 642 } 643 644 for i, test := range tests { 645 privKey, _ := PrivKeyFromBytes(S256(), decodeHex(test.key)) 646 hash := sha256.Sum256([]byte(test.msg)) 647 648 // Ensure deterministically generated nonce is the expected value. 649 gotNonce := nonceRFC6979(privKey.D, hash[:]).Bytes() 650 wantNonce := decodeHex(test.nonce) 651 if !bytes.Equal(gotNonce, wantNonce) { 652 t.Errorf("NonceRFC6979 #%d (%s): Nonce is incorrect: "+ 653 "%x (expected %x)", i, test.msg, gotNonce, 654 wantNonce) 655 continue 656 } 657 658 // Ensure deterministically generated signature is the expected value. 659 gotSig, err := privKey.Sign(hash[:]) 660 if err != nil { 661 t.Errorf("Sign #%d (%s): unexpected error: %v", i, 662 test.msg, err) 663 continue 664 } 665 gotSigBytes := gotSig.Serialize() 666 wantSigBytes := decodeHex(test.signature) 667 if !bytes.Equal(gotSigBytes, wantSigBytes) { 668 t.Errorf("Sign #%d (%s): mismatched signature: %x "+ 669 "(expected %x)", i, test.msg, gotSigBytes, 670 wantSigBytes) 671 continue 672 } 673 } 674} 675 676func TestSignatureIsEqual(t *testing.T) { 677 sig1 := &Signature{ 678 R: fromHex("0082235e21a2300022738dabb8e1bbd9d19cfb1e7ab8c30a23b0afbb8d178abcf3"), 679 S: fromHex("24bf68e256c534ddfaf966bf908deb944305596f7bdcc38d69acad7f9c868724"), 680 } 681 sig2 := &Signature{ 682 R: fromHex("4e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41"), 683 S: fromHex("181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09"), 684 } 685 686 if !sig1.IsEqual(sig1) { 687 t.Fatalf("value of IsEqual is incorrect, %v is "+ 688 "equal to %v", sig1, sig1) 689 } 690 691 if sig1.IsEqual(sig2) { 692 t.Fatalf("value of IsEqual is incorrect, %v is not "+ 693 "equal to %v", sig1, sig2) 694 } 695} 696