package secp256k1 import ( "bytes" "math/big" "testing" ) func TestGeneratePrivateKey(t *testing.T) { priv, err := GeneratePrivateKey() if err != nil { t.Fatalf("failed to generate key: %v", err) } // Should be in valid range [1, N-1] if priv.D.Sign() <= 0 { t.Error("private key should be positive") } if priv.D.Cmp(N) >= 0 { t.Error("private key should be less than N") } } func TestGeneratePrivateKeyUnique(t *testing.T) { // Generate two keys, they should be different priv1, _ := GeneratePrivateKey() priv2, _ := GeneratePrivateKey() if priv1.D.Cmp(priv2.D) == 0 { t.Error("two generated keys should not be identical") } } func TestPrivateKeyFromBytes(t *testing.T) { // 32 bytes of 0x01 b := make([]byte, 32) b[31] = 0x01 // value = 1 priv, err := NewPrivateKeyFromBytes(b) if err != nil { t.Fatalf("failed to create key: %v", err) } if priv.D.Cmp(big.NewInt(1)) != 0 { t.Errorf("expected D=1, got %s", priv.D.String()) } } func TestPrivateKeyFromBytesInvalidLength(t *testing.T) { b := make([]byte, 31) // wrong length _, err := NewPrivateKeyFromBytes(b) if err == nil { t.Error("should reject non-32-byte input") } } func TestPrivateKeyFromBytesZero(t *testing.T) { b := make([]byte, 32) // all zeros _, err := NewPrivateKeyFromBytes(b) if err == nil { t.Error("should reject zero private key") } } func TestPrivateKeyFromHex(t *testing.T) { hex := "0000000000000000000000000000000000000000000000000000000000000001" priv, err := NewPrivateKeyFromHex(hex) if err != nil { t.Fatalf("failed to create key: %v", err) } if priv.D.Cmp(big.NewInt(1)) != 0 { t.Errorf("expected D=1, got %s", priv.D.String()) } } func TestPrivateKeyFromHexInvalid(t *testing.T) { _, err := NewPrivateKeyFromHex("not-hex") if err == nil { t.Error("should reject invalid hex") } } func TestPublicKeyDerivation(t *testing.T) { // Private key = 1, public key should be G priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001") pub := priv.PublicKey() if !pub.Point.Equal(G) { t.Error("1 * G should equal G") } } func TestPublicKeyDerivation2(t *testing.T) { // Private key = 2, public key should be 2G priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000002") pub := priv.PublicKey() expected := G.Double() if !pub.Point.Equal(expected) { t.Error("2 * G should equal 2G") } } func TestPublicKeyOnCurve(t *testing.T) { priv, _ := GeneratePrivateKey() pub := priv.PublicKey() if !pub.Point.IsOnCurve() { t.Error("derived public key should be on curve") } } func TestPrivateKeyBytes(t *testing.T) { priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001") b := priv.Bytes() if len(b) != 32 { t.Errorf("expected 32 bytes, got %d", len(b)) } if b[31] != 0x01 { t.Errorf("expected last byte to be 0x01, got 0x%02x", b[31]) } } func TestPrivateKeyRoundTrip(t *testing.T) { priv1, _ := GeneratePrivateKey() b := priv1.Bytes() priv2, _ := NewPrivateKeyFromBytes(b) if priv1.D.Cmp(priv2.D) != 0 { t.Error("private key should survive bytes round-trip") } } func TestPublicKeyBytesUncompressed(t *testing.T) { priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001") pub := priv.PublicKey() b := pub.Bytes() if len(b) != 65 { t.Errorf("uncompressed pubkey should be 65 bytes, got %d", len(b)) } if b[0] != 0x04 { t.Errorf("uncompressed prefix should be 0x04, got 0x%02x", b[0]) } } func TestPublicKeyBytesCompressed(t *testing.T) { priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001") pub := priv.PublicKey() b := pub.BytesCompressed() if len(b) != 33 { t.Errorf("compressed pubkey should be 33 bytes, got %d", len(b)) } // G has odd y, so prefix should be 0x03 if b[0] != 0x02 && b[0] != 0x03 { t.Errorf("compressed prefix should be 0x02 or 0x03, got 0x%02x", b[0]) } } func TestPublicKeyHex(t *testing.T) { priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001") pub := priv.PublicKey() hex := pub.Hex() if len(hex) != 130 { // 65 bytes * 2 t.Errorf("uncompressed hex should be 130 chars, got %d", len(hex)) } hexComp := pub.HexCompressed() if len(hexComp) != 66 { // 33 bytes * 2 t.Errorf("compressed hex should be 66 chars, got %d", len(hexComp)) } } func TestPublicKeyEqual(t *testing.T) { priv1, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001") priv2, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001") priv3, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000002") pub1 := priv1.PublicKey() pub2 := priv2.PublicKey() pub3 := priv3.PublicKey() if !pub1.Equal(pub2) { t.Error("same private key should produce equal public keys") } if pub1.Equal(pub3) { t.Error("different private keys should produce different public keys") } } // Known test vector from Bitcoin wiki func TestKnownKeyVector(t *testing.T) { // Private key = 1 priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001") pub := priv.PublicKey() // Public key should be G expectedX := Gx expectedY := Gy if pub.Point.x.value.Cmp(expectedX) != 0 { t.Error("public key x doesn't match G.x") } if pub.Point.y.value.Cmp(expectedY) != 0 { t.Error("public key y doesn't match G.y") } // Check compressed format starts with correct x compressed := pub.BytesCompressed() xFromCompressed := compressed[1:33] expectedXBytes := make([]byte, 32) copy(expectedXBytes[32-len(expectedX.Bytes()):], expectedX.Bytes()) if !bytes.Equal(xFromCompressed, expectedXBytes) { t.Error("compressed pubkey x doesn't match") } }