---
title: "Cosigner Architecture"
description: "Cosigner architecture: components, transport channels, trust boundaries and the MPC session lifecycle."
url: https://docs.fystack.io/cosigner/architecture
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.

# Cosigner Architecture

What runs where, how the parts talk, and how a session is coordinated.

_Diagram: Cosigner architecture overview_

## Components

### Cosigner runtime

One Go binary, shipped as `ghcr.io/fystack/cosigner` for `linux/amd64` and `linux/arm64`. It joins sessions; it does not coordinate them.

- **MPC engine**: Fystack's fork of [tss-lib](https://github.com/bnb-chain/tss-lib), same as MPCium. ECDSA uses GG18 on secp256k1. EdDSA uses tss-lib threshold Ed25519.
- **Identity key**: Ed25519, created at pairing. Authenticates the cosigner and signs its messages.
- **Key store**: AES-256-GCM encrypted rows in SQLite (default), Badger or DynamoDB.
- **Gateway relay**: One outbound gRPC stream. Sends presence every 5 seconds.
- **Approval client**: Calls your [approval callback](https://docs.fystack.io/cosigner/approval-callback.md) before every session.
- **Audit log**: Signed, hash-chained JSONL.

### Your services

- **cosigner-cli**: Installs, verifies, pairs, starts and backs up the runtime.
- **Approval callback**: Your HTTPS server. Returns `approve` or `reject`.
- **Storage key source**: A password (`manual` profile) or AWS KMS (`unattended` profile).

### Fystack services

- **Apex**: Issues pairing tokens, registers cosigner keys, handles revocation, submits MPC requests.
- **Gateway**: Accepts cosigner streams, checks identity and revocation, bridges traffic to NATS. One live stream per cosigner across all replicas.
- **Orchestrator**: Runs the session state machine and signs every control message. Never touches key shares.
- **MPCium**: Fystack's MPC nodes. See [MPCium](https://docs.fystack.io/mpcium.md).

## Channels

| From → to | Transport | Auth | Carries |
| --- | --- | --- | --- |
| Cosigner → Apex | HTTPS | One-time pairing token | Identity registration |
| Cosigner ↔ Gateway | gRPC stream, TLS | EdDSA JWT, 60s lifetime | All session traffic |
| Gateway ↔ Orchestrator ↔ MPCium | NATS | Ed25519 per message | Coordination inside Fystack |
| Participant ↔ participant | Relayed | X25519 + ChaCha20-Poly1305 | MPC rounds, end-to-end encrypted |
| Cosigner → Callback | HTTPS | RS256 JWT both ways | Approve or reject |

### Stream envelopes

Every frame carries the authenticated `workspace_id`, `cosigner_id` and `participant_id`. The Gateway drops frames that don't match the stream identity.

| Kind | Direction | Subject |
| --- | --- | --- |
| `CONTROL` | Orchestrator → cosigner | `mpc.v1.peer.<participant_id>.control` |
| `SESSION_EVENT` | Cosigner → orchestrator | `mpc.v1.session.<session_id>.event` |
| `P2P` | Participant ↔ participant | `mpc.v1.peer.<to>.session.<session_id>.p2p` |
| `PRESENCE` | Cosigner → orchestrator | `mpc.v1.peer.<participant_id>.presence` |

## Trust boundaries

- **Gateway**: Relays ciphertext. Can drop or delay traffic, cannot read or forge MPC messages.
- **Orchestrator**: Signs every control message with a key the cosigner pinned at pairing. Unsigned or mis-signed messages are dropped.
- **Apex**: Cannot skip your callback. Every session goes to your callback first.
- **Your cosigner**: Cannot sign alone. The committee is fixed at keygen.

Details in [Security Model](https://docs.fystack.io/cosigner/security.md).

## Sessions

Each keygen, sign or reshare is one orchestrator session with a 120 second TTL.

_Diagram: Session states: created, waiting, key_exchange, active_mpc, completed, with failed and expired_

1. **Admission**: Orchestrator verifies the Apex signature, checks the committee and confirms every participant is online. One session per wallet and protocol at a time.
2. **waiting**: Participants receive a signed `session_start`, run local checks (the cosigner calls your callback) and reply `peer_joined`, `peer_ready`.
3. **key_exchange**: Participants exchange signed X25519 keys. Wallets with an approver also need its signed approval here.
4. **active_mpc**: Orchestrator sends `mpc_begin`. Participants run tss-lib rounds directly.
5. **completed**: All participants report the same result hash. Orchestrator signs and publishes the result.

A session **fails** on a participant error, a disconnect or mismatched results, and **expires** after 120 seconds. Either way the orchestrator broadcasts a signed `session_abort`.

### Committees

Threshold `t` means `t + 1` signers (tss-lib semantics). The committee of MPCium nodes and cosigners is fixed at keygen. Every later session must use the same party keys, identity keys and approver roles.

### Connections

- One live stream per cosigner identity. A second instance with the same identity is rejected.
- Each session is bound to the stream that was live when it started. If that stream drops, the session fails with `PARTICIPANT_DISCONNECTED`.
- A revoked cosigner gets `PermissionDenied` and stops.
