Skip to content

Multi-Device Linking and Rotation

Overview

VeliKey Messenger supports secure multi-device synchronization with independent per-device mailboxes and coordinated rotation cadence. This architecture ensures message delivery across all linked devices while maintaining privacy and security.

Architecture

Mailbox Design

Each user account maintains multiple mailboxes:

  1. Per-Device Mailboxes: Each linked device has its own ERAC mailbox for receiving messages
  2. Sync Mailbox: A shared mailbox for sent messages and read states across devices
  3. Rotation Coordination: Receiver-initiated CAS (Compare-And-Swap) rotation with jitter
graph LR
    A[Sender] --> B[Device 1 Mailbox]
    A --> C[Device 2 Mailbox]
    D[Device 1] --> E[Sync Mailbox]
    F[Device 2] --> E

Recovery Codes

Recovery codes enable secure device linking without exposing cryptographic material.

Format

  • 6 groups of 4 alphanumeric characters
  • Example: XXXX-XXXX-XXXX-XXXX-XXXX-XXXX
  • 24-hour expiration
  • Single-use only

Security Properties

  • Cryptographically random generation
  • Time-limited validity
  • Automatic invalidation after use
  • No key material transmission

Device Linking Flow

Primary Device (Initiator)

// Generate recovery code
const manager = new MultiDeviceManager();
const code = manager.generateRecoveryCode();
// Display code to user: "ABCD-1234-WXYZ-5678-MNOP-9012"

Secondary Device (Joiner)

// User enters recovery code
const manager = new MultiDeviceManager();
const device = manager.linkDevice(code, {
  deviceId: generateDeviceId(),
  deviceName: 'iPhone 15 Pro',
  publicKey: devicePublicKey,
  attestation: attestationData
});

// Set up mailboxes
manager.setDeviceMailbox(device.deviceId, newMailboxId);
manager.setSyncMailbox(sharedSyncMailboxId);

Rotation Management

CAS Rotation Protocol

The Compare-And-Swap rotation ensures only one device successfully rotates at a time:

type CASRotateRequest struct {
    MboxIDOld string // Current mailbox ID
    FromSeq   uint64 // Expected sequence number
    RCap      string // New redirect capsule
}

Rotation Cadence

Devices coordinate rotation using jittered intervals:

const rotationManager = new RotationManager({
  baseIntervalMs: 6 * 60 * 60 * 1000, // 6 hours
  jitterRatio: 0.2,                    // ±20% randomization
  messageThreshold: 100,               // Rotate after 100 messages
  minIntervalMs: 60 * 60 * 1000       // Minimum 1 hour between rotations
});

// Automatic rotation on app open
rotationManager.onAppOpen();

// Track message fetches
rotationManager.onMessagesFetched(messageCount);

Epoch Overlap

During rotation, both old and new epochs remain valid for a grace period:

  • Overlap Duration: 5 minutes default
  • Purpose: Handle in-flight messages during rotation
  • Cleanup: Old epoch expires after grace period

Message Routing

Incoming Messages

  1. Sender encrypts message for recipient
  2. Sender deposits to all recipient's device mailboxes
  3. Each device fetches from its own mailbox
  4. No cross-device mailbox access

Sent Messages

  1. Sending device encrypts message
  2. Copy deposited to sync mailbox
  3. All devices fetch from sync mailbox
  4. Sent messages visible across devices

Read States

  1. Device marks message as read
  2. Read state deposited to sync mailbox
  3. Other devices fetch and update UI

Security Considerations

Mailbox Independence

  • Each device mailbox uses unique keys
  • Compromise of one device doesn't affect others
  • Device revocation removes only its mailbox

Rotation Race Conditions

  • CAS ensures single winner in concurrent rotations
  • Sequence numbers prevent replay attacks
  • Exponential backoff on conflicts

Forward Secrecy

  • Regular rotation limits exposure window
  • Old keys deleted after epoch expiry
  • No long-term key material retention

Implementation

JavaScript/TypeScript SDK

import { MultiDeviceManager } from 'velikey-js-sdk';

const manager = new MultiDeviceManager();

// Generate recovery code for new device
const code = manager.generateRecoveryCode();

// Link device
const device = manager.linkDevice(code, request);

// Manage mailboxes
manager.setDeviceMailbox(deviceId, mailboxId);
manager.setSyncMailbox(syncMailboxId);

// Export/import state
const state = manager.exportState();
manager.importState(state);

iOS SDK (Swift)

import Aegis

let manager = MultiDeviceManager()

// Generate recovery code
let code = manager.generateRecoveryCode()

// Link device
if let device = manager.linkDevice(code: code, request: request) {
    // Success
}

// Secure persistence
try manager.saveToKeychain()
try manager.loadFromKeychain()

Android SDK (Kotlin)

import io.velikey.aegis.multidevice.MultiDeviceManager

val manager = MultiDeviceManager(context)

// Generate recovery code
val code = manager.generateRecoveryCode()

// Link device
val device = manager.linkDevice(code, request)

// Secure persistence
manager.saveToPreferences()
manager.loadFromPreferences()

Testing

Unit Tests

  • Recovery code generation and validation
  • Device linking and unlinking
  • Mailbox management
  • State persistence

Integration Tests

  • Cross-device message delivery
  • Rotation coordination
  • Conflict resolution
  • Network failure handling

E2E Tests

  • Full multi-device flow
  • Rotation race conditions
  • Message synchronization
  • Device revocation

Monitoring

Metrics

Monitor rotation health via spool metrics endpoint:

curl http://spool-service/v1/metrics

# HELP spool_rotate_success_total Successful CAS rotations
# TYPE spool_rotate_success_total counter
spool_rotate_success_total 1523

# HELP spool_rotate_conflict_total CAS rotation conflicts
# TYPE spool_rotate_conflict_total counter
spool_rotate_conflict_total 12

Console Dashboard

The Aegis Console provides real-time rotation metrics:

  • Success/conflict counts
  • Time-series visualization
  • Per-mailbox status inspector (dev mode)

Troubleshooting

Common Issues

  1. Recovery Code Invalid
  2. Check expiration (24 hours)
  3. Verify not already used
  4. Ensure correct entry

  5. Rotation Conflicts

  6. Normal during simultaneous device use
  7. Automatic retry with backoff
  8. Check rotation metrics

  9. Message Not Syncing

  10. Verify sync mailbox configuration
  11. Check network connectivity
  12. Review device linking status

Debug Tools

# Check mailbox status
curl "http://spool/v1/rotate-status?mbox_id=<id>"

# View rotation metrics
curl http://spool/v1/metrics | grep rotate

# Inspect device state (iOS)
po manager.getLinkedDevices()

# Inspect device state (Android)
Log.d("Devices", manager.getLinkedDevices().toString())

Best Practices

  1. Recovery Code Handling
  2. Display clearly with proper formatting
  3. Provide copy functionality
  4. Clear from memory after use

  5. Rotation Timing

  6. Avoid rotation during active messaging
  7. Implement grace periods for in-flight messages
  8. Use jitter to prevent thundering herd

  9. Device Management

  10. Limit number of linked devices (e.g., 5)
  11. Implement device naming for user clarity
  12. Provide easy revocation interface

  13. Error Handling

  14. Graceful fallback on rotation failure
  15. Retry with exponential backoff
  16. Clear user feedback on issues