How Key Resharing Works in MPCium When Nodes Join or Leave the Cluster
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 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. 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):
- Threshold check – Verifies at least
newThreshold+1peers are currently ready in the cluster - Peer list validation – Confirms
len(newPeerIDs) >= newThreshold+1and that every proposed peer ID corresponds to a ready node - Key metadata retrieval – Loads the existing
KeyInfousing the wallet ID and determines the signature scheme prefix (ecdsaoreddsa)
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 committeeisInNewCommittee– Whether the node appears in thenewPeerIDslist
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 (lines 57-84) and pkg/mpc/eddsa_resharing_session.go (lines 46-74).
Building the Resharing Context
The constructor performs four critical setup steps:
- Party ID selection – Chooses
newPartyIDsif the node is joining, or retainsoldPartyIDsif 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.NewReSharingParameterswith old and new committee sizes, respective thresholds, and the localPartyID - Legacy peer recording – Stores
oldPeerIDsto 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
LocalPartySaveDatausingkeygen.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.endChassaveData
Finalization and Storage
When the protocol completes (ECDSA lines 70-98, EdDSA lines 70-100), the session:
- Marshals the new share to JSON and stores it under a versioned key (
walletID:version) - Creates updated
KeyInfocontaining the new participant list andnewThreshold - Extracts and encodes the public key (using
encoding.EncodeS256PubKeyfor ECDSA) - 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. 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 innode.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:
// 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:
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 (
ecdsaReshareSessionandeddsaReshareSession) wrap the TSS library'sresharing.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:versionkeys and incrementing the version counter inKeyInfo, 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). 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. 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →