Migration Guide: Keychain Core 2.x to 3.0

Overview

Keychain Core 3.0 introduces significant architectural improvements focused on composable cryptography and decentralized identifiers (DIDs). This guide helps you migrate your applications from version 2.x to 3.0.

Breaking Changes

DID Implementation

Impact: Major breaking change affecting all identity-related code.

Change: The uri class has been replaced with DID (Decentralized Identifier) classes:

  • keychain_did - Individual keychain identifiers

  • persona_did - Combined encryption and signature DIDs for personas

Migration:

Version 2.x Version 3.0

uri persona_uri = persona.get_uri()

persona_did did = persona.get_did()

std::string uri_string = uri.serialize()

std::string did_string = did.serialize()

uri contact_uri = contact.get_uri()

persona_did contact_did = contact.get_did()

New Composable Cryptography Classes

Impact: Enhanced functionality, existing code continues to work but new patterns are recommended.

New Classes:

  • verifiable_data - Replaces basic signing operations

  • credential - W3C verifiable credentials

  • encrypted_data - Enhanced encryption with multi-recipient support

  • transaction - Consensus-based ledger operations

  • key_lock - Multi-recipient key management

Migration:

Version 2.x Version 3.0

std::string signature = gw.sign(data, persona)

verifiable_data signed = gw.sign(data, persona)

bool valid = gw.verify(signature, contact)

verification_result result = signed.verify(gw)

std::string encrypted = gw.encrypt(data, contact)

encrypted_data encrypted = gw.encrypt(data, contact)

Database Schema Changes

Impact: Requires manual database migration.

Change: Database schema version updated to 3.0 with new tables for DIDs and composable objects.

Migration: Run the migration tool included in the 3.0 package:

# Backup your existing database first
cp ~/.local/share/keychain/cache/keychain.db ~/.local/share/keychain/cache/keychain.db.backup

# Run migration utility
~/.local/share/keychain/validation/migrate-to-3.0.sh

Serialization Format Changes

Impact: Affects data interchange and storage.

Change:

  • XML format deprecated (still supported for reading legacy data)

  • Protocol Buffer binary format is now default

  • JSON format coming in future releases

Migration:

// Version 2.x
std::string xml_data = object.serialize_xml();

// Version 3.0 - Protocol Buffers (default)
std::string pb_data = object.serialize();

// For legacy compatibility, read XML data:
if (is_xml_format(legacy_data)) {
    object = MyClass(legacy_data); // Constructor handles XML parsing
}

New Features in 3.0

Multiple Signatures

Attach multiple signatures to any verifiable object:

// Create document with multiple signers
verifiable_data contract("Partnership agreement terms...");

// First party signs
verifiable_data signed_once = gw.sign(contract, partner1);

// Second party adds their signature
verifiable_data signed_twice = gw.sign(signed_once, partner2);

// Verify all signatures
verification_result result = signed_twice.verify(gw);
auto attestations = signed_twice.get_attestations();
std::cout << "Signatures: " << attestations.size() << std::endl;

Enhanced Encryption

Support for multiple recipients without re-encryption:

// Encrypt for initial recipient
encrypted_data confidential = gw.encrypt("Secret data", alice);

// Add additional recipients later
key_lock bob_access = gw.create_key_lock_for(confidential, bob);
confidential.attach_key_lock(bob_access);

key_lock charlie_access = gw.create_key_lock_for(confidential, charlie);
confidential.attach_key_lock(charlie_access);

// All three can now decrypt the same data

W3C Verifiable Credentials

Create standards-compliant digital credentials:

// Create university degree credential
credential degree;
degree.set_id("https://university.edu/credentials/123");
degree.set_type("UniversityDegreeCredential");
degree.set_issuer("did:keychain:university_registrar");
degree.set_subject("did:keychain:student_alice");

// Set validity period
uint64_t now = time(nullptr);
degree.set_valid_from(now);
degree.set_valid_until(now + (4 * 365 * 24 * 60 * 60)); // 4 years

