Persona Class

Overview

The Persona class represents locally created and maintained cryptographic identities in the Keychain system. A persona manages two separate cryptographic keychains (one for encryption, one for signing) and provides methods for encrypting, decrypting, signing, and verifying data.

Package: keychain.identity.persona

from keychain.identity.persona import Persona

Class Definition

class Persona(KeychainObject):
    """Represents a locally created and maintained cryptographic identity."""

Constructor

def __init__(self, c_pointer) -> None

Initialize a Persona object with a C library pointer. Personas are typically created through Gateway.create_persona() methods rather than direct construction.

Parameters:

  • c_pointer - C library pointer to the persona object

Properties

Basic Properties

name

@property
def name(self) -> str

Get the primary name of the persona.

Returns: Primary name string

subname

@property
def subname(self) -> str

Get the secondary name of the persona.

Returns: Secondary name string

did

@property
def did(self) -> PersonaDID

Get the persona’s decentralized identifier.

Returns: PersonaDID object

Configuration Properties

auto_renew

@property
def auto_renew(self) -> bool

Check if the persona automatically renews certificates.

Returns: True if auto-renewal is enabled

encryption_algorithm

@property
def encryption_algorithm(self) -> EncryptionScheme

Get the encryption algorithm used by this persona.

Returns: EncryptionScheme enumeration value

encryption_key_size

@property
def encryption_key_size(self) -> int

Get the encryption key size in bits.

Returns: Key size in bits

signature_algorithm

@property
def signature_algorithm(self) -> SignatureScheme

Get the signature algorithm used by this persona.

Returns: SignatureScheme enumeration value

signature_key_size

@property
def signature_key_size(self) -> int

Get the signature key size in bits.

Returns: Key size in bits

cipher

@property
def cipher(self) -> Cipher

Get the symmetric cipher algorithm used for encryption.

Returns: Cipher enumeration value

Contact Management Properties

contacts

@property
def contacts(self) -> List[Contact]

Get all contacts associated with this persona.

Returns: List of Contact objects

Status Methods

is_null()

def is_null(self) -> bool

Check if the persona is null (uninitialized).

Returns: True if persona is null

is_mature()

def is_mature(self) -> bool

Check if the persona is mature (ready for cryptographic operations).

Returns: True if persona is mature

Example:

if persona.is_mature():
    print("Persona is ready for operations")
else:
    print("Waiting for persona to mature...")
    gateway.await_persona_maturity(persona)

Keychain Access Methods

keychain(keychain_type)

def keychain(self, keychain_type: KeychainType) -> Keychain

Get a specific keychain from the persona.

Parameters:

  • keychain_type (KeychainType) - Type of keychain (ENCRYPT or SIGN)

Returns: Keychain object

encryption_keychain()

def encryption_keychain(self) -> Keychain

Get the encryption keychain.

Returns: Encryption Keychain object

signature_keychain()

def signature_keychain(self) -> Keychain

Get the signature keychain.

Returns: Signature Keychain object

Contact Management Methods

find_contact(name, subname)

def find_contact(self, name: str, subname: str) -> Contact

Find a contact by name and subname.

Parameters:

  • name (str) - Primary name of the contact

  • subname (str) - Secondary name of the contact

Returns: Contact object if found

Raises: KeychainNotFoundError if contact not found

Example:

try:
    bob_contact = persona.find_contact("bob", "company.com")
    print(f"Found contact: {bob_contact.name}.{bob_contact.subname}")
except KeychainNotFoundError:
    print("Contact not found")

get_contact(index)

def get_contact(self, index: int) -> Contact

Get a contact by index.

Parameters:

  • index (int) - Index of the contact in the contacts list

Returns: Contact object

Raises: IndexError if index is out of range

add_contact(name, subname, did)

def add_contact(self, name: str, subname: str, did: PersonaDID) -> Contact

Add a new contact to this persona.

Parameters:

  • name (str) - Primary name of the contact

  • subname (str) - Secondary name of the contact

  • did (PersonaDID) - Contact’s decentralized identifier

Returns: New Contact object

Example:

# Add a new contact
new_contact = persona.add_contact(
    name="charlie",
    subname="partner.org",
    did=charlie_did
)

Lifecycle Operations

refresh()

def refresh(self) -> None

Refresh persona data from the database.

renew_certificate()

def renew_certificate(self) -> None

Manually initiate certificate renewal for this persona.

set_auto_renew(auto_renew)

