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);
}

kc_persona_did_destruct()

int kc_persona_did_destruct(kc_persona_did_t** persona_did_ptr)

Destructs a persona DID object and frees its resources.

Parameters:

  • persona_did_ptr - Pointer to persona DID pointer (set to NULL on success)

Returns: Error code (0 = success)

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