From 7660868a38c8f696adfcb55c5ab4d54619c9619a Mon Sep 17 00:00:00 2001 From: hailin Date: Sat, 6 Dec 2025 07:46:32 -0800 Subject: [PATCH] fix(account): select t+1 parties for threshold signing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TSS threshold semantics: for threshold parameter t, the required number of signers is t+1. For 2-of-3 with t=2, we need 2+1=3 signers (all parties must participate). Previous error: 't+1=3 is not satisfied by the key count of 2' Fix: Changed from selecting t parties to selecting t+1 parties. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../account/adapters/input/http/account_handler.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/mpc-system/services/account/adapters/input/http/account_handler.go b/backend/mpc-system/services/account/adapters/input/http/account_handler.go index b8409344..8b0f9ce6 100644 --- a/backend/mpc-system/services/account/adapters/input/http/account_handler.go +++ b/backend/mpc-system/services/account/adapters/input/http/account_handler.go @@ -732,9 +732,10 @@ func (h *AccountHTTPHandler) CreateSigningSession(c *gin.Context) { zap.String("username", req.Username), zap.Strings("configured_parties", partyIDs)) } else { - // For threshold signing, select minimum required parties (threshold_t) - // For 2-of-3, we need exactly 2 parties to sign (not all 3) - requiredParties := accountOutput.Account.ThresholdT + // For threshold signing, select minimum required parties (threshold_t + 1) + // TSS threshold semantics: for threshold t, we need t+1 signers + // For 2-of-3: t=1, so we need t+1=2 parties to sign + requiredParties := accountOutput.Account.ThresholdT + 1 if len(allActivePartyIDs) < requiredParties { c.JSON(http.StatusBadRequest, gin.H{ "error": "insufficient active parties for signing", @@ -744,12 +745,13 @@ func (h *AccountHTTPHandler) CreateSigningSession(c *gin.Context) { return } - // Select first 'threshold_t' parties + // Select first 'threshold_t + 1' parties partyIDs = allActivePartyIDs[:requiredParties] logger.Info("Using minimum required parties for threshold signing", zap.String("username", req.Username), - zap.Int("threshold_t", requiredParties), + zap.Int("threshold_t", accountOutput.Account.ThresholdT), + zap.Int("required_signers", requiredParties), zap.Int("total_active", len(allActivePartyIDs)), zap.Strings("selected_parties", partyIDs)) }