def set_auto_renew(self, auto_renew: bool) -> None

Configure automatic certificate renewal.

Parameters:

  • auto_renew (bool) - Whether to enable auto-renewal

await_maturity()

def await_maturity(self) -> None

Block until this persona becomes mature.

Example:

# Wait for newly created persona to become ready
if not persona.is_mature():
    print("Waiting for persona to mature...")
    persona.await_maturity()
    print("Persona is now ready!")

Cryptographic Operations

encrypt(cleartext, recipients)

def encrypt(
    self,
    cleartext: Union[str, bytes],
    recipients: List[Contact]
) -> EncryptedData

Encrypt data for specified recipients using envelope encryption.

Parameters:

  • cleartext (str or bytes) - Data to encrypt

  • recipients (List[Contact]) - List of recipient contacts

Returns: EncryptedData object

Example:

# Encrypt a message for multiple recipients
recipients = [bob_contact, charlie_contact]
encrypted = persona.encrypt("Confidential message", recipients)

decrypt(ciphertext)

def decrypt(self, ciphertext: EncryptedData) -> Tuple[Union[str, bytes], CharEncoding]

Decrypt encrypted data using this persona’s private key.

Parameters:

  • ciphertext (EncryptedData) - Encrypted data to decrypt

Returns: Tuple of (decrypted data, character encoding)

Example:

# Decrypt received message
decrypted_data, encoding = persona.decrypt(encrypted_message)
print(f"Received: {decrypted_data}")

add_decrypt_access(encrypted_data, new_recipient)

def add_decrypt_access(
    self,
    encrypted_data: EncryptedData,
    new_recipient: Contact
) -> EncryptedData

Grant decrypt access to an additional recipient.

Parameters:

  • encrypted_data (EncryptedData) - Existing encrypted data

  • new_recipient (Contact) - New recipient to grant access to

Returns: Updated EncryptedData object

sign(cleartext, is_approval, tags, variables)

def sign(
    self,
    cleartext: SerializedData,
    is_approval: bool = False,
    tags: Optional[TagSet] = None,
    variables: Optional[TagSet] = None
) -> VerifiableData

Create verifiable (signed) data using this persona’s private key.

Parameters:

  • cleartext (SerializedData) - Data to sign

  • is_approval (bool) - Whether this is an approval signature

  • tags (TagSet, optional) - Metadata tags

  • variables (TagSet, optional) - Variable metadata

Returns: VerifiableData object

Example:

from keychain.core.serialized_data import SerializedData
from keychain.constants import DataType

# Create and sign a document
document = SerializedData.from_string(
    "Contract agreement terms",
    DataType.UTF8_STRING
)

signed_document = persona.sign(
    cleartext=document,
    is_approval=True
)

Credential Operations

create_credential(credential_id, credential_type, subject_id, start_timestamp, end_timestamp, claims, tags, variables)

def create_credential(
    self,
    credential_id: str,
    credential_type: str,
    subject_id: str,
    start_timestamp: int,
    end_timestamp: int,
    claims: TagSet,
    tags: Optional[TagSet] = None,
    variables: Optional[TagSet] = None
) -> Credential

Create and sign a W3C verifiable credential.

Parameters:

  • credential_id (str) - Unique credential identifier

  • credential_type (str) - Type of credential

  • subject_id (str) - Subject’s identifier

  • start_timestamp (int) - Validity start time (milliseconds since epoch)

  • end_timestamp (int) - Validity end time (milliseconds since epoch)

  • claims (TagSet) - Credential claims

  • tags (TagSet, optional) - Metadata tags

  • variables (TagSet, optional) - Variable metadata

Returns: Credential object

Example:

import time
from keychain.core.tag_set import TagSet

# Create employee credential
claims = TagSet()
claims.set_tag_value("", "employee_id", "12345")
claims.set_tag_value("", "name", "Alice Smith")
claims.set_tag_value("", "department", "Engineering")
claims.set_tag_value("", "role", "Senior Developer")

now = int(time.time() * 1000)
one_year = now + (365 * 24 * 60 * 60 * 1000)

credential = hr_persona.create_credential(
    credential_id="emp-alice-12345",
    credential_type="EmployeeCredential",
    subject_id="did:keychain:alice.company.com",
    start_timestamp=now,
    end_timestamp=one_year,
    claims=claims
)

create_transaction(consensus_algorithm, quorum, tags, base_variables)

