# Class BSV::Wallet::KeyDeriver <a id="class-BSV-Wallet-KeyDeriver"></a>

**Inherits:** `Object`

BRC-42/43 key derivation facade.

Wraps one or two root private keys (everyday + optional privileged) and
provides key derivation per the BRC-42 spec. Invoice numbers follow the BRC-43
format: "{security_level}-{protocol_name}-{key_id}".

**@example**
```ruby
kd = KeyDeriver.new(private_key: BSV::Primitives::PrivateKey.generate)
kd.identity_key  #=> "02abc...def" (66-char hex)
pub = kd.derive_public_key(protocol_id: [1, "my protocol"], key_id: "1", counterparty: "self")
```

## Constants
### `ANYONE_PRIVATE_KEY` <a id="constant-ANYONE_PRIVATE_KEY"></a> <a id="ANYONE_PRIVATE_KEY-constant"></a>
Not documented.

### `ANYONE_PUBLIC_KEY` <a id="constant-ANYONE_PUBLIC_KEY"></a> <a id="ANYONE_PUBLIC_KEY-constant"></a>
Not documented.

## Public Class Methods
### `validate_counterparty_hex!(hex)` <a id="method-c-validate_counterparty_hex-21"></a> <a id="validate_counterparty_hex!-class_method"></a>
Validate that `hex` is a syntactically well-formed compressed BRC-43
counterparty pubkey hex string (33-byte, `02`/`03` prefix, 66 hex chars total;
case-tolerant). Class method — a pure regex check with no instance state,
hoisted out of the private instance-method form so callers without a
`KeyDeriver` instance (e.g. <code>Engine::Transmission</code>) can validate
counterparties at the engine boundary before any DB write.

The `04` uncompressed shape is **not** accepted — the regex's 64 trailing hex
chars match only the compressed tail; an actual uncompressed pubkey needs 128
trailing hex chars and so falls through to the raise. The wallet has no caller
that passes uncompressed identity keys, and BRC-43 mandates compressed.
Callers that need stricter parity with the schema CHECK (lowercase only) layer
their own regex on top — see +Engine::Transmission#validate_counterparty!+.
- **@param** `hex` [String]
- **@raise** [BSV::Wallet::InvalidParameterError]

### `validate_identity_pubkey_hex!(hex, param_name: = 'identity_key')` <a id="method-c-validate_identity_pubkey_hex-21"></a> <a id="validate_identity_pubkey_hex!-class_method"></a>
Strict variant of <code>validate_counterparty_hex!</code> — lowercase hex
only, mirroring the certificates pubkey-shape CHECK in migration 003
(subject/certifier/verifier) and Engine::Transmission's
BRC43_COMPRESSED_LOWERCASE constant. Use this when the value is destined for a
column that has a lowercase-only CHECK; the looser counterparty variant
accepts mixed-case for derivation use.
- **@param** `hex` [String]
- **@param** `param_name` [String] field name for the error message
- **@raise** [BSV::Wallet::InvalidParameterError]

## Public Instance Methods
### `create_hmac(data:, protocol_id:, key_id:, counterparty:, privileged: = false)` <a id="method-i-create_hmac"></a> <a id="create_hmac-instance_method"></a>
Compute an HMAC-SHA-256 over data using an ECDH-derived symmetric key.

Derives the symmetric key for the given derivation parameters and returns the
HMAC-SHA-256 of the data keyed with that symmetric key.
- **@param** `data` [String] binary data to authenticate
- **@param** `protocol_id` [Array<Integer, String>] [security_level, protocol_name]
- **@param** `key_id` [String] key identifier
- **@param** `counterparty` [String] "self", "anyone", or hex public key
- **@param** `privileged` [Boolean] use privileged keyring
- **@return** [String] 32-byte HMAC

### `create_signature(protocol_id:, key_id:, counterparty:, data: = nil, hash_to_directly_sign: = nil, privileged: = false)` <a id="method-i-create_signature"></a> <a id="create_signature-instance_method"></a>
Sign data using ECDSA with a derived private key.

Either `data` or `hash_to_directly_sign` must be provided. When `data` is
given, it is SHA-256 hashed before signing. When `hash_to_directly_sign` is
given, it is used as-is (must be 32 bytes).
- **@param** `data` [String, nil] raw data to hash and sign
- **@param** `hash_to_directly_sign` [String, nil] pre-computed 32-byte hash to sign directly
- **@param** `protocol_id` [Array<Integer, String>] [security_level, protocol_name]
- **@param** `key_id` [String] key identifier
- **@param** `counterparty` [String] "self", "anyone", or hex public key
- **@param** `privileged` [Boolean] use privileged keyring
- **@return** [BSV::Primitives::Signature] the ECDSA signature

