pubkey_test.go raw

   1  // Copyright (c) 2013-2016 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  	"testing"
   9  
  10  	"next.orly.dev/pkg/nostr/utils"
  11  
  12  	"github.com/davecgh/go-spew/spew"
  13  )
  14  
  15  type pubKeyTest struct {
  16  	name    string
  17  	key     []byte
  18  	format  byte
  19  	isValid bool
  20  }
  21  
  22  var pubKeyTests = []pubKeyTest{
  23  	// pubkey from bitcoin blockchain tx
  24  	// 0437cd7f8525ceed2324359c2d0ba26006d92d85
  25  	{
  26  		name: "uncompressed ok",
  27  		key: []byte{
  28  			0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
  29  			0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
  30  			0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
  31  			0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
  32  			0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
  33  			0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
  34  			0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
  35  			0xb4, 0x12, 0xa3,
  36  		},
  37  		isValid: true,
  38  		format:  pubkeyUncompressed,
  39  	},
  40  	{
  41  		name: "uncompressed x changed",
  42  		key: []byte{
  43  			0x04, 0x15, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
  44  			0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
  45  			0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
  46  			0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
  47  			0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
  48  			0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
  49  			0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
  50  			0xb4, 0x12, 0xa3,
  51  		},
  52  		isValid: false,
  53  	},
  54  	{
  55  		name: "uncompressed y changed",
  56  		key: []byte{
  57  			0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
  58  			0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
  59  			0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
  60  			0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
  61  			0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
  62  			0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
  63  			0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
  64  			0xb4, 0x12, 0xa4,
  65  		},
  66  		isValid: false,
  67  	},
  68  	{
  69  		name: "uncompressed claims compressed",
  70  		key: []byte{
  71  			0x03, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
  72  			0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
  73  			0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
  74  			0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
  75  			0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
  76  			0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
  77  			0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
  78  			0xb4, 0x12, 0xa3,
  79  		},
  80  		isValid: false,
  81  	},
  82  	{
  83  		name: "uncompressed as hybrid ok",
  84  		key: []byte{
  85  			0x07, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
  86  			0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
  87  			0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
  88  			0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
  89  			0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
  90  			0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
  91  			0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
  92  			0xb4, 0x12, 0xa3,
  93  		},
  94  		isValid: true,
  95  		format:  pubkeyHybrid,
  96  	},
  97  	{
  98  		name: "uncompressed as hybrid wrong",
  99  		key: []byte{
 100  			0x06, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
 101  			0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
 102  			0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
 103  			0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
 104  			0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
 105  			0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
 106  			0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
 107  			0xb4, 0x12, 0xa3,
 108  		},
 109  		isValid: false,
 110  	},
 111  	// from tx 0b09c51c51ff762f00fb26217269d2a18e77a4fa87d69b3c363ab4df16543f20
 112  	{
 113  		name: "compressed ok (ybit = 0)",
 114  		key: []byte{
 115  			0x02, 0xce, 0x0b, 0x14, 0xfb, 0x84, 0x2b, 0x1b,
 116  			0xa5, 0x49, 0xfd, 0xd6, 0x75, 0xc9, 0x80, 0x75, 0xf1,
 117  			0x2e, 0x9c, 0x51, 0x0f, 0x8e, 0xf5, 0x2b, 0xd0, 0x21,
 118  			0xa9, 0xa1, 0xf4, 0x80, 0x9d, 0x3b, 0x4d,
 119  		},
 120  		isValid: true,
 121  		format:  pubkeyCompressed,
 122  	},
 123  	// from tx fdeb8e72524e8dab0da507ddbaf5f88fe4a933eb10a66bc4745bb0aa11ea393c
 124  	{
 125  		name: "compressed ok (ybit = 1)",
 126  		key: []byte{
 127  			0x03, 0x26, 0x89, 0xc7, 0xc2, 0xda, 0xb1, 0x33,
 128  			0x09, 0xfb, 0x14, 0x3e, 0x0e, 0x8f, 0xe3, 0x96, 0x34,
 129  			0x25, 0x21, 0x88, 0x7e, 0x97, 0x66, 0x90, 0xb6, 0xb4,
 130  			0x7f, 0x5b, 0x2a, 0x4b, 0x7d, 0x44, 0x8e,
 131  		},
 132  		isValid: true,
 133  		format:  pubkeyCompressed,
 134  	},
 135  	{
 136  		name: "compressed claims uncompressed (ybit = 0)",
 137  		key: []byte{
 138  			0x04, 0xce, 0x0b, 0x14, 0xfb, 0x84, 0x2b, 0x1b,
 139  			0xa5, 0x49, 0xfd, 0xd6, 0x75, 0xc9, 0x80, 0x75, 0xf1,
 140  			0x2e, 0x9c, 0x51, 0x0f, 0x8e, 0xf5, 0x2b, 0xd0, 0x21,
 141  			0xa9, 0xa1, 0xf4, 0x80, 0x9d, 0x3b, 0x4d,
 142  		},
 143  		isValid: false,
 144  	},
 145  	{
 146  		name: "compressed claims uncompressed (ybit = 1)",
 147  		key: []byte{
 148  			0x05, 0x26, 0x89, 0xc7, 0xc2, 0xda, 0xb1, 0x33,
 149  			0x09, 0xfb, 0x14, 0x3e, 0x0e, 0x8f, 0xe3, 0x96, 0x34,
 150  			0x25, 0x21, 0x88, 0x7e, 0x97, 0x66, 0x90, 0xb6, 0xb4,
 151  			0x7f, 0x5b, 0x2a, 0x4b, 0x7d, 0x44, 0x8e,
 152  		},
 153  		isValid: false,
 154  	},
 155  	{
 156  		name:    "wrong length)",
 157  		key:     []byte{0x05},
 158  		isValid: false,
 159  	},
 160  	{
 161  		name: "X == P",
 162  		key: []byte{
 163  			0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 164  			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 165  			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 166  			0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, 0xb2, 0xe0,
 167  			0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
 168  			0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
 169  			0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
 170  			0xb4, 0x12, 0xa3,
 171  		},
 172  		isValid: false,
 173  	},
 174  	{
 175  		name: "X > P",
 176  		key: []byte{
 177  			0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 178  			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 179  			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 180  			0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFD, 0x2F, 0xb2, 0xe0,
 181  			0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
 182  			0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
 183  			0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
 184  			0xb4, 0x12, 0xa3,
 185  		},
 186  		isValid: false,
 187  	},
 188  	{
 189  		name: "Y == P",
 190  		key: []byte{
 191  			0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
 192  			0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
 193  			0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
 194  			0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xFF, 0xFF,
 195  			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 196  			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 197  			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF,
 198  			0xFF, 0xFC, 0x2F,
 199  		},
 200  		isValid: false,
 201  	},
 202  	{
 203  		name: "Y > P",
 204  		key: []byte{
 205  			0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
 206  			0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
 207  			0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
 208  			0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xFF, 0xFF,
 209  			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 210  			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 211  			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF,
 212  			0xFF, 0xFD, 0x2F,
 213  		},
 214  		isValid: false,
 215  	},
 216  	{
 217  		name: "hybrid",
 218  		key: []byte{
 219  			0x06, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb,
 220  			0xac, 0x55, 0xa0, 0x62, 0x95, 0xce, 0x87, 0x0b, 0x07,
 221  			0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59,
 222  			0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98, 0x48, 0x3a,
 223  			0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, 0x5d, 0xa4, 0xfb,
 224  			0xfc, 0x0e, 0x11, 0x08, 0xa8, 0xfd, 0x17, 0xb4, 0x48,
 225  			0xa6, 0x85, 0x54, 0x19, 0x9c, 0x47, 0xd0, 0x8f, 0xfb,
 226  			0x10, 0xd4, 0xb8,
 227  		},
 228  		format:  pubkeyHybrid,
 229  		isValid: true,
 230  	},
 231  }
 232  
 233  func TestPubKeys(t *testing.T) {
 234  	for _, test := range pubKeyTests {
 235  		pk, err := ParsePubKey(test.key)
 236  		if err != nil {
 237  			if test.isValid {
 238  				t.Errorf(
 239  					"%s pubkey failed when shouldn't %v",
 240  					test.name, err,
 241  				)
 242  			}
 243  			continue
 244  		}
 245  		if !test.isValid {
 246  			t.Errorf(
 247  				"%s counted as valid when it should fail",
 248  				test.name,
 249  			)
 250  			continue
 251  		}
 252  		var pkStr []byte
 253  		switch test.format {
 254  		case pubkeyUncompressed:
 255  			pkStr = pk.SerializeUncompressed()
 256  		case pubkeyCompressed:
 257  			pkStr = pk.SerializeCompressed()
 258  		case pubkeyHybrid:
 259  			pkStr = test.key
 260  		}
 261  		if !utils.FastEqual(test.key, pkStr) {
 262  			t.Errorf(
 263  				"%s pubkey: serialized keys do not match.",
 264  				test.name,
 265  			)
 266  			spew.Dump(test.key)
 267  			spew.Dump(pkStr)
 268  		}
 269  	}
 270  }
 271  
 272  func TestPublicKeyIsEqual(t *testing.T) {
 273  	pubKey1, err := ParsePubKey(
 274  		[]byte{
 275  			0x03, 0x26, 0x89, 0xc7, 0xc2, 0xda, 0xb1, 0x33,
 276  			0x09, 0xfb, 0x14, 0x3e, 0x0e, 0x8f, 0xe3, 0x96, 0x34,
 277  			0x25, 0x21, 0x88, 0x7e, 0x97, 0x66, 0x90, 0xb6, 0xb4,
 278  			0x7f, 0x5b, 0x2a, 0x4b, 0x7d, 0x44, 0x8e,
 279  		},
 280  	)
 281  	if err != nil {
 282  		t.Fatalf("failed to parse raw bytes for pubKey1: %v", err)
 283  	}
 284  	pubKey2, err := ParsePubKey(
 285  		[]byte{
 286  			0x02, 0xce, 0x0b, 0x14, 0xfb, 0x84, 0x2b, 0x1b,
 287  			0xa5, 0x49, 0xfd, 0xd6, 0x75, 0xc9, 0x80, 0x75, 0xf1,
 288  			0x2e, 0x9c, 0x51, 0x0f, 0x8e, 0xf5, 0x2b, 0xd0, 0x21,
 289  			0xa9, 0xa1, 0xf4, 0x80, 0x9d, 0x3b, 0x4d,
 290  		},
 291  	)
 292  	if err != nil {
 293  		t.Fatalf("failed to parse raw bytes for pubKey2: %v", err)
 294  	}
 295  	if !pubKey1.IsEqual(pubKey1) {
 296  		t.Fatalf(
 297  			"value of IsEqual is incorrect, %v is "+
 298  				"equal to %v", pubKey1, pubKey1,
 299  		)
 300  	}
 301  	if pubKey1.IsEqual(pubKey2) {
 302  		t.Fatalf(
 303  			"value of IsEqual is incorrect, %v is not "+
 304  				"equal to %v", pubKey1, pubKey2,
 305  		)
 306  	}
 307  }
 308  
 309  func TestIsCompressed(t *testing.T) {
 310  	for _, test := range pubKeyTests {
 311  		isCompressed := IsCompressedPubKey(test.key)
 312  		wantCompressed := (test.format == pubkeyCompressed)
 313  		if isCompressed != wantCompressed {
 314  			t.Fatalf(
 315  				"%s (%x) pubkey: unexpected compressed result, "+
 316  					"got %v, want %v", test.name, test.key,
 317  				isCompressed, wantCompressed,
 318  			)
 319  		}
 320  	}
 321  }
 322