Persona DID Functions
#include <keychain/keychain_headers.h>
Overview
Persona DID functions work with persona-specific DIDs that combine two keychain DIDs since personas track two keychains - one for encryption and one for signature operations. The persona’s DID combines two keychain DIDs, providing a unified identifier that encompasses both cryptographic capabilities.
This inherits from basic DID functionality which implements W3C Decentralized Identifiers (DIDs) specification.
Object Lifecycle Functions
kc_persona_did_construct()
int kc_persona_did_construct(kc_persona_did_t** out_persona_did_ptr)
Creates an empty persona DID object.
Parameters:
-
out_persona_did_ptr
- Pointer to persona DID pointer (output, caller must free)
Returns: Error code (0 = success)
Example:
kc_persona_did_t* persona_did = NULL;
int result = kc_persona_did_construct(&persona_did);
if (result == 0) {
// Use empty persona DID...
kc_persona_did_destruct(&persona_did);
}
kc_persona_did_construct_from_serialized_string()
int kc_persona_did_construct_from_serialized_string(
kc_persona_did_t** out_persona_did_ptr,
const char* serialized_string,
const unsigned int serialized_string_size
)
Deserializes a persona DID from a string representation in W3C DID format.
Parameters:
-
out_persona_did_ptr
- Pointer to persona DID pointer (output, caller must free) -
serialized_string
- DID string in W3C DID format -
serialized_string_size
- Number of bytes in the serialized string
Returns: Error code (0 = success)
Example:
kc_persona_did_t* persona_did = NULL;
const char* did_string = "did:keychain:mainnet:alice.company.com";
int result = kc_persona_did_construct_from_serialized_string(&persona_did,
did_string, strlen(did_string));
if (result == 0) {
// Use persona DID...
kc_persona_did_destruct(&persona_did);
}
kc_persona_did_construct_from_keychain_did()
int kc_persona_did_construct_from_keychain_did(
kc_persona_did_t** out_persona_did_ptr,
const kc_keychain_did_t* encr_did,
const kc_keychain_did_t* sign_did
)
Creates a persona DID from two keychain DIDs (encryption and signature).
Parameters:
-
out_persona_did_ptr
- Pointer to persona DID pointer (output, caller must free) -
encr_did
- Encryption keychain DID -
sign_did
- Signature keychain DID
Returns: Error code (0 = success)
Example:
kc_keychain_did_t* encr_did = NULL;
kc_keychain_did_t* sign_did = NULL;
kc_persona_did_t* persona_did = NULL;
// ... create encr_did and sign_did ...
int result = kc_persona_did_construct_from_keychain_did(&persona_did,
encr_did, sign_did);
if (result == 0) {
// Use persona DID composed of both keychain DIDs...
kc_persona_did_destruct(&persona_did);
}
kc_persona_did_construct_from_copy()
int kc_persona_did_construct_from_copy(
kc_persona_did_t** out_persona_did_ptr,
const kc_persona_did_t* rhs_persona_did_ptr
)
Creates a deep copy of a persona DID object.
Parameters:
-
out_persona_did_ptr
- Pointer to new persona DID pointer (output, caller must free) -
rhs_persona_did_ptr
- Persona DID object to copy
Returns: Error code (0 = success)
Example:
kc_persona_did_t* original_did = NULL;
kc_persona_did_t* copied_did = NULL;
// ... create original_did ...
int result = kc_persona_did_construct_from_copy(&copied_did, original_did);
if (result == 0) {
// Use copied persona DID...
kc_persona_did_destruct(&copied_did);
}
Keychain DID Access Functions
kc_persona_did_encr_keychain_did()
int kc_persona_did_encr_keychain_did(
const kc_persona_did_t* persona_did_ptr,
kc_keychain_did_t** out_encr_keychain_did
)
Gets the encryption keychain DID from the persona DID.
Parameters:
-
persona_did_ptr
- Persona DID object to query -
out_encr_keychain_did
- Pointer to encryption keychain DID pointer (output, caller must free)
Returns: Error code (0 = success)
Example:
kc_keychain_did_t* encr_did = NULL;
int result = kc_persona_did_encr_keychain_did(persona_did, &encr_did);
if (result == 0) {
// Use encryption keychain DID...
char* network = NULL;
unsigned int network_size = 0;
kc_keychain_did_network(encr_did, &network, &network_size);
printf("Encryption network: %.*s\n", network_size, network ? network : "Unknown");
if (network) kc_common_delete_buffer(&network);
kc_keychain_did_destruct(&encr_did);
}
kc_persona_did_sign_keychain_did()
int kc_persona_did_sign_keychain_did(
const kc_persona_did_t* persona_did_ptr,
kc_keychain_did_t** out_sign_keychain_did
)
Gets the signature keychain DID from the persona DID.
Parameters:
-
persona_did_ptr
- Persona DID object to query -
out_sign_keychain_did
- Pointer to signature keychain DID pointer (output, caller must free)
Returns: Error code (0 = success)
Example:
kc_keychain_did_t* sign_did = NULL;
int result = kc_persona_did_sign_keychain_did(persona_did, &sign_did);
if (result == 0) {
// Use signature keychain DID...
char* nsid = NULL;
unsigned int nsid_size = 0;
kc_keychain_did_network_specific_id(sign_did, &nsid, &nsid_size);
printf("Signature entity: %.*s\n", nsid_size, nsid ? nsid : "Unknown");
if (nsid) kc_common_delete_buffer(&nsid);
kc_keychain_did_destruct(&sign_did);
}
Standard DID Component Access Functions
kc_persona_did_scheme()
int kc_persona_did_scheme(
const kc_persona_did_t* persona_did_ptr,
char** out_scheme,
unsigned int* out_size
)
Gets the DID scheme (always "did" for valid DIDs).
Parameters:
-
persona_did_ptr
- Persona DID object to query -
out_scheme
- Pointer to scheme string pointer (output, caller must free) -
out_size
- Pointer to scheme string size (output)
Returns: Error code (0 = success)
kc_persona_did_method()
int kc_persona_did_method(
const kc_persona_did_t* persona_did_ptr,
char** out_method,
unsigned int* out_size
)
Gets the DID method (typically "keychain" for persona DIDs).
Parameters:
-
persona_did_ptr
- Persona DID object to query -
out_method
- Pointer to method string pointer (output, caller must free) -
out_size
- Pointer to method string size (output)
Returns: Error code (0 = success)
kc_persona_did_id()
int kc_persona_did_id(
const kc_persona_did_t* persona_did_ptr,
char** out_id,
unsigned int* out_size
)
Gets the method-specific identifier portion of the DID.
Parameters:
-
persona_did_ptr
- Persona DID object to query -
out_id
- Pointer to ID string pointer (output, caller must free) -
out_size
- Pointer to ID string size (output)
Returns: Error code (0 = success)
Serialization Functions
kc_persona_did_serialize()
int kc_persona_did_serialize(
const kc_persona_did_t* persona_did_ptr,
char** out_serialized_str,
unsigned int* out_size
)
Serializes the persona DID to a string as defined in the W3C specification.
Parameters:
-
persona_did_ptr
- Persona DID object to serialize -
out_serialized_str
- Pointer to serialized string pointer (output, caller must free) -
out_size
- Pointer to string size (output)
Returns: Error code (0 = success)
Example:
char* serialized = NULL;
unsigned int serialized_size = 0;
int result = kc_persona_did_serialize(persona_did, &serialized, &serialized_size);
if (result == 0) {
printf("Serialized persona DID: %.*s\n", serialized_size, serialized);
kc_common_delete_buffer(&serialized);
}
Metadata Functions
kc_persona_did_data_type()
int kc_persona_did_data_type(
const kc_persona_did_t* persona_did_ptr,
unsigned int* out_data_type
)
Gets the data type value indicating this is a persona DID.
Parameters:
-
persona_did_ptr
- Persona DID object to query -
out_data_type
- Pointer to data type value (output)
Returns: Error code (0 = success)
Query Functions
kc_persona_did_equals()
int kc_persona_did_equals(
const kc_persona_did_t* lhs_persona_did_ptr,
bool* out_is_equal,
const kc_persona_did_t* rhs_persona_did_ptr
)
Tests equality of two persona DID objects.
Parameters:
-
lhs_persona_did_ptr
- First persona DID to compare -
out_is_equal
- Pointer to equality result (output) -
rhs_persona_did_ptr
- Second persona DID to compare
Returns: Error code (0 = success)
Example: Persona DID Analysis and Construction
void demonstrate_persona_did_construction() {
// Create keychain DIDs for encryption and signature
kc_keychain_did_t* encr_did = NULL;
kc_keychain_did_t* sign_did = NULL;
const char* encr_did_str = "did:keychain:mainnet:alice.encryption.company.com";
const char* sign_did_str = "did:keychain:mainnet:alice.signature.company.com";
int result1 = kc_keychain_did_construct_from_serialized_string(&encr_did,
encr_did_str, strlen(encr_did_str));
int result2 = kc_keychain_did_construct_from_serialized_string(&sign_did,
sign_did_str, strlen(sign_did_str));
if (result1 != 0 || result2 != 0) {
printf("Failed to create keychain DIDs\n");
if (encr_did) kc_keychain_did_destruct(&encr_did);
if (sign_did) kc_keychain_did_destruct(&sign_did);
return;
}
// Create persona DID from keychain DIDs
kc_persona_did_t* persona_did = NULL;
int result = kc_persona_did_construct_from_keychain_did(&persona_did,
encr_did, sign_did);
if (result == 0) {
printf("Persona DID created successfully\n");
// Analyze the persona DID
char* scheme = NULL;
char* method = NULL;
char* id = NULL;
unsigned int scheme_size, method_size, id_size;
kc_persona_did_scheme(persona_did, &scheme, &scheme_size);
kc_persona_did_method(persona_did, &method, &method_size);
kc_persona_did_id(persona_did, &id, &id_size);
printf("\nPersona DID Components:\n");
printf(" Scheme: %.*s\n", scheme_size, scheme ? scheme : "Unknown");
printf(" Method: %.*s\n", method_size, method ? method : "Unknown");
printf(" ID: %.*s\n", id_size, id ? id : "Unknown");
// Get constituent keychain DIDs
kc_keychain_did_t* retrieved_encr = NULL;
kc_keychain_did_t* retrieved_sign = NULL;
kc_persona_did_encr_keychain_did(persona_did, &retrieved_encr);
kc_persona_did_sign_keychain_did(persona_did, &retrieved_sign);
if (retrieved_encr && retrieved_sign) {
printf("\nConstituent Keychain DIDs:\n");
char* encr_serialized = NULL;
char* sign_serialized = NULL;
unsigned int encr_size, sign_size;
kc_keychain_did_serialize(retrieved_encr, &encr_serialized, &encr_size);
kc_keychain_did_serialize(retrieved_sign, &sign_serialized, &sign_size);
printf(" Encryption: %.*s\n", encr_size, encr_serialized ? encr_serialized : "Unknown");
printf(" Signature: %.*s\n", sign_size, sign_serialized ? sign_serialized : "Unknown");
if (encr_serialized) kc_common_delete_buffer(&encr_serialized);
if (sign_serialized) kc_common_delete_buffer(&sign_serialized);
kc_keychain_did_destruct(&retrieved_encr);
kc_keychain_did_destruct(&retrieved_sign);
}
// Test serialization
char* persona_serialized = NULL;
unsigned int persona_size = 0;
result = kc_persona_did_serialize(persona_did, &persona_serialized, &persona_size);
if (result == 0) {
printf("\nSerialized Persona DID: %.*s\n", persona_size, persona_serialized);
kc_common_delete_buffer(&persona_serialized);
}
// Cleanup
if (scheme) kc_common_delete_buffer(&scheme);
if (method) kc_common_delete_buffer(&method);
if (id) kc_common_delete_buffer(&id);
kc_persona_did_destruct(&persona_did);
} else {
printf("Failed to create persona DID: %d\n", result);
}
kc_keychain_did_destruct(&encr_did);
kc_keychain_did_destruct(&sign_did);
}
Example: Persona DID Validation and Network Consistency
bool validate_persona_did_consistency(kc_persona_did_t* persona_did) {
// Get both keychain DIDs
kc_keychain_did_t* encr_did = NULL;
kc_keychain_did_t* sign_did = NULL;
int result1 = kc_persona_did_encr_keychain_did(persona_did, &encr_did);
int result2 = kc_persona_did_sign_keychain_did(persona_did, &sign_did);
if (result1 != 0 || result2 != 0) {
printf("Failed to retrieve keychain DIDs from persona DID\n");
if (encr_did) kc_keychain_did_destruct(&encr_did);
if (sign_did) kc_keychain_did_destruct(&sign_did);
return false;
}
bool is_consistent = true;
// Check that both DIDs are on the same network
char* encr_network = NULL;
char* sign_network = NULL;
unsigned int encr_net_size, sign_net_size;
kc_keychain_did_network(encr_did, &encr_network, &encr_net_size);
kc_keychain_did_network(sign_did, &sign_network, &sign_net_size);
if (!encr_network || !sign_network ||
encr_net_size != sign_net_size ||
memcmp(encr_network, sign_network, encr_net_size) != 0) {
printf("✗ Network mismatch between encryption and signature DIDs\n");
printf(" Encryption network: %.*s\n", encr_net_size, encr_network ? encr_network : "Unknown");
printf(" Signature network: %.*s\n", sign_net_size, sign_network ? sign_network : "Unknown");
is_consistent = false;
} else {
printf("✓ Networks match: %.*s\n", encr_net_size, encr_network);
}
// Check that both DIDs have the same keychain type
unsigned int encr_type, sign_type;
int type_result1 = kc_keychain_did_keychain_type(encr_did, &encr_type);
int type_result2 = kc_keychain_did_keychain_type(sign_did, &sign_type);
if (type_result1 == 0 && type_result2 == 0) {
if (encr_type != sign_type) {
printf("✗ Keychain type mismatch\n");
printf(" Encryption type: %u\n", encr_type);
printf(" Signature type: %u\n", sign_type);
is_consistent = false;
} else {
printf("✓ Keychain types match: %u\n", encr_type);
}
}
// Check network-specific IDs for related entities
char* encr_nsid = NULL;
char* sign_nsid = NULL;
unsigned int encr_nsid_size, sign_nsid_size;
kc_keychain_did_network_specific_id(encr_did, &encr_nsid, &encr_nsid_size);
kc_keychain_did_network_specific_id(sign_did, &sign_nsid, &sign_nsid_size);
if (encr_nsid && sign_nsid) {
printf("Network-specific IDs:\n");
printf(" Encryption: %.*s\n", encr_nsid_size, encr_nsid);
printf(" Signature: %.*s\n", sign_nsid_size, sign_nsid);
// Check if they belong to the same entity (basic heuristic)
// This is a simple check - in practice, you might have more sophisticated rules
if (encr_nsid_size > 10 && sign_nsid_size > 10) {
// Compare first part before any subdomain indicators
const char* encr_dot = memchr(encr_nsid, '.', encr_nsid_size);
const char* sign_dot = memchr(sign_nsid, '.', sign_nsid_size);
if (encr_dot && sign_dot) {
size_t encr_prefix = encr_dot - encr_nsid;
size_t sign_prefix = sign_dot - sign_nsid;
if (encr_prefix == sign_prefix &&
memcmp(encr_nsid, sign_nsid, encr_prefix) == 0) {
printf("✓ Network-specific IDs appear to belong to same entity\n");
} else {
printf("⚠ Network-specific IDs may belong to different entities\n");
}
}
}
}
// Cleanup
if (encr_network) kc_common_delete_buffer(&encr_network);
if (sign_network) kc_common_delete_buffer(&sign_network);
if (encr_nsid) kc_common_delete_buffer(&encr_nsid);
if (sign_nsid) kc_common_delete_buffer(&sign_nsid);
kc_keychain_did_destruct(&encr_did);
kc_keychain_did_destruct(&sign_did);
return is_consistent;
}
void demonstrate_persona_did_validation() {
// Test valid persona DID
kc_keychain_did_t* valid_encr = NULL;
kc_keychain_did_t* valid_sign = NULL;
kc_keychain_did_construct_from_serialized_string(&valid_encr,
"did:keychain:mainnet:alice.encryption.company.com", 45);
kc_keychain_did_construct_from_serialized_string(&valid_sign,
"did:keychain:mainnet:alice.signature.company.com", 44);
kc_persona_did_t* valid_persona = NULL;
kc_persona_did_construct_from_keychain_did(&valid_persona, valid_encr, valid_sign);
printf("=== Valid Persona DID ===\n");
validate_persona_did_consistency(valid_persona);
// Test inconsistent persona DID (different networks)
kc_keychain_did_t* invalid_encr = NULL;
kc_keychain_did_t* invalid_sign = NULL;
kc_keychain_did_construct_from_serialized_string(&invalid_encr,
"did:keychain:mainnet:alice.encryption.company.com", 45);
kc_keychain_did_construct_from_serialized_string(&invalid_sign,
"did:keychain:testnet:alice.signature.company.com", 44);
kc_persona_did_t* invalid_persona = NULL;
kc_persona_did_construct_from_keychain_did(&invalid_persona, invalid_encr, invalid_sign);
printf("\n=== Invalid Persona DID (Network Mismatch) ===\n");
validate_persona_did_consistency(invalid_persona);
// Cleanup
kc_keychain_did_destruct(&valid_encr);
kc_keychain_did_destruct(&valid_sign);
kc_keychain_did_destruct(&invalid_encr);
kc_keychain_did_destruct(&invalid_sign);
kc_persona_did_destruct(&valid_persona);
kc_persona_did_destruct(&invalid_persona);
}
Example: Persona DID Comparison and Management
void compare_persona_dids(kc_persona_did_t* did1, kc_persona_did_t* did2,
const char* label1, const char* label2) {
printf("Comparing %s vs %s:\n", label1, label2);
// Test equality
bool are_equal = false;
int result = kc_persona_did_equals(did1, &are_equal, did2);
if (result == 0) {
printf(" Equal: %s\n", are_equal ? "Yes" : "No");
} else {
printf(" Comparison failed: %d\n", result);
return;
}
if (!are_equal) {
// Show differences in constituent DIDs
kc_keychain_did_t* encr1 = NULL, *sign1 = NULL;
kc_keychain_did_t* encr2 = NULL, *sign2 = NULL;
kc_persona_did_encr_keychain_did(did1, &encr1);
kc_persona_did_sign_keychain_did(did1, &sign1);
kc_persona_did_encr_keychain_did(did2, &encr2);
kc_persona_did_sign_keychain_did(did2, &sign2);
// Compare encryption DIDs
bool encr_equal = false;
kc_keychain_did_equals(encr1, &encr_equal, encr2);
printf(" Encryption DIDs equal: %s\n", encr_equal ? "Yes" : "No");
// Compare signature DIDs
bool sign_equal = false;
kc_keychain_did_equals(sign1, &sign_equal, sign2);
printf(" Signature DIDs equal: %s\n", sign_equal ? "Yes" : "No");
// Show serialized forms for comparison
char* serial1 = NULL, *serial2 = NULL;
unsigned int size1, size2;
kc_persona_did_serialize(did1, &serial1, &size1);
kc_persona_did_serialize(did2, &serial2, &size2);
printf(" %s: %.*s\n", label1, size1, serial1 ? serial1 : "Unknown");
printf(" %s: %.*s\n", label2, size2, serial2 ? serial2 : "Unknown");
// Cleanup
if (encr1) kc_keychain_did_destruct(&encr1);
if (sign1) kc_keychain_did_destruct(&sign1);
if (encr2) kc_keychain_did_destruct(&encr2);
if (sign2) kc_keychain_did_destruct(&sign2);
if (serial1) kc_common_delete_buffer(&serial1);
if (serial2) kc_common_delete_buffer(&serial2);
}
printf("\n");
}
void demonstrate_persona_did_management() {
// Create several persona DIDs for testing
const char* alice_encr = "did:keychain:mainnet:alice.encr.company.com";
const char* alice_sign = "did:keychain:mainnet:alice.sign.company.com";
const char* bob_encr = "did:keychain:mainnet:bob.encr.company.com";
const char* bob_sign = "did:keychain:mainnet:bob.sign.company.com";
// Create Alice's persona DID (first time)
kc_keychain_did_t* alice_e1 = NULL, *alice_s1 = NULL;
kc_keychain_did_construct_from_serialized_string(&alice_e1, alice_encr, strlen(alice_encr));
kc_keychain_did_construct_from_serialized_string(&alice_s1, alice_sign, strlen(alice_sign));
kc_persona_did_t* alice_did1 = NULL;
kc_persona_did_construct_from_keychain_did(&alice_did1, alice_e1, alice_s1);
// Create Alice's persona DID (second time - should be identical)
kc_keychain_did_t* alice_e2 = NULL, *alice_s2 = NULL;
kc_keychain_did_construct_from_serialized_string(&alice_e2, alice_encr, strlen(alice_encr));
kc_keychain_did_construct_from_serialized_string(&alice_s2, alice_sign, strlen(alice_sign));
kc_persona_did_t* alice_did2 = NULL;
kc_persona_did_construct_from_keychain_did(&alice_did2, alice_e2, alice_s2);
// Create Bob's persona DID
kc_keychain_did_t* bob_e = NULL, *bob_s = NULL;
kc_keychain_did_construct_from_serialized_string(&bob_e, bob_encr, strlen(bob_encr));
kc_keychain_did_construct_from_serialized_string(&bob_s, bob_sign, strlen(bob_sign));
kc_persona_did_t* bob_did = NULL;
kc_persona_did_construct_from_keychain_did(&bob_did, bob_e, bob_s);
// Compare the DIDs
compare_persona_dids(alice_did1, alice_did2, "Alice (instance 1)", "Alice (instance 2)");
compare_persona_dids(alice_did1, bob_did, "Alice", "Bob");
// Test copy functionality
kc_persona_did_t* alice_copy = NULL;
kc_persona_did_construct_from_copy(&alice_copy, alice_did1);
compare_persona_dids(alice_did1, alice_copy, "Alice (original)", "Alice (copy)");
// Cleanup
kc_keychain_did_destruct(&alice_e1);
kc_keychain_did_destruct(&alice_s1);
kc_keychain_did_destruct(&alice_e2);
kc_keychain_did_destruct(&alice_s2);
kc_keychain_did_destruct(&bob_e);
kc_keychain_did_destruct(&bob_s);
kc_persona_did_destruct(&alice_did1);
kc_persona_did_destruct(&alice_did2);
kc_persona_did_destruct(&bob_did);
kc_persona_did_destruct(&alice_copy);
}
Memory Management
-
Use
kc_persona_did_destruct()
to free persona DID objects -
Use
kc_keychain_did_destruct()
for keychain DID objects returned by component access functions -
Use
kc_common_delete_buffer()
for string outputs (scheme, method, ID, serialized data) -
Always check return codes before using output parameters
-
Persona DIDs manage their constituent keychain DIDs internally
Best Practices
-
Ensure encryption and signature keychain DIDs are on the same network for consistency
-
Use matching keychain types for both constituent DIDs
-
Validate persona DID consistency before using in cryptographic operations
-
Store persona DIDs in their canonical string form for persistence
-
Use appropriate network configurations for different environments
-
Consider entity naming conventions when creating network-specific IDs
See Also
-
DID Functions - Basic DID functionality
-
Keychain DID Functions - Keychain-specific DIDs
-
Persona Functions - Using persona DIDs with personas
-
Contact Functions - Contact management with DIDs
-
C++ Persona DID Class - Object-oriented interface