### `decrypt(ciphertext:, protocol_id:, key_id:, counterparty:, privileged: = false)` <a id="method-i-decrypt"></a> <a id="decrypt-instance_method"></a>
Decrypt ciphertext using AES-256-GCM with an ECDH-derived symmetric key.

Derives the same symmetric key used for encryption and decrypts.
- **@param** `ciphertext` [String] binary data to decrypt (IV + ciphertext + auth tag)
- **@param** `protocol_id` [Array<Integer, String>] [security_level, protocol_name]
- **@param** `key_id` [String] key identifier
- **@param** `counterparty` [String] "self", "anyone", or hex public key
- **@param** `privileged` [Boolean] use privileged keyring
- **@raise** [OpenSSL::Cipher::CipherError] if authentication fails
- **@return** [String] decrypted binary plaintext

### `derive_private_key(protocol_id:, key_id:, counterparty:, privileged: = false)` <a id="method-i-derive_private_key"></a> <a id="derive_private_key-instance_method"></a>
Derive a child private key using BRC-42.
- **@param** `protocol_id` [Array<Integer, String>] [security_level, protocol_name]
- **@param** `key_id` [String] key identifier
- **@param** `counterparty` [String] "self", "anyone", or hex public key
- **@param** `privileged` [Boolean] use privileged keyring
- **@return** [BSV::Primitives::PrivateKey] derived child private key

### `derive_public_key(protocol_id:, key_id:, counterparty:, for_self: = false, privileged: = false)` <a id="method-i-derive_public_key"></a> <a id="derive_public_key-instance_method"></a>
Derive a child public key using BRC-42.

In normal mode (for_self: false), derives OUR child public key that the
counterparty could also compute if they knew our public key. Equivalent to
derive_private_key(...).public_key.

In for_self mode, derives the COUNTERPARTY'S child public key —the key they
would have derived using their private key and our public key.
- **@param** `protocol_id` [Array<Integer, String>] [security_level, protocol_name]
- **@param** `key_id` [String] key identifier
- **@param** `counterparty` [String] "self", "anyone", or hex public key
- **@param** `for_self` [Boolean] reverse derivation direction
- **@param** `privileged` [Boolean] use privileged keyring
- **@return** [String] compressed public key bytes (33 bytes, binary)

### `derive_revelation_keyring(certificate:, fields_to_reveal:, verifier:, privileged: = false)` <a id="method-i-derive_revelation_keyring"></a> <a id="derive_revelation_keyring-instance_method"></a>
Derive a revelation keyring for a verifier from a certificate's master
keyring.

For each field in `fields_to_reveal`, decrypts the encrypted field key from
the certificate's keyring (using the certifier as counterparty per BRC-52),
then re-encrypts it for the specified verifier.
- **@param** `certificate` [Hash] certificate hash with :type, :serial_number, :certifier, :keyring
- **@param** `fields_to_reveal` [Array<String>] field names whose keys to reveal
- **@param** `verifier` [String] verifier's public key (hex string)
- **@param** `privileged` [Boolean] use privileged keyring
- **@raise** [BSV::Wallet::Error] if a field is not in the keyring or keyring is missing
- **@return** [Hash{String => String}] field names mapped to re-encrypted keys

### `encrypt(plaintext:, protocol_id:, key_id:, counterparty:, privileged: = false)` <a id="method-i-encrypt"></a> <a id="encrypt-instance_method"></a>
Encrypt plaintext using AES-256-GCM with an ECDH-derived symmetric key.

Derives child keys for both parties, computes the ECDH shared secret, and
encrypts using AES-256-GCM.
- **@param** `plaintext` [String] binary data to encrypt
- **@param** `protocol_id` [Array<Integer, String>] [security_level, protocol_name]
- **@param** `key_id` [String] key identifier
- **@param** `counterparty` [String] "self", "anyone", or hex public key
- **@param** `privileged` [Boolean] use privileged keyring
- **@return** [String] binary ciphertext (IV + ciphertext + auth tag)

### `identity_key()` <a id="method-i-identity_key"></a> <a id="identity_key-instance_method"></a>
Returns the compressed public key hex of the everyday key.

This is the BRC-100 `getPublicKey` emission value — the **identity** key
crosses BRC boundaries as hex by spec, so the canonical accessor returns hex.
Crypto-op consumers (hash160, ECDH input bytes) should use
`identity_key_bytes` instead of round-tripping this through
+[hex].pack('H*')+.

Derived pubkeys (`derive_public_key`) are returned as binary —they don't cross
a BRC boundary as themselves. See the "Public Key Convention" section of
CLAUDE.md for the full rule.
- **@return** [String] 66-character hex-encoded compressed public key

