# Resharing and Refreshing Keys

Once a [threshold key](/cryptography/mpc) has been generated, the Vertex can rotate its secret material or change its signing quorum, all without ever changing the public key:

* A **refresh** replaces the secret material of every party's Key Share while keeping the same `t-of-n` quorum and the same public key. Refreshing shares periodically means an adversary must compromise multiple parties at the same time in order to compromise the private key. For the cryptographic background, see [Key Refresh and Recovery](/cryptography/refresh-and-recovery).
* A **reshare** moves the key to a new `newT-of-newN` quorum for the same public key. Use it to add or remove parties, or to change the threshold.

:::note[Permissions]
All endpoints on this page require a User with the [`KeysManager` Role](/vertex/users_and_access_control#system-roles). In addition, the calling User must hold the `Admin` [Key Permission](/vertex/users_and_access_control#key-ownership-and-permissions) for the key being refreshed or reshared.
:::

The examples below use ECDSA. The same endpoints exist for all supported algorithms: `ecdsa`, `ed25519`, `bip340`, `exportable-ed25519` and `sr25519`.

## Refreshing a Key Share

Like key generation, a refresh is an MPC operation performed by all parties together.

### Creating a Room for the Refresh

For a `t-of-n` key, create a room of size `n` using the [`create-room`](https://docs.sodot.dev/vertex-api-reference/#tag/common/POST/create-room) endpoint:

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/create-room' \
-H 'Content-Type: application/json' \
-H 'Authorization: <USER_API_KEY>' \
--data-raw '{
  "room_size": 3
}'
```

### Refreshing the Key

All `n` parties call the [`refresh`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/ecdsa/refresh) endpoint (or the equivalent SDK method) with the same `room_uuid`:

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/ecdsa/refresh' \
-H 'Content-Type: application/json' \
-H 'Authorization: <USER_API_KEY>' \
--data-raw '{
  "key_id": "<KEY_ID>",
  "room_uuid": "<ROOM_UUID>"
}'
```

You can identify the key with either `key_id` or `key_name`, but not both.

In response we will receive a new `key_id` for the refreshed Key Share:

```json
{
  "key_id": "<NEW_KEY_ID>"
}
```

The refreshed share is stored under the new `key_id` and signs for the exact same public key. Note that the new share does not inherit the optional `key_name` of the old share.

:::warning[Delete the old share]
The refresh does **not** delete the old `key_id`. Since the old shares can still reconstruct the same private key, it is highly recommended to delete the old `key_id` on every party (using [`delete-key-share`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/DELETE/ecdsa/delete-key-share)) once the refresh has succeeded.
:::

:::tip
Calling `keygen` on a key that has already completed key generation fails with an [`already_performed_keygen`](/vertex/vertex_errors) error. Rotating an existing key is done with `refresh`, not with another `keygen`.
:::

The refresh endpoint for each algorithm:

* [ECDSA Refresh](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/ecdsa/refresh)
* [Ed25519 Refresh](https://docs.sodot.dev/vertex-api-reference/#tag/ed25519/POST/ed25519/refresh)
* [BIP340 Refresh](https://docs.sodot.dev/vertex-api-reference/#tag/bip340/POST/bip340/refresh)
* [Exportable Ed25519 Refresh](https://docs.sodot.dev/vertex-api-reference/#tag/exportableed25519/POST/exportable-ed25519/refresh)
* [Sr25519 Refresh](https://docs.sodot.dev/vertex-api-reference/#tag/sr25519/POST/sr25519/refresh)

## Resharing a Key Share

:::danger[Advanced feature]
Key resharing is an advanced feature of the Vertex. We strongly advise consulting with the Sodot team before using it, as incorrect usage might harm the security of the private key. At least `n - t + 1` parties of the old `t-of-n` quorum must delete their old shares, and the reshare must not be considered complete until that deletion has occurred. Since deleting a share cannot be guaranteed cryptographically, it must be guaranteed by your software architecture.
:::

In a reshare, every member of the new quorum participates in a single MPC operation:

* Parties that already hold a Key Share call [`reshare/existing-party`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/ecdsa/reshare/existing-party).
* Parties that are joining the quorum call [`reshare/new-party`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/ecdsa/reshare/new-party).

Both endpoints take the same request body.

### Step 1: Create Key Shares for the New Parties

Each joining party creates an empty Key Share, exactly as in the [key generation flow](/vertex/keygen/generating_keys), using the [`create-key`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/ecdsa/create) endpoint:

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/ecdsa/create' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: <USER_API_KEY>'
```

In response, each new party receives a `key_id` and a `keygen_id`.

### Step 2: Export the IDs of the Existing Parties

Each party that already holds a Key Share retrieves its ID for the reshare using the [`export-id`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/GET/ecdsa/export/exportId) endpoint:

```bash
curl -L -X GET 'https://<YOUR_VERTEX>/ecdsa/export/exportId?key_id=<KEY_ID>' \
-H 'Accept: application/json' \
-H 'Authorization: <USER_API_KEY>'
```

In response we will receive an `export_id`.

Collect the IDs of all parties in the new quorum (the `keygen_id` of each new party from Step 1 and the `export_id` of each existing party) and distribute the full set to every participant. This set is the `keygen_ids` parameter used in Step 4.

### Step 3: Create a Room for the Reshare

Create a room whose size is `newN`, the total number of parties in the new quorum, using the [`create-room`](https://docs.sodot.dev/vertex-api-reference/#tag/common/POST/create-room) endpoint (same as [above](#creating-a-room-for-the-refresh)).

### Step 4: Perform the Reshare

All parties must call their respective endpoint with the same `room_uuid`, `new_threshold` and `keygen_ids`.

Each existing party calls [`reshare/existing-party`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/ecdsa/reshare/existing-party), referencing its current Key Share:

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/ecdsa/reshare/existing-party' \
-H 'Content-Type: application/json' \
-H 'Authorization: <USER_API_KEY>' \
--data-raw '{
  "key_id": "<EXISTING_KEY_ID>",
  "new_threshold": 2,
  "keygen_ids": [
    "<ID_OF_PARTY_1>",
    "<ID_OF_PARTY_2>",
    "<ID_OF_PARTY_3>"
  ],
  "room_uuid": "<ROOM_UUID>"
}'
```

In response, each existing party receives a new `key_id` for its share in the new quorum:

```json
{
  "key_id": "<NEW_KEY_ID>"
}
```

The old `key_id` remains stored until you delete it (see Step 5).

Each new party calls [`reshare/new-party`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/ecdsa/reshare/new-party) with the `key_id` it created in Step 1:

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/ecdsa/reshare/new-party' \
-H 'Content-Type: application/json' \
-H 'Authorization: <USER_API_KEY>' \
--data-raw '{
  "key_id": "<KEY_ID_FROM_STEP_1>",
  "new_threshold": 2,
  "keygen_ids": [
    "<ID_OF_PARTY_1>",
    "<ID_OF_PARTY_2>",
    "<ID_OF_PARTY_3>"
  ],
  "room_uuid": "<ROOM_UUID>"
}'
```

Receiving a `200 OK` response indicates that the reshare was successful. The new party's share is stored under the `key_id` created in Step 1.

### Step 5: Delete the Old Key Shares

To complete the reshare, at least `n - t + 1` parties of the old quorum must delete their old shares using [`delete-key-share`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/DELETE/ecdsa/delete-key-share). This includes parties that left the quorum entirely as well as the old `key_id`s of remaining parties.

The reshare endpoints for each algorithm:

* ECDSA: [existing-party](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/ecdsa/reshare/existing-party), [new-party](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/ecdsa/reshare/new-party)
* Ed25519: [existing-party](https://docs.sodot.dev/vertex-api-reference/#tag/ed25519/POST/ed25519/reshare/existing-party), [new-party](https://docs.sodot.dev/vertex-api-reference/#tag/ed25519/POST/ed25519/reshare/new-party)
* BIP340: [existing-party](https://docs.sodot.dev/vertex-api-reference/#tag/bip340/POST/bip340/reshare/existing-party), [new-party](https://docs.sodot.dev/vertex-api-reference/#tag/bip340/POST/bip340/reshare/new-party)
* Exportable Ed25519: [existing-party](https://docs.sodot.dev/vertex-api-reference/#tag/exportableed25519/POST/exportable-ed25519/reshare/existing-party), [new-party](https://docs.sodot.dev/vertex-api-reference/#tag/exportableed25519/POST/exportable-ed25519/reshare/new-party)
* Sr25519: [existing-party](https://docs.sodot.dev/vertex-api-reference/#tag/sr25519/POST/sr25519/reshare/existing-party), [new-party](https://docs.sodot.dev/vertex-api-reference/#tag/sr25519/POST/sr25519/reshare/new-party)

## Resharing in Cluster Mode

When the parties are Vertex servers set up as a [Cluster](/vertex/keygen/cluster_keygen), there is no need to exchange `keygen_ids` for the reshare: the Cluster registry supplies them. A cluster reshare moves the key from an existing cluster A to a new cluster B, where B must contain all the parties from A that participate in the reshare.

The flow is:

1. Set up a new Cluster containing the remaining Vertex servers and any joining Vertex servers, as described in [Setting Up a Cluster](/vertex/keygen/cluster_keygen#setting-up-a-cluster).
2. Create a room of size `newN` using [`create-room`](https://docs.sodot.dev/vertex-api-reference/#tag/common/POST/create-room).
3. All members of the new Cluster call their respective cluster reshare endpoint with the same `room_uuid`, `new_threshold` and `cluster_name`.

Each Vertex that already holds a Key Share calls [`cluster reshare/existing-party`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/cluster/ecdsa/reshare/existing-party):

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/cluster/ecdsa/reshare/existing-party' \
-H 'Content-Type: application/json' \
-H 'Authorization: <USER_API_KEY>' \
--data-raw '{
  "cluster_name": "my_new_cluster",
  "key_id": "<EXISTING_KEY_ID>",
  "new_threshold": 2,
  "room_uuid": "<ROOM_UUID>"
}'
```

Each joining Vertex calls [`cluster reshare/new-party`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/cluster/ecdsa/reshare/new-party). Unlike the non-cluster flow, no `create-key` call is needed beforehand, and an optional `key_name` may be provided for the new Key Share:

```bash
curl -L -X POST 'https://<YOUR_VERTEX>/cluster/ecdsa/reshare/new-party' \
-H 'Content-Type: application/json' \
-H 'Authorization: <USER_API_KEY>' \
--data-raw '{
  "cluster_name": "my_new_cluster",
  "key_name": "my_reshared_key",
  "new_threshold": 2,
  "room_uuid": "<ROOM_UUID>"
}'
```

Both endpoints return a `key_id` for the party's share in the new quorum:

```json
{
  "key_id": "<NEW_KEY_ID>"
}
```

As with the non-cluster flow, existing parties keep their old `key_id` until it is deleted; make sure to complete [Step 5](#step-5-delete-the-old-key-shares) here as well.

:::note
There is no cluster variant of `refresh`. A refresh does not require exchanging `keygen_ids`, so Vertex servers in a Cluster simply call the regular [`refresh`](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/ecdsa/refresh) endpoint.
:::

The cluster reshare endpoints for each algorithm:

* ECDSA: [existing-party](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/cluster/ecdsa/reshare/existing-party), [new-party](https://docs.sodot.dev/vertex-api-reference/#tag/ecdsa/POST/cluster/ecdsa/reshare/new-party)
* Ed25519: [existing-party](https://docs.sodot.dev/vertex-api-reference/#tag/ed25519/POST/cluster/ed25519/reshare/existing-party), [new-party](https://docs.sodot.dev/vertex-api-reference/#tag/ed25519/POST/cluster/ed25519/reshare/new-party)
* BIP340: [existing-party](https://docs.sodot.dev/vertex-api-reference/#tag/bip340/POST/cluster/bip340/reshare/existing-party), [new-party](https://docs.sodot.dev/vertex-api-reference/#tag/bip340/POST/cluster/bip340/reshare/new-party)
* Exportable Ed25519: [existing-party](https://docs.sodot.dev/vertex-api-reference/#tag/exportableed25519/POST/cluster/exportable-ed25519/reshare/existing-party), [new-party](https://docs.sodot.dev/vertex-api-reference/#tag/exportableed25519/POST/cluster/exportable-ed25519/reshare/new-party)
* Sr25519: [existing-party](https://docs.sodot.dev/vertex-api-reference/#tag/sr25519/POST/cluster/sr25519/reshare/existing-party), [new-party](https://docs.sodot.dev/vertex-api-reference/#tag/sr25519/POST/cluster/sr25519/reshare/new-party)
