DID Class
Overview
The DID
class implements W3C Decentralized Identifiers (DIDs) as defined in the W3C DID specification. DIDs are a standardized way to identify entities in a decentralized manner, consisting of three components: scheme, method, and method-specific identifier.
Package: keychain.identity.did
from keychain.identity.did import DID
Constructor
def __init__(
self,
did_string: Optional[str] = None,
c_pointer: Optional[ctypes.c_void_p] = None,
) -> None
Initialize a DID object from a DID string or C pointer.
Parameters:
-
did_string
(str
, optional) - DID string to parse (e.g., "did:method:identifier") -
c_pointer
(ctypes.c_void_p
, optional) - Existing C pointer to wrap
Example:
# Create from DID string
did = DID("did:example:123456789abcdefghi")
# Create empty DID
empty_did = DID()
# Create from existing C pointer (typically from library functions)
did = DID(c_pointer=existing_pointer)
Properties
Methods
copy()
def copy(self) -> "DID"
Create a deep copy of this DID.
Returns: New DID
object that is a deep copy
Example:
original_did = DID("did:example:123456")
copied_did = original_did.copy()
serialize()
def serialize(self) -> bytes
Serialize the DID to bytes as defined in the W3C specification.
Returns: The DID serialized as UTF-8 encoded bytes
Example:
did = DID("did:example:123456")
serialized = did.serialize()
# Returns: b"did:example:123456"
is_null()
def is_null(self) -> bool
Check if this is a null DID.
Returns: True
if this is a null/empty DID, False
otherwise
parse_components()
def parse_components(self) -> Tuple[str, str, str]
Parse the DID into its component parts.
Returns: A tuple of (scheme, method, method_specific_id)
Example:
did = DID("did:example:123456")
scheme, method, method_id = did.parse_components()
print(f"Scheme: {scheme}, Method: {method}, ID: {method_id}")
# Output: Scheme: did, Method: example, ID: 123456
Class Methods
from_components(method, method_specific_id, scheme="did")
@classmethod
def from_components(
cls, method: str, method_specific_id: str, scheme: str = "did"
) -> "DID"
Create a DID from its component parts.
Parameters:
-
method
(str
) - The DID method -
method_specific_id
(str
) - The method-specific identifier -
scheme
(str
) - The DID scheme (defaults to "did")
Returns: New DID
object constructed from the components
Example:
did = DID.from_components("example", "123456789abcdefghi")
print(str(did)) # Output: did:example:123456789abcdefghi
Comparison Methods
Example: Working with DIDs
from keychain.identity.did import DID
# Create DIDs from strings
did1 = DID("did:example:123456789abcdefghi")
did2 = DID("did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK")
# Create DID from components
did3 = DID.from_components("web", "example.com")
print(f"DID 1: {did1}")
print(f"DID 2: {did2}")
print(f"DID 3: {did3}")
# Parse DID components
scheme, method, method_id = did1.parse_components()
print(f"Scheme: {scheme}")
print(f"Method: {method}")
print(f"Method-specific ID: {method_id}")
# Check individual components
print(f"DID 1 scheme: {did1.scheme}")
print(f"DID 1 method: {did1.method}")
print(f"DID 1 method-specific ID: {did1.method_specific_id}")
# Compare DIDs
if did1 == did2:
print("DIDs are equal")
else:
print("DIDs are different")
# Copy DIDs
copied_did = did1.copy()
if did1 == copied_did:
print("Original and copy are equal")
# Check if DID is null
empty_did = DID()
if empty_did.is_null():
print("Empty DID is null")
# Serialize DID
serialized = did1.serialize()
print(f"Serialized: {serialized}")
# Recreate from serialized data
reconstructed = DID(serialized.decode('utf-8'))
if did1 == reconstructed:
print("Serialization and deserialization successful")
Example: DID Validation and Parsing
from keychain.identity.did import DID
def validate_and_parse_did(did_string: str) -> dict:
"""Validate and parse a DID string."""
try:
did = DID(did_string)
if did.is_null():
return {
"valid": False,
"error": "DID is null or empty"
}
# Parse components
scheme, method, method_id = did.parse_components()
# Basic validation
if scheme != "did":
return {
"valid": False,
"error": f"Invalid scheme: {scheme} (expected 'did')"
}
if not method:
return {
"valid": False,
"error": "Missing DID method"
}
if not method_id:
return {
"valid": False,
"error": "Missing method-specific identifier"
}
return {
"valid": True,
"scheme": scheme,
"method": method,
"method_specific_id": method_id,
"serialized": did.serialize().decode('utf-8')
}
except Exception as e:
return {
"valid": False,
"error": f"Failed to parse DID: {str(e)}"
}
# Test DID validation
test_dids = [
"did:example:123456789abcdefghi",
"did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"did:web:example.com",
"not:a:valid:did",
"",
"did:method:",
"did::missing_method"
]
for did_string in test_dids:
result = validate_and_parse_did(did_string)
print(f"\nDID: {did_string}")
print(f"Valid: {result['valid']}")
if result['valid']:
print(f" Scheme: {result['scheme']}")
print(f" Method: {result['method']}")
print(f" Method-specific ID: {result['method_specific_id']}")
print(f" Serialized: {result['serialized']}")
else:
print(f" Error: {result['error']}")
Example: DID Registry and Management
from keychain.identity.did import DID
from typing import Dict, List, Optional
class DIDRegistry:
"""Simple DID registry for managing DIDs."""
def __init__(self):
self._dids: Dict[str, DID] = {}
self._aliases: Dict[str, str] = {}
def register_did(self, did: DID, alias: Optional[str] = None) -> str:
"""Register a DID in the registry."""
did_string = str(did)
self._dids[did_string] = did.copy()
if alias:
self._aliases[alias] = did_string
return did_string
def lookup_did(self, identifier: str) -> Optional[DID]:
"""Look up a DID by string or alias."""
# Check if it's an alias
if identifier in self._aliases:
identifier = self._aliases[identifier]
# Look up by DID string
if identifier in self._dids:
return self._dids[identifier].copy()
return None
def list_dids(self, method_filter: Optional[str] = None) -> List[DID]:
"""List all registered DIDs, optionally filtered by method."""
dids = []
for did in self._dids.values():
if method_filter is None or did.method == method_filter:
dids.append(did.copy())
return dids
def get_methods(self) -> List[str]:
"""Get all unique methods in the registry."""
methods = set()
for did in self._dids.values():
methods.add(did.method)
return sorted(list(methods))
def remove_did(self, identifier: str) -> bool:
"""Remove a DID from the registry."""
# Check if it's an alias
if identifier in self._aliases:
did_string = self._aliases[identifier]
del self._aliases[identifier]
identifier = did_string
# Remove by DID string
if identifier in self._dids:
del self._dids[identifier]
return True
return False
# Usage example
def did_registry_example():
"""Demonstrate DID registry usage."""
registry = DIDRegistry()
# Create and register some DIDs
example_did = DID("did:example:123456789abcdefghi")
key_did = DID("did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK")
web_did = DID("did:web:example.com")
# Register DIDs with aliases
registry.register_did(example_did, "alice")
registry.register_did(key_did, "bob")
registry.register_did(web_did, "company")
print("=== DID Registry Demo ===")
# List all DIDs
all_dids = registry.list_dids()
print(f"Total DIDs registered: {len(all_dids)}")
# List DIDs by method
for method in registry.get_methods():
method_dids = registry.list_dids(method_filter=method)
print(f"Method '{method}': {len(method_dids)} DIDs")
# Look up DIDs
alice_did = registry.lookup_did("alice")
if alice_did:
print(f"Alice's DID: {alice_did}")
# Look up by DID string
looked_up = registry.lookup_did(str(key_did))
if looked_up and looked_up == key_did:
print("DID lookup by string successful")
# Remove a DID
if registry.remove_did("company"):
print("Company DID removed")
print(f"DIDs remaining: {len(registry.list_dids())}")
if __name__ == "__main__":
did_registry_example()
Error Handling
DID operations can raise various exceptions:
Example:
from keychain.exceptions import KeychainValidationError
try:
# Create DID from string
did = DID("did:example:123456")
# Access properties
scheme = did.scheme
method = did.method
method_id = did.method_specific_id
# Serialize DID
serialized = did.serialize()
# Compare DIDs
other_did = DID("did:example:654321")
are_equal = (did == other_did)
except KeychainValidationError as e:
print(f"Validation error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
See Also
-
KeychainDID Class - Keychain-specific DIDs
-
PersonaDID Class - Persona DIDs
-
Persona Class - DID usage in personas
-
Contact Class - DID usage in contacts
-
Exception Classes - Error handling
-
W3C DID Core Specification - Official W3C specification