# How Key Resharing Works in MPCium When Nodes Join or Leave the Cluster

> Learn how MPCium's key resharing handles nodes joining or leaving the cluster. Discover versioned sessions, TSS protocols, and share persistence for seamless updates.

- Repository: [Fystack Labs/mpcium](https://github.com/fystack/mpcium)
- Tags: internals
- Published: 2026-03-02

---

**Key resharing in MPCium updates existing MPC key shares by creating versioned resharing sessions that reconcile old and new committees, running the TSS resharing protocol, and persisting new shares with incremented version tags.**

When the committee composition of an MPC cluster changes—whether nodes are added or removed—the `fystack/mpcium` repository performs **key resharing** to redistribute key material securely without exposing the underlying secret. This process is orchestrated by the `Node` type in [`pkg/mpc/node.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/node.go) and implemented through scheme-specific sessions that wrap the underlying TSS library protocols.

## Entry Point and Committee Validation

The resharing process begins at `Node.CreateReshareSession` in [`pkg/mpc/node.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/node.go). This method acts as the factory and validator for all resharing operations, ensuring the cluster can safely transition to a new committee structure.

### Prerequisites and Peer Validation

Before constructing a session, the node performs strict validation checks (lines 60-88):

1. **Threshold check** – Verifies at least `newThreshold+1` peers are currently ready in the cluster
2. **Peer list validation** – Confirms `len(newPeerIDs) >= newThreshold+1` and that every proposed peer ID corresponds to a ready node
3. **Key metadata retrieval** – Loads the existing `KeyInfo` using the wallet ID and determines the signature scheme prefix (`ecdsa` or `eddsa`)

### Role Determination: Old vs. New Committee

The function determines node participation by checking two boolean conditions (lines 104-115):

- **`isInOldCommittee`** – Whether the node holds an existing share from the current committee
- **`isInNewCommittee`** – Whether the node appears in the `newPeerIDs` list

If the node participates in neither committee, the function returns `nil` and the node ignores the operation. This filtering ensures only relevant nodes engage in the protocol, reducing network overhead and attack surface.

## Session Construction and TSS Parameters

Once validated, the node instantiates either an `ecdsaReshareSession` or `eddsaReshareSession` based on the `SessionType`. Both constructors follow an identical pattern defined in [`pkg/mpc/ecdsa_resharing_session.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/ecdsa_resharing_session.go) (lines 57-84) and [`pkg/mpc/eddsa_resharing_session.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/eddsa_resharing_session.go) (lines 46-74).

### Building the Resharing Context

The constructor performs four critical setup steps:

- **Party ID selection** – Chooses `newPartyIDs` if the node is joining, or retains `oldPartyIDs` if continuing
- **Topic composition** – Creates broadcast topics (`reshare:broadcast:<scheme>:<walletID>`) and direct message topics (`reshare:direct:<scheme>:<from>:<to>:<walletID>`)
- **TSS parameter generation** – Invokes `tss.NewReSharingParameters` with old and new committee sizes, respective thresholds, and the local `PartyID`
- **Legacy peer recording** – Stores `oldPeerIDs` to calculate departing nodes later

### Legacy Committee Handling

When nodes leave the cluster, they form the "legacy committee." Both session types expose `GetLegacyCommitteePeers()` (ECDSA lines 22-38, EdDSA lines 12-27) which computes the set difference between `oldPeerIDs` and `newPeerIDs`. These departing nodes must remain active during the protocol to forward their final share data to the incoming committee, ensuring no share material is lost during transition.

## The Resharing Protocol Lifecycle

The session implements a three-phase lifecycle managed through the `ReshareSession` interface.

### Initialization Phase (Init)

During `session.Init()`, nodes prepare their cryptographic state based on committee membership:

- **New nodes** generate empty `LocalPartySaveData` using `keygen.NewLocalPartySaveData` (they possess no prior share material)
- **Existing nodes** load their current shares via `loadOldShareDataGeneric`
- **Party creation** – Both types instantiate `resharing.NewLocalParty(s.reshareParams, share, s.outCh, s.endCh)` to bind the TSS protocol to the session's communication channels

### Execution Phase (Reshare/Run)

The `session.Reshare()` method launches the protocol in a dedicated goroutine by calling `s.party.Start()`. During execution:

- Incoming messages from peers route through `s.handleTssMessage`
- The TSS library coordinates the multi-round protocol between old and new committees
- Upon completion, the final share material emits on `s.endCh` as `saveData`

### Finalization and Storage

When the protocol completes (ECDSA lines 70-98, EdDSA lines 70-100), the session:

1. Marshals the new share to JSON and stores it under a versioned key (`walletID:version`)
2. Creates updated `KeyInfo` containing the new participant list and `newThreshold`
3. Extracts and encodes the public key (using `encoding.EncodeS256PubKey` for ECDSA)
4. Publishes a resharing-success event to the `resultQueue`

The version is always `oldVersion + 1`, enabling backward-compatible key lookups and preventing replay attacks.

## Version Management and Security Considerations

MPCium implements strict version tracking through the `walletIDWithVersion` helper in [`pkg/types/tss.go`](https://github.com/fystack/mpcium/blob/main/pkg/types/tss.go). Each resharing operation increments the version counter, which serves dual purposes:

- **Storage isolation** – New shares live under distinct KV-store keys, preventing overwrite of old shares during failed resharing attempts
- **Pre-parameter rotation** – New nodes select pre-parameters using `p.ecdsaPreParams[version%2]` (lines 55-59 in [`node.go`](https://github.com/fystack/mpcium/blob/main/node.go)), ensuring fresh randomness for each committee generation and mitigating collision attacks

## Implementation Example

The following example demonstrates initiating a resharing operation when a new node joins the cluster:

```go
// Node instance already running and connected
walletID     := "corporate-wallet-001"
newThreshold := 2
newPeers     := []string{"node1", "node2", "node3"} // includes existing and new nodes
isNewPeer    := true // This node is joining the new committee

// Setup result queue for completion notification
resultQueue, _ := manager.NewMessageQueue("mpc_reshare_result")

// Create session via the orchestrator
session, err := node.CreateReshareSession(
    SessionTypeECDSA,
    walletID,
    newThreshold,
    newPeers,
    isNewPeer,
    resultQueue,
)
if err != nil {
    log.Fatalf("Resharing session creation failed: %v", err)
}

// Initialize cryptographic state
if err = session.Init(); err != nil {
    log.Fatalf("Failed to initialize TSS state: %v", err)
}

// Execute protocol with callback
session.Reshare(func() {
    log.Println("Key resharing completed successfully")
})

```

To handle departing nodes, the event consumer can retrieve legacy peers:

```go
legacyPeers := session.GetLegacyCommitteePeers()
for _, peer := range legacyPeers {
    log.Printf("Routing final share from departing node: %s", peer)
}

```

## Summary

- **Key resharing** in MPCium is triggered through `Node.CreateReshareSession`, which validates that the new committee satisfies threshold requirements (`newThreshold+1`) and identifies whether the local node belongs to the old committee, new committee, or both.
- **Scheme-specific sessions** (`ecdsaReshareSession` and `eddsaReshareSession`) wrap the TSS library's `resharing.NewLocalParty`, handling the cryptographic protocol while managing messaging topics and peer routing.
- **Legacy committee members** (nodes leaving the cluster) remain active during resharing to forward their share contributions, calculated via `GetLegacyCommitteePeers()` as the set difference between old and new peer IDs.
- **Versioned storage** ensures atomic upgrades by persisting shares under `walletID:version` keys and incrementing the version counter in `KeyInfo`, preventing conflicts and enabling rollback capabilities.
- **Pre-parameter rotation** uses the version number to select fresh cryptographic parameters for new nodes, protecting against replay attacks and ensuring unique share generation per committee epoch.

## Frequently Asked Questions

### What happens if a node is neither in the old nor new committee?

The `CreateReshareSession` method returns `nil` and the node skips the operation entirely (lines 108-115 in [`pkg/mpc/node.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/node.go)). This prevents irrelevant nodes from consuming resources or accidentally interfering with the protocol.

### How does MPCium prevent old shares from being overwritten during resharing?

The system uses versioned storage keys constructed via `walletIDWithVersion` in [`pkg/types/tss.go`](https://github.com/fystack/mpcium/blob/main/pkg/types/tss.go). New shares are stored under keys incorporating `oldVersion + 1`, ensuring distinct storage locations for each committee generation and enabling recovery from failed resharing attempts.

### Can the threshold change during a resharing operation?

Yes. The `newThreshold` parameter in `CreateReshareSession` allows the security policy to change when the committee updates. The function validates that `len(newPeerIDs) >= newThreshold+1` and that at least `newThreshold+1` peers are ready before allowing the session to proceed.

### What is the role of the TSS library in the resharing process?

MPCium delegates the cryptographic heavy lifting to the TSS library through `tss.NewReSharingParameters` and `resharing.NewLocalParty`. These constructs manage the secure multi-party computation protocol that redistributes key shares between the old and new committees without reconstructing the master secret.