Class persona

#include <keychain/cache/persona.hpp>

Namespace: keychain

Inheritance: facadepersona

Description

persona represents a cryptographic identity, the private keys of which are created and managed within the same local database used by the gateway object that created the persona. The cryptographic identity comprises of an encryption keychain and a signature keychain. The persona class functions primarily as a handle for persona objects that are established by the gateway object.

Multiple personas may be managed by the same gateway object, and each persona maps to a different set of contacts. As such, persona objects provide context for gateway cryptographic operations such as encryption and signing.

The distinction between a persona and a contact is that a gateway creates a persona locally whereas a contact is created by another device.

persona objects are not constructed by the user directly. They are created through the gateway.

In fact, persona is a snapshot view of the underlying object at the time it is created or requested, because persona has no reference to the gateway or blockchain at all. This means developers should always refresh their view of the currently active persona with gateway#get_active_persona before acting on the object, as the persona_state may have changed.

Since: v2.0 (significantly enhanced in v3.0)

Constructors

Copy Constructor

persona(const persona& rhs)

Creates a deep copy of a persona object.

Parameters:

  • rhs - The persona object to copy

Returns: A new persona object that is a copy of the right-hand side persona

Property Methods

auto_renew()

bool auto_renew() const

Gets whether the persona is configured to renew key certificates automatically.

Returns: true if the persona is configured to renew certificates automatically, false otherwise

encryption_algorithm()

kc::encryption_scheme encryption_algorithm() const

Gets the asymmetric encryption algorithm being used to encrypt data with this persona.

Returns: The encryption algorithm scheme (e.g., ecies_ecp_secp256r1, rsa_oaep_sha256)

encryption_key_size()

size_t encryption_key_size() const

Gets the asymmetric encryption key size in bits.

Returns: The encryption key size in bits (e.g., 256, 2048, 4096)

signature_algorithm()

kc::signature_scheme signature_algorithm() const

Gets the asymmetric signature algorithm being used to sign data with this persona.

Returns: The signature algorithm scheme (e.g., ecdsa_ecp_secp256r1, rsa_pss_sha256)

signature_key_size()

size_t signature_key_size() const

Gets the asymmetric signature key size in bits.

Returns: The signature key size in bits (e.g., 256, 2048, 4096)

cipher()

kc::cipher cipher() const

Gets the symmetric cipher algorithm being used to encrypt cleartext and public keys with this persona.

Returns: The symmetric cipher (e.g., aes_gcm_256, chacha20_poly1305)

Contact Management

contacts()

std::vector<kc::contact> contacts() const

Gets the list of contacts associated with this persona.

Returns: Vector of contact objects belonging to this persona

find_contact()

kc::contact find_contact(std::string name, std::string subname) const

Finds a contact with the given name and subname.

Parameters:

  • name - The contact’s name

  • subname - The contact’s subname

Returns: The contact with matching name and subname (exact match)

Throws: Exception if no contact is found with the specified name and subname

add_contact()

kc::contact add_contact(
    const std::string& name,
    const std::string& sub_name,
    const kc::persona_did& did
)

Adds a new contact to this persona by its DID. This method inserts a new contact into the database as a contact owned by this persona, then resolves the public key information from the DID using a method that is dependent on the DID method field (for example, looking up the PKI if necessary).

Parameters:

  • name - The contact name

  • sub_name - The contact subname

  • did - The contact’s DID for key resolution

Returns: The newly created contact object

Lifecycle Management

refresh()

void refresh()

Refreshes this persona’s data from the database. This method looks up and updates the persona object with current persona state data from the database.

Note: Since persona objects are snapshots, always refresh before performing operations to ensure you have the latest state.

renew_certificate()

void renew_certificate()

Manually initiates key rollover for this persona. Note that key rollover proceeds asynchronously, and the rollover process usually completes at a time well after the return of this method.

set_property_auto_renew()

void set_property_auto_renew(bool auto_renew)

Sets whether the gateway will renew this persona’s certificate (extend its keychain) automatically.

Parameters:

  • auto_renew - Whether the gateway should auto renew (true = yes, false = no)

