diff --git a/backend/mpc-system/pkg/tss/keygen.go b/backend/mpc-system/pkg/tss/keygen.go index cfdc3519..2f6643b7 100644 --- a/backend/mpc-system/pkg/tss/keygen.go +++ b/backend/mpc-system/pkg/tss/keygen.go @@ -117,8 +117,11 @@ func NewKeygenSession( sortedPartyIDs := tss.SortPartyIDs(tssPartyIDs) // Create peer context and parameters + // IMPORTANT: TSS-lib threshold convention: threshold=t means (t+1) signers required + // User says "2-of-3" meaning 2 signers needed, so we pass (Threshold-1) to TSS-lib peerCtx := tss.NewPeerContext(sortedPartyIDs) - params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), config.Threshold) + tssThreshold := config.Threshold - 1 + params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), tssThreshold) return &KeygenSession{ config: config, diff --git a/backend/mpc-system/pkg/tss/signing.go b/backend/mpc-system/pkg/tss/signing.go index f9d01e40..ae319af7 100644 --- a/backend/mpc-system/pkg/tss/signing.go +++ b/backend/mpc-system/pkg/tss/signing.go @@ -132,14 +132,15 @@ func NewSigningSession( keygenIndexToSortedIndex, selfParty.PartyID) // Create peer context and parameters - // CRITICAL: threshold must match keygen exactly! - // Use len(sortedPartyIDs) as partyCount - this is the number of CURRENT signers + // IMPORTANT: TSS-lib threshold convention: threshold=t means (t+1) signers required + // This MUST match keygen exactly! Both use (Threshold-1) // The BuildLocalSaveDataSubset call in Start() will filter the save data to match peerCtx := tss.NewPeerContext(sortedPartyIDs) - params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), config.Threshold) + tssThreshold := config.Threshold - 1 + params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), tssThreshold) - fmt.Printf("[TSS-SIGN] NewParameters: partyCount=%d, threshold=%d party_id=%s\n", - len(sortedPartyIDs), config.Threshold, selfParty.PartyID) + fmt.Printf("[TSS-SIGN] NewParameters: partyCount=%d, tssThreshold=%d (from config.Threshold=%d) party_id=%s\n", + len(sortedPartyIDs), tssThreshold, config.Threshold, selfParty.PartyID) // Convert message hash to big.Int msgHash := new(big.Int).SetBytes(messageHash) diff --git a/backend/mpc-system/services/service-party-app/tss-party/main.go b/backend/mpc-system/services/service-party-app/tss-party/main.go index 5a2e3a57..5f8fb8bd 100644 --- a/backend/mpc-system/services/service-party-app/tss-party/main.go +++ b/backend/mpc-system/services/service-party-app/tss-party/main.go @@ -241,13 +241,14 @@ func executeKeygen( sortedPartyIDs := tss.SortPartyIDs(tssPartyIDs) // Create peer context and parameters - // NOTE: We use thresholdT directly (not thresholdT-1) to maintain backward compatibility - // with existing wallets. In our system, thresholdT=2 means "need 2 signers" but TSS-lib - // interprets threshold=2 as "need 3 signers". This is intentional to match existing keygen data. + // IMPORTANT: TSS-lib threshold convention: threshold=t means (t+1) signers required + // User says "2-of-3" meaning 2 signers needed, so we pass (thresholdT-1) to TSS-lib + // For 2-of-3: thresholdT=2, tss-lib threshold=1, signers_needed=1+1=2 ✓ peerCtx := tss.NewPeerContext(sortedPartyIDs) - params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), thresholdT) - fmt.Fprintf(os.Stderr, "[TSS-KEYGEN] NewParameters: partyCount=%d, threshold=%d\n", - len(sortedPartyIDs), thresholdT) + tssThreshold := thresholdT - 1 + params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), tssThreshold) + fmt.Fprintf(os.Stderr, "[TSS-KEYGEN] NewParameters: partyCount=%d, tssThreshold=%d (from thresholdT=%d, means %d signers needed)\n", + len(sortedPartyIDs), tssThreshold, thresholdT, thresholdT) // Create channels outCh := make(chan tss.Message, thresholdN*10) @@ -600,13 +601,15 @@ func executeSign( sortedPartyIDs := tss.SortPartyIDs(tssPartyIDs) // Create peer context and parameters - // CRITICAL: threshold must match keygen exactly! - // Keygen uses: NewParameters(..., len(sortedPartyIDs), thresholdT) - // Sign must use the same threshold value for Lagrange coefficients to work correctly. + // IMPORTANT: TSS-lib threshold convention: threshold=t means (t+1) signers required + // User says "2-of-3" meaning 2 signers needed, so we pass (thresholdT-1) to TSS-lib + // This MUST match keygen exactly! + // For 2-of-3: thresholdT=2, tss-lib threshold=1, signers_needed=1+1=2 ✓ peerCtx := tss.NewPeerContext(sortedPartyIDs) - params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), thresholdT) - fmt.Fprintf(os.Stderr, "[TSS-SIGN] NewParameters: partyCount=%d, threshold=%d (must match keygen)\n", - len(sortedPartyIDs), thresholdT) + tssThreshold := thresholdT - 1 + params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), tssThreshold) + fmt.Fprintf(os.Stderr, "[TSS-SIGN] NewParameters: partyCount=%d, tssThreshold=%d (from thresholdT=%d, means %d signers needed)\n", + len(sortedPartyIDs), tssThreshold, thresholdT, thresholdT) // CRITICAL: Build a subset of the keygen save data for the current signing parties // This is required when signing with a subset of the original keygen participants. diff --git a/backend/mpc-system/services/tss-wasm/main.go b/backend/mpc-system/services/tss-wasm/main.go index 76919b3e..aeec102f 100644 --- a/backend/mpc-system/services/tss-wasm/main.go +++ b/backend/mpc-system/services/tss-wasm/main.go @@ -160,8 +160,11 @@ func startKeygen(this js.Value, args []js.Value) interface{} { sortedPartyIDs := tss.SortPartyIDs(tssPartyIDs) // Create peer context and parameters + // IMPORTANT: TSS-lib threshold convention: threshold=t means (t+1) signers required + // User says "2-of-3" meaning 2 signers needed, so we pass (thresholdT-1) to TSS-lib peerCtx := tss.NewPeerContext(sortedPartyIDs) - params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), thresholdT) + tssThreshold := thresholdT - 1 + params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), tssThreshold) // Build party index map session.PartyIndexMap = make(map[int]*tss.PartyID) @@ -281,9 +284,11 @@ func startSigning(this js.Value, args []js.Value) interface{} { sortedPartyIDs := tss.SortPartyIDs(tssPartyIDs) // Create peer context and parameters - // CRITICAL: threshold must match keygen exactly! + // IMPORTANT: TSS-lib threshold convention: threshold=t means (t+1) signers required + // This MUST match keygen exactly! Both use (thresholdT-1) peerCtx := tss.NewPeerContext(sortedPartyIDs) - params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), thresholdT) + tssThreshold := thresholdT - 1 + params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), tssThreshold) // Build party index map session.PartyIndexMap = make(map[int]*tss.PartyID)