github.com/lbryio/lbcd@v0.22.119/btcec/signature_test.go (about) 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 5 package btcec 6 7 import ( 8 "bytes" 9 "crypto/rand" 10 "crypto/sha256" 11 "encoding/hex" 12 "fmt" 13 "math/big" 14 "reflect" 15 "testing" 16 ) 17 18 type 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. 28 func 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 38 var 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 336 func 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. 361 func 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 465 func testSignCompact(t *testing.T, tag string, curve *KoblitzCurve, 466 data []byte, isCompressed bool) { 467 priv, _ := NewPrivateKey(curve) 468 469 hashed := []byte("testing") 470 sig, err := SignCompact(curve, priv, hashed, isCompressed) 471 if err != nil { 472 t.Errorf("%s: error signing: %s", tag, err) 473 return 474 } 475 476 pk, wasCompressed, err := RecoverCompact(curve, sig, hashed) 477 if err != nil { 478 t.Errorf("%s: error recovering: %s", tag, err) 479 return 480 } 481 if pk.X.Cmp(priv.X) != 0 || pk.Y.Cmp(priv.Y) != 0 { 482 t.Errorf("%s: recovered pubkey doesn't match original "+ 483 "(%v,%v) vs (%v,%v) ", tag, pk.X, pk.Y, priv.X, priv.Y) 484 return 485 } 486 if wasCompressed != isCompressed { 487 t.Errorf("%s: recovered pubkey doesn't match compressed state "+ 488 "(%v vs %v)", tag, isCompressed, wasCompressed) 489 return 490 } 491 492 // If we change the compressed bit we should get the same key back, 493 // but the compressed flag should be reversed. 494 if isCompressed { 495 sig[0] -= 4 496 } else { 497 sig[0] += 4 498 } 499 500 pk, wasCompressed, err = RecoverCompact(curve, sig, hashed) 501 if err != nil { 502 t.Errorf("%s: error recovering (2): %s", tag, err) 503 return 504 } 505 if pk.X.Cmp(priv.X) != 0 || pk.Y.Cmp(priv.Y) != 0 { 506 t.Errorf("%s: recovered pubkey (2) doesn't match original "+ 507 "(%v,%v) vs (%v,%v) ", tag, pk.X, pk.Y, priv.X, priv.Y) 508 return 509 } 510 if wasCompressed == isCompressed { 511 t.Errorf("%s: recovered pubkey doesn't match reversed "+ 512 "compressed state (%v vs %v)", tag, isCompressed, 513 wasCompressed) 514 return 515 } 516 } 517 518 func TestSignCompact(t *testing.T) { 519 for i := 0; i < 256; i++ { 520 name := fmt.Sprintf("test %d", i) 521 data := make([]byte, 32) 522 _, err := rand.Read(data) 523 if err != nil { 524 t.Errorf("failed to read random data for %s", name) 525 continue 526 } 527 compressed := i%2 != 0 528 testSignCompact(t, name, S256(), data, compressed) 529 } 530 } 531 532 // recoveryTests assert basic tests for public key recovery from signatures. 533 // The cases are borrowed from github.com/fjl/btcec-issue. 534 var recoveryTests = []struct { 535 msg string 536 sig string 537 pub string 538 err error 539 }{ 540 { 541 // Valid curve point recovered. 542 msg: "ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008", 543 sig: "0190f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc93", 544 pub: "04E32DF42865E97135ACFB65F3BAE71BDC86F4D49150AD6A440B6F15878109880A0A2B2667F7E725CEEA70C673093BF67663E0312623C8E091B13CF2C0F11EF652", 545 }, 546 { 547 // Invalid curve point recovered. 548 msg: "00c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c", 549 sig: "0100b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549", 550 err: fmt.Errorf("invalid square root"), 551 }, 552 { 553 // Point at infinity recovered 554 msg: "6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9", 555 sig: "0079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9", 556 err: fmt.Errorf("point (Qx, Qy) equals the point at infinity"), 557 }, 558 { 559 // Low R and S values. 560 msg: "ba09edc1275a285fb27bfe82c4eea240a907a0dbaf9e55764b8f318c37d5974f", 561 sig: "00000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000004", 562 pub: "04A7640409AA2083FDAD38B2D8DE1263B2251799591D840653FB02DBBA503D7745FCB83D80E08A1E02896BE691EA6AFFB8A35939A646F1FC79052A744B1C82EDC3", 563 }, 564 { 565 // Zero R value 566 // 567 // Test case contributed by Ethereum Swarm: GH-1651 568 msg: "3060d2c77c1e192d62ad712fb400e04e6f779914a6876328ff3b213fa85d2012", 569 sig: "65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037a3", 570 err: fmt.Errorf("signature R is 0"), 571 }, 572 { 573 // Zero R value 574 // 575 // Test case contributed by Ethereum Swarm: GH-1651 576 msg: "2bcebac60d8a78e520ae81c2ad586792df495ed429bd730dcd897b301932d054", 577 sig: "060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c", 578 err: fmt.Errorf("signature R is 0"), 579 }, 580 { 581 // R = N (curve order of secp256k1) 582 msg: "2bcebac60d8a78e520ae81c2ad586792df495ed429bd730dcd897b301932d054", 583 sig: "65fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036414100000000000000000000000000000000000000000000000000000000000037a3", 584 err: fmt.Errorf("signature R is >= curve order"), 585 }, 586 { 587 // Zero S value 588 msg: "ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008", 589 sig: "0190f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549980000000000000000000000000000000000000000000000000000000000000000", 590 err: fmt.Errorf("signature S is 0"), 591 }, 592 { 593 // S = N (curve order of secp256k1) 594 msg: "ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008", 595 sig: "0190f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e54998fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 596 err: fmt.Errorf("signature S is >= curve order"), 597 }, 598 } 599 600 func TestRecoverCompact(t *testing.T) { 601 for i, test := range recoveryTests { 602 msg := decodeHex(test.msg) 603 sig := decodeHex(test.sig) 604 605 // Magic DER constant. 606 sig[0] += 27 607 608 pub, _, err := RecoverCompact(S256(), sig, msg) 609 610 // Verify that returned error matches as expected. 611 if !reflect.DeepEqual(test.err, err) { 612 t.Errorf("unexpected error returned from pubkey "+ 613 "recovery #%d: wanted %v, got %v", 614 i, test.err, err) 615 continue 616 } 617 618 // If check succeeded because a proper error was returned, we 619 // ignore the returned pubkey. 620 if err != nil { 621 continue 622 } 623 624 // Otherwise, ensure the correct public key was recovered. 625 exPub, _ := ParsePubKey(decodeHex(test.pub), S256()) 626 if !exPub.IsEqual(pub) { 627 t.Errorf("unexpected recovered public key #%d: "+ 628 "want %v, got %v", i, exPub, pub) 629 } 630 } 631 } 632 633 func TestRFC6979(t *testing.T) { 634 // Test vectors matching Trezor and CoreBitcoin implementations. 635 // - https://github.com/trezor/trezor-crypto/blob/9fea8f8ab377dc514e40c6fd1f7c89a74c1d8dc6/tests.c#L432-L453 636 // - https://github.com/oleganza/CoreBitcoin/blob/e93dd71207861b5bf044415db5fa72405e7d8fbc/CoreBitcoin/BTCKey%2BTests.m#L23-L49 637 tests := []struct { 638 key string 639 msg string 640 nonce string 641 signature string 642 }{ 643 { 644 "cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", 645 "sample", 646 "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3", 647 "3045022100af340daf02cc15c8d5d08d7735dfe6b98a474ed373bdb5fbecf7571be52b384202205009fb27f37034a9b24b707b7c6b79ca23ddef9e25f7282e8a797efe53a8f124", 648 }, 649 { 650 // This signature hits the case when S is higher than halforder. 651 // If S is not canonicalized (lowered by halforder), this test will fail. 652 "0000000000000000000000000000000000000000000000000000000000000001", 653 "Satoshi Nakamoto", 654 "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15", 655 "3045022100934b1ea10a4b3c1757e2b0c017d0b6143ce3c9a7e6a4a49860d7a6ab210ee3d802202442ce9d2b916064108014783e923ec36b49743e2ffa1c4496f01a512aafd9e5", 656 }, 657 { 658 "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", 659 "Satoshi Nakamoto", 660 "33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90", 661 "3045022100fd567d121db66e382991534ada77a6bd3106f0a1098c231e47993447cd6af2d002206b39cd0eb1bc8603e159ef5c20a5c8ad685a45b06ce9bebed3f153d10d93bed5", 662 }, 663 { 664 "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181", 665 "Alan Turing", 666 "525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1", 667 "304402207063ae83e7f62bbb171798131b4a0564b956930092b33b07b395615d9ec7e15c022058dfcc1e00a35e1572f366ffe34ba0fc47db1e7189759b9fb233c5b05ab388ea", 668 }, 669 { 670 "0000000000000000000000000000000000000000000000000000000000000001", 671 "All those moments will be lost in time, like tears in rain. Time to die...", 672 "38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3", 673 "30450221008600dbd41e348fe5c9465ab92d23e3db8b98b873beecd930736488696438cb6b0220547fe64427496db33bf66019dacbf0039c04199abb0122918601db38a72cfc21", 674 }, 675 { 676 "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2", 677 "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!", 678 "1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d", 679 "3045022100b552edd27580141f3b2a5463048cb7cd3e047b97c9f98076c32dbdf85a68718b0220279fa72dd19bfae05577e06c7c0c1900c371fcd5893f7e1d56a37d30174671f6", 680 }, 681 } 682 683 for i, test := range tests { 684 privKey, _ := PrivKeyFromBytes(S256(), decodeHex(test.key)) 685 hash := sha256.Sum256([]byte(test.msg)) 686 687 // Ensure deterministically generated nonce is the expected value. 688 gotNonce := nonceRFC6979(privKey.D, hash[:]).Bytes() 689 wantNonce := decodeHex(test.nonce) 690 if !bytes.Equal(gotNonce, wantNonce) { 691 t.Errorf("NonceRFC6979 #%d (%s): Nonce is incorrect: "+ 692 "%x (expected %x)", i, test.msg, gotNonce, 693 wantNonce) 694 continue 695 } 696 697 // Ensure deterministically generated signature is the expected value. 698 gotSig, err := privKey.Sign(hash[:]) 699 if err != nil { 700 t.Errorf("Sign #%d (%s): unexpected error: %v", i, 701 test.msg, err) 702 continue 703 } 704 gotSigBytes := gotSig.Serialize() 705 wantSigBytes := decodeHex(test.signature) 706 if !bytes.Equal(gotSigBytes, wantSigBytes) { 707 t.Errorf("Sign #%d (%s): mismatched signature: %x "+ 708 "(expected %x)", i, test.msg, gotSigBytes, 709 wantSigBytes) 710 continue 711 } 712 } 713 } 714 715 func TestSignatureIsEqual(t *testing.T) { 716 sig1 := &Signature{ 717 R: fromHex("0082235e21a2300022738dabb8e1bbd9d19cfb1e7ab8c30a23b0afbb8d178abcf3"), 718 S: fromHex("24bf68e256c534ddfaf966bf908deb944305596f7bdcc38d69acad7f9c868724"), 719 } 720 sig2 := &Signature{ 721 R: fromHex("4e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41"), 722 S: fromHex("181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09"), 723 } 724 725 if !sig1.IsEqual(sig1) { 726 t.Fatalf("value of IsEqual is incorrect, %v is "+ 727 "equal to %v", sig1, sig1) 728 } 729 730 if sig1.IsEqual(sig2) { 731 t.Fatalf("value of IsEqual is incorrect, %v is not "+ 732 "equal to %v", sig1, sig2) 733 } 734 }