// Add degree claims
tag_set claims;
claims.set("degree", "Bachelor of Science");
claims.set("major", "Computer Science");
claims.set("gpa", "3.85");
degree.set_claims(claims);

// Sign by university
verifiable_data signed_degree = gw.sign(degree, university_persona);

Cryptographic Composability

Combine operations in any order:

std::string document = "Confidential legal document";

// Pattern 1: Sign then encrypt
verifiable_data signed = gw.sign(document, lawyer_persona);
encrypted_data signed_then_encrypted = gw.encrypt(signed.serialize(), client_persona);

// Pattern 2: Encrypt then sign
encrypted_data encrypted = gw.encrypt(document, client_persona);
verifiable_data encrypted_then_signed = gw.sign(encrypted.serialize(), lawyer_persona);

// Pattern 3: Multiple signatures on encrypted data
encrypted_data multi_access = gw.encrypt(document, party1);
key_lock party2_lock = gw.create_key_lock_for(multi_access, party2);
multi_access.attach_key_lock(party2_lock);
verifiable_data multi_signed = gw.sign(multi_access.serialize(), witness_persona);

Flexible Security Levels

Explicit control over cryptographic algorithms:

// Create persona with specific security requirements
persona high_security = gw.create_persona(
    "secure_identity",
    security_level::HIGH,  // 256-bit keys
    encryption_scheme::ECIES_SECP256R1,
    signature_scheme::ECDSA_SECP256R1
);

// Create low-overhead persona for IoT devices
persona iot_device = gw.create_persona(
    "sensor_node",
    security_level::LOW,   // 128-bit keys
    encryption_scheme::ECIES_SECP160R1,
    signature_scheme::ECDSA_SECP160R1
);

Migration Checklist

Pre-Migration

  • Backup your existing database: ~/.local/share/keychain/cache/keychain.db

  • Backup your existing personas and contacts

  • Document current URI usage in your application

  • Test migration on a development environment first

During Migration

  • Install Keychain Core 3.0

  • Run database migration utility

  • Update application code to use DIDs instead of URIs

  • Replace basic signing with verifiable_data objects

  • Update encryption code to use encrypted_data objects

  • Test persona and contact operations

Post-Migration

  • Verify all personas are accessible

  • Test cryptographic operations (sign, encrypt, verify, decrypt)

  • Confirm contact relationships are preserved

  • Update any stored serialized data to new format

  • Performance test with new composable operations

API Changes Summary

Component Version 2.x Version 3.0

Identity

uri class

keychain_did, persona_did classes

Signing

gateway.sign() returns string

gateway.sign() returns verifiable_data

Encryption

gateway.encrypt() returns string

gateway.encrypt() returns encrypted_data

Verification

gateway.verify() returns bool

object.verify() returns verification_result

Serialization

XML default

Protocol Buffers default

Multiple signatures

Not supported

Supported via attestations

Multi-recipient encryption

Requires re-encryption

Dynamic via key locks

Common Issues

Database Migration Failures

If migration fails:

  1. Restore from backup

  2. Check disk space and permissions

  3. Ensure no other processes are using the database

  4. Run migration with verbose logging:

~/.local/share/keychain/validation/migrate-to-3.0.sh --verbose

DID Resolution Issues

If personas/contacts become inaccessible:

  1. Check if DID format is correct

  2. Verify cache database integrity

  3. Re-sync with PKI if necessary:

gateway gw;
gw.start_monitor(); // Re-sync with PKI

Performance Concerns

If operations seem slower:

  1. Use Protocol Buffer serialization (default)

  2. Consider security level requirements

  3. Cache verifiable objects when possible

  4. Use detached attestations for signature exchange

Getting Help

  • Check the Error Codes reference for specific error meanings

  • Review example code in /usr/local/share/keychain/examples/

  • Post questions on the community forum with migration logs

See Also