await_maturity()

void await_maturity()

Blocks control flow until this persona becomes mature. A persona is mature if and only if for each keychain tip, there exists a PKI-based DID that is beyond or reaches the CONFIRMED state. Returns immediately if the persona is already mature.

Cryptographic Operations

encrypt()

kc::encrypted_data encrypt(
    const kc::serialized_data& clear_text,
    const std::vector<kc::contact>& recipients
)

Encrypts serialized data with the persona’s current public key and the recipients' current public keys. This method encrypts the cleartext with a symmetric cipher using envelope encryption.

Parameters:

  • clear_text - The serialized data to encrypt

  • recipients - List of contacts who will be given decrypt access to the encrypted data

Returns: Encrypted data object, envelope encrypted so that only the persona and the recipients can decrypt

Note: For self-encryption (encrypt for storage), pass an empty recipients vector

add_decrypt_access()

kc::key_lock add_decrypt_access(
    kc::encrypted_data& in_out_ciphertext,
    const kc::contact& new_recipient,
    bool attachable = true
)

Adds decrypt access to encrypted data with the specified new recipient’s current public keys. Upon successful execution, the encrypted data will be modified to include an additional key lock for the new recipient.

Parameters:

  • in_out_ciphertext - The original encrypted data (modified in place)

  • new_recipient - The contact to which access will be granted

  • attachable - Whether the resulting key lock should contain additional metadata for reattachment (default: true)

Returns: The key lock that was attached to the encrypted data

decrypt()

kc::serialized_data decrypt(const kc::encrypted_data& ciphertext)

Decrypts encrypted data with the persona’s private key that matches a public key in the access list of the ciphertext.

Parameters:

  • ciphertext - The encrypted data to decrypt

Returns: The decrypted data as serialized data

Throws: Exception if the persona doesn’t have access to decrypt the data

generate_signature()

std::string generate_signature(const std::string& cleartext)

Generates a signature for plain text using the persona’s current private key.

Parameters:

  • cleartext - The plain text to sign

Returns: The signature in hex-encoded DER format

sign()

kc::verifiable_data sign(
    const kc::serialized_data& cleartext,
    const bool approval = true,
    const kc::tag_set& tags = kc::tag_set(),
    const kc::tag_set& variables = kc::tag_set()
)

Signs (creates verifiable data from) serialized data using the persona’s current private key.

Parameters:

  • cleartext - The serialized data to be signed

  • approval - Whether the signature represents approval (true) or rejection (false) (default: true)

  • tags - Tags to add to the resulting attestation (default: empty)

  • variables - Variables to add to the resulting attestation (default: empty)

Returns: The signed, verifiable data signed with the persona’s most recently created signature key

create_verifiable_data()

kc::verifiable_data create_verifiable_data(
    const kc::serialized_data& cleartext,
    const bool is_approval = true,
    const kc::tag_set& tags = kc::tag_set(),
    const kc::tag_set& variables = kc::tag_set()
)

Alias for sign(). Creates verifiable data from serialized data using the persona’s current private key.

Parameters:

  • cleartext - The serialized data to be signed

  • is_approval - Whether the signature represents approval (true) or rejection (false) (default: true)

  • tags - Tags to add to the resulting attestation (default: empty)

  • variables - Variables to add to the resulting attestation (default: empty)

Returns: The signed, verifiable data

verify()

std::vector<kc::verification_result> verify(const tkc::verifiable& signed_msg)

Verifies the signatures on a verifiable object using the persona’s current private key.

Parameters:

  • signed_msg - The verifiable object (verifiable data, credential, or transaction)

Returns: A vector of verification results, one for each signature in the verifiable object

Advanced Operations

create_credential()

kc::credential create_credential(
    const std::string& credential_id,
    const std::string& type,
    const std::string& subject,
    kc::timestamp_t start_timestamp,
    kc::timestamp_t end_timestamp,
    const kc::tag_set& claims,
    const kc::tag_set& tags = kc::tag_set(),
    const kc::tag_set& variables = kc::tag_set()
)

Creates and signs a credential using the persona’s current private key. This creates a W3C-compatible verifiable credential.

