pubkey_test.go raw

   1  package p256k1
   2  
   3  import (
   4  	"crypto/rand"
   5  	"testing"
   6  )
   7  
   8  func TestECPubkeyCreate(t *testing.T) {
   9  	// Generate a random private key
  10  	seckey := make([]byte, 32)
  11  	if _, err := rand.Read(seckey); err != nil {
  12  		t.Fatal(err)
  13  	}
  14  
  15  	// Ensure it's a valid private key (not zero, not >= order)
  16  	var scalar Scalar
  17  	for !scalar.setB32Seckey(seckey) {
  18  		if _, err := rand.Read(seckey); err != nil {
  19  			t.Fatal(err)
  20  		}
  21  	}
  22  
  23  	// Create public key
  24  	var pubkey PublicKey
  25  	err := ECPubkeyCreate(&pubkey, seckey)
  26  	if err != nil {
  27  		t.Errorf("ECPubkeyCreate failed: %v", err)
  28  	}
  29  
  30  	// Verify the public key is valid by parsing it
  31  	var parsed PublicKey
  32  	var serialized [65]byte
  33  	length := ECPubkeySerialize(serialized[:], &pubkey, ECUncompressed)
  34  	if length != 65 {
  35  		t.Error("uncompressed serialization should be 65 bytes")
  36  	}
  37  
  38  	err = ECPubkeyParse(&parsed, serialized[:length])
  39  	if err != nil {
  40  		t.Errorf("failed to parse created public key: %v", err)
  41  	}
  42  
  43  	// Compare original and parsed
  44  	if ECPubkeyCmp(&pubkey, &parsed) != 0 {
  45  		t.Error("parsed public key should equal original")
  46  	}
  47  }
  48  
  49  func TestECPubkeyParse(t *testing.T) {
  50  	// Test with generator point (known valid point)
  51  	// Generator X: 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
  52  	// Generator Y: 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
  53  
  54  	// Uncompressed format
  55  	uncompressed := []byte{
  56  		0x04,
  57  		0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07,
  58  		0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98,
  59  		0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, 0xA8,
  60  		0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, 0xB8,
  61  	}
  62  
  63  	var pubkey PublicKey
  64  	err := ECPubkeyParse(&pubkey, uncompressed)
  65  	if err != nil {
  66  		t.Errorf("failed to parse uncompressed generator: %v", err)
  67  	}
  68  
  69  	// Compressed format (even Y)
  70  	compressed := []byte{
  71  		0x02,
  72  		0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07,
  73  		0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98,
  74  	}
  75  
  76  	var pubkey2 PublicKey
  77  	err = ECPubkeyParse(&pubkey2, compressed)
  78  	if err != nil {
  79  		t.Errorf("failed to parse compressed generator: %v", err)
  80  	}
  81  
  82  	// Both should be equal
  83  	if ECPubkeyCmp(&pubkey, &pubkey2) != 0 {
  84  		t.Error("compressed and uncompressed generator should be equal")
  85  	}
  86  
  87  	// Test invalid inputs
  88  	invalidInputs := [][]byte{
  89  		{},                    // empty
  90  		{0x05},               // invalid prefix
  91  		{0x04, 0x00},         // too short
  92  		make([]byte, 66),     // too long
  93  		{0x02},               // compressed too short
  94  		make([]byte, 34),     // compressed too long
  95  	}
  96  
  97  	for i, invalid := range invalidInputs {
  98  		var dummy PublicKey
  99  		err := ECPubkeyParse(&dummy, invalid)
 100  		if err == nil {
 101  			t.Errorf("invalid input %d should have failed", i)
 102  		}
 103  	}
 104  }
 105  
 106  func TestECPubkeySerialize(t *testing.T) {
 107  	// Create a public key from a known private key
 108  	seckey := []byte{
 109  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 110  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 111  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 112  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 113  	}
 114  
 115  	var pubkey PublicKey
 116  	err := ECPubkeyCreate(&pubkey, seckey)
 117  	if err != nil {
 118  		t.Fatalf("failed to create public key: %v", err)
 119  	}
 120  
 121  	// Test compressed serialization
 122  	var compressed [33]byte
 123  	compressedLength := ECPubkeySerialize(compressed[:], &pubkey, ECCompressed)
 124  	if compressedLength != 33 {
 125  		t.Errorf("compressed serialization should return 33 bytes, got %d", compressedLength)
 126  	}
 127  	if compressed[0] != 0x02 && compressed[0] != 0x03 {
 128  		t.Errorf("compressed format should start with 0x02 or 0x03, got 0x%02x", compressed[0])
 129  	}
 130  
 131  	// Test uncompressed serialization
 132  	var uncompressed [65]byte
 133  	uncompressedLength := ECPubkeySerialize(uncompressed[:], &pubkey, ECUncompressed)
 134  	if uncompressedLength != 65 {
 135  		t.Errorf("uncompressed serialization should return 65 bytes, got %d", uncompressedLength)
 136  	}
 137  	if uncompressed[0] != 0x04 {
 138  		t.Errorf("uncompressed format should start with 0x04, got 0x%02x", uncompressed[0])
 139  	}
 140  
 141  	// Test round-trip
 142  	var parsed1, parsed2 PublicKey
 143  	err = ECPubkeyParse(&parsed1, compressed[:compressedLength])
 144  	if err != nil {
 145  		t.Errorf("failed to parse compressed: %v", err)
 146  	}
 147  
 148  	err = ECPubkeyParse(&parsed2, uncompressed[:uncompressedLength])
 149  	if err != nil {
 150  		t.Errorf("failed to parse uncompressed: %v", err)
 151  	}
 152  
 153  	if ECPubkeyCmp(&parsed1, &parsed2) != 0 {
 154  		t.Error("round-trip should preserve public key")
 155  	}
 156  
 157  	// Test buffer too small
 158  	var small [32]byte
 159  	smallLength := ECPubkeySerialize(small[:], &pubkey, ECCompressed)
 160  	if smallLength != 0 {
 161  		t.Error("serialization with small buffer should return 0")
 162  	}
 163  
 164  	// Test invalid flags
 165  	invalidLength := ECPubkeySerialize(compressed[:], &pubkey, 0xFF)
 166  	if invalidLength != 0 {
 167  		t.Error("serialization with invalid flags should return 0")
 168  	}
 169  }
 170  
 171  func TestECPubkeyCmp(t *testing.T) {
 172  	// Create two different public keys
 173  	seckey1 := []byte{
 174  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 175  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 176  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 177  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 178  	}
 179  	seckey2 := []byte{
 180  		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
 181  		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
 182  		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
 183  		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
 184  	}
 185  
 186  	var pubkey1, pubkey2, pubkey3 PublicKey
 187  	
 188  	err := ECPubkeyCreate(&pubkey1, seckey1)
 189  	if err != nil {
 190  		t.Fatalf("failed to create pubkey1: %v", err)
 191  	}
 192  	
 193  	err = ECPubkeyCreate(&pubkey2, seckey2)
 194  	if err != nil {
 195  		t.Fatalf("failed to create pubkey2: %v", err)
 196  	}
 197  	
 198  	err = ECPubkeyCreate(&pubkey3, seckey1) // Same as pubkey1
 199  	if err != nil {
 200  		t.Fatalf("failed to create pubkey3: %v", err)
 201  	}
 202  
 203  	// Test equality
 204  	if ECPubkeyCmp(&pubkey1, &pubkey3) != 0 {
 205  		t.Error("identical public keys should compare equal")
 206  	}
 207  
 208  	// Test inequality
 209  	cmp := ECPubkeyCmp(&pubkey1, &pubkey2)
 210  	if cmp == 0 {
 211  		t.Error("different public keys should not compare equal")
 212  	}
 213  
 214  	// Test symmetry
 215  	cmp2 := ECPubkeyCmp(&pubkey2, &pubkey1)
 216  	if (cmp > 0 && cmp2 >= 0) || (cmp < 0 && cmp2 <= 0) {
 217  		t.Error("comparison should be antisymmetric")
 218  	}
 219  }
 220  
 221  func BenchmarkECPubkeyCreate(b *testing.B) {
 222  	seckey := []byte{
 223  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 224  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 225  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 226  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 227  	}
 228  
 229  	b.ResetTimer()
 230  	for i := 0; i < b.N; i++ {
 231  		var pubkey PublicKey
 232  		ECPubkeyCreate(&pubkey, seckey)
 233  	}
 234  }
 235  
 236  func BenchmarkECPubkeySerializeCompressed(b *testing.B) {
 237  	seckey := []byte{
 238  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 239  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 240  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 241  		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 242  	}
 243  
 244  	var pubkey PublicKey
 245  	ECPubkeyCreate(&pubkey, seckey)
 246  	var output [33]byte
 247  
 248  	b.ResetTimer()
 249  	for i := 0; i < b.N; i++ {
 250  		ECPubkeySerialize(output[:], &pubkey, ECCompressed)
 251  	}
 252  }
 253  
 254  func BenchmarkECPubkeyParse(b *testing.B) {
 255  	// Use generator point in compressed format
 256  	compressed := []byte{
 257  		0x02,
 258  		0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07,
 259  		0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98,
 260  	}
 261  
 262  	b.ResetTimer()
 263  	for i := 0; i < b.N; i++ {
 264  		var pubkey PublicKey
 265  		ECPubkeyParse(&pubkey, compressed)
 266  	}
 267  }
 268