def create_transaction(
    self,
    consensus_algorithm: ConsensusAlgorithm,
    quorum: TagSet,
    tags: Optional[TagSet] = None,
    base_variables: Optional[TagSet] = None
) -> Transaction

Create and sign a consensus transaction.

Parameters:

  • consensus_algorithm (ConsensusAlgorithm) - Consensus algorithm to use

  • quorum (TagSet) - Participant definitions

  • tags (TagSet, optional) - Metadata tags

  • base_variables (TagSet, optional) - Initial variables

Returns: Transaction object

add_signature_to_verifiable_data(verifiable_data, is_approval, tags, variables)

def add_signature_to_verifiable_data(
    self,
    verifiable_data: VerifiableData,
    is_approval: bool = False,
    tags: Optional[TagSet] = None,
    variables: Optional[TagSet] = None
) -> VerifiableData

Add this persona’s signature to existing verifiable data.

Parameters:

  • verifiable_data (VerifiableData) - Existing verifiable data

  • is_approval (bool) - Whether this is an approval signature

  • tags (TagSet, optional) - Metadata tags

  • variables (TagSet, optional) - Variable metadata

Returns: Updated VerifiableData object

add_signature_to_credential(credential, is_approval, tags, variables)

def add_signature_to_credential(
    self,
    credential: Credential,
    is_approval: bool = False,
    tags: Optional[TagSet] = None,
    variables: Optional[TagSet] = None
) -> Credential

Add this persona’s signature to an existing credential.

Parameters:

  • credential (Credential) - Existing credential

  • is_approval (bool) - Whether this is an approval signature

  • tags (TagSet, optional) - Metadata tags

  • variables (TagSet, optional) - Variable metadata

Returns: Updated Credential object

add_signature_to_transaction(transaction, is_approval, tags, variables)

def add_signature_to_transaction(
    self,
    transaction: Transaction,
    is_approval: bool = False,
    tags: Optional[TagSet] = None,
    variables: Optional[TagSet] = None
) -> Transaction

Add this persona’s signature to an existing transaction.

Parameters:

  • transaction (Transaction) - Existing transaction

  • is_approval (bool) - Whether this is an approval signature

  • tags (TagSet, optional) - Metadata tags

  • variables (TagSet, optional) - Variable metadata

Returns: Updated Transaction object

Verification Operations

verify_verifiable_data(verifiable_data)

def verify_verifiable_data(self, verifiable_data: VerifiableData) -> VerificationResult

Verify verifiable data signatures using this persona’s contact information.

Parameters:

  • verifiable_data (VerifiableData) - Data to verify

Returns: VerificationResult object

verify_credential(credential)

def verify_credential(self, credential: Credential) -> VerificationResult

Verify credential signatures using this persona’s contact information.

Parameters:

  • credential (Credential) - Credential to verify

Returns: VerificationResult object

verify_transaction(transaction)

def verify_transaction(self, transaction: Transaction) -> VerificationResult

Verify transaction signatures using this persona’s contact information.

Parameters:

  • transaction (Transaction) - Transaction to verify

Returns: VerificationResult object

verify(data)

def verify(self, data: Union[VerifiableData, Credential, Transaction]) -> VerificationResult

Generic verification method for any verifiable data type.

Parameters:

  • data (VerifiableData, Credential, or Transaction) - Data to verify

Returns: VerificationResult object

Example:

# Verify different types of signed data
vdata_result = persona.verify(signed_document)
cred_result = persona.verify(employee_credential)
tx_result = persona.verify(consensus_transaction)

for result in [vdata_result, cred_result, tx_result]:
    if result.is_verified():
        signer = result.signer()
        print(f"Valid signature from {signer.name}.{signer.subname}")
    else:
        print("Invalid signature")

Comparison Methods

eq(other)

def __eq__(self, other: object) -> bool

Test equality with another persona.

Parameters:

  • other (Persona) - Persona to compare with

Returns: True if personas are equal

Example:

# Check if two persona references are the same
if persona1 == persona2:
    print("Same persona")
else:
    print("Different personas")

Example: Complete Persona Workflow

from keychain.gateway import Gateway
from keychain.constants import SecurityLevel, DataType, KeychainType
from keychain.core.serialized_data import SerializedData
from keychain.core.tag_set import TagSet
from keychain.exceptions import KeychainNotFoundError
import time

# Initialize gateway
settings = Gateway.init("keychain.config")
gateway = Gateway(settings)