Parameters:

  • credential_id - The credential ID (as suggested by W3C)

  • type - The credential type (as suggested by W3C)

  • subject - An identifier for the credential subject (for example, a DID)

  • start_timestamp - The starting validity time

  • end_timestamp - The validity end time

  • claims - A set of claims for the subject

  • tags - Tags for the credential (default: empty)

  • variables - Variables for the credential (default: empty)

Returns: The signed credential

create_transaction()

kc::transaction create_transaction(
    kc::consensus_algorithm consensus,
    const kc::quorum& quorum,
    const kc::tag_set& tags,
    const kc::tag_set& variables
)

Creates and signs a ledger transaction using the persona’s current private key. Keychain ledger transactions are exchanged as part of the application-level consensus. Keychain ledger transactions and public-key infrastructure transactions (such as blockchain transactions) are distinct concepts.

Parameters:

  • consensus - The consensus algorithm to use

  • quorum - The set of participants required to participate in the consensus

  • tags - Tags for the transaction

  • variables - Variables for the transaction

Returns: The signed transaction

add_signature()

kc::attestation add_signature(
    tkc::verifiable& in_out_signed_verifiable,
    bool is_approval = true,
    const kc::tag_set& tags = kc::tag_set(),
    const kc::tag_set& vars = tkc::tag_set()
)

Adds a signature to a verifiable object (verifiable data, credential, or transaction) using the persona’s current private key.

Parameters:

  • in_out_signed_verifiable - The verifiable object (modified in place)

  • is_approval - Whether the signature represents approval (true) or rejection (false) (default: true)

  • tags - Tags to add to the resulting attestation (default: empty)

  • vars - Variables to add to the resulting attestation (default: empty)

Returns: The resulting attestation that was also added to the input verifiable data

Example Usage

Basic Persona Operations

#include <keychain/keychain_headers.hpp>

