mldsatss

package
v2.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 30, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package mldsatss implements threshold ML-DSA (FIPS 204) signing.

The protocol is the ML-DSA variant from "Threshold Signatures Reloaded: ML-DSA and Enhanced Raccoon with Identifiable Aborts" by Borin, Celi, del Pino, Espitau, Niot, Prest (ePrint 2025/1166). It produces byte-identical FIPS 204 signatures that verify against a stock ML-DSA public key.

The current implementation targets ML-DSA-44 and supports any (threshold t, parties n) with 2 ≤ t ≤ n ≤ 6. Key generation uses a trusted dealer (matching the paper's reference); a distributed key generation protocol is not yet defined for this scheme and is left as future work.

WARNING: This is an academic-grade prototype. It has NOT received independent cryptanalytic review and is NOT suitable for production use.

In particular, the scheme's security rests on the (as-yet unproven in this setting) masking argument of ePrint 2025/1166: each party makes a local rejection decision and reveals its per-try w_i and z_i, which in principle leak information about the secret's norm. Whether the hyperball masking fully hides that leakage is a construction- and parameter-level question for expert human review. Do not deploy this package, or vary its (t, n) parameters, without such review.

Index

Constants

View Source
const (
	MsgTypeR1_44 = "mldsa44:sign:round1"
	MsgTypeR2_44 = "mldsa44:sign:round2"
	MsgTypeR3_44 = "mldsa44:sign:round3"
)

Message type strings routed through tss.MessageBroker.

View Source
const MaxParties = 6

MaxParties is the upper bound on N in the (t, n) parameter table. The table is derived from params/recover.py in the reference implementation at github.com/GuilhemN/threshold-ml-dsa-and-raccoon and is only defined for N ≤ 6.

Variables

View Source
var ErrAllTriesRejected = errors.New("mldsatss: all tries rejected; retry")

ErrAllTriesRejected is returned when every one of the K parallel tries in a single 3-round signing exchange is rejected (by party-side bound or Combine-side correctness). Callers should retry with a fresh attempt.

Functions

func TrustedDealerKeygen44

func TrustedDealerKeygen44(seed [32]byte, params *ThresholdParams44) (*PublicKey, []*Key44, error)

TrustedDealerKeygen44 derives a threshold ML-DSA-44 public key and N per-party private-key shares from a 32-byte seed. It mirrors thmldsa44/internal/NewThresholdKeysFromSeed from the reference implementation (a trusted dealer; no DKG).

The returned PublicKey is byte-identical to a stock FIPS 204 ML-DSA-44 public key and can be used with mldsa.PublicKey44.Verify.

Types

type ErrPartyResponseInvalid added in v2.3.1

type ErrPartyResponseInvalid struct {
	Slot  int    // committee slot of the offending party
	KeyId uint8  // Key44.Id of the offending party
	Try   int    // which of the K tries failed
	Cause string // human-readable reason
}

ErrPartyResponseInvalid is returned by combine when a specific party's round-3 response block fails the per-party validity check. Unlike ErrAllTriesRejected (a non-attributable retry signal), this error names the offending committee slot so the abort is identifiable. The caller should drop/penalize that party rather than blindly retry.

NOTE: the check this error reports is a *partial* identifiable-abort check (a structural L2 bound on each z_i, mirroring the L-part of the party's own rejection gate). A full algebraic check — verifying A·z_i − c·t_i matches the committed w_i — requires each party's public key share t_i = A·s1_i + s2_i, which this protocol never transmits or stores. See validatePartyResponses.

func (*ErrPartyResponseInvalid) Error added in v2.3.1

func (e *ErrPartyResponseInvalid) Error() string

type Key44

type Key44 struct {
	Id     uint8                                   `json:"id"`
	Rho    [32]byte                                `json:"rho"`
	Tr     [64]byte                                `json:"tr"`
	T1     [mldsa.K44]mldsa.RingElement            `json:"t1"`
	Shares map[uint8]*Share44                      `json:"shares"`
	A      [mldsa.K44 * mldsa.L44]mldsa.NttElement `json:"-"` // reconstructed from Rho
}

Key44 is one party's full secret-key material for threshold ML-DSA-44. It contains all shares whose honest-signer mask includes this party's Id, plus the public t1 vector needed for signature assembly.

func (*Key44) AddShare

func (k *Key44) AddShare(mask uint8, s *Share44)

AddShare inserts or replaces a share. If s1h/s2h are zero-valued the NTT caches are recomputed from S1/S2 here.

func (*Key44) Destroy added in v2.3.1

func (k *Key44) Destroy()

Destroy best-effort wipes every secret share held by this key (both the plain and NTT-domain s1/s2 polynomials) and clears the share map. The public fields (Rho, Tr, T1, A) are left intact. Like the package's other zeroization, this is best-effort: Go's GC may already have copied the secret elsewhere. After Destroy, the key can no longer participate in signing (Validate will fail with "key has no shares").

func (*Key44) Matrix

func (k *Key44) Matrix() *[mldsa.K44 * mldsa.L44]mldsa.NttElement

A returns the cached public matrix, expanding from Rho on first access.

func (*Key44) Share

func (k *Key44) Share(mask uint8) *Share44

Share returns the share indexed by mask, or nil if this party does not hold it.

func (*Key44) Validate

func (k *Key44) Validate() error

Validate checks that k is well-formed.

type Parameters

type Parameters struct {
	// contains filtered or unexported fields
}

Parameters bundles the session configuration for a threshold ML-DSA-44 signing run.

func NewParameters

func NewParameters(
	partyID *tss.PartyID,
	parties *tss.PeerContext,
	thParams *ThresholdParams44,
	keyIds []uint8,
	broker tss.MessageBroker,
) (*Parameters, error)

NewParameters builds a Parameters value. parties must be the sorted signing committee (length equal to thParams.T), keyIds must be the Key44.Id of each party in the same order.

func (*Parameters) SetAttemptID

func (p *Parameters) SetAttemptID(id uint32)

SetAttemptID sets a per-session id that is appended to the message type strings, so that multiple attempts on the same broker do not collide.

func (*Parameters) SetRand

func (p *Parameters) SetRand(r io.Reader)

SetRand overrides the randomness source (defaults to crypto/rand.Reader).

type PublicKey

type PublicKey = mldsa.PublicKey44

PublicKey is a threshold ML-DSA-44 public key. It is byte-identical to a stock FIPS 204 public key and can be used with mldsa.PublicKey44.Verify.

type Share44

type Share44 struct {
	S1  [mldsa.L44]mldsa.RingElement // plain domain
	S2  [mldsa.K44]mldsa.RingElement
	S1h [mldsa.L44]mldsa.NttElement // cached NTT(S1)
	S2h [mldsa.K44]mldsa.NttElement // cached NTT(S2)
}

Share44 is one (s1, s2) share held by a party for a specific honest-signer subset. The share's identity is the subset mask under which it was drawn.

type SignatureData

type SignatureData struct {
	Signature []byte
}

SignatureData is the output of a successful threshold ML-DSA-44 signing session. Signature is byte-identical to a stock FIPS 204 signature and verifies with mldsa.PublicKey44.Verify.

type Signing44

type Signing44 struct {
	Done chan *SignatureData
	Err  chan error
	// contains filtered or unexported fields
}

Signing44 drives the 3-round threshold ML-DSA-44 signing protocol for one attempt. If all K tries are rejected, Signing44 signals ErrAllTriesRejected via Err; callers can retry by creating a new Signing44 with a fresh attempt id.

func NewSigning44

func NewSigning44(ctx context.Context, params *Parameters, key *Key44, msg, msgCtx []byte) (*Signing44, error)

NewSigning44 starts a threshold ML-DSA-44 signing session. It registers round-1/2/3 receivers on the params.Broker and immediately broadcasts the party's Round 1 commitment.

The returned Signing44 emits the final signature on Done, or an error on Err. If every try in this attempt is rejected, Err receives ErrAllTriesRejected; the caller should retry with a new attempt id.

type ThresholdParams44

type ThresholdParams44 struct {
	T  uint8   // threshold: minimum signers required
	N  uint8   // total parties
	K  uint16  // parallel signing tries per attempt (fresh w per try)
	Nu float64 // ν: anisotropic scaling factor of the L-part in the hyperball
	R  float64 // r: primary ν-scaled L2 radius (party rejection bound)
	Rp float64 // r': secondary L2 radius used in Combine-side correctness check
}

ThresholdParams44 holds the parameters for one (t, n) configuration of threshold ML-DSA-44. See ePrint 2025/1166 for the meaning of K, R, Rp, Nu.

func GetThresholdParams44

func GetThresholdParams44(t, n int) (*ThresholdParams44, error)

GetThresholdParams44 returns the (t, n) parameters if supported.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL