github.com/palcoin-project/palcd@v1.0.0/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 // Low R and S values. 554 msg: "ba09edc1275a285fb27bfe82c4eea240a907a0dbaf9e55764b8f318c37d5974f", 555 sig: "00000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000004", 556 pub: "04A7640409AA2083FDAD38B2D8DE1263B2251799591D840653FB02DBBA503D7745FCB83D80E08A1E02896BE691EA6AFFB8A35939A646F1FC79052A744B1C82EDC3", 557 }, 558 { 559 // Zero R value 560 // 561 // Test case contributed by Ethereum Swarm: GH-1651 562 msg: "3060d2c77c1e192d62ad712fb400e04e6f779914a6876328ff3b213fa85d2012", 563 sig: "65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037a3", 564 err: fmt.Errorf("signature R is 0"), 565 }, 566 { 567 // Zero R value 568 // 569 // Test case contributed by Ethereum Swarm: GH-1651 570 msg: "2bcebac60d8a78e520ae81c2ad586792df495ed429bd730dcd897b301932d054", 571 sig: "060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c", 572 err: fmt.Errorf("signature R is 0"), 573 }, 574 { 575 // R = N (curve order of secp256k1) 576 msg: "2bcebac60d8a78e520ae81c2ad586792df495ed429bd730dcd897b301932d054", 577 sig: "65fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036414100000000000000000000000000000000000000000000000000000000000037a3", 578 err: fmt.Errorf("signature R is >= curve order"), 579 }, 580 { 581 // Zero S value 582 msg: "ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008", 583 sig: "0190f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549980000000000000000000000000000000000000000000000000000000000000000", 584 err: fmt.Errorf("signature S is 0"), 585 }, 586 { 587 // S = N (curve order of secp256k1) 588 msg: "ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008", 589 sig: "0190f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e54998fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 590 err: fmt.Errorf("signature S is >= curve order"), 591 }, 592 } 593 594 func TestRecoverCompact(t *testing.T) { 595 for i, test := range recoveryTests { 596 msg := decodeHex(test.msg) 597 sig := decodeHex(test.sig) 598 599 // Magic DER constant. 600 sig[0] += 27 601 602 pub, _, err := RecoverCompact(S256(), sig, msg) 603 604 // Verify that returned error matches as expected. 605 if !reflect.DeepEqual(test.err, err) { 606 t.Errorf("unexpected error returned from pubkey "+ 607 "recovery #%d: wanted %v, got %v", 608 i, test.err, err) 609 continue 610 } 611 612 // If check succeeded because a proper error was returned, we 613 // ignore the returned pubkey. 614 if err != nil { 615 continue 616 } 617 618 // Otherwise, ensure the correct public key was recovered. 619 exPub, _ := ParsePubKey(decodeHex(test.pub), S256()) 620 if !exPub.IsEqual(pub) { 621 t.Errorf("unexpected recovered public key #%d: "+ 622 "want %v, got %v", i, exPub, pub) 623 } 624 } 625 } 626 627 func TestRFC6979(t *testing.T) { 628 // Test vectors matching Trezor and CoreBitcoin implementations. 629 // - https://github.com/trezor/trezor-crypto/blob/9fea8f8ab377dc514e40c6fd1f7c89a74c1d8dc6/tests.c#L432-L453 630 // - https://github.com/oleganza/CoreBitcoin/blob/e93dd71207861b5bf044415db5fa72405e7d8fbc/CoreBitcoin/BTCKey%2BTests.m#L23-L49 631 tests := []struct { 632 key string 633 msg string 634 nonce string 635 signature string 636 }{ 637 { 638 "cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", 639 "sample", 640 "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3", 641 "3045022100af340daf02cc15c8d5d08d7735dfe6b98a474ed373bdb5fbecf7571be52b384202205009fb27f37034a9b24b707b7c6b79ca23ddef9e25f7282e8a797efe53a8f124", 642 }, 643 { 644 // This signature hits the case when S is higher than halforder. 645 // If S is not canonicalized (lowered by halforder), this test will fail. 646 "0000000000000000000000000000000000000000000000000000000000000001", 647 "Satoshi Nakamoto", 648 "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15", 649 "3045022100934b1ea10a4b3c1757e2b0c017d0b6143ce3c9a7e6a4a49860d7a6ab210ee3d802202442ce9d2b916064108014783e923ec36b49743e2ffa1c4496f01a512aafd9e5", 650 }, 651 { 652 "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", 653 "Satoshi Nakamoto", 654 "33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90", 655 "3045022100fd567d121db66e382991534ada77a6bd3106f0a1098c231e47993447cd6af2d002206b39cd0eb1bc8603e159ef5c20a5c8ad685a45b06ce9bebed3f153d10d93bed5", 656 }, 657 { 658 "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181", 659 "Alan Turing", 660 "525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1", 661 "304402207063ae83e7f62bbb171798131b4a0564b956930092b33b07b395615d9ec7e15c022058dfcc1e00a35e1572f366ffe34ba0fc47db1e7189759b9fb233c5b05ab388ea", 662 }, 663 { 664 "0000000000000000000000000000000000000000000000000000000000000001", 665 "All those moments will be lost in time, like tears in rain. Time to die...", 666 "38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3", 667 "30450221008600dbd41e348fe5c9465ab92d23e3db8b98b873beecd930736488696438cb6b0220547fe64427496db33bf66019dacbf0039c04199abb0122918601db38a72cfc21", 668 }, 669 { 670 "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2", 671 "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!", 672 "1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d", 673 "3045022100b552edd27580141f3b2a5463048cb7cd3e047b97c9f98076c32dbdf85a68718b0220279fa72dd19bfae05577e06c7c0c1900c371fcd5893f7e1d56a37d30174671f6", 674 }, 675 } 676 677 for i, test := range tests { 678 privKey, _ := PrivKeyFromBytes(S256(), decodeHex(test.key)) 679 hash := sha256.Sum256([]byte(test.msg)) 680 681 // Ensure deterministically generated nonce is the expected value. 682 gotNonce := nonceRFC6979(privKey.D, hash[:]).Bytes() 683 wantNonce := decodeHex(test.nonce) 684 if !bytes.Equal(gotNonce, wantNonce) { 685 t.Errorf("NonceRFC6979 #%d (%s): Nonce is incorrect: "+ 686 "%x (expected %x)", i, test.msg, gotNonce, 687 wantNonce) 688 continue 689 } 690 691 // Ensure deterministically generated signature is the expected value. 692 gotSig, err := privKey.Sign(hash[:]) 693 if err != nil { 694 t.Errorf("Sign #%d (%s): unexpected error: %v", i, 695 test.msg, err) 696 continue 697 } 698 gotSigBytes := gotSig.Serialize() 699 wantSigBytes := decodeHex(test.signature) 700 if !bytes.Equal(gotSigBytes, wantSigBytes) { 701 t.Errorf("Sign #%d (%s): mismatched signature: %x "+ 702 "(expected %x)", i, test.msg, gotSigBytes, 703 wantSigBytes) 704 continue 705 } 706 } 707 } 708 709 func TestSignatureIsEqual(t *testing.T) { 710 sig1 := &Signature{ 711 R: fromHex("0082235e21a2300022738dabb8e1bbd9d19cfb1e7ab8c30a23b0afbb8d178abcf3"), 712 S: fromHex("24bf68e256c534ddfaf966bf908deb944305596f7bdcc38d69acad7f9c868724"), 713 } 714 sig2 := &Signature{ 715 R: fromHex("4e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41"), 716 S: fromHex("181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09"), 717 } 718 719 if !sig1.IsEqual(sig1) { 720 t.Fatalf("value of IsEqual is incorrect, %v is "+ 721 "equal to %v", sig1, sig1) 722 } 723 724 if sig1.IsEqual(sig2) { 725 t.Fatalf("value of IsEqual is incorrect, %v is not "+ 726 "equal to %v", sig1, sig2) 727 } 728 }