int main() {
    try {
        // Assuming gateway is already initialized and persona exists
        kc::persona alice = gateway.find_persona("alice", "personal");

        // Check persona properties
        std::cout << "Auto-renew: " << alice.auto_renew() << std::endl;
        std::cout << "Encryption algorithm: " << (int)alice.encryption_algorithm() << std::endl;
        std::cout << "Encryption key size: " << alice.encryption_key_size() << " bits" << std::endl;
        std::cout << "Signature algorithm: " << (int)alice.signature_algorithm() << std::endl;
        std::cout << "Signature key size: " << alice.signature_key_size() << " bits" << std::endl;
        std::cout << "Cipher: " << (int)alice.cipher() << std::endl;

        return 0;
    } catch (const kc::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
}

Self-Encryption (Secure Storage)

// Create data to encrypt
std::string secret = "My confidential information";
kc::serialized_data data(secret);

// Encrypt for self (empty recipients list)
std::vector<kc::contact> recipients; // empty = self-encryption
kc::encrypted_data encrypted = alice.encrypt(data, recipients);

// Store encrypted data safely...

// Later: decrypt the data
kc::serialized_data decrypted = alice.decrypt(encrypted);
std::string recovered = decrypted.utf8_string();

std::cout << "Original: " << secret << std::endl;
std::cout << "Recovered: " << recovered << std::endl;
// Output: Original and recovered should match

Digital Signing and Verification

// Create document to sign
std::string document = "Important contract v1.2";
kc::serialized_data doc_data(document);

// Sign with approval
kc::verifiable_data signed_doc = alice.sign(doc_data, true);

// Add metadata tags
kc::tag_set tags;
tags.set_tag("document", "type", kc::serialized_data("contract"));
tags.set_tag("version", "number", kc::serialized_data("1.2"));
tags.set_tag("legal", "binding", kc::serialized_data(true));

kc::verifiable_data signed_with_metadata = alice.sign(doc_data, true, tags);

// Verify signature
std::vector<kc::verification_result> results = alice.verify(signed_doc);

for (const auto& result : results) {
    if (result.is_verified()) {
        std::cout << "✓ Valid signature" << std::endl;
        std::cout << "Signer DID: " << result.signer_did().serialize() << std::endl;
    } else {
        std::cout << "✗ Invalid signature" << std::endl;
    }
}

Multi-Recipient Encryption

// Add contacts to persona
kc::persona_did bob_did("did:keychain:bob:work");
kc::persona_did charlie_did("did:keychain:charlie:team");

kc::contact bob = alice.add_contact("bob", "work", bob_did);
kc::contact charlie = alice.add_contact("charlie", "team", charlie_did);

// Encrypt for multiple recipients
std::string message = "Team meeting at 3pm";
kc::serialized_data msg_data(message);
std::vector<kc::contact> team = {bob, charlie};

kc::encrypted_data team_encrypted = alice.encrypt(msg_data, team);

// Now alice, bob, and charlie can all decrypt this message
// (assuming they have access to their respective personas)

Contact Management

// List all contacts
std::vector<kc::contact> all_contacts = alice.contacts();
std::cout << "Alice has " << all_contacts.size() << " contacts:" << std::endl;

for (const auto& contact : all_contacts) {
    std::cout << "- " << contact.name() << "." << contact.sub_name() << std::endl;
}

// Find specific contact
try {
    kc::contact bob = alice.find_contact("bob", "work");
    std::cout << "Found Bob: " << bob.did().serialize() << std::endl;
} catch (const kc::exception& e) {
    std::cout << "Bob not found: " << e.what() << std::endl;
}

Persona Lifecycle Management

// Refresh persona state from database
alice.refresh();

// Check if automatic renewal is enabled
if (!alice.auto_renew()) {
    std::cout << "Enabling auto-renewal for alice" << std::endl;
    alice.set_property_auto_renew(true);
}

// Manually trigger certificate renewal
std::cout << "Initiating certificate renewal..." << std::endl;
alice.renew_certificate();

// Wait for persona to become mature (for new personas)
std::cout << "Waiting for persona maturity..." << std::endl;
alice.await_maturity();
std::cout << "Persona is now mature and ready for operations" << std::endl;

Creating Verifiable Credentials

// Create identity verification credential
kc::tag_set identity_claims;
identity_claims.set_tag("identity", "verified", kc::serialized_data(true));
identity_claims.set_tag("identity", "method", kc::serialized_data("government_id"));
identity_claims.set_tag("personal", "name", kc::serialized_data("Alice Smith"));
identity_claims.set_tag("personal", "date_of_birth", kc::serialized_data("1990-01-15"));

kc::credential identity_vc = alice.create_credential(
    "https://issuer.example/credentials/identity/12345",
    "IdentityCredential",
    alice.did().serialize(), // subject is alice herself
    time(nullptr), // valid from now
    time(nullptr) + (5 * 365 * 24 * 60 * 60), // valid for 5 years
    identity_claims
);

// Verify the credential
std::vector<kc::verification_result> vc_verification = alice.verify(identity_vc);
if (!vc_verification.empty() && vc_verification[0].is_verified()) {
    std::cout << "✓ Credential is valid and self-signed" << std::endl;
}

Thread Safety and Best Practices

// Personas are snapshots - always refresh before critical operations
class SafePersonaOperations {
private:
    kc::gateway& gateway_;
    std::string persona_name_;
    std::string persona_subname_;

public:
    SafePersonaOperations(kc::gateway& gw, const std::string& name, const std::string& subname)
        : gateway_(gw), persona_name_(name), persona_subname_(subname) {}

    kc::encrypted_data safe_encrypt(const kc::serialized_data& data,
                                   const std::vector<kc::contact>& recipients) {
        // Always get fresh persona state
        kc::persona current = gateway_.find_persona(persona_name_, persona_subname_);
        current.refresh(); // Ensure latest state

        return current.encrypt(data, recipients);
    }

    kc::verifiable_data safe_sign(const kc::serialized_data& data) {
        // Always get fresh persona state
        kc::persona current = gateway_.find_persona(persona_name_, persona_subname_);
        current.refresh(); // Ensure latest state

        return current.sign(data);
    }
};
Methods inherited from class facade

get_id, get_name, get_status, get_sub_name, get_uri, is_null