---
title: "Key Lifecycle & Signing Flow"
description: "How the cosigner runs keygen, threshold signing and resharing, and every check it applies before signing."
url: https://docs.fystack.io/cosigner/signing-flow
last_updated: 2026-10-14
---

> ## Documentation index
> Fetch the complete documentation index at: https://docs.fystack.io/llms.txt
> Use it to discover all available pages before exploring further.

# 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.

1. Orchestrator sends a signed `session_start` with `KEYGEN`, the `key_id`, protocol and threshold.
2. Cosigner verifies the signature and asks your callback.
3. Participants run tss-lib keygen. Each ends with its own share and the shared public key.
4. Cosigner encrypts its share, stores it as `shares:<protocol>:<key_id>` and records the committee.
5. Only the public key and a result hash leave the cosigner.
6. 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.

> **Note:** ECDSA needs Paillier pre-parameters. The cosigner generates them on first boot (up to 5 minutes) and reports not ready until done.

## Signing

_Diagram: Signing sequence: Apex requests, orchestrator starts the session, cosigner asks the callback, participants sign, orchestrator returns the signature_

### 1. Admission

A request that passes your workspace [policies](https://docs.fystack.io/product/policies.md) 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:

1. Message under 128 KiB.
2. Valid orchestrator signature (key pinned at pairing).
3. Under 20 starts and 10 aborts per minute.
4. Under 5 concurrent sessions.
5. `session_start` written to the audit log.
6. Your callback returns `approve`. Otherwise the session fails with `CALLBACK_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_ready` and 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.

1. Old committee and threshold come from the keygen record, not the caller.
2. At least `threshold + 1` old members must be online.
3. Old and new members run tss-lib resharing. New shares are staged; old ones stay active.
4. All participants report the same result and an unchanged public key.
5. 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.

> **Note:** 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. |
