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
|
// SigningConfig contains configuration for signing
|
||||||
type SigningConfig struct {
|
type SigningConfig struct {
|
||||||
Threshold int // t in t-of-n (number of signers required)
|
Threshold int // t in t-of-n threshold value from keygen
|
||||||
TotalSigners int // Number of parties participating in this signing
|
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
|
Timeout time.Duration // Signing timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,8 +113,10 @@ func NewSigningSession(
|
||||||
sortedPartyIDs := tss.SortPartyIDs(tssPartyIDs)
|
sortedPartyIDs := tss.SortPartyIDs(tssPartyIDs)
|
||||||
|
|
||||||
// Create peer context and parameters
|
// 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)
|
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
|
// Convert message hash to big.Int
|
||||||
msgHash := new(big.Int).SetBytes(messageHash)
|
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)
|
// 2. Get share data - either from user input (delegate) or from database (persistent)
|
||||||
var shareData []byte
|
var shareData []byte
|
||||||
var keyShareForUpdate *entities.PartyKeyShare
|
var keyShareForUpdate *entities.PartyKeyShare
|
||||||
|
var originalThresholdN int // Original total parties from keygen
|
||||||
|
|
||||||
if len(input.UserShareData) > 0 {
|
if len(input.UserShareData) > 0 {
|
||||||
// Delegate party: use share provided by user
|
// Delegate party: use share provided by user
|
||||||
|
|
@ -88,6 +89,8 @@ func (uc *ParticipateSigningUseCase) Execute(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// For delegate party, get threshold info from session
|
||||||
|
originalThresholdN = sessionInfo.ThresholdN
|
||||||
logger.Info("Using user-provided share (delegate party)",
|
logger.Info("Using user-provided share (delegate party)",
|
||||||
zap.String("party_id", input.PartyID),
|
zap.String("party_id", input.PartyID),
|
||||||
zap.String("session_id", input.SessionID.String()))
|
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)
|
// Use the most recent key share (in production, would match by public key or session reference)
|
||||||
keyShareForUpdate = keyShares[len(keyShares)-1]
|
keyShareForUpdate = keyShares[len(keyShares)-1]
|
||||||
|
|
||||||
|
// Get original threshold_n from keygen
|
||||||
|
originalThresholdN = keyShareForUpdate.ThresholdN
|
||||||
|
|
||||||
// Decrypt share data
|
// Decrypt share data
|
||||||
shareData, err = uc.cryptoService.DecryptShare(keyShareForUpdate.ShareData, input.PartyID)
|
shareData, err = uc.cryptoService.DecryptShare(keyShareForUpdate.ShareData, input.PartyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -108,7 +114,9 @@ func (uc *ParticipateSigningUseCase) Execute(
|
||||||
}
|
}
|
||||||
logger.Info("Using database share (persistent party)",
|
logger.Info("Using database share (persistent party)",
|
||||||
zap.String("party_id", input.PartyID),
|
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
|
// 4. Find self in participants and build party index map
|
||||||
|
|
@ -141,6 +149,7 @@ func (uc *ParticipateSigningUseCase) Execute(
|
||||||
selfIndex,
|
selfIndex,
|
||||||
sessionInfo.Participants,
|
sessionInfo.Participants,
|
||||||
sessionInfo.ThresholdT,
|
sessionInfo.ThresholdT,
|
||||||
|
originalThresholdN,
|
||||||
shareData,
|
shareData,
|
||||||
messageHash,
|
messageHash,
|
||||||
msgChan,
|
msgChan,
|
||||||
|
|
@ -179,6 +188,7 @@ func (uc *ParticipateSigningUseCase) runSigningProtocol(
|
||||||
selfIndex int,
|
selfIndex int,
|
||||||
participants []ParticipantInfo,
|
participants []ParticipantInfo,
|
||||||
t int,
|
t int,
|
||||||
|
n int, // Original total parties from keygen
|
||||||
shareData []byte,
|
shareData []byte,
|
||||||
messageHash []byte,
|
messageHash []byte,
|
||||||
msgChan <-chan *MPCMessage,
|
msgChan <-chan *MPCMessage,
|
||||||
|
|
@ -189,6 +199,8 @@ func (uc *ParticipateSigningUseCase) runSigningProtocol(
|
||||||
zap.String("party_id", partyID),
|
zap.String("party_id", partyID),
|
||||||
zap.Int("self_index", selfIndex),
|
zap.Int("self_index", selfIndex),
|
||||||
zap.Int("t", t),
|
zap.Int("t", t),
|
||||||
|
zap.Int("n", n),
|
||||||
|
zap.Int("current_signers", len(participants)),
|
||||||
zap.Int("message_hash_len", len(messageHash)))
|
zap.Int("message_hash_len", len(messageHash)))
|
||||||
|
|
||||||
// Create message handler adapter
|
// Create message handler adapter
|
||||||
|
|
@ -204,8 +216,11 @@ func (uc *ParticipateSigningUseCase) runSigningProtocol(
|
||||||
go msgHandler.convertMessages(ctx, msgChan)
|
go msgHandler.convertMessages(ctx, msgChan)
|
||||||
|
|
||||||
// Create signing config
|
// 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{
|
config := tss.SigningConfig{
|
||||||
Threshold: t,
|
Threshold: t,
|
||||||
|
TotalParties: n, // Original total from keygen
|
||||||
TotalSigners: len(participants),
|
TotalSigners: len(participants),
|
||||||
Timeout: 5 * time.Minute,
|
Timeout: 5 * time.Minute,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue