Skip to main content

KeyRefresh with Reconcile Protocol

Overview

refresh rotates the keyshares of an existing key without changing its public key. Like keygen, it does not overwrite your active share directly: the newly rotated share is written to the staged slot, and a reconcile exchange with the cloud settles it before it replaces the current share.

The difference from keygen is that a refresh has a share to fall back to. The ReconcileStoreDao keeps the previous share in currentKeyshare while the new one sits in stagedKeyshare, so if the reconcile is interrupted or rejected, the key remains fully usable on the old share — nothing is lost, and a share captured before the refresh is useless afterward. This two-slot design is what makes the rotation crash-safe across all three parties, and your StorageClient is the source of truth the SDK reads back to decide how to finish.

Reconcile runs automatically as the final step of keygen, refresh, import, recover, and hardDerivation (hardDerivation is ECDSA-only) — you normally never call it yourself. TrioSession exposes reconcile(keyId:) async -> Result<Data, Error> only as a manual retry: if a prior operation crashed mid-reconcile, call it with the affected keyId to complete the protocol. The diagram below shows what the SDK does internally, including the rollback path when reconcile does not complete.

Outcomes

A refresh reconcile settles into one of three results:

  • Complete — the staged share landed; the SDK promotes it to current and clears staged.
  • Already applied — a prior interrupted attempt had already committed; the SDK confirms storage matches.
  • Rollback — the staged share is discarded and the previous current share is kept, so the key stays usable exactly as it was before the refresh.

Key Components

ComponentDescriptionInterface
StorageClientManages keyshare transactions/states and storage operationsStorageClientInterface app supposed to implement
Mobile SDKSilentShard SDK-
CloudCloud node-
Current KeyshareKeyshare went through reconcile protocol successfully-
Staged KeyshareKeyshare which will be subjected to reconcile protocol and could potentially become current keyshare if it goes through reconcile successfully-
Reconcile Outcome : CompleteStaged Keyshare successfully completed the reconcile protocol and could be saved as current keyshare-
Reconcile Outcome : RollbackStaged Keyshare is supposed to be discarded-
Loading Diagram...

Retrying after a crash

refresh, keygen, import, recover, and hardDerivation reconcile internally, so you normally never call reconcile yourself. The exception is recovery after a crash: if the app is killed mid-reconcile, the rotated share stays in the staged slot and was never promoted (the key is still fully usable on the current share). Calling reconcile(keyId:) on next launch settles it — promoting or rolling back — without re-running the refresh.

Reconciling every stored key on startup closes this gap:

// Run once on app launch.
func reconcileOnStartup(trioSession: TrioSession, storedKeyIds: [String]) async {
for keyId in storedKeyIds {
if case .failure(let error) = await trioSession.reconcile(keyId: keyId) {
Swift.print("reconcile failed for \(keyId): \(error)")
}
}
}