Key Lifecycle & Signing Flow
Keygen, signing and resharing from the cosigner's side.
Keygen
Creating a wallet in a workspace with a cosigner runs distributed key generation across the MPCium nodes and your cosigner.
- Orchestrator sends a signed
session_startwithKEYGEN, thekey_id, protocol and threshold. - Cosigner verifies the signature and asks your callback.
- Participants run tss-lib keygen. Each ends with its own share and the shared public key.
- Cosigner encrypts its share, stores it as
shares:<protocol>:<key_id>and records the committee. - Only the public key and a result hash leave the cosigner.
- Orchestrator checks all public keys match and returns them to Apex.
Wallets needing both ECDSA and EdDSA run two linked sessions. If one fails, both abort.
ECDSA needs Paillier pre-parameters. The cosigner generates them on first boot (up to 5 minutes) and reports not ready until done.
Signing

1. Admission
A request that passes your workspace policies goes from Apex to the orchestrator, signed with the Apex initiator key. The orchestrator checks the committee against the keygen record, confirms everyone is online, and sends a signed session_start.
session_start carries key_id, the raw signing_input, optional signing_context (transaction details, max 64 KiB), HD derivation, threshold and participants.
2. Local checks
The cosigner rejects the session unless all pass, in order:
- Message under 128 KiB.
- Valid orchestrator signature (key pinned at pairing).
- Under 20 starts and 10 aborts per minute.
- Under 5 concurrent sessions.
session_startwritten to the audit log.- Your callback returns
approve. Otherwise the session fails withCALLBACK_REJECTED.
If the orchestrator aborts while the callback is pending, the cosigner stops waiting.
3. Key exchange
- Session must match the pinned committee: threshold, party keys, identity keys, approver flags.
- Cosigner sends
peer_joined,peer_readyand a signed X25519 key to each peer. - Each peer pair gets a per-direction ChaCha20-Poly1305 key (HKDF over X25519, bound to the session).
4. Threshold signing
The orchestrator sends mpc_begin. If the wallet has an approver (for example a Fystack mobile approver), mpc_begin must include its signed approval of this exact signing input. Without it the cosigner fails the session with APPROVAL_REQUIRED.
Participants then run tss-lib rounds. Every message is signed and sequence-numbered, so replays are dropped.
5. Result
Each participant reports a hash of its signature. The orchestrator requires all hashes to match, then returns the signed result (signature, r, s, recovery id) to Apex. The cosigner logs session_end and deletes its checkpoint.
Resharing
Replaces shares, optionally with a new committee or threshold. Public key and addresses don't change.
- Old committee and threshold come from the keygen record, not the caller.
- At least
threshold + 1old members must be online. - Old and new members run tss-lib resharing. New shares are staged; old ones stay active.
- All participants report the same result and an unchanged public key.
- Orchestrator persists the decision, then sends a signed
reshare_commit. Each participant swaps in the new share.
Abort before commit keeps the old shares. After commit it only rolls forward: the commit is retried until every participant confirms, including after a crash.
Resharing is enabled per deployment. Contact Fystack before changing a committee.
Failure codes
| Code | Meaning |
|---|---|
CALLBACK_REJECTED |
Callback rejected, timed out or returned an invalid response. |
APPROVAL_REQUIRED |
Wallet approver's signed approval missing. |
UNAVAILABLE |
A participant was offline at submission. |
PARTICIPANT_FAILED |
A participant reported a failure. See failure_reason. |
PARTICIPANT_DISCONNECTED |
A participant's stream dropped mid-session. |
SESSION_TIMEOUT |
Not done within 120 seconds. |
RESULT_HASH_MISMATCH |
Participants disagreed on the result. |
CONFLICT |
Another session is running for this wallet and protocol. |