Class: BSV::Wallet::KeyDeriver

Inherits:
Object
  • Object
show all
Defined in:
lib/bsv/wallet_interface/key_deriver.rb

Overview

BRC-42/43 key derivation for the wallet interface.

Derives child keys from a root private key using BKDS (BSV Key Derivation Scheme). Supports protocol IDs, key IDs, counterparties, and security levels as defined in BRC-43.

Constant Summary collapse

ANYONE_BN =
OpenSSL::BN.new(1)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root_key) ⇒ KeyDeriver

Returns a new instance of KeyDeriver.

Parameters:

  • root_key (BSV::Primitives::PrivateKey, String)

    a private key or ‘anyone’



18
19
20
21
22
23
24
25
26
# File 'lib/bsv/wallet_interface/key_deriver.rb', line 18

def initialize(root_key)
  @root_key = if root_key == 'anyone'
                BSV::Primitives::PrivateKey.new(ANYONE_BN)
              elsif root_key.is_a?(BSV::Primitives::PrivateKey)
                root_key
              else
                raise ArgumentError, "expected a BSV::Primitives::PrivateKey or 'anyone', got #{root_key.class}"
              end
end

Instance Attribute Details

#root_keyObject (readonly)

Returns the value of attribute root_key.



15
16
17
# File 'lib/bsv/wallet_interface/key_deriver.rb', line 15

def root_key
  @root_key
end

Instance Method Details

#derive_private_key(protocol_id, key_id, counterparty) ⇒ BSV::Primitives::PrivateKey

Derives a private key using BRC-42 key derivation.

Parameters:

  • protocol_id (Array)
    security_level, protocol_name
  • key_id (String)

    key identifier

  • counterparty (String)

    public key hex, ‘self’, or ‘anyone’

Returns:

  • (BSV::Primitives::PrivateKey)


60
61
62
63
64
65
66
# File 'lib/bsv/wallet_interface/key_deriver.rb', line 60

def derive_private_key(protocol_id, key_id, counterparty)
  Validators.validate_protocol_id!(protocol_id)
  Validators.validate_key_id!(key_id)
  invoice = compute_invoice_number(protocol_id, key_id)
  counterparty_pub = resolve_counterparty(counterparty)
  @root_key.derive_child(counterparty_pub, invoice)
end

#derive_public_key(protocol_id, key_id, counterparty, for_self: false) ⇒ BSV::Primitives::PublicKey

Derives a public key using BRC-42 key derivation.

Parameters:

  • protocol_id (Array)
    security_level, protocol_name
  • key_id (String)

    key identifier

  • counterparty (String)

    public key hex, ‘self’, or ‘anyone’

  • for_self (Boolean) (defaults to: false)

    derive from own identity rather than counterparty’s

Returns:

  • (BSV::Primitives::PublicKey)


41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/bsv/wallet_interface/key_deriver.rb', line 41

def derive_public_key(protocol_id, key_id, counterparty, for_self: false)
  Validators.validate_protocol_id!(protocol_id)
  Validators.validate_key_id!(key_id)
  invoice = compute_invoice_number(protocol_id, key_id)
  counterparty_pub = resolve_counterparty(counterparty)

  if for_self
    @root_key.derive_child(counterparty_pub, invoice).public_key
  else
    counterparty_pub.derive_child(@root_key, invoice)
  end
end

#derive_symmetric_key(protocol_id, key_id, counterparty) ⇒ BSV::Primitives::SymmetricKey

Derives a symmetric key for encryption/HMAC operations.

Uses ECDH between the derived private and public child keys to produce a shared secret, then uses the X-coordinate as the key.

Parameters:

  • protocol_id (Array)
    security_level, protocol_name
  • key_id (String)

    key identifier

  • counterparty (String)

    public key hex, ‘self’, or ‘anyone’

Returns:

  • (BSV::Primitives::SymmetricKey)


77
78
79
80
81
82
83
84
85
86
87
# File 'lib/bsv/wallet_interface/key_deriver.rb', line 77

def derive_symmetric_key(protocol_id, key_id, counterparty)
  Validators.validate_protocol_id!(protocol_id)
  Validators.validate_key_id!(key_id)
  invoice = compute_invoice_number(protocol_id, key_id)
  counterparty_pub = resolve_counterparty(counterparty)

  derived_private = @root_key.derive_child(counterparty_pub, invoice)
  derived_public = counterparty_pub.derive_child(@root_key, invoice)

  BSV::Primitives::SymmetricKey.from_ecdh(derived_private, derived_public)
end

#identity_keyString

Returns the identity public key as a hex string.

Returns:

  • (String)

    66-character compressed public key hex



30
31
32
# File 'lib/bsv/wallet_interface/key_deriver.rb', line 30

def identity_key
  @root_key.public_key.to_hex
end

#reveal_counterparty_secret(counterparty) ⇒ String

Reveals the ECDH shared secret between this wallet and a counterparty. Used for BRC-69 Method 1 (counterparty key linkage).

Parameters:

  • counterparty (String)

    public key hex (not ‘self’)

Returns:

  • (String)

    compressed shared secret bytes

Raises:



94
95
96
97
98
99
# File 'lib/bsv/wallet_interface/key_deriver.rb', line 94

def reveal_counterparty_secret(counterparty)
  raise InvalidParameterError.new('counterparty', 'not "self" for key linkage revelation') if counterparty == 'self'

  counterparty_pub = resolve_counterparty(counterparty)
  @root_key.derive_shared_secret(counterparty_pub).compressed
end

#reveal_specific_secret(counterparty, protocol_id, key_id) ⇒ String

Reveals the specific key offset for a particular derived key. Used for BRC-69 Method 2 (specific key linkage).

Parameters:

  • counterparty (String)

    public key hex

  • protocol_id (Array)
    security_level, protocol_name
  • key_id (String)

    key identifier

Returns:

  • (String)

    HMAC-SHA256 bytes (the key offset)



108
109
110
111
112
113
114
115
# File 'lib/bsv/wallet_interface/key_deriver.rb', line 108

def reveal_specific_secret(counterparty, protocol_id, key_id)
  Validators.validate_protocol_id!(protocol_id)
  Validators.validate_key_id!(key_id)
  counterparty_pub = resolve_counterparty(counterparty)
  shared = @root_key.derive_shared_secret(counterparty_pub)
  invoice = compute_invoice_number(protocol_id, key_id)
  BSV::Primitives::Digest.hmac_sha256(shared.compressed, invoice.encode('UTF-8'))
end