# Class BSV::Primitives::PublicKey <a id="class-BSV-Primitives-PublicKey"></a>

**Inherits:** `Object`

A secp256k1 public key for address derivation and signature verification.

Public keys are points on the secp256k1 curve. They can be serialised in
compressed (33-byte) or uncompressed (65-byte) form, converted to Bitcoin
addresses, and used to verify ECDSA signatures.

**@example Derive address from a public key**
```ruby
pub = private_key.public_key
pub.address #=> "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
```

## Constants
### `MAINNET_PUBKEY_HASH` <a id="constant-MAINNET_PUBKEY_HASH"></a> <a id="MAINNET_PUBKEY_HASH-constant"></a>
Address version byte for mainnet P2PKH addresses.

### `TESTNET_PUBKEY_HASH` <a id="constant-TESTNET_PUBKEY_HASH"></a> <a id="TESTNET_PUBKEY_HASH-constant"></a>
Address version byte for testnet P2PKH addresses.

## Attributes
### `point` [R] <a id="attribute-i-point"></a> <a id="point-instance_method"></a>
- **@return** [OpenSSL::PKey::EC::Point] the underlying curve point

## Public Class Methods
### `from_bytes(bytes)` <a id="method-c-from_bytes"></a> <a id="from_bytes-class_method"></a>
Create a public key from raw bytes (compressed or uncompressed).
- **@param** `bytes` [String] 33-byte compressed or 65-byte uncompressed encoding
- **@return** [PublicKey]

### `from_hex(hex)` <a id="method-c-from_hex"></a> <a id="from_hex-class_method"></a>
Create a public key from a hex string.
- **@param** `hex` [String] hex-encoded compressed or uncompressed public key
- **@return** [PublicKey]

### `from_private_key(private_key)` <a id="method-c-from_private_key"></a> <a id="from_private_key-class_method"></a>
Derive the public key from a {PrivateKey}.
- **@param** `private_key` [PrivateKey] the private key
- **@return** [PublicKey]

## Public Instance Methods
### `==(other)` <a id="method-i--3D-3D"></a> <a id="==-instance_method"></a>
- **@param** `other` [Object] the object to compare
- **@return** [Boolean] +true+ if both keys represent the same curve point

### `address(network: = :mainnet)` <a id="method-i-address"></a> <a id="address-instance_method"></a>
Derive a Base58Check-encoded Bitcoin address.
- **@param** `network` [Symbol] +:mainnet+ or +:testnet+
- **@return** [String] the P2PKH address

### `compressed()` <a id="method-i-compressed"></a> <a id="compressed-instance_method"></a>
Return the compressed (33-byte) encoding.
- **@return** [String] compressed public key bytes

### `derive_child(private_key, invoice_number)` <a id="method-i-derive_child"></a> <a id="derive_child-instance_method"></a>
Derive a child public key using BRC-42 key derivation.

Computes HMAC-SHA256(key: ECDH_shared_secret, msg: invoice_number) and adds
the corresponding curve point to this public key. The result matches the
public key of {PrivateKey#derive_child} with the same inputs, enabling
public-key-only derivation.
- **@param** `private_key` [PrivateKey] the counterparty's private key
- **@param** `invoice_number` [String] the invoice number (UTF-8)
- **@return** [PublicKey] the derived child public key

### `derive_shared_secret(private_key)` <a id="method-i-derive_shared_secret"></a> <a id="derive_shared_secret-instance_method"></a>
Derive an ECDH shared secret with another party's private key.

Computes the shared point by multiplying this public key by the given private
key's scalar. The result is commutative:
    alice_pub.derive_shared_secret(bob_priv) ==
      bob_pub.derive_shared_secret(alice_priv)

Uses constant-time scalar multiplication to protect the private key scalar
from timing side-channels.

This is the foundational primitive for BRC-42 key derivation, BRC-77/78
messaging, and ECIES encryption.
- **@param** `private_key` [PrivateKey] the other party's private key
- **@return** [PublicKey] the shared secret as a public key (curve point)

### `hash160()` <a id="method-i-hash160"></a> <a id="hash160-instance_method"></a>
Compute the Hash160 (RIPEMD-160 of SHA-256) of the compressed public key.
- **@return** [String] 20-byte public key hash

### `initialize(point)` <a id="method-i-initialize"></a> <a id="initialize-instance_method"></a>
- **@param** `point` [OpenSSL::PKey::EC::Point] a point on the secp256k1 curve
- **@raise** [ArgumentError] if point is not an EC point or is at infinity
- **@return** [PublicKey] a new instance of PublicKey

### `to_hex(compressed: = true)` <a id="method-i-to_hex"></a> <a id="to_hex-instance_method"></a>
Return the public key as a hex string.
- **@param** `compressed` [Boolean] whether to use compressed encoding (default: true)
- **@return** [String] hex-encoded public key

### `uncompressed()` <a id="method-i-uncompressed"></a> <a id="uncompressed-instance_method"></a>
Return the uncompressed (65-byte) encoding.
- **@return** [String] uncompressed public key bytes

### `verify(hash, signature)` <a id="method-i-verify"></a> <a id="verify-instance_method"></a>
Verify an ECDSA signature against a message hash.
- **@param** `hash` [String] 32-byte message digest
- **@param** `signature` [Signature] the signature to verify
- **@return** [Boolean] +true+ if the signature is valid
