mirror of
https://github.com/luxfi/threshold.git
synced 2026-10-30 15:15:53 +00:00
VerifyMessage/StoreMessage/MessageContent/Number/BroadcastContent on round structs were value receivers. Go FAQ: "if any method on T takes *T, all methods should take *T." Finalize already takes *T (it mutates round state) so the others should too. Aligns the method set, removes silent struct-copies on every dispatch, and prevents future drift where a value-receiver method accidentally observes pre-Finalize state. No behavior change — all current methods are no-ops or return constants. Touched: round.Abort, round.Output, all CMP keygen/presign/sign rounds, all Doerner keygen/sign rounds, all FROST keygen/sign rounds, xor example. Build + vet clean; CMP/FROST/Doerner -race tests PASS.
157 lines
3.8 KiB
Go
157 lines
3.8 KiB
Go
package sign
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/luxfi/threshold/internal/round"
|
|
"github.com/luxfi/threshold/pkg/math/curve"
|
|
"github.com/luxfi/threshold/pkg/party"
|
|
zklogstar "github.com/luxfi/threshold/pkg/zk/logstar"
|
|
)
|
|
|
|
var _ round.Round = (*round4)(nil)
|
|
|
|
type round4 struct {
|
|
*round3
|
|
// DeltaShares[j] = δⱼ
|
|
DeltaShares map[party.ID]curve.Scalar
|
|
|
|
// BigDeltaShares[j] = Δⱼ = [kⱼ]•Γⱼ
|
|
BigDeltaShares map[party.ID]curve.Point
|
|
|
|
// Gamma = ∑ᵢ Γᵢ
|
|
Gamma curve.Point
|
|
|
|
// ChiShare = χᵢ
|
|
ChiShare curve.Scalar
|
|
}
|
|
|
|
type message4 struct {
|
|
ProofLog *zklogstar.Proof
|
|
}
|
|
|
|
type broadcast4 struct {
|
|
round.NormalBroadcastContent
|
|
// DeltaShare = δⱼ
|
|
DeltaShare curve.Scalar
|
|
// BigDeltaShare = Δⱼ = [kⱼ]•Γⱼ
|
|
BigDeltaShare curve.Point
|
|
}
|
|
|
|
// StoreBroadcastMessage implements round.BroadcastRound.
|
|
//
|
|
// - store δⱼ, Δⱼ
|
|
func (r *round4) StoreBroadcastMessage(msg round.Message) error {
|
|
body, ok := msg.Content.(*broadcast4)
|
|
if !ok || body == nil {
|
|
return round.ErrInvalidContent
|
|
}
|
|
if body.DeltaShare.IsZero() || body.BigDeltaShare.IsIdentity() {
|
|
return round.ErrNilFields
|
|
}
|
|
r.BigDeltaShares[msg.From] = body.BigDeltaShare
|
|
r.DeltaShares[msg.From] = body.DeltaShare
|
|
return nil
|
|
}
|
|
|
|
// VerifyMessage implements round.Round.
|
|
//
|
|
// - Verify Π(log*)(ϕ”ᵢⱼ, Δⱼ, Γ).
|
|
func (r *round4) VerifyMessage(msg round.Message) error {
|
|
from, to := msg.From, msg.To
|
|
body, ok := msg.Content.(*message4)
|
|
if !ok || body == nil {
|
|
return round.ErrInvalidContent
|
|
}
|
|
|
|
zkLogPublic := zklogstar.Public{
|
|
C: r.K[from],
|
|
X: r.BigDeltaShares[from],
|
|
G: r.Gamma,
|
|
Prover: r.Paillier[from],
|
|
Aux: r.Pedersen[to],
|
|
}
|
|
if !body.ProofLog.Verify(r.HashForID(from), zkLogPublic) {
|
|
return errors.New("failed to validate log proof")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// StoreMessage implements round.Round.
|
|
func (*round4) StoreMessage(round.Message) error {
|
|
return nil
|
|
}
|
|
|
|
// Finalize implements round.Round
|
|
//
|
|
// - set δ = ∑ⱼ δⱼ
|
|
// - set Δ = ∑ⱼ Δⱼ
|
|
// - verify Δ = [δ]G
|
|
// - compute σᵢ = rχᵢ + kᵢm.
|
|
func (r *round4) Finalize(out chan<- *round.Message) (round.Session, error) {
|
|
// δ = ∑ⱼ δⱼ
|
|
// Δ = ∑ⱼ Δⱼ
|
|
Delta := r.Group().NewScalar()
|
|
BigDelta := r.Group().NewPoint()
|
|
for _, j := range r.PartyIDs() {
|
|
Delta.Add(r.DeltaShares[j])
|
|
BigDelta = BigDelta.Add(r.BigDeltaShares[j])
|
|
}
|
|
|
|
// Δ == [δ]G
|
|
deltaComputed := Delta.ActOnBase()
|
|
if !deltaComputed.Equal(BigDelta) {
|
|
return r.AbortRound(errors.New("computed Δ is inconsistent with [δ]G")), nil
|
|
}
|
|
|
|
deltaInv := r.Group().NewScalar().Set(Delta).Invert() // δ⁻¹
|
|
BigR := deltaInv.Act(r.Gamma) // R = [δ⁻¹] Γ
|
|
R := BigR.XScalar() // r = R|ₓ
|
|
|
|
// km = Hash(m)⋅kᵢ
|
|
km := curve.FromHash(r.Group(), r.Message)
|
|
km.Mul(r.KShare)
|
|
|
|
// σᵢ = rχᵢ + kᵢm
|
|
SigmaShare := r.Group().NewScalar().Set(R).Mul(r.ChiShare).Add(km)
|
|
|
|
// Send to all
|
|
err := r.BroadcastMessage(out, &broadcast5{SigmaShare: SigmaShare})
|
|
if err != nil {
|
|
return r, err
|
|
}
|
|
return &round5{
|
|
round4: r,
|
|
SigmaShares: map[party.ID]curve.Scalar{r.SelfID(): SigmaShare},
|
|
Delta: Delta,
|
|
BigDelta: BigDelta,
|
|
BigR: BigR,
|
|
R: R,
|
|
}, nil
|
|
}
|
|
|
|
// RoundNumber implements round.Content.
|
|
func (message4) RoundNumber() round.Number { return 4 }
|
|
|
|
// MessageContent implements round.Round.
|
|
func (r *round4) MessageContent() round.Content {
|
|
return &message4{
|
|
ProofLog: zklogstar.Empty(r.Group()),
|
|
}
|
|
}
|
|
|
|
// RoundNumber implements round.Content.
|
|
func (broadcast4) RoundNumber() round.Number { return 4 }
|
|
|
|
// BroadcastContent implements round.BroadcastRound.
|
|
func (r *round4) BroadcastContent() round.BroadcastContent {
|
|
return &broadcast4{
|
|
DeltaShare: r.Group().NewScalar(),
|
|
BigDeltaShare: r.Group().NewPoint(),
|
|
}
|
|
}
|
|
|
|
// Number implements round.Round.
|
|
func (*round4) Number() round.Number { return 4 }
|