try:
    # Create personas
    alice = gateway.create_persona(
        name="alice",
        subname="company.com",
        security_level=SecurityLevel.HIGH,
        auto_renew=True
    )

    bob = gateway.create_persona(
        name="bob",
        subname="company.com",
        security_level=SecurityLevel.HIGH,
        auto_renew=True
    )

    # Wait for personas to mature
    if not alice.is_mature():
        print("Waiting for Alice's persona to mature...")
        alice.await_maturity()

    if not bob.is_mature():
        print("Waiting for Bob's persona to mature...")
        bob.await_maturity()

    print(f"Alice's persona: {alice.name}.{alice.subname}")
    print(f"  Encryption: {alice.encryption_algorithm} ({alice.encryption_key_size} bits)")
    print(f"  Signature: {alice.signature_algorithm} ({alice.signature_key_size} bits)")
    print(f"  Cipher: {alice.cipher}")
    print(f"  Auto-renew: {alice.auto_renew}")

    # Add Bob as a contact for Alice
    bob_contact = alice.add_contact(
        name="bob",
        subname="company.com",
        did=bob.did
    )

    # Add Alice as a contact for Bob
    alice_contact = bob.add_contact(
        name="alice",
        subname="company.com",
        did=alice.did
    )

    print(f"Alice has {len(alice.contacts)} contacts")
    print(f"Bob has {len(bob.contacts)} contacts")

    # Alice encrypts a message for Bob
    message = "Confidential project status update"
    encrypted = alice.encrypt(message, [bob_contact])
    print("Message encrypted by Alice")

    # Bob decrypts the message
    decrypted_data, encoding = bob.decrypt(encrypted)
    print(f"Bob decrypted: {decrypted_data}")

    # Alice signs a document
    document_content = "Important contract agreement"
    document = SerializedData.from_string(document_content, DataType.UTF8_STRING)

    signed_document = alice.sign(
        cleartext=document,
        is_approval=True
    )
    print("Document signed by Alice")

    # Bob verifies Alice's signature
    verification_result = bob.verify(signed_document)

    if verification_result.is_verified():
        signer = verification_result.signer()
        print(f"✓ Signature verified! Signed by: {signer.name}.{signer.subname}")
    else:
        print("✗ Signature verification failed")

    # Alice creates a credential for Bob
    claims = TagSet()
    claims.set_tag_value("", "employee_id", "54321")
    claims.set_tag_value("", "name", "Bob Johnson")
    claims.set_tag_value("", "department", "Marketing")
    claims.set_tag_value("", "clearance_level", "Standard")

    now = int(time.time() * 1000)
    six_months = now + (180 * 24 * 60 * 60 * 1000)

    credential = alice.create_credential(
        credential_id="emp-bob-54321",
        credential_type="EmployeeCredential",
        subject_id=str(bob.did),
        start_timestamp=now,
        end_timestamp=six_months,
        claims=claims
    )

    print("Employee credential created for Bob")

    # Bob verifies the credential
    cred_verification = bob.verify(credential)
    if cred_verification.is_verified():
        print("✓ Credential verified")
    else:
        print("✗ Credential verification failed")

    # Demonstrate contact management
    print("\nContact Management:")
    print(f"Alice's contacts:")
    for i, contact in enumerate(alice.contacts):
        print(f"  {i}: {contact.name}.{contact.subname}")

    # Find specific contact
    try:
        found_contact = alice.find_contact("bob", "company.com")
        print(f"Found Bob's contact: {found_contact.name}.{found_contact.subname}")
    except KeychainNotFoundError:
        print("Bob's contact not found")

    # Access keychains
    print(f"\nKeychain Information:")
    enc_keychain = alice.encryption_keychain()
    sig_keychain = alice.signature_keychain()
    print(f"Alice has encryption and signature keychains")

    # Certificate renewal
    print(f"\nCertificate Management:")
    print(f"Alice auto-renew: {alice.auto_renew}")

    # Manually renew if needed
    alice.renew_certificate()
    print("Certificate renewal initiated for Alice")

finally:
    # Cleanup
    Gateway.close()

Error Handling

Persona methods can raise various exceptions:

  • KeychainNotFoundError - Contact or resource not found

  • KeychainSecurityError - Cryptographic operation failures

  • KeychainValidationError - Input validation errors

  • KeychainMemoryError - Memory allocation failures

Always wrap persona operations in appropriate try-catch blocks.

See Also