mirror of
https://github.com/luxfi/threshold.git
synced 2026-10-30 15:15:53 +00:00
round.Helper was the canonical anti-pattern: a bare-noun
qualifier-name that told you nothing about what the type does. The
type is the embeddable Session implementation that protocol round
structs anchor on — its VALUE is "the base every round builds on".
Rename it to that.
type Helper struct { ... } → type Base struct { ... }
func (h *Helper) ... → func (h *Base) ...
func NewSession(...) (*Helper, error) → (*Base, error)
Output { *Helper } → Output { *Base }
Abort { *Helper } → Abort { *Base }
round.Helper → round.Base (18 files)
Helper: helper → Base: helper (struct literal init)
r.Helper.X / r.Helper → r.Base.X / r.Base (field access)
internal/round/helper.go → base.go
internal/round/helper_test.go → base_test.go
Forward-only — no type alias, no deprecation. The Go FAQ pointer-
receiver consistency landed in the prior commit (f7b1365) so the
method set is already aligned; this commit only renames the type.
Build + vet clean; round / CMP keygen smoke / FROST keygen all
PASS unchanged.
148 lines
3.3 KiB
Go
148 lines
3.3 KiB
Go
package sign
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"errors"
|
|
"sync"
|
|
|
|
"github.com/luxfi/threshold/internal/round"
|
|
"github.com/luxfi/threshold/pkg/math/curve"
|
|
"github.com/luxfi/threshold/pkg/math/sample"
|
|
"github.com/luxfi/threshold/pkg/party"
|
|
"github.com/luxfi/threshold/protocols/lss/config"
|
|
)
|
|
|
|
// round1 generates nonces for signing
|
|
type round1 struct {
|
|
*round.Base
|
|
|
|
config *config.Config
|
|
signers []party.ID
|
|
messageHash []byte
|
|
|
|
// Our nonce pair
|
|
k curve.Scalar // Secret nonce
|
|
K curve.Point // Public nonce commitment g^k
|
|
|
|
// Storage for received nonces from other parties
|
|
receivedNonces sync.Map // map[party.ID]curve.Point
|
|
}
|
|
|
|
// broadcast1 contains the nonce commitment
|
|
type broadcast1 struct {
|
|
round.NormalBroadcastContent
|
|
|
|
// Public nonce commitment - stored as bytes for CBOR compatibility
|
|
K []byte
|
|
}
|
|
|
|
// Number implements round.Round
|
|
func (r *round1) Number() round.Number {
|
|
return 1
|
|
}
|
|
|
|
// BroadcastContent implements round.BroadcastRound
|
|
func (r *round1) BroadcastContent() round.BroadcastContent {
|
|
return &broadcast1{}
|
|
}
|
|
|
|
// MessageContent implements round.Round
|
|
func (r *round1) MessageContent() round.Content {
|
|
return nil // No P2P messages in round 1
|
|
}
|
|
|
|
// RoundNumber implements round.Content
|
|
func (broadcast1) RoundNumber() round.Number {
|
|
return 1
|
|
}
|
|
|
|
// VerifyMessage implements round.Round
|
|
func (r *round1) VerifyMessage(_ round.Message) error {
|
|
return nil // No P2P messages
|
|
}
|
|
|
|
// StoreMessage implements round.Round
|
|
func (r *round1) StoreMessage(_ round.Message) error {
|
|
return nil // No P2P messages
|
|
}
|
|
|
|
// Finalize implements round.Round
|
|
func (r *round1) Finalize(out chan<- *round.Message) (round.Session, error) {
|
|
// Generate random nonce
|
|
r.k = sample.Scalar(rand.Reader, r.Group())
|
|
r.K = r.k.ActOnBase()
|
|
|
|
// Marshal K to bytes for broadcast
|
|
kBytes, err := r.K.MarshalBinary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Broadcast nonce commitment
|
|
if err := r.BroadcastMessage(out, &broadcast1{
|
|
K: kBytes,
|
|
}); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Collect received nonces from sync.Map
|
|
nonces := make(map[party.ID]curve.Point)
|
|
r.receivedNonces.Range(func(key, value interface{}) bool {
|
|
id := key.(party.ID)
|
|
nonces[id] = value.(curve.Point)
|
|
return true
|
|
})
|
|
|
|
return &round2{
|
|
round1: r,
|
|
nonces: nonces,
|
|
}, nil
|
|
}
|
|
|
|
// StoreBroadcastMessage implements round.BroadcastRound
|
|
func (r *round1) StoreBroadcastMessage(msg round.Message) error {
|
|
body, ok := msg.Content.(*broadcast1)
|
|
if !ok || body == nil {
|
|
return round.ErrInvalidContent
|
|
}
|
|
|
|
// Unmarshal K from bytes
|
|
K, err := body.GetK(r.Group())
|
|
if err != nil {
|
|
return errors.New("invalid nonce commitment: " + err.Error())
|
|
}
|
|
|
|
// Verify K is not identity
|
|
if K.IsIdentity() {
|
|
return errors.New("invalid nonce commitment: identity point")
|
|
}
|
|
|
|
// Verify sender is a signer
|
|
isSigner := false
|
|
for _, id := range r.signers {
|
|
if id == msg.From {
|
|
isSigner = true
|
|
break
|
|
}
|
|
}
|
|
if !isSigner {
|
|
return errors.New("sender not in signers list")
|
|
}
|
|
|
|
// Store using sync.Map for thread safety
|
|
r.receivedNonces.Store(msg.From, K)
|
|
return nil
|
|
}
|
|
|
|
// GetK unmarshals the K bytes into a curve.Point
|
|
func (b *broadcast1) GetK(group curve.Curve) (curve.Point, error) {
|
|
if len(b.K) == 0 {
|
|
return nil, errors.New("missing nonce commitment")
|
|
}
|
|
point := group.NewPoint()
|
|
if err := point.UnmarshalBinary(b.K); err != nil {
|
|
return nil, err
|
|
}
|
|
return point, nil
|
|
}
|