sign

package
v0.1.4 Latest Latest
Warning

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

Go to latest
Published: May 16, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package sign implements the FROST 2-round Schnorr threshold signing protocol (RFC 9591). The math is upstream-equivalent — the only Lens-specific decisions are:

  • Domain-separation tags for the binding factor and challenge ("LENS-RHO-v1", "LENS-CHALLENGE-v1") so that a Lens signature cannot be replayed under any other Schnorr profile.
  • The hash transcript uses BLAKE3 over canonical point and party-ID encodings to match the Lens hash suite contract.

Round 1: every party samples (d_i, e_i), broadcasts (D_i = d_i·G,

E_i = e_i·G).

Round 2: every party computes

  • the binding factors ρ_i = H_rho(message, B, i)
  • R_shares[i] = D_i + ρ_i · E_i
  • R = Σ R_shares[l]
  • challenge c = H_c(R, X, message)
  • z_i = d_i + ρ_i · e_i + λ_i · s_i · c

and broadcasts z_i. Aggregate: any party computes z = Σ z_l. (R, z) is a Schnorr signature under the unchanged group public key X.

The Verify routine takes the canonical (R, z) signature, recomputes c, and checks z·G ?= R + c·X.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrIdentityCommit    = errors.New("sign: nonce commitment is the identity point")
	ErrSignerSetMismatch = errors.New("sign: signer set mismatch between rounds")
	ErrMissingCommit     = errors.New("sign: missing commit from signer")
	ErrMissingResponse   = errors.New("sign: missing response from signer")
	ErrInvalidResponse   = errors.New("sign: partial response failed verification")
	ErrInvalidSignature  = errors.New("sign: signature failed Schnorr verification")
)

Errors returned by the sign package.

Functions

func Verify

func Verify(gk *threshold.GroupKey, message []byte, sig *Signature) error

Verify checks a (R, z) Schnorr signature against `message` under the group public key in `gk`. Returns nil if valid.

Types

type CommitMsg

type CommitMsg struct {
	PartyID int
	D       primitives.Point
	E       primitives.Point
}

CommitMsg is one signer's Round-1 broadcast.

type ResponseMsg

type ResponseMsg struct {
	PartyID int
	Z       primitives.Scalar
}

ResponseMsg is one signer's Round-2 broadcast.

type Signature

type Signature struct {
	R primitives.Point
	Z primitives.Scalar
}

Signature is the aggregated Schnorr signature.

func Aggregate

func Aggregate(
	gk *threshold.GroupKey,
	message []byte,
	signers []int,
	commits map[int]*CommitMsg,
	responses map[int]*ResponseMsg,
	verShares map[int]primitives.Point,
) (*Signature, error)

Aggregate combines the Round-1 commits and Round-2 responses into a final (R, z) Schnorr signature under the GroupKey. Any signer can run this — the result is byte-identical regardless of who computes it.

func (*Signature) Bytes

func (sig *Signature) Bytes() ([]byte, error)

Bytes returns the canonical serialization of the signature (R || Z, fixed-width).

type Signer

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

Signer holds the per-round state of one party in the FROST signing protocol.

func NewSigner

func NewSigner(share *threshold.KeyShare) *Signer

NewSigner constructs a Signer from a KeyShare. The Lambda field on the share is used during Round 2 — it MUST be set to the Lagrange coefficient λ_i evaluated at 0 over the current signing set.

func (*Signer) Round1

func (s *Signer) Round1(message []byte, signers []int, randSource io.Reader) (*CommitMsg, error)

Round1 produces the (d_i, e_i) nonces and (D_i, E_i) commitments for this signer. The CommitMsg is broadcast to every signer in the set.

The randomness is hedged: a deterministic component derived from the secret share + message + signer set, XORed with fresh randomness from `rand`. This protects against bad randomness without sacrificing determinism for KAT replay (use a deterministic `rand` for replay).

func (*Signer) Round2

func (s *Signer) Round2(message []byte, commits map[int]*CommitMsg) (*ResponseMsg, error)

Round2 consumes the collected Round-1 commits, computes the binding factor + challenge, and produces the partial response z_i.

Jump to

Keyboard shortcuts

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