KeychainElement Class
Overview
The KeychainElement
class represents an element of a keychain, comprised of the public key and metadata about the public key. Each element represents a specific key pair within a keychain’s lifecycle and includes associated DIDs, cryptographic proofs, and status information.
Unlike other keychain classes, KeychainElement is not serializable and is typically obtained through keychain operations rather than constructed directly.
Package: keychain.identity.keychain_element
from keychain.identity.keychain_element import KeychainElement
Class Definition
class KeychainElement(KeychainObject):
"""Represents an element of a keychain with public key and metadata."""
Constructor
def __init__(self, c_pointer: Optional[ctypes.c_void_p] = None) -> None
Initialize a KeychainElement object.
Parameters:
-
c_pointer
(ctypes.c_void_p
, optional) - Existing C pointer to wrap
Note: KeychainElement objects are typically created through keychain operations, not constructed directly by users.
Example:
# Usually obtained from keychain operations
keychain = get_keychain()
elements = keychain.get_elements()
element = elements[0] # First element
# Or from existing C pointer (internal use)
element = KeychainElement(c_pointer=existing_pointer)
Instance Methods
copy()
def copy(self) -> "KeychainElement"
Create a deep copy of this keychain element.
Returns: A new KeychainElement
object that is a deep copy
Example:
original_element = get_keychain_element()
copied_element = original_element.copy()
did_status()
def did_status(self, did: KeychainDID) -> DidStatus
Get the status of a DID in the keychain element’s DID list.
Parameters:
-
did
(KeychainDID
) - The keychain DID to check status for
Returns: The DidStatus
of the DID
Raises: ValueError
if the DID is not found in this element
Example:
from keychain.constants import DidStatus
element = get_keychain_element()
dids = element.dids
for did in dids:
try:
status = element.did_status(did)
print(f"DID {did} status: {status.name}")
except ValueError as e:
print(f"Error: {e}")
Properties
Key Properties
public_key
@property
def public_key(self) -> str
Get the public key.
Returns: The public key in hex-encoded DER format
Example:
element = get_keychain_element()
public_key = element.public_key
print(f"Public key: {public_key[:32]}...") # First 32 characters
print(f"Key length: {len(public_key)} characters")
Identity Properties
dids
@property
def dids(self) -> List[KeychainDID]
Get the DIDs for this element.
Returns: List of KeychainDID
objects associated with this element
Example:
element = get_keychain_element()
dids = element.dids
print(f"Element has {len(dids)} associated DIDs:")
for i, did in enumerate(dids):
print(f" {i}: {did}")
print(f" Type: {did.keychain_type_str}")
print(f" Network: {did.network}")
Algorithm Properties
algorithm
@property
def algorithm(self) -> int
Get the cryptographic algorithm.
Returns: The algorithm as an integer (cast to signature_scheme or encryption_scheme depending on keychain type)
Example:
from keychain.constants import SignatureScheme, EncryptionScheme, KeychainType
element = get_keychain_element()
algorithm_value = element.algorithm
# Determine if this is encryption or signature keychain
dids = element.dids
if dids:
first_did = dids[0]
if first_did.keychain_type == KeychainType.ENCRYPT:
algorithm = EncryptionScheme(algorithm_value)
print(f"Encryption algorithm: {algorithm.name}")
elif first_did.keychain_type == KeychainType.SIGN:
algorithm = SignatureScheme(algorithm_value)
print(f"Signature algorithm: {algorithm.name}")
else:
print(f"Algorithm value: {algorithm_value}")
Comparison Methods
eq()
def __eq__(self, other: object) -> bool
Test equality of two keychain elements.
Parameters:
-
other
(KeychainElement
) - The other keychain element to compare
Returns: True
if element fields test equal, False
otherwise
Example:
element1 = get_keychain_element()
element2 = element1.copy()
if element1 == element2:
print("Elements are identical")
Example: Working with Keychain Elements
from keychain.identity.keychain_element import KeychainElement
from keychain.constants import KeychainType, SignatureScheme, EncryptionScheme
def analyze_keychain_element(element: KeychainElement):
"""Analyze a keychain element and display its properties."""
print("=== Keychain Element Analysis ===")
# Basic properties
print(f"Index: {element.index}")
print(f"Algorithm value: {element.algorithm}")
# Public key information
public_key = element.public_key
print(f"Public key length: {len(public_key)} characters")
print(f"Public key (first 32 chars): {public_key[:32]}...")
# Proof information
proof = element.proof
print(f"Proof: {proof}")
# Associated DIDs
dids = element.dids
print(f"\\nAssociated DIDs: {len(dids)}")
for i, did in enumerate(dids):
print(f" DID {i}:")
print(f" String: {did}")
print(f" Type: {did.keychain_type_str}")
print(f" Network: {did.network}")
print(f" Network ID: {did.network_specific_id}")
# Check DID status
try:
status = element.did_status(did)
print(f" Status: {status.name}")
except ValueError as e:
print(f" Status: Error - {e}")
# Determine algorithm type based on DIDs
if dids:
first_did = dids[0]
algorithm_value = element.algorithm
if first_did.keychain_type == KeychainType.ENCRYPT:
try:
algorithm = EncryptionScheme(algorithm_value)
print(f"\\nEncryption Algorithm: {algorithm.name}")
except ValueError:
print(f"\\nUnknown encryption algorithm: {algorithm_value}")
elif first_did.keychain_type == KeychainType.SIGN:
try:
algorithm = SignatureScheme(algorithm_value)
print(f"\\nSignature Algorithm: {algorithm.name}")
except ValueError:
print(f"\\nUnknown signature algorithm: {algorithm_value}")
def compare_keychain_elements(elements: list[KeychainElement]):
"""Compare multiple keychain elements for analysis."""
if not elements:
print("No elements to compare")
return
print("=== Keychain Elements Comparison ===")
# Basic statistics
print(f"Total elements: {len(elements)}")
# Algorithm distribution
algorithms = {}
keychain_types = {}
for i, element in enumerate(elements):
algorithm_value = element.algorithm
algorithms[algorithm_value] = algorithms.get(algorithm_value, 0) + 1
# Determine keychain type from DIDs
dids = element.dids
if dids:
kc_type = dids[0].keychain_type.name
keychain_types[kc_type] = keychain_types.get(kc_type, 0) + 1
print("\\nAlgorithm distribution:")
for alg, count in sorted(algorithms.items()):
print(f" Algorithm {alg}: {count} elements")
print("\\nKeychain type distribution:")
for kc_type, count in keychain_types.items():
print(f" {kc_type}: {count} elements")
# Index sequence validation
indices = [element.index for element in elements]
expected_indices = list(range(len(elements)))
if sorted(indices) == expected_indices:
print("\\nā Element indices form a valid sequence (0 to n-1)")
else:
missing = set(expected_indices) - set(indices)
duplicates = len(indices) - len(set(indices))
print(f"\\nā Invalid index sequence:")
if missing:
print(f" Missing indices: {sorted(missing)}")
if duplicates > 0:
print(f" Duplicate indices: {duplicates}")
def extract_keychain_element_info(element: KeychainElement) -> dict:
"""Extract comprehensive information from a keychain element."""
try:
# Basic properties
info = {
"index": element.index,
"algorithm": element.algorithm,
"public_key": {
"length": len(element.public_key),
"preview": element.public_key[:32] + "..."
},
"proof": element.proof,
"dids": []
}
# DID information
dids = element.dids
for did in dids:
did_info = {
"did_string": str(did),
"keychain_type": did.keychain_type_str,
"network": did.network,
"network_id": did.network_specific_id
}
# Try to get status
try:
status = element.did_status(did)
did_info["status"] = status.name
except ValueError:
did_info["status"] = "unknown"
info["dids"].append(did_info)
# Algorithm interpretation
if dids:
first_did = dids[0]
algorithm_value = element.algorithm
if first_did.keychain_type == KeychainType.ENCRYPT:
try:
algorithm = EncryptionScheme(algorithm_value)
info["algorithm_name"] = algorithm.name
info["algorithm_type"] = "encryption"
except ValueError:
info["algorithm_name"] = f"unknown_encryption_{algorithm_value}"
info["algorithm_type"] = "encryption"
elif first_did.keychain_type == KeychainType.SIGN:
try:
algorithm = SignatureScheme(algorithm_value)
info["algorithm_name"] = algorithm.name
info["algorithm_type"] = "signature"
except ValueError:
info["algorithm_name"] = f"unknown_signature_{algorithm_value}"
info["algorithm_type"] = "signature"
return info
except Exception as e:
return {"error": str(e)}
def validate_keychain_elements(elements: list[KeychainElement]) -> dict:
"""Validate a list of keychain elements."""
validation_result = {
"valid": True,
"errors": [],
"warnings": [],
"element_count": len(elements),
"statistics": {}
}
if not elements:
validation_result["warnings"].append("No elements to validate")
return validation_result
# Check index sequence
indices = [element.index for element in elements]
expected_indices = list(range(len(elements)))
if sorted(indices) != expected_indices:
validation_result["valid"] = False
validation_result["errors"].append("Invalid index sequence")
# Check for duplicate elements
seen_public_keys = set()
duplicates = []
for i, element in enumerate(elements):
try:
public_key = element.public_key
if public_key in seen_public_keys:
duplicates.append(i)
else:
seen_public_keys.add(public_key)
except Exception as e:
validation_result["errors"].append(f"Element {i}: Cannot access public key - {e}")
validation_result["valid"] = False
if duplicates:
validation_result["warnings"].append(f"Duplicate public keys at indices: {duplicates}")
# Check DID consistency
networks = set()
keychain_types = set()
for i, element in enumerate(elements):
try:
dids = element.dids
if not dids:
validation_result["warnings"].append(f"Element {i}: No associated DIDs")
continue
for did in dids:
networks.add(did.network)
keychain_types.add(did.keychain_type.name)
except Exception as e:
validation_result["errors"].append(f"Element {i}: Cannot access DIDs - {e}")
validation_result["valid"] = False
# Statistics
validation_result["statistics"] = {
"unique_networks": len(networks),
"networks": list(networks),
"keychain_types": list(keychain_types),
"duplicate_elements": len(duplicates)
}
return validation_result
# Usage examples
def keychain_element_examples():
"""Demonstrate keychain element usage."""
# Get elements from some source (e.g., keychain)
elements = get_keychain_elements()
if elements:
# Analyze first element
analyze_keychain_element(elements[0])
# Compare multiple elements
if len(elements) > 1:
compare_keychain_elements(elements)
# Extract information
info = extract_keychain_element_info(elements[0])
print(f"\\n=== Element Information ===")
for key, value in info.items():
if isinstance(value, dict):
print(f"{key}:")
for subkey, subvalue in value.items():
print(f" {subkey}: {subvalue}")
elif isinstance(value, list):
print(f"{key}: {len(value)} items")
for i, item in enumerate(value):
print(f" {i}: {item}")
else:
print(f"{key}: {value}")
# Validate elements
validation = validate_keychain_elements(elements)
print(f"\\n=== Validation Results ===")
print(f"Valid: {validation['valid']}")
if validation['errors']:
print("Errors:")
for error in validation['errors']:
print(f" - {error}")
if validation['warnings']:
print("Warnings:")
for warning in validation['warnings']:
print(f" - {warning}")
if __name__ == "__main__":
keychain_element_examples()
Example: Keychain Element Management
from keychain.identity.keychain_element import KeychainElement
from keychain.constants import DidStatus, KeychainType
class KeychainElementManager:
"""Manager for working with keychain elements."""
def __init__(self):
self.elements = []
def add_element(self, element: KeychainElement) -> None:
"""Add an element to the manager."""
self.elements.append(element.copy())
def get_element_by_index(self, index: int) -> KeychainElement:
"""Get an element by its keychain index."""
for element in self.elements:
if element.index == index:
return element
raise ValueError(f"No element found with index {index}")
def get_elements_by_type(self, keychain_type: KeychainType) -> list[KeychainElement]:
"""Get all elements of a specific keychain type."""
matching_elements = []
for element in self.elements:
dids = element.dids
if dids and dids[0].keychain_type == keychain_type:
matching_elements.append(element)
return matching_elements
def get_elements_by_network(self, network: str) -> list[KeychainElement]:
"""Get all elements associated with a specific network."""
matching_elements = []
for element in self.elements:
dids = element.dids
for did in dids:
if did.network == network:
matching_elements.append(element)
break # Found at least one DID for this network
return matching_elements
def find_element_by_public_key(self, public_key: str) -> KeychainElement:
"""Find an element by its public key."""
for element in self.elements:
if element.public_key == public_key:
return element
raise ValueError(f"No element found with public key {public_key[:16]}...")
def get_element_summary(self) -> dict:
"""Get a summary of all managed elements."""
summary = {
"total_elements": len(self.elements),
"by_type": {},
"by_network": {},
"algorithms": {},
"index_range": None
}
if not self.elements:
return summary
indices = []
for element in self.elements:
indices.append(element.index)
# Count by type
dids = element.dids
if dids:
kc_type = dids[0].keychain_type.name
summary["by_type"][kc_type] = summary["by_type"].get(kc_type, 0) + 1
# Count by network
for did in dids:
network = did.network
summary["by_network"][network] = summary["by_network"].get(network, 0) + 1
# Count algorithms
algorithm = element.algorithm
summary["algorithms"][algorithm] = summary["algorithms"].get(algorithm, 0) + 1
if indices:
summary["index_range"] = (min(indices), max(indices))
return summary
def validate_elements(self) -> dict:
"""Validate all managed elements."""
return validate_keychain_elements(self.elements)
def export_element_data(self) -> list[dict]:
"""Export data for all elements."""
return [extract_keychain_element_info(element) for element in self.elements]
def keychain_element_manager_example():
"""Demonstrate keychain element management."""
manager = KeychainElementManager()
# Add elements from keychain
keychain_elements = get_keychain_elements()
for element in keychain_elements:
manager.add_element(element)
print("=== Keychain Element Manager Demo ===")
# Get summary
summary = manager.get_element_summary()
print(f"Total elements: {summary['total_elements']}")
if summary['index_range']:
start, end = summary['index_range']
print(f"Index range: {start} to {end}")
print("\\nBy type:")
for kc_type, count in summary['by_type'].items():
print(f" {kc_type}: {count}")
print("\\nBy network:")
for network, count in summary['by_network'].items():
print(f" {network}: {count}")
# Find specific elements
try:
encrypt_elements = manager.get_elements_by_type(KeychainType.ENCRYPT)
print(f"\\nEncryption elements: {len(encrypt_elements)}")
if encrypt_elements:
first_encrypt = encrypt_elements[0]
print(f"First encryption element index: {first_encrypt.index}")
except Exception as e:
print(f"Error finding encryption elements: {e}")
# Validate elements
validation = manager.validate_elements()
print(f"\\nValidation: {'ā Valid' if validation['valid'] else 'ā Invalid'}")
if validation['errors']:
print("Errors:")
for error in validation['errors']:
print(f" - {error}")
if __name__ == "__main__":
keychain_element_manager_example()
Error Handling
KeychainElement operations can raise various exceptions:
Example:
from keychain.exceptions import KeychainValidationError
try:
# Access element properties
element = get_keychain_element()
public_key = element.public_key
index = element.index
dids = element.dids
# Check DID status
if dids:
status = element.did_status(dids[0])
print(f"DID status: {status.name}")
# Work with algorithm
algorithm_value = element.algorithm
if dids and dids[0].keychain_type == KeychainType.SIGN:
algorithm = SignatureScheme(algorithm_value)
print(f"Signature algorithm: {algorithm.name}")
except ValueError as e:
print(f"Value error: {e}")
except KeychainValidationError as e:
print(f"Validation error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
See Also
-
KeychainDID Class - DIDs associated with elements
-
Persona Class - Uses keychain elements for identity
-
Constants and Enums - DidStatus, KeychainType, and algorithm enums
-
Exception Classes - Error handling