Skip to content

Class BSV::Auth::MasterCertificate

Inherits: BSV::Auth::Certificate

A Certificate subclass that manages a master keyring for certificate issuance and selective field disclosure.

MasterCertificate adds a master_keyring to the base Certificate. The master keyring maps each field name to a Base64-encoded encrypted symmetric key that was used to encrypt that field's value. This allows the certificate holder to:

  1. Decrypt all fields via {.decrypt_fields}.
  2. Re-encrypt individual field keys for a specific verifier via {.create_keyring_for_verifier}, producing a {VerifiableCertificate}.

Protocol details

Field encryption uses BRC-42 key derivation:

  • Protocol: +[2, 'certificate field encryption']+
  • Master key ID (no serial): field_name
  • Verifier key ID (with serial): +"#{serial_number} #{field_name}"+

Wallet parameters are duck-typed — any object responding to :encrypt, :decrypt, and :get_public_key is accepted.

  • @see BSV::Auth::Certificate base class
  • @see BSV::Auth::VerifiableCertificate consumer of verifier keyrings

Attributes

master_keyring [R]

  • @return [Hash] mapping field names to Base64-encoded encrypted symmetric keys

Public Class Methods

create_certificate_fields(creator_wallet, certifier_or_subject, fields, privileged: = false, privileged_reason: = nil)

Encrypts certificate fields and generates a master keyring.

For each field: 1. Generates a random {BSV::Primitives::SymmetricKey}. 2. Encrypts the field value with that key. 3. Encrypts the symmetric key bytes for certifier_or_subject using BRC-42 with key_id = field_name (no serial number). - @param creator_wallet [#encrypt] wallet used to encrypt field keys - @param certifier_or_subject [String] counterparty pubkey hex, +'self'+, or +'anyone'+ — the party who will later decrypt the master keyring - @param fields [Hash] plain-text field name → plain-text field value - @param privileged [Boolean] whether this is a privileged operation - @param privileged_reason [String, nil] reason for privileged access - @return [Hash] +{ certificate_fields: Hash, master_keyring: Hash }+

create_keyring_for_verifier(subject_wallet, certifier:, verifier:, fields:, fields_to_reveal:, master_keyring:, serial_number:, privileged: = false, privileged_reason: = nil)

Creates a verifier-specific keyring for selective field disclosure.

For each field in fields_to_reveal: 1. Decrypts the master symmetric key (counterparty = certifier, key_id = field_name only). 2. Verifies the decrypted key actually decrypts the field value. 3. Re-encrypts the key for the verifier with key_id = +"#{serial_number} #{field_name}"+.

The resulting keyring is suitable for constructing a {VerifiableCertificate}. - @param subject_wallet [#encrypt, #decrypt] subject's wallet - @param certifier [String] certifier pubkey hex, +'self'+, or +'anyone'+ - @param verifier [String] verifier pubkey hex, +'self'+, or +'anyone'+ - @param fields [Hash] field name → encrypted field value (Base64) - @param fields_to_reveal [Array] subset of field names to expose - @param master_keyring [Hash] field name → Base64 encrypted symmetric key - @param serial_number [String] certificate serial number (Base64) - @param privileged [Boolean] whether this is a privileged operation - @param privileged_reason [String, nil] reason for privileged access - @raise [ArgumentError] if +fields_to_reveal+ is not an Array - @raise [ArgumentError] if a field to reveal does not exist in +fields+ - @return [Hash] field name → Base64 encrypted key (verifier-specific)

decrypt_field(wallet, master_keyring, field_name, field_value, counterparty, privileged: = false, privileged_reason: = nil)

Decrypts a single certificate field.

  1. Decrypts the encrypted symmetric key from master_keyring for field_name.
  2. Uses the decrypted key bytes as a {BSV::Primitives::SymmetricKey}.
  3. Decrypts the field value and returns both the key and plaintext.
  4. @param wallet [#decrypt] subject's or certifier's wallet
  5. @param master_keyring [Hash] field name → Base64 encrypted symmetric key
  6. @param field_name [String] name of the field to decrypt
  7. @param field_value [String] Base64-encoded encrypted field value
  8. @param counterparty [String] pubkey hex, +'self'+, or +'anyone'+
  9. @param privileged [Boolean] whether this is a privileged operation
  10. @param privileged_reason [String, nil] reason for privileged access
  11. @raise [ArgumentError] if +master_keyring+ is nil or empty
  12. @raise [RuntimeError] if decryption fails
  13. @return [Hash] +{ field_revelation_key: Array, decrypted_field_value: String }+

decrypt_fields(wallet, master_keyring, fields, counterparty, privileged: = false, privileged_reason: = nil)

Decrypts all fields in the certificate using a master keyring. - @param wallet [#decrypt] subject's or certifier's wallet - @param master_keyring [Hash] field name → Base64 encrypted symmetric key - @param fields [Hash] field name → Base64 encrypted field value - @param counterparty [String] pubkey hex, +'self'+, or +'anyone'+ - @param privileged [Boolean] whether this is a privileged operation - @param privileged_reason [String, nil] reason for privileged access - @raise [ArgumentError] if +master_keyring+ is nil or empty - @raise [RuntimeError] if decryption fails for any field - @return [Hash] field name → decrypted plaintext string

from_hash(hash)

Construct a MasterCertificate from a plain Hash.

Accepts both snake_case and camelCase key variants. - @param hash [Hash] certificate data - @return [MasterCertificate]

issue_certificate_for_subject(certifier_wallet, subject, fields, certificate_type, get_revocation_outpoint: = nil, serial_number: = nil)

Issues a signed MasterCertificate for a subject.

  1. Generates a random 32-byte serial_number if none provided.
  2. Calls {.create_certificate_fields} to encrypt fields and build the master keyring.
  3. Resolves +'self'+ subject to the certifier's identity key.
  4. Obtains a revocation outpoint (via callback or default placeholder).
  5. Constructs and signs the MasterCertificate.
  6. @param certifier_wallet [#encrypt, #create_signature, #get_public_key] certifier's wallet
  7. @param subject [String] subject pubkey hex, +'self'+, or +'anyone'+
  8. @param fields [Hash] plain-text field name → plain-text field value
  9. @param certificate_type [String] Base64-encoded type (32 bytes decoded)
  10. @param get_revocation_outpoint [Proc, nil] called with serial_number; returns outpoint string
  11. @param serial_number [String, nil] custom serial_number (Base64); randomly generated if nil
  12. @return [MasterCertificate] signed certificate

Public Instance Methods

initialize(type:, serial_number:, subject:, certifier:, revocation_outpoint:, fields:, master_keyring:, signature: = nil)

  • @param type [String] Base64 string (32 bytes decoded)
  • @param serial_number [String] Base64 string (32 bytes decoded)
  • @param subject [String] compressed public key hex
  • @param certifier [String] compressed public key hex
  • @param revocation_outpoint [String] +"."+
  • @param fields [Hash] field name strings to encrypted value strings (Base64)
  • @param master_keyring [Hash] field name strings to Base64-encoded encrypted symmetric keys
  • @param signature [String, nil] DER-encoded signature hex, or nil
  • @raise [ArgumentError] if any field in +fields+ is missing from +master_keyring+
  • @return [MasterCertificate] a new instance of MasterCertificate

to_h()

Return the certificate as a plain Hash with snake_case keys, including master_keyring. - @return [Hash]