### `identity_key_bytes()` <a id="method-i-identity_key_bytes"></a> <a id="identity_key_bytes-instance_method"></a>
Returns the compressed public key as 33 raw bytes — the binary form for
crypto-op consumers (hash160, ECDH input). Memoised symmetrically with
`identity_key`.
- **@return** [String] 33-byte binary string (compressed public key)

### `identity_pubkey_hash()` <a id="method-i-identity_pubkey_hash"></a> <a id="identity_pubkey_hash-instance_method"></a>
Returns the `hash160` of the compressed identity public key — the 20-byte
binary used as the wallet's root P2PKH pubkey hash. This is the single source
of truth for the wallet's identity hash; the per-wallet
<code>outputs.spendable_recoverable</code> CHECK is built from this value at
migration time (see <code>BSV::Wallet::Migration</code>, HLR #467). Crypto-op
callers (engine root-script construction, BRC-29 receive validation) should
reach for this accessor rather than recomputing +hash160(identity_key_bytes)+
inline.
- **@return** [String] 20-byte binary +hash160+ of the identity pubkey

### `initialize(private_key:, privileged_key: = nil)` <a id="method-i-initialize"></a> <a id="initialize-instance_method"></a>
- **@param** `private_key` [BSV::Primitives::PrivateKey] everyday root key
- **@param** `privileged_key` [BSV::Primitives::PrivateKey, nil] optional privileged root key
- **@return** [KeyDeriver] a new instance of KeyDeriver

### `inspect()` <a id="method-i-inspect"></a> <a id="inspect-instance_method"></a>
Elide +@root_key+ from inspect output. The identity key is the only field
surfaced — that's an interchange identifier, not a secret, per the pubkey-hex
carve-out.

### `reveal_counterparty_linkage(counterparty:, verifier:, privileged: = false)` <a id="method-i-reveal_counterparty_linkage"></a> <a id="reveal_counterparty_linkage-instance_method"></a>
Reveal the ECDH shared secret between this wallet and a counterparty,
encrypted for a verifier with a Schnorr proof (BRC-69 Method 1).
- **@param** `counterparty` [String] hex public key (not 'self' or 'anyone')
- **@param** `verifier` [String] hex public key of the verifier
- **@param** `privileged` [Boolean] use privileged keyring
- **@return** [Hash] revelation result with encrypted linkage and proof

### `reveal_specific_linkage(counterparty:, verifier:, protocol_id:, key_id:, privileged: = false)` <a id="method-i-reveal_specific_linkage"></a> <a id="reveal_specific_linkage-instance_method"></a>
Reveal the specific key offset for a particular derived key, encrypted for a
verifier (BRC-69 Method 2).
- **@param** `counterparty` [String] hex public key (not 'self' or 'anyone')
- **@param** `verifier` [String] hex public key of the verifier
- **@param** `protocol_id` [Array<Integer, String>] [security_level, protocol_name]
- **@param** `key_id` [String] key identifier
- **@param** `privileged` [Boolean] use privileged keyring
- **@return** [Hash] revelation result with encrypted linkage and proof_type 0

### `root_private_key()` <a id="method-i-root_private_key"></a> <a id="root_private_key-instance_method"></a>
The root (everyday) private key, for signing UTXOs paid directly to the
identity address (no BRC-42/43 derivation).

### `root_private_key_bytes()` <a id="method-i-root_private_key_bytes"></a> <a id="root_private_key_bytes-instance_method"></a>
The 32-byte raw scalar of the root private key. Used for HMAC computations
(e.g., WBIKD recovery markers).

### `verify_signature(signature:, protocol_id:, key_id:, counterparty:, data: = nil, hash_to_directly_verify: = nil, for_self: = false, privileged: = false)` <a id="method-i-verify_signature"></a> <a id="verify_signature-instance_method"></a>
Verify an ECDSA signature against data using a derived public key.

Either `data` or `hash_to_directly_verify` must be provided. When `data` is
given, it is SHA-256 hashed before verification.
- **@param** `signature` [BSV::Primitives::Signature] the signature to verify
- **@param** `data` [String, nil] raw data that was signed
- **@param** `hash_to_directly_verify` [String, nil] pre-computed 32-byte hash
- **@param** `protocol_id` [Array<Integer, String>] [security_level, protocol_name]
- **@param** `key_id` [String] key identifier
- **@param** `counterparty` [String] "self", "anyone", or hex public key
- **@param** `for_self` [Boolean] reverse derivation direction for verification
- **@param** `privileged` [Boolean] use privileged keyring
- **@return** [Boolean] true if the signature is valid
