fix(tss): correct threshold signing to support t-of-n properly
Previously, signing incorrectly required all n parties from keygen to participate. For 2-of-3 threshold, it required all 3 parties instead of just 2. Root cause: tss.NewParameters was using len(currentSigners) instead of the original n from keygen. Changes: - Added TotalParties field to SigningConfig to store original n from keygen - Modified participate_signing.go to read threshold_n from database - Updated tss.NewParameters to use TotalParties instead of current signer count - Added logging to show t, n, and current_signers For 2-of-3: threshold_t=2, threshold_n=3, any 2 parties can now sign. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
6fdd2905b1
commit
eb63b9341b
|
|
@ -43,8 +43,9 @@ type SigningParty struct {
|
|||
|
||||
// SigningConfig contains configuration for signing
|
||||
type SigningConfig struct {
|
||||
Threshold int // t in t-of-n (number of signers required)
|
||||
TotalSigners int // Number of parties participating in this signing
|
||||
Threshold int // t in t-of-n threshold value from keygen
|
||||
TotalParties int // n in t-of-n - total parties from keygen (NOT current signers)
|
||||
TotalSigners int // Number of parties participating in this signing session
|
||||
Timeout time.Duration // Signing timeout
|
||||
}
|
||||
|
||||
|
|
@ -112,8 +113,10 @@ func NewSigningSession(
|
|||
sortedPartyIDs := tss.SortPartyIDs(tssPartyIDs)
|
||||
|
||||
// Create peer context and parameters
|
||||
// IMPORTANT: Use TotalParties from keygen, not len(sortedPartyIDs) which is current signers
|
||||
// For 2-of-3: threshold=2, TotalParties=3, but only 2 parties might participate in signing
|
||||
peerCtx := tss.NewPeerContext(sortedPartyIDs)
|
||||
params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, len(sortedPartyIDs), config.Threshold)
|
||||
params := tss.NewParameters(tss.S256(), peerCtx, selfTSSID, config.TotalParties, config.Threshold)
|
||||
|
||||
// Convert message hash to big.Int
|
||||
msgHash := new(big.Int).SetBytes(messageHash)
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ func (uc *ParticipateSigningUseCase) Execute(
|
|||
// 2. Get share data - either from user input (delegate) or from database (persistent)
|
||||
var shareData []byte
|
||||
var keyShareForUpdate *entities.PartyKeyShare
|
||||
var originalThresholdN int // Original total parties from keygen
|
||||
|
||||
if len(input.UserShareData) > 0 {
|
||||
// Delegate party: use share provided by user
|
||||
|
|
@ -88,6 +89,8 @@ func (uc *ParticipateSigningUseCase) Execute(
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// For delegate party, get threshold info from session
|
||||
originalThresholdN = sessionInfo.ThresholdN
|
||||
logger.Info("Using user-provided share (delegate party)",
|
||||
zap.String("party_id", input.PartyID),
|
||||
zap.String("session_id", input.SessionID.String()))
|
||||
|
|
@ -101,6 +104,9 @@ func (uc *ParticipateSigningUseCase) Execute(
|
|||
// Use the most recent key share (in production, would match by public key or session reference)
|
||||
keyShareForUpdate = keyShares[len(keyShares)-1]
|
||||
|
||||
// Get original threshold_n from keygen
|
||||
originalThresholdN = keyShareForUpdate.ThresholdN
|
||||
|
||||
// Decrypt share data
|
||||
shareData, err = uc.cryptoService.DecryptShare(keyShareForUpdate.ShareData, input.PartyID)
|
||||
if err != nil {
|
||||
|
|
@ -108,7 +114,9 @@ func (uc *ParticipateSigningUseCase) Execute(
|
|||
}
|
||||
logger.Info("Using database share (persistent party)",
|
||||
zap.String("party_id", input.PartyID),
|
||||
zap.String("session_id", input.SessionID.String()))
|
||||
zap.String("session_id", input.SessionID.String()),
|
||||
zap.Int("original_threshold_n", originalThresholdN),
|
||||
zap.Int("threshold_t", keyShareForUpdate.ThresholdT))
|
||||
}
|
||||
|
||||
// 4. Find self in participants and build party index map
|
||||
|
|
@ -141,6 +149,7 @@ func (uc *ParticipateSigningUseCase) Execute(
|
|||
selfIndex,
|
||||
sessionInfo.Participants,
|
||||
sessionInfo.ThresholdT,
|
||||
originalThresholdN,
|
||||
shareData,
|
||||
messageHash,
|
||||
msgChan,
|
||||
|
|
@ -179,6 +188,7 @@ func (uc *ParticipateSigningUseCase) runSigningProtocol(
|
|||
selfIndex int,
|
||||
participants []ParticipantInfo,
|
||||
t int,
|
||||
n int, // Original total parties from keygen
|
||||
shareData []byte,
|
||||
messageHash []byte,
|
||||
msgChan <-chan *MPCMessage,
|
||||
|
|
@ -189,6 +199,8 @@ func (uc *ParticipateSigningUseCase) runSigningProtocol(
|
|||
zap.String("party_id", partyID),
|
||||
zap.Int("self_index", selfIndex),
|
||||
zap.Int("t", t),
|
||||
zap.Int("n", n),
|
||||
zap.Int("current_signers", len(participants)),
|
||||
zap.Int("message_hash_len", len(messageHash)))
|
||||
|
||||
// Create message handler adapter
|
||||
|
|
@ -204,8 +216,11 @@ func (uc *ParticipateSigningUseCase) runSigningProtocol(
|
|||
go msgHandler.convertMessages(ctx, msgChan)
|
||||
|
||||
// Create signing config
|
||||
// IMPORTANT: TotalParties must be the original n from keygen, not current signers
|
||||
// For 2-of-3: t=2, n=3, but only 2 parties participate in signing
|
||||
config := tss.SigningConfig{
|
||||
Threshold: t,
|
||||
TotalParties: n, // Original total from keygen
|
||||
TotalSigners: len(participants),
|
||||
Timeout: 5 * time.Minute,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue