Skip to content

Class BSV::Wallet::ProtoWallet

Inherits: Object Includes: BSV::Wallet::Interface::BRC100

Minimal cryptographic wallet implementing the BRC-100 interface.

ProtoWallet is a direct, in-process implementation of the BRC-100 crypto operations. It requires no external gem, no storage, and no blockchain access — making it suitable for use inside the SDK itself (e.g. the Auth module) as well as lightweight applications that need cryptographic operations without full wallet infrastructure.

Supported BRC-100 areas

  • Public key management — {#get_public_key}, {#reveal_counterparty_key_linkage}, {#reveal_specific_key_linkage}
  • Cryptography — {#encrypt}, {#decrypt}, {#create_hmac}, {#verify_hmac}, {#create_signature}, {#verify_signature}
  • Certificates (read-only stub) — {#list_certificates} returns an empty list; {#prove_certificate} raises {UnsupportedActionError}

NOT supported

The following BRC-100 areas are not implemented and will raise NotImplementedError:

  • Transactions (create_action, sign_action, list_actions, etc.)
  • Output management (list_outputs, relinquish_output, etc.)
  • Authentication (authenticated?, wait_for_authentication)
  • Blockchain / network data (get_height, get_header_for_height, etc.)
  • Certificate acquisition / discovery (acquire_certificate, discover_by_identity_key, etc.)

For full wallet functionality, use the bsv-wallet gem. See docs/sdk/wallet.md for usage guidance.

Construction

Pass a {BSV::Primitives::PrivateKey} or the special string 'anyone'. The 'anyone' variant uses a well-known key (private key = 1) and is suitable for verifying or encrypting data that should be readable by any party — it must not be used where secrecy is required.

@example Normal usage

wallet = BSV::Wallet::ProtoWallet.new(BSV::Primitives::PrivateKey.generate)
sig = wallet.create_signature(protocol_id: [1, 'my-app'], key_id: 'msg-1',
                              data: 'hello'.bytes)

@example Anyone wallet

wallet = BSV::Wallet::ProtoWallet.new('anyone')
pub = wallet.get_public_key(identity_key: true)

Public Instance Methods

abort_action(reference:, originator: = nil)

Aborts a transaction that has not yet been finalized. - @raise [NotImplementedError]

acquire_certificate(type:, certifier:, acquisition_protocol:, fields:, serial_number: = nil, revocation_outpoint: = nil, signature: = nil, certifier_url: = nil, keyring_revealer: = nil, keyring_for_subject: = nil, privileged: = false, privileged_reason: = nil, originator: = nil)

Acquires an identity certificate from a certifier or by direct receipt. - @param acquisition_protocol [Symbol] :direct or :issuance - @param fields [Hash{String => String}] certificate field names to values - @raise [NotImplementedError]

authenticated?(originator: = nil)

Checks whether the user is authenticated. - @raise [NotImplementedError] - @return [Boolean]

create_action(description:, input_beef: = nil, inputs: = nil, outputs: = nil, lock_time: = nil, version: = nil, labels: = nil, sign_and_process: = true, accept_delayed_broadcast: = true, trust_self: = nil, known_txids: = nil, return_txid_only: = false, no_send: = false, no_send_change: = nil, send_with: = nil, randomize_outputs: = true, originator: = nil)

Creates a new Bitcoin transaction. - @param description [String] human-readable description (5-50 chars) - @param inputs [Array] optional inputs to consume - :outpoint [String] txid.index being consumed - :unlocking_script [String] hex unlocking script - :unlocking_script_length [Integer] length, if script provided later via {#sign_action} - :input_description [String] what this input consumes (5-50 chars) - :sequence_number [Integer] optional sequence number - @param outputs [Array] optional outputs to create - :locking_script [String] hex locking script - :satoshis [Integer] output value - :output_description [String] what this output represents (5-50 chars) - :basket [String] optional basket name for UTXO tracking - :custom_instructions [String] application-specific context - :tags [Array] output tags for filtering - @raise [NotImplementedError] - @return [Hash] BRC-100 spec-mandated keys: :txid (display-order hex), :tx, :no_send_change, :send_with_results, :signable_transaction

create_hmac(data:, protocol_id:, key_id:, counterparty: = nil, privileged: = false, privileged_reason: = nil, seek_permission: = true, originator: = nil)

Creates an HMAC-SHA256 using a derived symmetric key. - @param data [Array] byte array to authenticate - @param protocol_id [Array] [security_level, protocol_name] - @param key_id [String] key identifier - @param counterparty [String] pubkey hex, 'self', or 'anyone' - @return [Hash] { hmac: Array }

create_signature(protocol_id:, key_id:, data: = nil, hash_to_directly_sign: = nil, counterparty: = nil, privileged: = false, privileged_reason: = nil, seek_permission: = true, originator: = nil)

Creates an ECDSA signature using a derived private key. - @param protocol_id [Array] [security_level, protocol_name] - @param key_id [String] key identifier - @param data [Array] data to hash and sign - @param hash_to_directly_sign [Array] pre-computed 32-byte hash - @param counterparty [String] pubkey hex, 'self', or 'anyone' - @return [Hash] { signature: Array } DER-encoded signature as byte array

decrypt(ciphertext:, protocol_id:, key_id:, counterparty: = nil, privileged: = false, privileged_reason: = nil, seek_permission: = true, originator: = nil)

Decrypts ciphertext using AES-256-GCM with a derived symmetric key. - @param ciphertext [Array] byte array to decrypt - @param protocol_id [Array] [security_level, protocol_name] - @param key_id [String] key identifier - @param counterparty [String] pubkey hex, 'self', or 'anyone' - @return [Hash] { plaintext: Array }

discover_by_attributes(attributes:, limit: = 10, offset: = 0, seek_permission: = true, originator: = nil)

Discovers certificates matching specific attribute values. - @param attributes [Hash{String => String}] field name/value pairs to match - @raise [NotImplementedError]

discover_by_identity_key(identity_key:, limit: = 10, offset: = 0, seek_permission: = true, originator: = nil)

Discovers certificates issued to a given identity key. - @raise [NotImplementedError]

encrypt(plaintext:, protocol_id:, key_id:, counterparty: = nil, privileged: = false, privileged_reason: = nil, seek_permission: = true, originator: = nil)

Encrypts plaintext using AES-256-GCM with a derived symmetric key. - @param plaintext [Array] byte array to encrypt - @param protocol_id [Array] [security_level, protocol_name] - @param key_id [String] key identifier - @param counterparty [String] pubkey hex, 'self', or 'anyone' - @return [Hash] { ciphertext: Array }

get_header_for_height(height:, originator: = nil)

Returns the 80-byte block header at the given height. - @raise [NotImplementedError]

get_height(originator: = nil)

Returns the current blockchain height. - @raise [NotImplementedError]

get_network(originator: = nil)

Returns the network (:mainnet or :testnet). - @raise [NotImplementedError]

get_public_key(identity_key: = false, protocol_id: = nil, key_id: = nil, counterparty: = nil, for_self: = false, privileged: = false, privileged_reason: = nil, seek_permission: = true, originator: = nil)

Returns a derived or identity public key. - @param identity_key [Boolean] return the root identity key - @param protocol_id [Array] [security_level, protocol_name] - @param key_id [String] key identifier - @param counterparty [String] pubkey hex, 'self', or 'anyone' - @param for_self [Boolean] derive from own identity - @return [Hash] { public_key: String } hex-encoded compressed public key

get_version(originator: = nil)

Returns the wallet version string. - @raise [NotImplementedError]

initialize(root_key)

  • @param root_key [BSV::Primitives::PrivateKey, String] a private key or 'anyone'
  • @return [ProtoWallet] a new instance of ProtoWallet

internalize_action(tx:, outputs:, description:, labels: = nil, seek_permission: = true, originator: = nil)

Internalizes a transaction — labels it, pays outputs to the wallet balance, inserts outputs into baskets, and/or tags them. - @param tx [Array] Atomic BEEF-formatted transaction (byte array) - @param outputs [Array] metadata per output - :output_index [Integer] index within the transaction - :protocol [Symbol] :wallet_payment or :basket_insertion - :payment_remittance [Hash] for payments: { derivation_prefix:, derivation_suffix:, sender_identity_key: } - :insertion_remittance [Hash] for insertions: { basket:, custom_instructions:, tags: } - @raise [NotImplementedError]

list_actions(labels:, label_query_mode: = :any, include_labels: = false, include_inputs: = false, include_input_source_locking_scripts: = false, include_input_unlocking_scripts: = false, include_outputs: = false, include_output_locking_scripts: = false, limit: = 10, offset: = 0, seek_permission: = true, originator: = nil)

Lists transactions matching the specified labels. - @raise [NotImplementedError] - @return [Hash] :total_actions, :actions

list_certificates(certifiers: = nil, types: = nil, limit: = 10, offset: = 0, privileged: = false, privileged_reason: = nil, originator: = nil)

Returns an empty certificate list.

ProtoWallet has no storage, so there are never any certificates. - @return [Hash] { certificates: [] }

list_outputs(basket:, tags: = nil, tag_query_mode: = :any, include: = nil, include_custom_instructions: = false, include_tags: = false, include_labels: = false, limit: = 10, offset: = 0, seek_permission: = true, originator: = nil)

Lists spendable outputs in a basket. - @param include [Symbol] nil, :locking_scripts, or :entire_transactions - @raise [NotImplementedError] - @return [Hash] :total_outputs, :beef, :outputs

prove_certificate(certificate: = nil, fields_to_reveal: = nil, verifier: = nil, privileged: = false, privileged_reason: = nil, originator: = nil)

Not supported — ProtoWallet has no certificate storage. - @raise [UnsupportedActionError] always

relinquish_certificate(type:, serial_number:, certifier:, originator: = nil)

Removes a certificate from the wallet. - @raise [NotImplementedError]

relinquish_output(basket:, output:, originator: = nil)

Removes an output from a basket without spending it. - @raise [NotImplementedError]

reveal_counterparty_key_linkage(counterparty:, verifier:, privileged: = false, privileged_reason: = nil, originator: = nil)

Reveals counterparty key linkage to a verifier (BRC-69 Method 1). - @param counterparty [String] counterparty public key hex (not 'self' or 'anyone') - @param verifier [String] verifier public key hex - @raise [InvalidParameterError] - @return [Hash] { prover:, verifier:, counterparty:, revelation_time:, encrypted_linkage:, encrypted_linkage_proof: }

reveal_specific_key_linkage(counterparty:, verifier:, protocol_id:, key_id:, privileged: = false, privileged_reason: = nil, originator: = nil)

Reveals specific key linkage for a particular interaction (BRC-69 Method 2). - @param counterparty [String] counterparty public key hex - @param verifier [String] verifier public key hex - @param protocol_id [Array] [security_level, protocol_name] - @param key_id [String] key identifier - @raise [InvalidParameterError] - @return [Hash] { prover:, verifier:, counterparty:, protocol_id:, key_id:, encrypted_linkage:, encrypted_linkage_proof:, proof_type: }

sign_action(spends:, reference:, accept_delayed_broadcast: = true, return_txid_only: = false, no_send: = false, send_with: = nil, originator: = nil)

Signs a transaction previously created with {#create_action}. - @param spends [Hash{Integer => Hash}] input index => { unlocking_script:, sequence_number: } - @param reference [String] reference returned by {#create_action} - @raise [NotImplementedError]

verify_hmac(data:, hmac:, protocol_id:, key_id:, counterparty: = nil, privileged: = false, privileged_reason: = nil, seek_permission: = true, originator: = nil)

Verifies an HMAC-SHA256 using a derived symmetric key. - @param data [Array] byte array that was authenticated - @param hmac [Array] HMAC to verify - @param protocol_id [Array] [security_level, protocol_name] - @param key_id [String] key identifier - @param counterparty [String] pubkey hex, 'self', or 'anyone' - @raise [InvalidHmacError] if the HMAC does not match - @return [Hash] { valid: true }

verify_signature(signature:, protocol_id:, key_id:, data: = nil, hash_to_directly_verify: = nil, counterparty: = nil, for_self: = false, privileged: = false, privileged_reason: = nil, seek_permission: = true, originator: = nil)

Verifies an ECDSA signature using a derived public key. - @param signature [Array] DER-encoded signature as byte array - @param protocol_id [Array] [security_level, protocol_name] - @param key_id [String] key identifier - @param data [Array] original data that was signed - @param hash_to_directly_verify [Array] pre-computed 32-byte hash - @param counterparty [String] pubkey hex, 'self', or 'anyone' - @param for_self [Boolean] verify own derived key (default false) - @raise [InvalidSignatureError] if the signature does not verify - @return [Hash] { valid: true }

wait_for_authentication(originator: = nil)

Blocks until the user is authenticated. - @raise [NotImplementedError]