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