tss

package module
v0.0.0-...-f8554af Latest Latest
Warning

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

Go to latest
Published: Oct 5, 2026 License: MIT Imports: 24 Imported by: 0

README

tss

Transport- and storage-neutral threshold-signature protocols for Go.

The module provides FROST-style threshold Ed25519 and CGGMP21-style threshold ECDSA over secp256k1, plus shared envelope validation, durable integration contracts, refresh and resharing, and non-hardened HD derivation.

[!WARNING] This repository is not a production-audited TSS stack. The CGGMP21 Paillier/ZK layer has not received independent cryptographic review. Treat the APIs and wire records as pre-production, and read the security model before evaluating an integration.

Requirements

Go 1.26.3 or later is required.

go get github.com/islishude/tss

Packages

Package Responsibility
github.com/islishude/tss Shared identifiers, envelopes, guards, replay and broadcast validation, signing context, HD types, and refresh helpers.
github.com/islishude/tss/tssrun Run acceptance, active-session routing, unknown-session policy, and durable lifecycle interfaces.
github.com/islishude/tss/frost/ed25519 FROST-style Ed25519 DKG, signing, refresh, resharing, import, reconstruction, and derivation.
github.com/islishude/tss/cggmp21/secp256k1 CGGMP21-style threshold ECDSA, including Paillier MtA and zero-knowledge proofs.

The library does not provide a production network, peer authentication, database, KMS/HSM, distributed scheduler, or control plane. In-memory stores, the passphrase helpers, and tssrun.FileLifecycleStore are reference implementations, not production durability or key management.

Protocol Surface

Capability frost/ed25519 cggmp21/secp256k1
Dealerless keygen Three-round proof-gated DKG with final confirmation Figure 6 followed by Figure 7/F.1 and final confirmation
Trusted import Interactive contributions or centralized provisioning Interactive contributions or centralized provisioning
Reconstruction Explicit interpolation of the canonical Ed25519 group scalar Explicit interpolation of the secp256k1 private scalar
Signing Two online rounds; standard 64-byte Ed25519 signature Three-round Figure 8 presign; one-round Figure 10 signing
Refresh Same party set and threshold; caller-managed compare-and-swap Same party set and threshold; lifecycle-managed auxiliary-key rotation and cutover
Resharing Party-set and threshold change with target-holder confirmation Old-dealer/new-receiver handoff, fresh Figure 7/F.1 epoch, and lifecycle-managed commit
HD derivation Local non-hardened Ed25519-BIP32-style public derivation Explicit non-hardened child lineage with a fresh auxiliary epoch
Attributable failures Public blame evidence for defined failure classes Signed equivocation, Figure 7 accusations, Figure 9 proofs, and invalid partials

FROST signing uses RFC 9591 signing equations and produces signatures accepted by crypto/ed25519.Verify. Dealerless DKG, lifecycle confirmation, refresh, resharing, nonce binding, and Ed25519-BIP32-style derivation are repository extensions, so the package is described as FROST-style rather than as a wire-compatible implementation of an RFC ciphersuite.

CGGMP21 follows Figures 6-10 of the bundled 2024 paper revision. The current proof inventory and implementation mapping live in docs/paillier-zk-proofs.md and docs/cggmp21-paper-mapping.md.

Default limits and CGGMP21 security parameters are production-policy profiles. Reduced profiles are explicit non-production intent and are bound into plans and persisted state where applicable.

Quick Start

Run the executable 2-of-2 FROST DKG and signing example:

go test ./frost/ed25519 -run '^ExampleSign$' -count=1

Run the integration-tagged CGGMP21 lifecycle example:

go test -tags=integration ./cggmp21/secp256k1 \
  -run '^Example_full_lifecycle$' -count=1

These examples simulate several parties in one process while exercising the public plans, guards, envelopes, and state machines. They are executable references, not deployment templates. See frost/ed25519/examples_test.go, cggmp21/secp256k1/integration_example_test.go, and the integration model.

Trusted-import examples are separate:

go test ./frost/ed25519 -run '^ExampleGenerateTrustedDealerKeyShares$' -count=1
go test ./cggmp21/secp256k1 -run '^ExampleNewTrustedDealerImport$' -count=1

Integration Boundary

Each participant runs one local state machine. A deployment must:

  1. Authorize and durably accept one tssrun.RunIntent with a fresh shared session ID.
  2. Reconstruct the same protocol plan at every party and accept the same RunIntent.AcceptanceDigest() before releasing data-plane messages.
  3. Build an EnvelopeGuard with the protocol policy set, durable replay cache, broadcast-ack verifier, and any required envelope-signature verifier.
  4. Derive ReceiveInfo from the authenticated transport, call tss.OpenEnvelope, and dispatch the immutable InboundEnvelope to the registered local session. Secret direct messages require confidential transport; broadcast messages require the configured consistency certificate.
  5. Treat tssrun.DispatchResult as a caller-owned outbox transaction: persist it durably, deliver only the persisted envelopes, record delivery, and then call Destroy. Dispatcher never sends automatically.
  6. Persist key generations and protocol results at their documented durable boundary. Both protocol packages provide InstallKeyShare helpers for a confirmed initial generation; CGGMP21 presign, sign, refresh, reshare, and child flows use tssrun.LifecycleStore directly.
  7. Drive sessions through Status, reconcile CommitPending with the exact protocol recovery method, and retry Abort/Close while ClosePending. Handle is cooperatively cancelable at decode, proof-loop, preparation, and pre-commit boundaries.

Production protocol starts require the exact canonical digest of FROSTPolicies() or CGGMP21Policies(). Relaxed policy sets and guards are test-only and cannot be constructed as production guards.

See docs/tssrun.md for API contracts, docs/integration.md for the end-to-end flow, and docs/deployment.md for operational controls.

CGGMP21 presigns are one-use. A commit with unknown outcome remains bound to the exact attempt; reconcile it or call ResumeSign, and never release or reuse the presign. Trusted import and reconstruction are separate, explicitly authorized exfiltration ceremonies. See docs/security.md for both boundaries.

Development

The Makefile is the command source of truth:

Command Scope
make help List supported targets.
make check Build, vet, lint, formatting/module hygiene, and API-boundary checks.
make ci make check plus Tier 0 and reduced-parameter Tier 1 tests.
make test-integration Tier 2 lifecycle, adversarial delivery, restart, and recovery flows.
make test-slowcrypto Tier 3 production-parameter Paillier/ZK smoke tests.
make test-race Integration flows under the race detector.
make fuzz-smoke Short decoder and reject-path fuzz runs.
make vectors-verify-all Verify committed wire, protocol, and fixture vectors.

Read docs/testing-rules.md for test selection and docs/testing-invariants.md for required behavioral contracts.

Documentation

Area Entry points
Integration Integration model, tssrun API, deployment
Security Threat model, wire format, root package
Protocols FROST Ed25519, CGGMP21 secp256k1
Review Architecture, Paillier/ZK proofs, audit guide, CGGMP21 checklist
Verification Testing rules, testing invariants, test inventory, vectors

License

MIT

Documentation

Overview

Package tss defines transport-neutral building blocks shared by the threshold-signature protocol packages in this module.

The root package intentionally does not provide a network transport, durable storage, or secret-at-rest encryption. Callers are responsible for authenticated delivery of envelopes and must construct InboundEnvelope values with OpenEnvelope and transport-verified ReceiveInfo. Confidentiality requirements are defined per payload type by the protocol PolicySet and enforced by EnvelopeGuard.

Security Model

Every protocol session must receive an EnvelopeGuard at its Start* entry point before it can emit or process protocol envelopes. The guard enforces:

Sessions reject startup and inbound handling when no guard is configured. Production integrations must construct a guard via NewEnvelopeGuard or GuardConfig.BuildGuard with a production PolicySet and a durable ReplayCache.

See docs/security.md for the complete threat model and integration checklist.

Example (EncryptDecrypt)

ExampleStorage_encryptDecrypt demonstrates password-based encryption and decryption of key material using the reference EncryptKeyShareWithPassphrase and DecryptKeyShareWithPassphrase helpers. These functions are intended for local storage encryption at rest; they are NOT a substitute for transport encryption between parties.

package main

import (
	"fmt"

	"github.com/islishude/tss"
)

func main() {
	passphrase := []byte("correct horse battery staple")
	keyMaterial := []byte("this is a serialized key share")

	// --- 1. Encrypt key material with a passphrase ---
	// The optional PassphraseParams can tune Argon2id cost parameters.
	// Nil parameters use the documented production defaults.
	encrypted, err := tss.EncryptKeyShareWithPassphrase(keyMaterial, passphrase, "my-key-id", nil)
	if err != nil {
		panic(err)
	}

	// --- 2. Decrypt the ciphertext with the same passphrase ---
	// DecryptKeyShareWithPassphrase verifies the key ID and AEAD tag,
	// returning the original plaintext only if both are correct.
	decrypted, err := tss.DecryptKeyShareWithPassphrase(encrypted, passphrase, "my-key-id")
	if err != nil {
		panic(err)
	}

	fmt.Println(string(decrypted))
}
Output:
this is a serialized key share

Index

Examples

Constants

View Source
const (
	// ErrCodeInvalidConfig marks invalid local protocol configuration.
	ErrCodeInvalidConfig = "invalid_config"
	// ErrCodeInvalidMessage marks malformed or cross-session protocol messages.
	ErrCodeInvalidMessage = "invalid_message"
	// ErrCodeDuplicate marks replayed or repeated messages for a round.
	ErrCodeDuplicate = "duplicate_message"
	// ErrCodeRound marks a message delivered to the wrong protocol round.
	ErrCodeRound = "wrong_round"
	// ErrCodeVerification marks a failed cryptographic or transcript check.
	ErrCodeVerification = "verification_failed"
	// ErrCodeAggregateSignInvalid marks an aggregate signature that failed verification.
	// The blamed parties form a suspect set — individual partials cannot be verified
	// independently in the current protocol, so all signers are listed as candidate
	// sources. This is not a proof that any specific signer acted maliciously.
	ErrCodeAggregateSignInvalid = "aggregate_sign_invalid"
	// ErrCodeNotReady marks a protocol state that has not collected enough messages.
	ErrCodeNotReady = "not_ready"
	// ErrCodeConsumed marks one-use material that has already been consumed.
	ErrCodeConsumed = "consumed"
	// ErrCodeCompleted marks a protocol session that has already completed.
	ErrCodeCompleted = "completed"
	// ErrCodeAborted marks a protocol session that previously hit an attributable abort.
	ErrCodeAborted = "aborted"
	// ErrCodeNotImplemented marks intentionally unsupported protocol features.
	ErrCodeNotImplemented = "not_implemented"
	// ErrCodeLimitExceeded marks a value that exceeds a configured hard cap.
	ErrCodeLimitExceeded = "limit_exceeded"
	// ErrCodeTooManyParties marks a party set that exceeds the configured maximum.
	ErrCodeTooManyParties = "too_many_parties"
	// ErrCodeTooManySigners marks a signer set that exceeds the configured maximum.
	ErrCodeTooManySigners = "too_many_signers"
	// ErrCodePayloadTooLarge marks a payload that exceeds its byte cap.
	ErrCodePayloadTooLarge = "payload_too_large"
	// ErrCodeProofTooLarge marks a proof input that exceeds its byte cap.
	ErrCodeProofTooLarge = "proof_too_large"
	// ErrCodeInvariant marks an implementation-invariant failure. This is not a
	// protocol-level blame event — it indicates a bug in the library or corrupted
	// local state. No participants are blamed.
	ErrCodeInvariant = "invariant"
)
View Source
const (
	// DefaultMaxParties is the maximum number of participants across algorithms.
	DefaultMaxParties = 64
	// DefaultMaxThreshold is the maximum threshold value across algorithms.
	DefaultMaxThreshold = 64
	// DefaultMaxSigners is the maximum number of concurrent signers.
	DefaultMaxSigners = 64
)
View Source
const (
	// DefaultMaxWireFields caps the field count inside a TLV message.
	DefaultMaxWireFields = 256
	// DefaultMaxWireFieldBytes caps a single TLV field value.
	DefaultMaxWireFieldBytes = 1 << 20
)
View Source
const (
	// DefaultMaxEnvelopeBytes is the maximum wire-encoded envelope size (1 MiB).
	DefaultMaxEnvelopeBytes = 1 << 20
	// DefaultMaxEnvelopePayloadBytes is the maximum payload inside an envelope (1 MiB).
	DefaultMaxEnvelopePayloadBytes = 1 << 20
	// DefaultMaxPayloadTypeBytes caps the payload type identifier length.
	DefaultMaxPayloadTypeBytes = 128
	// DefaultMaxProtocolNameBytes caps the protocol name length inside envelopes.
	DefaultMaxProtocolNameBytes = 64
	// DefaultMaxEnvelopeSignatureBytes caps a portable sender signature.
	DefaultMaxEnvelopeSignatureBytes = 4096
)
View Source
const (
	// DefaultMaxBlameEvidenceBytes caps the total encoded blame evidence size (1 MiB).
	DefaultMaxBlameEvidenceBytes = 1 << 20
	// DefaultMaxEvidenceReasonBytes caps the reason string length in blame evidence.
	DefaultMaxEvidenceReasonBytes = 256
	// DefaultMaxEvidenceFieldCount caps the number of public input fields in blame evidence.
	DefaultMaxEvidenceFieldCount = 64
	// DefaultMaxEvidenceFieldKeyBytes caps a single evidence field key length.
	DefaultMaxEvidenceFieldKeyBytes = 128
	// DefaultMaxEvidenceFieldValueBytes caps a single evidence field value length.
	DefaultMaxEvidenceFieldValueBytes = 1 << 20
)
View Source
const (
	// DefaultMaxSerializedKeyShareBytes caps serialized KeyShare size (2 MiB).
	DefaultMaxSerializedKeyShareBytes = 2 << 20
	// DefaultMaxSerializedPresignBytes caps serialized Presign size (2 MiB).
	DefaultMaxSerializedPresignBytes = 2 << 20
	// DefaultMaxSerializedResharePlanBytes caps serialized public reshare plans (1 MiB).
	DefaultMaxSerializedResharePlanBytes = 1 << 20
	// DefaultMaxSerializedTrustedDealerPlanBytes caps serialized trusted-dealer import plans (1 MiB).
	DefaultMaxSerializedTrustedDealerPlanBytes = 1 << 20
	// DefaultMaxSerializedTrustedDealerContributionBytes caps one serialized secret contribution (64 KiB).
	DefaultMaxSerializedTrustedDealerContributionBytes = 64 << 10
)
View Source
const (
	// DefaultMaxPointBytes caps curve point encoding size.
	DefaultMaxPointBytes = 65
	// DefaultMaxScalarBytes caps curve scalar encoding size.
	DefaultMaxScalarBytes = 32
)
View Source
const (
	// DefaultMaxPaillierModulusBits caps the Paillier modulus size (8192 bits).
	DefaultMaxPaillierModulusBits = 8192
	// DefaultMaxPaillierPublicKeyBytes caps marshaled Paillier public key size.
	DefaultMaxPaillierPublicKeyBytes = 2048
	// DefaultMaxPaillierPrivateKeyBytes caps marshaled Paillier private key size.
	DefaultMaxPaillierPrivateKeyBytes = 4096
	// DefaultMaxPaillierCiphertextBytes caps a Paillier ciphertext (N^2 encoding).
	DefaultMaxPaillierCiphertextBytes = 2048
	// DefaultMaxPaillierProofBytes caps Paillier-related ZK proof size (256 KiB).
	DefaultMaxPaillierProofBytes = 256 << 10
	// DefaultMaxRingPedersenParamsBytes caps Ring-Pedersen parameter marshaling.
	DefaultMaxRingPedersenParamsBytes = 16384
	// DefaultMaxMTAResponseBytes caps an MtA response message size (512 KiB).
	DefaultMaxMTAResponseBytes = 512 << 10
	// DefaultMaxZKProofBytes caps any ZK proof input (512 KiB).
	DefaultMaxZKProofBytes = 512 << 10
)
View Source
const HardenedKeyStart uint32 = 1 << 31

HardenedKeyStart is the first index reserved for hardened BIP32 derivation. Online signing APIs currently accept only indices below this value.

View Source
const (

	// IdentificationRecordEvidenceKey is the fixed BlameEvidence.PublicInputs
	// key carrying a canonical IdentificationRecord.
	IdentificationRecordEvidenceKey = "identification_record"
)
View Source
const MaxDerivationDepth = 255

MaxDerivationDepth is the maximum path depth representable by BIP32 extended keys and derivation results.

View Source
const ProtocolVersion uint16 = 1

ProtocolVersion is the semantic protocol version bound into transcripts and durable protocol records.

Variables

View Source
var (
	// ErrChainCodeRequired reports that a key share or derivation input lacks chain code.
	ErrChainCodeRequired = errors.New("chain code required")
	// ErrInvalidChainCodeLength reports that a chain code is not exactly 32 bytes.
	ErrInvalidChainCodeLength = errors.New("invalid chain code length")
	// ErrInvalidPublicKey reports that a derivation input public key is not valid for the scheme.
	ErrInvalidPublicKey = errors.New("invalid public key")
	// ErrHardenedDerivationUnsupported reports that an online signing path contains a hardened index.
	ErrHardenedDerivationUnsupported = errors.New("hardened derivation unsupported")
	// ErrInvalidChild reports that public derivation produced an invalid child.
	ErrInvalidChild = errors.New("invalid child derivation")
	// ErrDerivationDepthOverflow reports that a path exceeds the BIP32 255-level depth.
	ErrDerivationDepthOverflow = errors.New("derivation depth overflow")
	// ErrInvalidChildMode reports an undefined invalid-child handling mode.
	ErrInvalidChildMode = errors.New("invalid child mode")
	// ErrInvalidExtendedPublicKey is returned when an extended public key fails
	// validation (bad version, invalid point, etc.).
	ErrInvalidExtendedPublicKey = errors.New("invalid extended public key")
)
View Source
var ErrBroadcastEquivocation = errors.New("broadcast equivocation detected")

ErrBroadcastEquivocation is returned when a sender sends different payloads to different parties.

View Source
var ErrDuplicateMessage = errors.New("duplicate message")

ErrDuplicateMessage is returned when an identical message (same slot, same payload hash) is delivered more than once.

View Source
var ErrEquivocation = errors.New("equivocation detected")

ErrEquivocation is returned when a party sends different payloads to different recipients for the same protocol message slot: the slot exists but with a different payload hash.

View Source
var ErrExpectedBroadcastMessage = errors.New("expected broadcast message")

ErrExpectedBroadcastMessage is returned when a direct envelope arrives for a broadcast-only payload type.

View Source
var ErrExpectedDirectMessage = errors.New("expected direct message")

ErrExpectedDirectMessage is returned when a broadcast envelope arrives for a direct-only payload type.

View Source
var ErrInvalidBroadcastCertificate = errors.New("invalid broadcast certificate")

ErrInvalidBroadcastCertificate is returned when a broadcast certificate fails validation.

View Source
var ErrInvalidChannelProtection = errors.New("invalid channel protection")

ErrInvalidChannelProtection is returned when the receive path reports an undefined non-zero channel-protection value.

View Source
var ErrInvalidEnvelopeSignature = errors.New("invalid envelope sender signature")

ErrInvalidEnvelopeSignature is returned when portable sender authentication fails.

View Source
var ErrInvalidSessionID = errors.New("invalid session id")

ErrInvalidSessionID is returned when a session is created with a zero or invalid session ID.

View Source
var ErrMissingAckVerifier = errors.New("missing broadcast ack verifier")

ErrMissingAckVerifier is returned when broadcast ACK verification is required but no verifier is configured.

View Source
var ErrMissingBroadcastCertificate = errors.New("missing broadcast certificate")

ErrMissingBroadcastCertificate is returned when a broadcast-consistency-required payload has no certificate.

View Source
var ErrMissingChannelProtection = errors.New("missing channel protection")

ErrMissingChannelProtection is returned when the receive path does not report whether an envelope arrived over plaintext or confidential transport.

View Source
var ErrMissingConfidentiality = errors.New("missing transport confidentiality")

ErrMissingConfidentiality is returned when a confidential-required payload arrives over plaintext.

View Source
var ErrMissingEnvelopeGuard = errors.New("missing envelope guard")

ErrMissingEnvelopeGuard is returned when an envelope arrives without a configured guard.

View Source
var ErrMissingEnvelopeSignature = errors.New("missing envelope sender signature")

ErrMissingEnvelopeSignature is returned when policy requires portable sender authentication.

View Source
var ErrMissingEnvelopeSignatureVerifier = errors.New("missing envelope signature verifier")

ErrMissingEnvelopeSignatureVerifier is returned when signature policy has no verifier.

View Source
var ErrMissingEnvelopeSigner = errors.New("missing envelope signer")

ErrMissingEnvelopeSigner indicates that a protocol requiring portable direct message signatures was started without a local transport-identity signer.

View Source
var ErrMissingReplayCache = errors.New("missing replay cache")

ErrMissingReplayCache is returned when a session constructor receives a nil ReplayCache.

View Source
var ErrPlanHashMismatch = errors.New("lifecycle plan hash mismatch")

ErrPlanHashMismatch is returned when protocol input is bound to a different lifecycle plan.

View Source
var ErrRefreshCommitOutcomeUnknown = errors.New("refresh key-share commit outcome unknown")

ErrRefreshCommitOutcomeUnknown marks a CommitKeyShare error whose durable outcome cannot be determined. When this error is wrapped, the callback keeps ownership of the refreshed key share for recovery and reconciliation.

View Source
var ErrRefreshSchedulerRunning = errors.New("refresh scheduler is already running")

ErrRefreshSchedulerRunning is returned when Run or RunOnce is called while another scheduler run is active.

View Source
var ErrReplayCacheFull = errors.New("replay cache full")

ErrReplayCacheFull is returned when a bounded replay cache cannot record a new message slot without forgetting previously accepted protocol traffic.

View Source
var ErrSelfSender = errors.New("envelope sender is local party")

ErrSelfSender is returned when a local guard receives an envelope claiming to have been sent by the same local party.

View Source
var ErrSenderIdentityMismatch = errors.New("sender identity mismatch")

ErrSenderIdentityMismatch is returned when the transport-authenticated party differs from Envelope.From.

View Source
var ErrStorageKeyIDMismatch = errors.New("storage key id mismatch")

ErrStorageKeyIDMismatch is returned when an authenticated storage record is valid but is bound to a different caller-assigned key ID.

View Source
var ErrUnauthenticatedTransport = errors.New("unauthenticated transport")

ErrUnauthenticatedTransport is returned when an envelope arrives over an unauthenticated transport.

View Source
var ErrUnexpectedConfidentiality = errors.New("unexpected transport confidentiality")

ErrUnexpectedConfidentiality is returned when a confidential-forbidden payload arrives over a confidential channel.

View Source
var ErrUnknownPayloadPolicy = errors.New("unknown payload delivery policy")

ErrUnknownPayloadPolicy is returned when no delivery policy matches the envelope's protocol/round/payloadType.

View Source
var ErrWrongRecipient = errors.New("wrong envelope recipient")

ErrWrongRecipient is returned when a direct message is addressed to the wrong party.

Functions

func AckDigest

func AckDigest(protocol ProtocolID, sessionID SessionID, round uint8, from PartyID, payloadType PayloadType, payloadHash [32]byte, envelopeDigest EnvelopeDigest) [32]byte

AckDigest computes the canonical digest that parties sign for a broadcast ack. It binds the ack to the complete broadcast message identity.

func CheckHandlerContext

func CheckHandlerContext(delivery, session context.Context) error

CheckHandlerContext checks both the per-delivery context and the session context. Protocol handlers call it at state-transition boundaries; it does not claim to interrupt one indivisible cryptographic operation.

func ContainsParty

func ContainsParty(parties PartySet, id PartyID) bool

ContainsParty reports whether id appears in parties.

func DecodeBinary

func DecodeBinary[T any](in []byte) (*T, error)

DecodeBinary decodes a binary-encoded value through its standard encoding.BinaryUnmarshaler implementation.

func DecodeBinaryValue

func DecodeBinaryValue[T any](in []byte) (T, error)

DecodeBinaryValue decodes a binary-encoded value and returns it by value.

func DecodeBinaryValueWithLimits

func DecodeBinaryValueWithLimits[T any, L any](in []byte, limits L) (T, error)

DecodeBinaryValueWithLimits decodes a limits-aware binary value and returns it by value.

func DecodeBinaryWithLimits

func DecodeBinaryWithLimits[T any, L any](in []byte, limits L) (*T, error)

DecodeBinaryWithLimits decodes a binary-encoded value through its limits-aware unmarshaler implementation.

func DecryptKeyShareWithPassphrase

func DecryptKeyShareWithPassphrase(encoded, passphrase []byte, expectedKeyID string) ([]byte, error)

DecryptKeyShareWithPassphrase decrypts an encoding produced by EncryptKeyShareWithPassphrase and requires its authenticated key ID to match expectedKeyID.

func DecryptPresignWithPassphrase

func DecryptPresignWithPassphrase(encoded, passphrase []byte, expectedKeyID string) ([]byte, error)

DecryptPresignWithPassphrase decrypts an encoding produced by EncryptPresignWithPassphrase and requires its authenticated key ID to match expectedKeyID.

func DecryptSignAttemptWithPassphrase

func DecryptSignAttemptWithPassphrase(encoded, passphrase []byte, expectedKeyID string) ([]byte, error)

DecryptSignAttemptWithPassphrase decrypts an encoding produced by EncryptSignAttemptWithPassphrase and requires its authenticated key ID to match expectedKeyID.

func DecryptSignAttemptWithPassphraseAndKeyID

func DecryptSignAttemptWithPassphraseAndKeyID(encoded, passphrase []byte) ([]byte, string, error)

DecryptSignAttemptWithPassphraseAndKeyID decrypts a sign-attempt encoding and returns its authenticated caller-assigned key ID. Callers that use keyID to bind object kind or storage identity must compare the returned value with the expected value after decoding the plaintext record.

func EncryptKeyShareWithPassphrase

func EncryptKeyShareWithPassphrase(plaintext, passphrase []byte, keyID string, params *PassphraseParams) ([]byte, error)

EncryptKeyShareWithPassphrase encrypts a key-share with a passphrase using Argon2id key derivation and ChaCha20-Poly1305. keyID is an optional caller-assigned identifier that is authenticated as AAD (empty string is allowed).

This is a reference/demo implementation. Production deployments should use a KMS or HSM for key material protection.

func EncryptPresignWithPassphrase

func EncryptPresignWithPassphrase(plaintext, passphrase []byte, keyID string, params *PassphraseParams) ([]byte, error)

EncryptPresignWithPassphrase encrypts a presign record with a passphrase using Argon2id key derivation and ChaCha20-Poly1305. keyID is an optional caller-assigned identifier that is authenticated as AAD (empty string is allowed).

This is a reference/demo implementation. Production deployments should use a KMS or HSM for key material protection.

func EncryptSignAttemptWithPassphrase

func EncryptSignAttemptWithPassphrase(plaintext, passphrase []byte, keyID string, params *PassphraseParams) ([]byte, error)

EncryptSignAttemptWithPassphrase encrypts a sign-attempt record with a passphrase using Argon2id key derivation and ChaCha20-Poly1305. keyID is an optional caller-assigned identifier that is authenticated as AAD.

This is a reference/demo implementation. Production deployments should use a KMS or HSM for confidential signing-outbox records.

func EnvelopeSigningDigest

func EnvelopeSigningDigest(e Envelope) [32]byte

EnvelopeSigningDigest computes the digest authenticated by SenderSignature. The signature field itself is deliberately excluded.

func IsAttributableError

func IsAttributableError(err error) bool

IsAttributableError reports whether err carries blame evidence and should cause the session to abort. Verification failures with blame are attributable; duplicate messages are not.

This matches the [shouldAbortSession] logic used by protocol handlers.

func IsSessionAborted

func IsSessionAborted(err error) bool

IsSessionAborted reports whether err is a ProtocolError with code ErrCodeAborted, indicating the protocol session was aborted due to an attributable verification failure.

func IsSessionCompleted

func IsSessionCompleted(err error) bool

IsSessionCompleted reports whether err is a ProtocolError with code ErrCodeCompleted, indicating the protocol session has already finished.

func MarshalEnvelopeWithLimits

func MarshalEnvelopeWithLimits(env Envelope, limits EnvelopeLimits) ([]byte, error)

MarshalEnvelopeWithLimits encodes the envelope using the object-level wire codec, enforcing the provided size limits.

func MarshalEvidenceWithLimits

func MarshalEvidenceWithLimits(e *BlameEvidence, l EvidenceLimits) ([]byte, error)

MarshalEvidenceWithLimits encodes BlameEvidence using the object-level wire codec with explicit limits. Fields are sorted into canonical order so that logically equivalent evidence records produce identical hashes.

func PartySetHash

func PartySetHash(parties PartySet, label string) []byte

PartySetHash returns a SHA-256 digest that binds a label and a sorted party set.

Parties are sorted with tss.SortParties before hashing so that the same set always produces the same 32-byte digest regardless of input order.

Different labels guarantee domain separation — the same party set hashed under "keygen" and "signing" labels will produce distinct digests.

func PayloadHashFromEnvelope

func PayloadHashFromEnvelope(env Envelope) [32]byte

PayloadHashFromEnvelope returns the SHA-256 hash of the envelope payload. It is used with ReplayCache.CheckAndStore as the content discriminator: two messages in the same slot with different payload hashes are equivocation.

func RequireEnvelopeGuard

func RequireEnvelopeGuard(guard *EnvelopeGuard, expectedProtocol ProtocolID, expectedSession SessionID, self PartyID, expectedPolicies PolicySet) error

RequireEnvelopeGuard verifies that guard is bound to the expected protocol session and has the fixed validation dependencies required by inbound handlers. It does not validate the guard's party set; protocol handlers pass the per-message allowed sender set to ValidateInbound.

func ValidateEnvelopePolicy

func ValidateEnvelopePolicy(env InboundEnvelope, self PartyID, policies PolicySet) error

ValidateEnvelopePolicy checks delivery mode and confidentiality against a PolicySet. It is a lightweight complement for the test fallback path (when no EnvelopeGuard is set and the transport is unauthenticated). It does NOT check broadcast consistency or replay — those require guard infrastructure.

func ValidateInbound

func ValidateInbound(guard *EnvelopeGuard, env InboundEnvelope, expectedProtocol ProtocolID, expectedSession SessionID, allowedSenders PartySet, self PartyID) error

ValidateInbound validates an incoming envelope through the provided guard. The guard must be non-nil — a nil guard returns ErrMissingEnvelopeGuard. This ensures transport authentication, confidentiality enforcement, broadcast consistency, and replay detection are applied uniformly in all code paths.

The allowedSenders parameter specifies which participants are accepted as senders for this message. The guard's configured EnvelopeGuard.Parties field is the construction-time party universe; callers must supply the appropriate allowed sender set per round or per payload type. For sessions where the trusted party universe changes between rounds (e.g. reshare with old and new party subsets), this design avoids coupling guard construction to per-message validation.

func ValidateInboundWithoutReplay

func ValidateInboundWithoutReplay(guard *EnvelopeGuard, env InboundEnvelope, expectedProtocol ProtocolID, expectedSession SessionID, allowedSenders PartySet, self PartyID) error

ValidateInboundWithoutReplay validates a retryable early message without mutating the guard's replay cache. Once the protocol becomes ready, callers must pass the message through ValidateInbound before processing it.

func ValidateSignerSet

func ValidateSignerSet(keyParties PartySet, threshold int, signers PartySet, limits ThresholdLimits) error

ValidateSignerSet checks signers against a key's participant set and limits. It verifies: non-empty, minimum size (threshold), maximum size, membership, and no duplicates. For algorithms where AllowOversizedSignerSet is false, signer count must exactly equal threshold.

func VerifyBroadcastAck

func VerifyBroadcastAck(env Envelope, ack BroadcastAck, verifier BroadcastAckVerifier) error

VerifyBroadcastAck checks that an ack is valid for the given envelope and party.

func VerifyBroadcastCertificateWithSignatures

func VerifyBroadcastCertificateWithSignatures(env Envelope, parties PartySet, cert *BroadcastCertificate, verifier BroadcastAckVerifier) error

VerifyBroadcastCertificateWithSignatures performs full certificate validation including individual ack signature verification. Prefer BroadcastCertificate.VerifyFull for new code.

func VerifyEnvelopeSignature

func VerifyEnvelopeSignature(e Envelope, verifier EnvelopeSignatureVerifier) error

VerifyEnvelopeSignature verifies the portable sender signature carried by e.

Types

type Algorithm

type Algorithm string

Algorithm names a threshold signature algorithm implemented by this module.

const (
	// AlgorithmCGGMP21Secp256k1 identifies the CGGMP21-style threshold ECDSA package.
	AlgorithmCGGMP21Secp256k1 Algorithm = "cggmp21-secp256k1"
	// AlgorithmFROSTEd25519 identifies the FROST-style threshold Ed25519 package.
	AlgorithmFROSTEd25519 Algorithm = "frost-ed25519"
)

type AttackMode

type AttackMode uint8

AttackMode specifies a type of transport-layer attack for testing.

const (
	// AttackSenderSpoof opens an envelope with ReceiveInfo.Peer different from Envelope.From.
	AttackSenderSpoof AttackMode = iota
	// AttackPlaintextConfidential reports plaintext delivery for confidential-required messages.
	AttackPlaintextConfidential
	// AttackReplay sends the same envelope twice.
	AttackReplay
	// AttackWrongRecipient delivers a direct message to the wrong party.
	AttackWrongRecipient
	// AttackBroadcastEquivocation sends different payloads to different parties.
	AttackBroadcastEquivocation
	// AttackDropAck fails to include an ack in the broadcast certificate.
	AttackDropAck
	// AttackInvalidAckSignature includes an ack with an invalid signature.
	AttackInvalidAckSignature
)

type BinaryUnmarshalerWithLimits

type BinaryUnmarshalerWithLimits[L any] interface {
	UnmarshalBinaryWithLimits([]byte, L) error
}

BinaryUnmarshalerWithLimits is implemented by binary decoders that require caller-provided resource limits.

type Blame

type Blame struct {
	Reason   string   `json:"reason"`
	Parties  PartySet `json:"parties"`
	Evidence []byte   `json:"evidence,omitempty"`
}

Blame identifies parties and public evidence associated with a protocol failure.

type BlameEvidence

type BlameEvidence struct {
	Protocol       ProtocolID      `wire:"1"`
	SessionID      SessionID       `wire:"2,len=32"`
	Round          uint8           `wire:"3"`
	From           PartyID         `wire:"4"`
	To             PartyID         `wire:"5"`
	PayloadType    PayloadType     `wire:"6,max_bytes=payload_type"`
	PayloadHash    []byte          `wire:"7,len=32"`
	EnvelopeDigest []byte          `wire:"8"`
	Kind           EvidenceKind    `wire:"9"`
	Reason         string          `wire:"10,max_bytes=evidence_reason"`
	PublicInputs   []EvidenceField `wire:"11,max_items=evidence_fields"`
}

BlameEvidence is intentionally public-only. Confidential protocol messages should be represented by hashes or other public inputs, not by plaintext.

Example (Lifecycle)

ExampleBlameEvidence_lifecycle demonstrates the full blame evidence lifecycle: creation from a misbehaving envelope, binary encoding, decoding via UnmarshalBlameEvidence, and self-validation.

Blame evidence captures the evidence needed to attribute a protocol fault to a specific party. It is designed to be stored or transmitted for later dispute resolution.

package main

import (
	"bytes"
	"fmt"

	"github.com/islishude/tss"
)

func main() {
	sessionID, err := tss.NewSessionID(bytes.NewReader(bytes.Repeat([]byte{0x33}, 32)))
	if err != nil {
		panic(err)
	}

	// --- 1. Construct the envelope that triggered the fault ---
	envelope := tss.Envelope{
		Protocol:    "example",
		SessionID:   sessionID,
		Round:       1,
		From:        1,
		PayloadType: "example.payload",
		Payload:     []byte("bad partial"),
	}

	// --- 2. Create blame evidence binding the envelope to a fault ---
	// EvidenceKind describes the protocol phase where the fault occurred.
	// EvidenceFields carry structured key-value metadata (e.g., hashes,
	// party sets) that verifiers can cross-check.
	evidence, err := tss.NewBlameEvidence(
		envelope,
		tss.EvidenceKindSignPartial,
		"invalid partial signature",
		[]tss.EvidenceField{
			{Key: "public_hash", Value: []byte{1, 2, 3}},
		},
	)
	if err != nil {
		panic(err)
	}

	// --- 3. Serialize blame evidence for storage or transmission ---
	encoded, err := evidence.MarshalBinary()
	if err != nil {
		panic(err)
	}

	// --- 4. Deserialize using the typed unmarshaler ---
	// UnmarshalBlameEvidence returns a *BlameEvidence (not a raw struct)
	// so the Validate method is available on the decoded value.
	decoded, err := tss.DecodeBinary[tss.BlameEvidence](encoded)
	if err != nil {
		panic(err)
	}

	// --- 5. Validate structural integrity ---
	// Validate checks that Kind is a known evidence kind and that From is
	// non-zero. Additional context-dependent checks (session ID, party
	// membership) are performed by protocol-specific verifiers.
	fmt.Println(decoded.Kind, decoded.From, decoded.Validate() == nil)
}
Output:
sign_partial 1 true

func NewBlameEvidence

func NewBlameEvidence(env Envelope, kind EvidenceKind, reason string, inputs []EvidenceField) (*BlameEvidence, error)

NewBlameEvidence builds a public evidence record bound to an envelope hash. PublicInputs are stored in canonical order so that logically equivalent evidence records produce identical hashes regardless of caller-provided slice ordering.

func NewBlameEvidenceWithLimits

func NewBlameEvidenceWithLimits(env Envelope, kind EvidenceKind, reason string, inputs []EvidenceField, limits EvidenceLimits) (*BlameEvidence, error)

NewBlameEvidenceWithLimits builds public evidence using explicit resource limits. This is intended for protocol phases whose canonical public proof is deliberately larger than the conservative default; it does not widen any default decoder or encoder.

func UnmarshalBlameEvidenceWithLimits

func UnmarshalBlameEvidenceWithLimits(in []byte, l EvidenceLimits) (*BlameEvidence, error)

UnmarshalBlameEvidenceWithLimits decodes and validates public blame evidence with explicit size limits.

func (*BlameEvidence) BeforeMarshalWire

func (e *BlameEvidence) BeforeMarshalWire() error

BeforeMarshalWire canonicalizes the PublicInputs field ordering before encoding, so that logically equivalent evidence records produce identical wire representations regardless of caller-provided slice ordering.

func (*BlameEvidence) Field

func (e *BlameEvidence) Field(key string) ([]byte, bool)

Field returns a copy of a named public input field.

func (*BlameEvidence) Hash

func (e *BlameEvidence) Hash() ([]byte, error)

Hash returns the SHA-256 digest of the deterministic evidence encoding.

func (*BlameEvidence) MarshalBinary

func (e *BlameEvidence) MarshalBinary() ([]byte, error)

MarshalBinary encodes BlameEvidence using the object-level wire codec with conservative default limits. Use MarshalEvidenceWithLimits for explicit control.

func (*BlameEvidence) MarshalBinaryWithLimits

func (e *BlameEvidence) MarshalBinaryWithLimits(l EvidenceLimits) ([]byte, error)

MarshalBinaryWithLimits encodes BlameEvidence using the object-level wire codec with explicit limits.

func (*BlameEvidence) UnmarshalBinary

func (e *BlameEvidence) UnmarshalBinary(in []byte) error

UnmarshalBinary decodes and validates public blame evidence using conservative default limits.

func (*BlameEvidence) UnmarshalBinaryWithLimits

func (e *BlameEvidence) UnmarshalBinaryWithLimits(in []byte, l EvidenceLimits) error

UnmarshalBinaryWithLimits decodes and validates public blame evidence into the receiver with explicit size limits.

func (*BlameEvidence) Validate

func (e *BlameEvidence) Validate() error

Validate checks structural invariants for a public blame evidence record using conservative default limits. Use BlameEvidence.ValidateWithLimits for explicit control.

func (*BlameEvidence) ValidateWithLimits

func (e *BlameEvidence) ValidateWithLimits(l EvidenceLimits) error

ValidateWithLimits checks structural invariants for a public blame evidence record against the provided limits. Canonical ordering of PublicInputs is handled by BlameEvidence.BeforeMarshalWire, which is called automatically by wire.Marshal before encoding.

func (BlameEvidence) WireType

func (BlameEvidence) WireType() string

WireType returns the canonical wire type identifier for BlameEvidence.

func (BlameEvidence) WireVersion

func (BlameEvidence) WireVersion() uint16

WireVersion returns the wire format version for BlameEvidence.

type BroadcastAck

type BroadcastAck struct {
	Party PartyID `wire:"1,u32"`

	PayloadHash    [32]byte       `wire:"2,bytes,len=32"`
	EnvelopeDigest EnvelopeDigest `wire:"3,bytes,len=32"`

	Signature []byte `wire:"4,bytes,max_bytes=broadcast_signature"`
}

BroadcastAck is one party's signed acknowledgment of a broadcast message.

func SignBroadcastAck

func SignBroadcastAck(env Envelope, party PartyID, signer BroadcastAckSigner) (BroadcastAck, error)

SignBroadcastAck produces a signed BroadcastAck for a party over an envelope. The caller must provide a signer bound to the party's identity key.

func (BroadcastAck) Clone

func (a BroadcastAck) Clone() BroadcastAck

Clone returns a deep copy of the broadcast ack.

func (BroadcastAck) Equal

func (a BroadcastAck) Equal(b BroadcastAck) bool

Equal reports whether a and other are the same BroadcastAck.

func (BroadcastAck) MarshalBinary

func (a BroadcastAck) MarshalBinary() ([]byte, error)

MarshalBinary encodes the broadcast acknowledgment using canonical TLV.

func (*BroadcastAck) UnmarshalBinary

func (a *BroadcastAck) UnmarshalBinary(in []byte) error

UnmarshalBinary decodes a canonical broadcast acknowledgment.

func (BroadcastAck) Validate

func (a BroadcastAck) Validate() error

Validate checks the broadcast acknowledgment's structural invariants.

func (BroadcastAck) WireType

func (BroadcastAck) WireType() string

WireType returns the canonical wire type identifier for BroadcastAck.

func (BroadcastAck) WireVersion

func (BroadcastAck) WireVersion() uint16

WireVersion returns the wire format version for BroadcastAck.

type BroadcastAckSigner

type BroadcastAckSigner interface {
	// SignAck returns a cryptographic signature over the canonical ack digest.
	SignAck(digest [32]byte) (signature []byte, err error)
}

BroadcastAckSigner produces a signature over a broadcast ack digest. Implementations bind an identity key to a PartyID.

type BroadcastAckVerifier

type BroadcastAckVerifier interface {
	// VerifyAck returns nil when signature is a valid signature by party over digest.
	VerifyAck(party PartyID, digest [32]byte, signature []byte) error
}

BroadcastAckVerifier checks that a broadcast ack signature is valid for a party.

type BroadcastCertificate

type BroadcastCertificate struct {
	Protocol    ProtocolID  `wire:"1,string,max_bytes=protocol_name"`
	SessionID   SessionID   `wire:"2,bytes,len=32"`
	Round       uint8       `wire:"3,u8"`
	From        PartyID     `wire:"4,u32"`
	PayloadType PayloadType `wire:"5,string,max_bytes=payload_type"`

	PayloadHash    [32]byte       `wire:"6,bytes,len=32"`
	EnvelopeDigest EnvelopeDigest `wire:"7,bytes,len=32"`

	Recipients PartySet       `wire:"8,u32list,max_items=broadcast_recipients"`
	Acks       []BroadcastAck `wire:"9,recordlist,max_items=broadcast_recipients"`
}

BroadcastCertificate proves that all parties received the same broadcast payload.

func NewBroadcastCertificate

func NewBroadcastCertificate(env Envelope, recipients PartySet, acks []BroadcastAck) (*BroadcastCertificate, error)

NewBroadcastCertificate constructs a certificate from an envelope and a complete set of signed acks. It verifies that every ack covers the same digest and that every party in recipients contributed exactly one ack.

Callers must have already verified each individual ack signature via BroadcastAckVerifier before calling this constructor.

func (*BroadcastCertificate) BeforeMarshalWire

func (c *BroadcastCertificate) BeforeMarshalWire() error

BeforeMarshalWire canonicalizes recipient and acknowledgment ordering.

func (*BroadcastCertificate) Clone

Clone returns a deep copy of the broadcast certificate.

func (*BroadcastCertificate) Equal

Equal reports whether r and other are the same BroadcastCertificate. Both nil receivers compare equal. A nil receiver and a non-nil other are not equal.

func (*BroadcastCertificate) MarshalBinary

func (c *BroadcastCertificate) MarshalBinary() ([]byte, error)

MarshalBinary encodes the broadcast certificate using canonical TLV.

func (*BroadcastCertificate) UnmarshalBinary

func (c *BroadcastCertificate) UnmarshalBinary(in []byte) error

UnmarshalBinary decodes a canonical broadcast certificate.

func (*BroadcastCertificate) Validate

func (c *BroadcastCertificate) Validate() error

Validate checks the broadcast certificate's canonical structural invariants.

func (*BroadcastCertificate) VerifyFull

func (c *BroadcastCertificate) VerifyFull(env Envelope, parties PartySet, verifier BroadcastAckVerifier) error

VerifyFull performs complete certificate validation: structure checks plus individual ack signature verification against the provided verifier. Production code must use this method; [VerifyStructure] is for tests and low-level parsing only.

func (*BroadcastCertificate) VerifyStructure

func (c *BroadcastCertificate) VerifyStructure(env Envelope, parties PartySet) error

VerifyStructure checks that the certificate binds to env and that every party acknowledged the same digest. It does NOT verify individual ack signatures — use [VerifyFull] for production paths that require signature verification.

func (BroadcastCertificate) WireType

func (BroadcastCertificate) WireType() string

WireType returns the canonical wire type identifier for BroadcastCertificate.

func (BroadcastCertificate) WireVersion

func (BroadcastCertificate) WireVersion() uint16

WireVersion returns the wire format version for BroadcastCertificate.

type BroadcastConsistency

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

BroadcastConsistency tracks the collection of broadcast acks for one (session, round, from, payloadType) and detects equivocation.

It is safe for concurrent use.

func NewBroadcastConsistency

func NewBroadcastConsistency(protocol ProtocolID, sessionID SessionID, round uint8, from PartyID, payloadType PayloadType, recipients PartySet, verifier BroadcastAckVerifier) (*BroadcastConsistency, error)

NewBroadcastConsistency starts tracking a new broadcast consistency session. The verifier is used to check each ack signature as it arrives. It must not be nil — a nil verifier causes a panic in AddAck.

func (*BroadcastConsistency) AckCount

func (bc *BroadcastConsistency) AckCount() int

AckCount returns the number of verified acks collected so far.

func (*BroadcastConsistency) AddAck

func (bc *BroadcastConsistency) AddAck(env Envelope, ack BroadcastAck) error

AddAck records a party's broadcast acknowledgment. It verifies the ack signature, checks for digest consistency, and returns an error on:

  • signature verification failure
  • digest mismatch (equivocation)
  • duplicate ack
  • unknown party

func (*BroadcastConsistency) Certificate

func (bc *BroadcastConsistency) Certificate() (*BroadcastCertificate, error)

Certificate builds the BroadcastCertificate from collected acks. It returns an error if not all acks have been collected.

func (*BroadcastConsistency) Commit

func (bc *BroadcastConsistency) Commit(env Envelope) (bool, error)

Commit records the canonical broadcast digest for this consistency session. Any subsequent ack with a different digest is treated as equivocation.

The first call to Commit returns (true, nil). Subsequent calls with the same digest return (false, nil). A call with a different digest returns (false, ErrBroadcastEquivocation).

func (*BroadcastConsistency) Complete

func (bc *BroadcastConsistency) Complete() bool

Complete returns true when every recipient has submitted a valid ack.

type BroadcastConsistencyPolicy

type BroadcastConsistencyPolicy uint8

BroadcastConsistencyPolicy specifies whether broadcast messages require a consistency certificate.

const (
	// BroadcastConsistencyNone means no broadcast certificate is required.
	BroadcastConsistencyNone BroadcastConsistencyPolicy = iota
	// BroadcastConsistencyRequired means a valid BroadcastCertificate must be present.
	BroadcastConsistencyRequired
)

type ChannelProtection

type ChannelProtection uint8

ChannelProtection describes the channel protection actually observed by the receive transport. The zero value is invalid and fails closed.

const (
	// ChannelProtectionUnknown means the receive path did not report channel protection.
	ChannelProtectionUnknown ChannelProtection = iota
	// ChannelPlaintext means the receive path explicitly observed plaintext delivery.
	ChannelPlaintext
	// ChannelConfidential means the receive path explicitly observed confidential delivery.
	ChannelConfidential
)

type ConfidentialityPolicy

type ConfidentialityPolicy uint8

ConfidentialityPolicy specifies whether a message must be encrypted in transit.

const (
	// ConfidentialityForbidden means the message must NOT be sent over a confidential channel.
	// Prefer ConfidentialityOptional for most non-secret payloads; use Forbidden only when
	// confidential transport would actively break the protocol (e.g. audit logging that
	// requires visibility into plaintext).
	ConfidentialityForbidden ConfidentialityPolicy = iota
	// ConfidentialityOptional means either plaintext or confidential transport is acceptable.
	// This is the safe default for payloads that contain no secret material (commitments,
	// public keys, ciphertexts). TLS/mTLS deployments can safely mark transport as
	// Confidential=true without triggering policy rejection.
	ConfidentialityOptional
	// ConfidentialityRequired means the message MUST be sent over a confidential channel.
	// Use for payloads that contain secret shares, nonces, or other material that must
	// never appear in plaintext.
	ConfidentialityRequired
)

type DeliveryMode

type DeliveryMode uint8

DeliveryMode classifies an envelope delivery path.

const (
	// DeliveryDirect is a point-to-point message addressed to a single recipient.
	DeliveryDirect DeliveryMode = iota
	// DeliveryBroadcast is a message sent to all parties.
	DeliveryBroadcast
)

type DeliveryPolicy

type DeliveryPolicy struct {
	Protocol    ProtocolID
	Round       uint8
	PayloadType PayloadType

	Mode DeliveryMode

	Confidentiality ConfidentialityPolicy

	BroadcastConsistency BroadcastConsistencyPolicy

	// RequireSenderSignature requires portable sender authentication in
	// addition to transport authentication.
	RequireSenderSignature bool
}

DeliveryPolicy defines the transport requirements for one protocol message kind.

type DerivationPath

type DerivationPath []uint32

DerivationPath is a non-hardened HD derivation path. Nil and empty paths are the master path "m".

func MustParseDerivationPath

func MustParseDerivationPath(s string) DerivationPath

MustParseDerivationPath parses s and panics on error.

func NewDerivationPath

func NewDerivationPath(pathes ...uint32) DerivationPath

NewDerivationPath returns a DerivationPath containing bip32 pathes in the given order.

func ParseDerivationPath

func ParseDerivationPath(s string) (DerivationPath, error)

ParseDerivationPath parses paths in the form "m" or "m/0/1/2".

func (DerivationPath) Clone

func (p DerivationPath) Clone() DerivationPath

Clone returns a caller-owned copy of the path.

func (DerivationPath) IsMaster

func (p DerivationPath) IsMaster() bool

IsMaster reports whether the path is the master path.

func (DerivationPath) String

func (p DerivationPath) String() string

String returns the canonical path string, using "m" for the master path.

func (DerivationPath) ValidateNonHardened

func (p DerivationPath) ValidateNonHardened() error

ValidateNonHardened rejects paths deeper than BIP32 permits and hardened indices.

type DerivationRequest

type DerivationRequest struct {
	Scheme           DerivationScheme `json:"scheme" wire:"1,string"`
	Path             DerivationPath   `json:"path" wire:"2,u32list"`
	InvalidChildMode InvalidChildMode `json:"invalid_child_mode" wire:"3,u8"`
	ResolvedPath     DerivationPath   `json:"resolved_path,omitempty" wire:"4,u32list"`
}

DerivationRequest describes a requested public child-key derivation.

func (DerivationRequest) Clone

Clone returns a caller-owned copy of the request.

type DerivationResult

type DerivationResult struct {
	Scheme            DerivationScheme `json:"scheme" wire:"1,string"`
	ChildPublicKey    []byte           `json:"child_public_key" wire:"2,bytes"`
	ChildChainCode    []byte           `json:"child_chain_code" wire:"3,bytes,len=32"`
	RequestedPath     DerivationPath   `json:"requested_path" wire:"4,u32list"`
	ResolvedPath      DerivationPath   `json:"resolved_path" wire:"5,u32list"`
	Depth             uint8            `json:"depth" wire:"6,u8"`
	ParentFingerprint [4]byte          `json:"parent_fingerprint" wire:"7,bytes,len=4"`
	ChildNumber       uint32           `json:"child_number" wire:"8,u32"`
	AdditiveShift     []byte           `json:"additive_shift,omitempty" wire:"9,bytes"`
}

DerivationResult is the result of resolving a public child-key derivation.

func (*DerivationResult) Clone

func (r *DerivationResult) Clone() *DerivationResult

Clone returns a caller-owned copy of the derivation result.

func (*DerivationResult) Destroy

func (r *DerivationResult) Destroy()

Destroy clears derivation result buffers and resets metadata in place.

func (*DerivationResult) Equal

func (r *DerivationResult) Equal(other *DerivationResult) bool

Equal reports whether r and other are the same derivation result. Both nil receivers compare equal. A nil receiver and a non-nil other are not equal.

func (*DerivationResult) MarshalBinary

func (r *DerivationResult) MarshalBinary() ([]byte, error)

MarshalBinary encodes the derivation result using the object-level wire codec.

func (*DerivationResult) UnmarshalBinary

func (r *DerivationResult) UnmarshalBinary(in []byte) error

UnmarshalBinary decodes a canonical derivation result record.

func (*DerivationResult) Validate

func (r *DerivationResult) Validate() error

Validate checks structural invariants for a derivation result.

func (*DerivationResult) VerificationKeyBytes

func (r *DerivationResult) VerificationKeyBytes() []byte

VerificationKeyBytes returns a copy of ChildPublicKey.

func (DerivationResult) WireType

func (DerivationResult) WireType() string

WireType returns the canonical wire type identifier for DerivationResult.

func (DerivationResult) WireVersion

func (DerivationResult) WireVersion() uint16

WireVersion returns the wire format version for DerivationResult.

type DerivationScheme

type DerivationScheme string

DerivationScheme identifies the public child-key derivation algorithm.

const (
	// DerivationSchemeBIP32Secp256k1 is standard non-hardened BIP32 CKDpub over secp256k1.
	DerivationSchemeBIP32Secp256k1 DerivationScheme = "bip32-secp256k1"
	// DerivationSchemeEd25519KhovratovichLaw is the Cardano/Khovratovich-Law Ed25519-BIP32 public derivation scheme.
	DerivationSchemeEd25519KhovratovichLaw DerivationScheme = "ed25519-bip32-khovratovich-law"
)

type DeriveConfig

type DeriveConfig struct {
	InvalidChildMode InvalidChildMode
	// HMACFunc is an optional custom HMAC-SHA512 function. When nil (the default),
	// the normal crypto/hmac-based SHA512 implementation is used.
	// The function must return exactly 64 bytes.
	HMACFunc func(key, data []byte) []byte
}

DeriveConfig is the resolved configuration for HD public derivation.

func ResolveDeriveConfig

func ResolveDeriveConfig(opts []DeriveOption) DeriveConfig

ResolveDeriveConfig resolves derivation options into a concrete config.

type DeriveOption

type DeriveOption interface {
	// contains filtered or unexported methods
}

DeriveOption is a functional option for HD public derivation.

func WithHMACFunc

func WithHMACFunc(fn func(key, data []byte) []byte) DeriveOption

WithHMACFunc sets a custom HMAC-SHA512 function for BIP32 public derivation. When fn is nil or the option is not passed, the default crypto/hmac-based SHA512 implementation is used.

func WithInvalidChildMode

func WithInvalidChildMode(mode InvalidChildMode) DeriveOption

WithInvalidChildMode sets the invalid child handling strategy.

type Envelope

type Envelope struct {
	Protocol    ProtocolID  `wire:"1,string"`
	SessionID   SessionID   `wire:"2,bytes,len=32"`
	Round       uint8       `wire:"3,u8"`
	From        PartyID     `wire:"4,u32"`
	To          PartyID     `wire:"5,u32"` // zero means broadcast
	PayloadType PayloadType `wire:"6,string"`
	Payload     []byte      `wire:"7,bytes"`
	// SenderSignature authenticates EnvelopeSigningDigest. The optional field
	// remains absent for protocols whose policy does not require it.
	SenderSignature []byte `wire:"8,bytes"`
}

Envelope is a transport-neutral protocol wire message.

Example (Roundtrip)

ExampleEnvelope_roundtrip demonstrates the full lifecycle of an Envelope: construction via NewEnvelope, binary encoding, decoding, and validation. Envelopes carry protocol messages between parties; each envelope identifies the protocol, session, round, sender, and recipient for routing and duplicate detection.

package main

import (
	"fmt"

	"github.com/islishude/tss"
)

func main() {
	// --- 1. Create a session ID that binds all messages in this run ---
	sessionID, err := tss.NewSessionID(nil)
	if err != nil {
		panic(err)
	}

	// --- 2. Construct an envelope with the NewEnvelope constructor ---
	// NewEnvelope validates fields, copies the payload, and returns a
	// ready-to-send envelope. Always prefer NewEnvelope over
	// constructing the struct directly.
	envelope, err := tss.NewEnvelope(tss.EnvelopeInput{
		Protocol:    "example",
		SessionID:   sessionID,
		Round:       1,
		From:        1,
		PayloadType: "example.payload",
		Payload:     []byte("roundtrip test"),
	})
	if err != nil {
		panic(err)
	}

	// --- 3. Serialize the envelope for transport ---
	encoded, err := envelope.MarshalBinary()
	if err != nil {
		panic(err)
	}

	// --- 4. Deserialize on the receiving side ---
	var decoded tss.Envelope
	if err := decoded.UnmarshalBinary(encoded); err != nil {
		panic(err)
	}

	fmt.Println(string(decoded.Payload))
}
Output:
roundtrip test

func NewEnvelope

func NewEnvelope(input EnvelopeInput) (Envelope, error)

NewEnvelope constructs an envelope from caller-provided fields using conservative default limits. Use NewEnvelopeWithLimits for explicit control.

func NewEnvelopeWithLimits

func NewEnvelopeWithLimits(input EnvelopeInput, limits EnvelopeLimits) (Envelope, error)

NewEnvelopeWithLimits constructs an envelope from caller-provided fields, enforcing the provided size limits. It validates basic fields and copies the payload.

func SignEnvelope

func SignEnvelope(e Envelope, signer EnvelopeSigner) (Envelope, error)

SignEnvelope returns an independently owned envelope carrying a portable sender signature.

func UnmarshalEnvelopeWithLimits

func UnmarshalEnvelopeWithLimits(in []byte, limits EnvelopeLimits) (Envelope, error)

UnmarshalEnvelopeWithLimits decodes a canonical TLV envelope enforcing the provided size limits. It returns a decoded envelope or an error.

func (Envelope) Clone

func (e Envelope) Clone() Envelope

Clone returns a deep copy of the envelope.

func (Envelope) Digest

func (e Envelope) Digest() EnvelopeDigest

Digest computes the domain-separated digest of the envelope metadata and payload. This digest is used for envelope equality checks and not for signing. For the digest that the sender signs, use SigningDigest.

func (Envelope) MarshalBinary

func (e Envelope) MarshalBinary() ([]byte, error)

MarshalBinary encodes the envelope using the object-level wire codec with conservative default limits. Use MarshalEnvelopeWithLimits for explicit control.

func (Envelope) MarshalBinaryWithLimits

func (e Envelope) MarshalBinaryWithLimits(limits EnvelopeLimits) ([]byte, error)

MarshalBinaryWithLimits encodes the envelope using the object-level wire codec, enforcing the provided size limits.

func (Envelope) SigningDigest

func (e Envelope) SigningDigest() [32]byte

SigningDigest computes the domain-separated digest of the envelope metadata and payload, excluding the sender signature. This is the digest that the sender signs to produce SenderSignature.

func (*Envelope) UnmarshalBinary

func (e *Envelope) UnmarshalBinary(in []byte) error

UnmarshalBinary decodes a canonical TLV envelope using the object-level wire codec with conservative default limits. Use UnmarshalEnvelopeWithLimits for explicit control.

func (*Envelope) UnmarshalBinaryWithLimits

func (e *Envelope) UnmarshalBinaryWithLimits(in []byte, limits EnvelopeLimits) error

UnmarshalBinaryWithLimits decodes a canonical TLV envelope into the receiver, enforcing the provided size limits.

func (Envelope) WireType

func (Envelope) WireType() string

WireType returns the canonical wire type identifier for Envelope.

func (Envelope) WireVersion

func (Envelope) WireVersion() uint16

WireVersion returns the wire format version for Envelope.

type EnvelopeDigest

type EnvelopeDigest [32]byte

EnvelopeDigest is the domain-separated digest of one envelope.

type EnvelopeGuard

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

EnvelopeGuard validates incoming envelopes against protocol, transport, and session policies. Every protocol handler must run Validate before processing the envelope.

func NewEnvelopeGuard

func NewEnvelopeGuard(self PartyID, parties PartySet, protocol ProtocolID, sessionID SessionID, policies PolicySet, cache ReplayCache) (*EnvelopeGuard, error)

NewEnvelopeGuard constructs a guard with the required security configuration. It returns an error if parties is empty, Self is not in Parties, or if the SessionID is invalid.

func NewTestEnvelopeGuard

func NewTestEnvelopeGuard(self PartyID, parties PartySet, protocol ProtocolID, sessionID SessionID, policies PolicySet) *EnvelopeGuard

NewTestEnvelopeGuard constructs a guard suitable for tests. It uses an in-memory replay cache and a no-op ack verifier. This function MUST NOT be used in production code — production callers must use GuardConfig.BuildGuard with a real verifier.

It panics when not running under "go test" to prevent accidental production use.

func NewTestEnvelopeGuardWithCache

func NewTestEnvelopeGuardWithCache(self PartyID, parties PartySet, protocol ProtocolID, sessionID SessionID, policies PolicySet, cache ReplayCache) *EnvelopeGuard

NewTestEnvelopeGuardWithCache is NewTestEnvelopeGuard with an explicit replay cache for bounded-cache and failure-injection tests.

func (*EnvelopeGuard) AckVerifier

func (g *EnvelopeGuard) AckVerifier() BroadcastAckVerifier

AckVerifier returns the guard's broadcast acknowledgement verifier.

func (*EnvelopeGuard) EnvelopeVerifier

func (g *EnvelopeGuard) EnvelopeVerifier() EnvelopeSignatureVerifier

EnvelopeVerifier returns the guard's portable sender-signature verifier.

func (*EnvelopeGuard) Parties

func (g *EnvelopeGuard) Parties() PartySet

Parties returns a caller-owned copy of the guard's construction-time party universe.

func (*EnvelopeGuard) Policies

func (g *EnvelopeGuard) Policies() PolicySet

Policies returns the guard's immutable policy set.

func (*EnvelopeGuard) PolicyDigest

func (g *EnvelopeGuard) PolicyDigest() [32]byte

PolicyDigest returns the canonical delivery-policy digest bound at construction.

func (*EnvelopeGuard) Protocol

func (g *EnvelopeGuard) Protocol() ProtocolID

Protocol returns the protocol bound to the guard.

func (*EnvelopeGuard) ReplayCache

func (g *EnvelopeGuard) ReplayCache() ReplayCache

ReplayCache returns the guard's replay cache authority.

func (*EnvelopeGuard) RequiresSenderSignatures

func (g *EnvelopeGuard) RequiresSenderSignatures() bool

RequiresSenderSignatures reports whether any delivery policy configured on the guard requires canonical sender signatures.

func (*EnvelopeGuard) Self

func (g *EnvelopeGuard) Self() PartyID

Self returns the local party bound to the guard.

func (*EnvelopeGuard) SessionID

func (g *EnvelopeGuard) SessionID() SessionID

SessionID returns the session identifier bound to the guard.

func (*EnvelopeGuard) Validate

func (g *EnvelopeGuard) Validate(env InboundEnvelope) error

Validate executes the full security validation sequence on an incoming envelope against the guard's configured party set. It returns nil only when the envelope passes all checks.

func (*EnvelopeGuard) ValidateForRound

func (g *EnvelopeGuard) ValidateForRound(env InboundEnvelope, allowedSenders PartySet) error

ValidateForRound validates an incoming envelope against the sender set allowed by the current protocol round or payload. The guard's configured Parties field remains the construction-time party universe; allowedSenders is the lifecycle-specific sender set for this message.

func (*EnvelopeGuard) ValidateWithParties

func (g *EnvelopeGuard) ValidateWithParties(env InboundEnvelope, parties PartySet) error

ValidateWithParties is like Validate but validates sender membership and broadcast certificates against the provided party set instead of the guard's configured set. This is used by sessions (e.g. reshare) that accept messages from different participant subsets depending on payload type.

func (*EnvelopeGuard) ValidateWithoutReplay

func (g *EnvelopeGuard) ValidateWithoutReplay(env InboundEnvelope, parties PartySet) error

ValidateWithoutReplay performs all transport, identity, delivery-policy, confidentiality, signature, and broadcast-certificate checks without reserving a replay slot. It is intended only for protocol messages that are explicitly rejected as too early and may be retried after readiness changes.

type EnvelopeInput

type EnvelopeInput struct {
	Protocol    ProtocolID
	SessionID   SessionID
	Round       uint8
	From        PartyID
	To          PartyID
	PayloadType PayloadType
	Payload     []byte
	// SenderSignature is optional at generic construction time. Delivery
	// policies decide whether portable sender authentication is required.
	SenderSignature []byte
}

EnvelopeInput carries the caller-provided fields for constructing an Envelope.

type EnvelopeLimits

type EnvelopeLimits struct {
	MaxBytes             int
	MaxPayloadBytes      int
	MaxPayloadTypeBytes  int
	MaxProtocolNameBytes int
	MaxSignatureBytes    int
	TLV                  TLVLimits
}

EnvelopeLimits caps envelope encoding and metadata sizes.

func DefaultEnvelopeLimits

func DefaultEnvelopeLimits() EnvelopeLimits

DefaultEnvelopeLimits returns a caller-owned copy of the conservative production envelope limits used by NewEnvelope, MarshalBinary, and UnmarshalBinary.

type EnvelopeSignatureVerifier

type EnvelopeSignatureVerifier interface {
	VerifyEnvelopeSignature(party PartyID, digest [32]byte, signature []byte) error
}

EnvelopeSignatureVerifier verifies a canonical envelope signature for party.

type EnvelopeSigner

type EnvelopeSigner interface {
	SignEnvelopeDigest(digest [32]byte) ([]byte, error)
}

EnvelopeSigner signs a canonical envelope digest with the local party's transport identity key.

type EvidenceField

type EvidenceField struct {
	Key   string `wire:"1,max_bytes=evidence_field_key"`
	Value []byte `wire:"2,max_bytes=evidence_field_value"`
}

EvidenceField carries one public input or public-input hash for blame evidence.

func IdentificationEvidenceField

func IdentificationEvidenceField(record *IdentificationRecord) (EvidenceField, error)

IdentificationEvidenceField encodes record under the fixed evidence key.

func IdentificationEvidenceFieldWithLimits

func IdentificationEvidenceFieldWithLimits(record *IdentificationRecord, limits IdentificationRecordLimits) (EvidenceField, error)

IdentificationEvidenceFieldWithLimits encodes a record under the fixed evidence key using explicit resource limits.

func (EvidenceField) Clone

func (f EvidenceField) Clone() EvidenceField

Clone returns a deep copy of an evidence field.

type EvidenceKind

type EvidenceKind string

EvidenceKind names the protocol failure class captured in blame evidence.

const (
	// EvidenceKindKeygenCommitment marks an invalid keygen public commitment.
	EvidenceKindKeygenCommitment EvidenceKind = "keygen_commitment"
	// EvidenceKindPaillierAux marks invalid Paillier, Ring-Pedersen, or
	// receiver-specific factor-proof auxiliary material in any lifecycle.
	EvidenceKindPaillierAux EvidenceKind = "paillier_aux"
	// EvidenceKindKeygenShare marks a DKG share that does not match commitments.
	EvidenceKindKeygenShare EvidenceKind = "keygen_share"
	// EvidenceKindRefreshShare marks a proactive refresh share that does not match commitments.
	EvidenceKindRefreshShare EvidenceKind = "refresh_share"
	// EvidenceKindRefreshCommitment marks invalid proactive-refresh polynomial commitments.
	EvidenceKindRefreshCommitment EvidenceKind = "refresh_commitment"
	// EvidenceKindReshareShare marks a CGGMP21 reshare share that does not match commitments.
	EvidenceKindReshareShare EvidenceKind = "reshare_share"
	// EvidenceKindReshareCommitment marks invalid CGGMP21 reshare dealer commitments.
	EvidenceKindReshareCommitment EvidenceKind = "reshare_commitment"
	// EvidenceKindPresignRound1 marks invalid presign nonce commitment material.
	EvidenceKindPresignRound1 EvidenceKind = "presign_round1"
	// EvidenceKindPresignRound2 marks invalid pairwise MtA response material.
	EvidenceKindPresignRound2 EvidenceKind = "presign_round2"
	// EvidenceKindPresignRound3 marks invalid presign delta broadcast material.
	EvidenceKindPresignRound3 EvidenceKind = "presign_round3"
	// EvidenceKindPresignRedAlert marks an invalid Figure 9 presign red-alert proof.
	EvidenceKindPresignRedAlert EvidenceKind = "presign_red_alert"
	// EvidenceKindSignPartial marks invalid online signing partial material.
	EvidenceKindSignPartial EvidenceKind = "sign_partial"
	// EvidenceKindAggregateSign marks a final aggregate signature verification failure.
	EvidenceKindAggregateSign EvidenceKind = "aggregate_signature"
	// EvidenceKindFrostKeygenShare marks an invalid FROST DKG share.
	EvidenceKindFrostKeygenShare EvidenceKind = "frost_keygen_share"
	// EvidenceKindFrostKeygenCommitment marks invalid public FROST DKG commitment or proof material.
	EvidenceKindFrostKeygenCommitment EvidenceKind = "frost_keygen_commitment"
	// EvidenceKindFrostReshareShare marks an invalid FROST reshare share.
	EvidenceKindFrostReshareShare EvidenceKind = "frost_reshare_share"
	// EvidenceKindFrostNonceCommitment marks an invalid FROST signing nonce commitment.
	EvidenceKindFrostNonceCommitment EvidenceKind = "frost_nonce_commitment"
	// EvidenceKindFrostPartialSignature marks an invalid FROST partial signature.
	EvidenceKindFrostPartialSignature EvidenceKind = "frost_partial_signature"
	// EvidenceKindFrostAggregateSignature marks a failed FROST aggregate Ed25519 signature.
	EvidenceKindFrostAggregateSignature EvidenceKind = "frost_aggregate_signature"
)

type EvidenceLimits

type EvidenceLimits struct {
	MaxBytes            int
	MaxReasonBytes      int
	MaxFieldCount       int
	MaxFieldKeyBytes    int
	MaxFieldValueBytes  int
	MaxPayloadTypeBytes int
	TLV                 TLVLimits
}

EvidenceLimits caps blame evidence encoding and field sizes.

func DefaultEvidenceLimits

func DefaultEvidenceLimits() EvidenceLimits

DefaultEvidenceLimits returns a caller-owned copy of the conservative production limits used by NewBlameEvidence and BlameEvidence.MarshalBinary.

type GuardConfig

type GuardConfig struct {
	Self      PartyID
	Parties   PartySet
	Protocol  ProtocolID
	SessionID SessionID
	Policies  PolicySet
	Cache     ReplayCache

	// AckVerifier, when non-nil, enables broadcast ack signature verification
	// during guard validation. Production deployments SHOULD set this.
	AckVerifier BroadcastAckVerifier
	// EnvelopeVerifier verifies portable sender signatures required by policy.
	EnvelopeVerifier EnvelopeSignatureVerifier
}

GuardConfig carries the guard configuration for protocol sessions that process inbound envelopes. It is required for production sessions.

func TestGuardConfig

func TestGuardConfig(self PartyID, parties PartySet, protocol ProtocolID, sessionID SessionID, policies PolicySet) GuardConfig

TestGuardConfig returns a GuardConfig suitable for tests using an in-memory replay cache. The caller must provide the protocol-specific PolicySet.

func (GuardConfig) BuildGuard

func (c GuardConfig) BuildGuard() (*EnvelopeGuard, error)

BuildGuard constructs an EnvelopeGuard from the configuration or returns an error. Production deployments must provide a non-nil AckVerifier; test code should use NewTestEnvelopeGuard instead.

type IdentificationRecord

type IdentificationRecord struct {
	FailureClass         string          `wire:"1,string,max_bytes=identification_class"`
	AlertDigest          []byte          `wire:"2,bytes,len=32"`
	Accused              PartyID         `wire:"3,u32"`
	SignedEnvelopeA      []byte          `wire:"4,bytes,max_bytes=envelope"`
	SignedEnvelopeB      []byte          `wire:"5,bytes,max_bytes=envelope"`
	BroadcastCertificate []byte          `wire:"6,bytes,max_bytes=broadcast_certificate"`
	Statement            []byte          `wire:"7,bytes,max_bytes=identification_statement"`
	Proof                []byte          `wire:"8,bytes,max_bytes=zk_proof"`
	TranscriptHashes     []EvidenceField `wire:"9,recordlist,max_items=identification_hashes"`
}

IdentificationRecord contains the public statement needed to verify one identifiable-abort accusation. It must never contain protocol witnesses.

func (*IdentificationRecord) BeforeMarshalWire

func (r *IdentificationRecord) BeforeMarshalWire() error

BeforeMarshalWire canonicalizes named transcript hashes.

func (IdentificationRecord) Clone

Clone returns an independently owned record.

func (IdentificationRecord) ComputeAlertDigest

func (r IdentificationRecord) ComputeAlertDigest() [32]byte

ComputeAlertDigest hashes the public failure class, artifacts, and trusted transcript hashes that existed before the identification proof was made.

func (*IdentificationRecord) MarshalBinary

func (r *IdentificationRecord) MarshalBinary() ([]byte, error)

MarshalBinary returns the strict canonical wire encoding.

func (*IdentificationRecord) MarshalBinaryWithLimits

func (r *IdentificationRecord) MarshalBinaryWithLimits(limits IdentificationRecordLimits) ([]byte, error)

MarshalBinaryWithLimits returns the strict canonical wire encoding under explicit resource limits.

func (*IdentificationRecord) UnmarshalBinary

func (r *IdentificationRecord) UnmarshalBinary(in []byte) error

UnmarshalBinary decodes a strict canonical wire record.

func (*IdentificationRecord) UnmarshalBinaryWithLimits

func (r *IdentificationRecord) UnmarshalBinaryWithLimits(in []byte, limits IdentificationRecordLimits) error

UnmarshalBinaryWithLimits decodes a strict canonical identification record under explicit resource limits.

func (*IdentificationRecord) Validate

func (r *IdentificationRecord) Validate() error

Validate rejects incomplete, non-public, or non-canonical record shapes.

func (*IdentificationRecord) ValidateWithLimits

func (r *IdentificationRecord) ValidateWithLimits(limits IdentificationRecordLimits) error

ValidateWithLimits rejects incomplete, non-public, or non-canonical record shapes using explicit resource limits.

func (IdentificationRecord) WireType

func (IdentificationRecord) WireType() string

WireType returns the canonical wire type identifier.

func (IdentificationRecord) WireVersion

func (IdentificationRecord) WireVersion() uint16

WireVersion returns the canonical wire version.

type IdentificationRecordLimits

type IdentificationRecordLimits struct {
	MaxBytes                     int
	MaxFailureClassBytes         int
	MaxEnvelopeBytes             int
	MaxBroadcastCertificateBytes int
	MaxStatementBytes            int
	MaxProofBytes                int
	MaxTranscriptHashCount       int
	MaxTranscriptHashKeyBytes    int
	TLV                          TLVLimits
}

IdentificationRecordLimits caps one portable identifiable-abort record. The conservative defaults remain suitable for ordinary protocol evidence; protocols with intentionally larger public proofs must opt in explicitly.

func DefaultIdentificationRecordLimits

func DefaultIdentificationRecordLimits() IdentificationRecordLimits

DefaultIdentificationRecordLimits returns a caller-owned copy of the conservative limits used by IdentificationRecord.MarshalBinary and IdentificationRecord.UnmarshalBinary.

type InMemoryAckSigner

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

InMemoryAckSigner is a simple BroadcastAckSigner that uses an in-memory mapping from PartyID to an Ed25519-like signing function. It is intended for tests and single-process deployments.

func NewInMemoryAckSigner

func NewInMemoryAckSigner(party PartyID, signFn func(digest [32]byte) ([]byte, error)) *InMemoryAckSigner

NewInMemoryAckSigner creates a signer bound to a party.

func (*InMemoryAckSigner) SignAck

func (s *InMemoryAckSigner) SignAck(digest [32]byte) ([]byte, error)

SignAck implements BroadcastAckSigner.

type InMemoryAckVerifier

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

InMemoryAckVerifier is a simple BroadcastAckVerifier that uses an in-memory mapping from PartyID to a verification function. It is intended for tests and single-process deployments.

func NewInMemoryAckVerifier

func NewInMemoryAckVerifier(verifyFn func(party PartyID, digest [32]byte, signature []byte) error) *InMemoryAckVerifier

NewInMemoryAckVerifier creates a verifier.

func (*InMemoryAckVerifier) VerifyAck

func (v *InMemoryAckVerifier) VerifyAck(party PartyID, digest [32]byte, signature []byte) error

VerifyAck implements BroadcastAckVerifier.

type InMemoryReplayCache

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

InMemoryReplayCache is a simple mutex-protected ReplayCache for use in tests and single-process deployments. Production multi-process deployments should use a durable shared cache (e.g. Redis) keyed by session ID + slot key.

MaxEntries limits the number of cached slots (0 = use default of 100000). The cache fails closed with ErrReplayCacheFull instead of evicting security state that may still be needed to reject a replay or equivocation.

func NewBoundedReplayCache

func NewBoundedReplayCache(maxEntries int) *InMemoryReplayCache

NewBoundedReplayCache returns a bounded in-memory replay cache. Once full, new slots fail with ErrReplayCacheFull; existing slots remain available for duplicate and equivocation checks.

maxEntries must be positive. Values <= 0 are replaced with the default of [defaultReplayCacheMaxEntries]. The default is intentionally large enough to accommodate normal protocol message volumes; callers operating in constrained environments should pick an explicit value based on expected throughput.

func NewInMemoryReplayCache

func NewInMemoryReplayCache() *InMemoryReplayCache

NewInMemoryReplayCache returns an initialized in-memory replay cache with a default bound of 100000 entries to prevent unbounded memory growth in long-running processes. For an explicit bound, use NewBoundedReplayCache.

func (*InMemoryReplayCache) CheckAndStore

func (c *InMemoryReplayCache) CheckAndStore(slot MessageSlotKey, payloadHash [32]byte) error

CheckAndStore implements ReplayCache. It atomically checks whether a message slot has been seen and returns nil on first use, ErrDuplicateMessage when the same payload hash is replayed, or ErrEquivocation when a different payload hash occupies the same slot.

A nil receiver returns ErrMissingReplayCache (fail-closed) — callers must initialize the cache.

func (*InMemoryReplayCache) RetireSession

func (c *InMemoryReplayCache) RetireSession(protocol ProtocolID, sessionID SessionID) error

RetireSession removes replay history for a terminal session. Callers must durably prevent the session ID from being reused before retiring its state.

type InMemoryTransport

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

InMemoryTransport is a reference implementation of Transport that uses Go channels for in-process message delivery. Each party gets its own transport instance. Messages are opened with authenticated ReceiveInfo.

Direct messages are delivered only to the addressed recipient. Broadcast messages are delivered to all parties.

Broadcast certificates are NOT generated automatically.

func NewInMemoryTransport

func NewInMemoryTransport(self PartyID, parties PartySet, policies PolicySet) *InMemoryTransport

NewInMemoryTransport creates a transport for one party.

func (*InMemoryTransport) Broadcast

func (t *InMemoryTransport) Broadcast(_ context.Context, env Envelope) error

Broadcast delivers an envelope to all parties.

func (*InMemoryTransport) ConnectOutbox

func (t *InMemoryTransport) ConnectOutbox(party PartyID, outbox chan<- InboundEnvelope)

ConnectOutbox registers the outbox channel for a remote party. In a real deployment this would be a network connection.

func (*InMemoryTransport) Inbox

func (t *InMemoryTransport) Inbox() <-chan InboundEnvelope

Inbox returns the receive channel for this transport.

func (*InMemoryTransport) Parties

func (t *InMemoryTransport) Parties() PartySet

Parties returns the party set for this transport instance.

func (*InMemoryTransport) Receive

Receive returns the next envelope from the inbox.

func (*InMemoryTransport) Send

Send delivers a direct envelope to the addressed recipient.

type InboundEnvelope

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

InboundEnvelope is a received envelope bound to transport-verified facts.

Its fields are intentionally unexported so callers cannot mutate wire data or receive facts after opening and validation.

func OpenEnvelope

func OpenEnvelope(raw []byte, info ReceiveInfo, opts ...OpenOption) (InboundEnvelope, error)

OpenEnvelope decodes a wire envelope and binds it to transport-verified receive facts. Protocol policy checks are performed later by EnvelopeGuard.

func OpenEnvelopeWithLimits

func OpenEnvelopeWithLimits(raw []byte, info ReceiveInfo, limits EnvelopeLimits, opts ...OpenOption) (InboundEnvelope, error)

OpenEnvelopeWithLimits decodes a wire envelope with explicit limits and binds it to transport-verified receive facts.

func (InboundEnvelope) BroadcastCertificate

func (in InboundEnvelope) BroadcastCertificate() *BroadcastCertificate

BroadcastCertificate returns a deep copy of the attached broadcast certificate.

func (InboundEnvelope) Digest

func (in InboundEnvelope) Digest() EnvelopeDigest

Digest computes the domain-separated digest of the inbound envelope.

func (InboundEnvelope) Envelope

func (in InboundEnvelope) Envelope() Envelope

Envelope returns a deep copy of the inbound wire envelope.

func (InboundEnvelope) From

func (in InboundEnvelope) From() PartyID

From returns the sender party ID from the wire envelope.

func (InboundEnvelope) Payload

func (in InboundEnvelope) Payload() []byte

Payload returns a copy of the envelope payload bytes.

func (InboundEnvelope) PayloadType

func (in InboundEnvelope) PayloadType() PayloadType

PayloadType returns the payload type name.

func (InboundEnvelope) Protocol

func (in InboundEnvelope) Protocol() ProtocolID

Protocol returns the envelope protocol identifier.

func (InboundEnvelope) ReceiveInfo

func (in InboundEnvelope) ReceiveInfo() ReceiveInfo

ReceiveInfo returns a copy of the transport receive facts.

func (InboundEnvelope) Round

func (in InboundEnvelope) Round() uint8

Round returns the protocol round.

func (InboundEnvelope) SessionID

func (in InboundEnvelope) SessionID() SessionID

SessionID returns the envelope session ID.

func (InboundEnvelope) To

func (in InboundEnvelope) To() PartyID

To returns the recipient party ID from the wire envelope, or zero for broadcast.

type InvalidChildMode

type InvalidChildMode uint8

InvalidChildMode controls behavior when public derivation produces an invalid child.

const (
	// ErrorOnInvalidChild returns an error immediately when an invalid child is encountered.
	ErrorOnInvalidChild InvalidChildMode = iota
	// SkipInvalidChild increments the index and retries until a valid child or hardened range.
	SkipInvalidChild
)

func (InvalidChildMode) Valid

func (m InvalidChildMode) Valid() bool

Valid reports whether mode is a defined invalid-child handling strategy.

type KeyShare

type KeyShare interface {
	Algorithm() Algorithm
	PartyID() PartyID
	Derive(path DerivationPath, opts ...DeriveOption) (*DerivationResult, error)
	MarshalBinary() ([]byte, error)
	Destroy()
}

KeyShare is the common interface implemented by algorithm-specific shares.

type LocalConfig

type LocalConfig struct {
	Self           PartyID
	Rand           io.Reader       `json:"-"`
	Context        context.Context `json:"-"`
	Log            Logger          `json:"-"`
	EnvelopeSigner EnvelopeSigner  `json:"-"`
}

LocalConfig contains per-process runtime configuration for one protocol participant. Consensus parameters such as threshold, party set, session ID, signer set, derivation context, and HD enablement belong in protocol-specific plan objects, not in LocalConfig.

func (LocalConfig) Ctx

func (c LocalConfig) Ctx() context.Context

Ctx returns the local configuration context or context.Background when unset.

func (LocalConfig) Logger

func (c LocalConfig) Logger() Logger

Logger returns the configured Logger or a no-op implementation when unset.

func (LocalConfig) Reader

func (c LocalConfig) Reader() io.Reader

Reader returns the configured randomness source or crypto/rand.

type Logger

type Logger interface {
	Debug(ctx context.Context, msg string, fields ...any)
	Info(ctx context.Context, msg string, fields ...any)
	Warn(ctx context.Context, msg string, fields ...any)
	Error(ctx context.Context, msg string, fields ...any)
}

Logger is the logging interface used by protocol sessions. The zero-value is a no-op implementation that discards all messages.

func NopLogger

func NopLogger() Logger

NopLogger returns a logger that discards all messages.

type MaliciousTransport

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

MaliciousTransport wraps an InMemoryTransport and applies a specified transport-layer attack for security testing. Every attack mode must be caught by EnvelopeGuard.Validate before reaching the protocol handler.

func NewMaliciousTransport

func NewMaliciousTransport(inner *InMemoryTransport, mode AttackMode) *MaliciousTransport

NewMaliciousTransport creates a transport that applies the given attack.

func (*MaliciousTransport) Broadcast

func (m *MaliciousTransport) Broadcast(ctx context.Context, env Envelope) error

Broadcast applies the attack mode and delegates to the inner transport.

func (*MaliciousTransport) Receive

Receive delegates to the inner transport.

func (*MaliciousTransport) Send

func (m *MaliciousTransport) Send(ctx context.Context, env Envelope) error

Send applies the attack mode and delegates to the inner transport.

type MessageSlotKey

type MessageSlotKey struct {
	Protocol    ProtocolID
	SessionID   SessionID
	Round       uint8
	From        PartyID
	To          PartyID
	PayloadType PayloadType
}

MessageSlotKey identifies a unique protocol message slot for equivocation detection. It does not include the payload hash: two different payloads occupying the same slot constitute equivocation.

func SlotKeyFromEnvelope

func SlotKeyFromEnvelope(env Envelope) MessageSlotKey

SlotKeyFromEnvelope constructs a MessageSlotKey from the envelope's identifying fields. The payload is excluded so that different payloads for the same slot are detected as equivocation.

type OpenOption

type OpenOption func(*openOptions)

OpenOption configures OpenEnvelope.

func WithBroadcastCertificate

func WithBroadcastCertificate(cert *BroadcastCertificate) OpenOption

WithBroadcastCertificate attaches a transport-collected broadcast certificate to the opened inbound envelope. OpenEnvelope deep-clones the certificate before storing it, so the caller retains ownership of the original.

func WithEnvelopeLimits

func WithEnvelopeLimits(limits EnvelopeLimits) OpenOption

WithEnvelopeLimits configures explicit envelope size limits while opening.

type PartyID

type PartyID = uint32

PartyID identifies a protocol participant. The zero value is reserved to mean unset and broadcast mode for Envelope.

const BroadcastPartyId PartyID = 0

BroadcastPartyId is the receiver of broadcast mode

type PartySet

type PartySet []PartyID

PartySet is an ordered set of protocol participants.

func MergePartySet

func MergePartySet(sets ...PartySet) PartySet

MergePartySet takes a set slice and returns a new sorted set containing elements which are in either or both of this set and the given set

func NewPartySet

func NewPartySet(parties ...PartyID) PartySet

NewPartySet returns a PartySet containing parties in the given order.

func SortParties

func SortParties(parties PartySet) PartySet

SortParties returns a sorted copy of parties.

func (PartySet) Add

func (ps PartySet) Add(ids ...PartyID) PartySet

Add returns a new PartySet with given PartyID list

func (PartySet) Clone

func (ps PartySet) Clone() PartySet

Clone returns a copy of PartySet with a separate backing array

func (PartySet) Contains

func (ps PartySet) Contains(id PartyID) bool

Contains reports whether ps contains id

func (PartySet) Sorted

func (ps PartySet) Sorted() PartySet

Sorted returns a sorted copy of PartySet.

type PassphraseParams

type PassphraseParams struct {
	// Time is the number of Argon2id iterations (passes).
	// RFC 9106 §7.3 recommends 3 for non-interactive use.
	Time uint32
	// Memory is the memory cost in kibibytes.
	// RFC 9106 §7.3 recommends at least 65536 (64 MiB) for non-interactive use.
	Memory uint32
	// Threads is the degree of parallelism.
	// RFC 9106 §7.3 recommends 4 for non-interactive use.
	Threads uint8
}

PassphraseParams holds Argon2id parameters for passphrase-based key derivation. The zero value is not valid; use DefaultPassphraseParams or populate every field.

func DefaultPassphraseParams

func DefaultPassphraseParams() *PassphraseParams

DefaultPassphraseParams returns RFC 9106 recommended Argon2id parameters for non-interactive passphrase-based key derivation (time=3, memory=64 MiB, threads=4).

type PayloadType

type PayloadType string

PayloadType names a protocol message payload kind.

type PolicySet

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

PolicySet is a collection of delivery policies with O(1) lookup by (protocol, round, payloadType). Use NewPolicySet to construct. It must return ErrUnknownPayloadPolicy for unregistered payload types.

func MustNewPolicySet

func MustNewPolicySet(policies ...DeliveryPolicy) PolicySet

MustNewPolicySet is like NewPolicySet but panics on duplicate keys or when a broadcast-mode policy does not require BroadcastConsistencyRequired. It is intended for package-level var initialization where errors are a programmer mistake.

func NewPolicySet

func NewPolicySet(policies ...DeliveryPolicy) (PolicySet, error)

NewPolicySet builds a PolicySet from a list of delivery policies. It clones the input slice so callers cannot mutate the policy entries after construction. Duplicate keys are rejected.

func NewTestPolicySet

func NewTestPolicySet(policies ...DeliveryPolicy) (PolicySet, error)

NewTestPolicySet builds a structurally valid policy set whose mandatory broadcast-consistency or sender-signature requirements may be relaxed for deterministic tests. It panics outside a Go test binary and production guards reject the returned set.

func (PolicySet) Digest

func (ps PolicySet) Digest() [32]byte

Digest returns the canonical delivery-policy digest. Registration order does not affect the result; every field that changes guard behavior is bound.

func (PolicySet) Entries

func (ps PolicySet) Entries() []DeliveryPolicy

Entries returns a copy of the policy entries in registration order.

func (PolicySet) Match

func (ps PolicySet) Match(protocol ProtocolID, round uint8, payloadType PayloadType) (DeliveryPolicy, error)

Match returns the policy for a given message kind or ErrUnknownPayloadPolicy.

func (PolicySet) ValidateBroadcastConsistency

func (ps PolicySet) ValidateBroadcastConsistency() error

ValidateBroadcastConsistency checks that every broadcast-mode DeliveryPolicy requires BroadcastConsistencyRequired. It returns an error listing any broadcast policy that does not. Production callers should invoke this once during initialization.

type ProtocolError

type ProtocolError struct {
	Code  string
	Round uint8
	Party PartyID
	Blame *Blame
	Err   error
}

ProtocolError is the stable error shape returned by protocol state machines.

func NewProtocolError

func NewProtocolError(code string, round uint8, party PartyID, err error) *ProtocolError

NewProtocolError constructs a ProtocolError without blame evidence.

func (*ProtocolError) Error

func (e *ProtocolError) Error() string

Error formats the protocol code with optional round, party, and wrapped error.

func (*ProtocolError) Unwrap

func (e *ProtocolError) Unwrap() error

Unwrap returns the underlying error for errors.Is/errors.As callers.

type ProtocolID

type ProtocolID string

ProtocolID names a threshold signature protocol implemented by this module.

const (
	// ProtocolCGGMP21Secp256k1 identifies the CGGMP21-style threshold ECDSA protocol.
	ProtocolCGGMP21Secp256k1 ProtocolID = "cggmp21-secp256k1"
	// ProtocolFROSTEd25519 identifies the FROST-style threshold Ed25519 protocol.
	ProtocolFROSTEd25519 ProtocolID = "frost-ed25519"
)

type ReceiveInfo

type ReceiveInfo struct {
	Peer       PartyID
	Protection ChannelProtection
	ChannelID  string
	PeerKeyID  string
	ReceivedAt time.Time
}

ReceiveInfo records transport-verified facts for a received envelope.

type RefreshRunConfig

type RefreshRunConfig struct {
	SessionID        SessionID
	ReplayCache      ReplayCache
	AckVerifier      BroadcastAckVerifier
	EnvelopeSigner   EnvelopeSigner
	EnvelopeVerifier EnvelopeSignatureVerifier
}

RefreshRunConfig carries the security configuration for one refresh run.

type RefreshRunner

type RefreshRunner[K KeyShare] interface {
	// Protocol returns the protocol whose replay state the runner uses.
	Protocol() ProtocolID
	// StartRefresh constructs one algorithm-specific refresh session.
	StartRefresh(context.Context, K, RefreshRunConfig) (RefreshSession[K], []Envelope, error)
}

RefreshRunner adapts an algorithm-specific, externally committed refresh protocol to the shared scheduler. Protocols whose session owns a durable lifecycle lease or cutover transaction must be driven through their native lifecycle API instead.

type RefreshScheduler

type RefreshScheduler[K KeyShare] struct {
	// contains filtered or unexported fields
}

RefreshScheduler periodically drives proactive refresh protocols that use an external compare-and-swap commit callback. It does not support protocols whose session owns its lifecycle cutover. A scheduler permits only one active Run or RunOnce call at a time.

func NewRefreshScheduler

func NewRefreshScheduler[K KeyShare](opts RefreshSchedulerOptions[K]) (*RefreshScheduler[K], error)

NewRefreshScheduler constructs a proactive refresh scheduler.

func (*RefreshScheduler[K]) Run

func (s *RefreshScheduler[K]) Run(ctx context.Context) error

Run executes refresh periodically until ctx is cancelled or a run fails. The first refresh starts after one interval.

func (*RefreshScheduler[K]) RunOnce

func (s *RefreshScheduler[K]) RunOnce(ctx context.Context) error

RunOnce immediately executes one refresh run.

Example

ExampleRefreshScheduler_RunOnce demonstrates an operationally triggered refresh with an atomic compare-and-swap commit callback.

package main

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/islishude/tss"
)

type exampleRefreshShare struct {
	generation int
}

func (*exampleRefreshShare) Algorithm() tss.Algorithm { return tss.AlgorithmFROSTEd25519 }
func (*exampleRefreshShare) PartyID() tss.PartyID     { return 1 }
func (*exampleRefreshShare) PublicKeyBytes() []byte   { return []byte("group-public-key") }
func (*exampleRefreshShare) ChainCodeBytes() []byte   { return make([]byte, 32) }
func (*exampleRefreshShare) Derive(path tss.DerivationPath, opts ...tss.DeriveOption) (*tss.DerivationResult, error) {
	return &tss.DerivationResult{
		Scheme:         tss.DerivationSchemeEd25519KhovratovichLaw,
		ChildPublicKey: []byte("group-public-key"),
		ChildChainCode: make([]byte, 32),
		RequestedPath:  path.Clone(),
		ResolvedPath:   path.Clone(),
		AdditiveShift:  make([]byte, 32),
	}, nil
}
func (*exampleRefreshShare) MarshalBinary() ([]byte, error) { return []byte("example-share"), nil }
func (*exampleRefreshShare) Destroy()                       {}

type exampleRefreshRunner struct{}

func (exampleRefreshRunner) Protocol() tss.ProtocolID { return tss.ProtocolFROSTEd25519 }

func (exampleRefreshRunner) StartRefresh(context.Context, *exampleRefreshShare, tss.RefreshRunConfig) (tss.RefreshSession[*exampleRefreshShare], []tss.Envelope, error) {
	return exampleRefreshSession{refreshed: &exampleRefreshShare{generation: 2}}, nil, nil
}

type exampleRefreshSession struct {
	refreshed *exampleRefreshShare
}

func (exampleRefreshSession) Handle(context.Context, tss.InboundEnvelope) ([]tss.Envelope, error) {
	return nil, errors.New("example refresh is already complete")
}

func (s exampleRefreshSession) KeyShare() (*exampleRefreshShare, bool) {
	return s.refreshed, true
}

func (exampleRefreshSession) Close(context.Context) error { return nil }

type exampleRefreshTransport struct{}

func (exampleRefreshTransport) Send(context.Context, tss.Envelope) error      { return nil }
func (exampleRefreshTransport) Broadcast(context.Context, tss.Envelope) error { return nil }
func (exampleRefreshTransport) Receive(context.Context) (tss.InboundEnvelope, error) {
	return tss.InboundEnvelope{}, errors.New("example refresh is already complete")
}

type exampleAckVerifier struct{}

func (exampleAckVerifier) VerifyAck(tss.PartyID, [32]byte, []byte) error { return nil }

// ExampleRefreshScheduler_RunOnce demonstrates an operationally triggered
// refresh with an atomic compare-and-swap commit callback.
func main() {
	current := &exampleRefreshShare{generation: 1}
	scheduler, err := tss.NewRefreshScheduler(tss.RefreshSchedulerOptions[*exampleRefreshShare]{
		Interval:    24 * time.Hour,
		Transport:   exampleRefreshTransport{},
		Runner:      exampleRefreshRunner{},
		ReplayCache: tss.NewInMemoryReplayCache(),
		AckVerifier: exampleAckVerifier{},
		LoadKeyShare: func(context.Context) (*exampleRefreshShare, error) {
			return current, nil
		},
		SessionIDSource: func(context.Context, *exampleRefreshShare) (tss.SessionID, error) {
			return tss.SessionID{1}, nil
		},
		ClaimSessionID: func(context.Context, tss.SessionID) error {
			return nil
		},
		CommitKeyShare: func(_ context.Context, previous, refreshed *exampleRefreshShare) error {
			if current != previous {
				return errors.New("key share changed concurrently")
			}
			current = refreshed
			return nil
		},
	})
	if err != nil {
		panic(err)
	}
	if err := scheduler.RunOnce(context.Background()); err != nil {
		panic(err)
	}
	fmt.Println(current.generation)
}
Output:
2

type RefreshSchedulerOptions

type RefreshSchedulerOptions[K KeyShare] struct {
	// Interval is the delay before the first refresh and between successful runs.
	Interval time.Duration
	// Transport delivers protocol envelopes with authenticated receive metadata.
	Transport Transport
	// Runner starts algorithm-specific refresh sessions.
	Runner RefreshRunner[K]
	// ReplayCache stores seen refresh envelopes across scheduler runs.
	ReplayCache ReplayCache
	// AckVerifier verifies broadcast consistency certificates.
	AckVerifier BroadcastAckVerifier
	// EnvelopeSigner authenticates local direct refresh envelopes.
	EnvelopeSigner EnvelopeSigner
	// EnvelopeVerifier authenticates direct refresh envelopes from peers.
	EnvelopeVerifier EnvelopeSignatureVerifier
	// LoadKeyShare returns the current key share at the start of each run.
	LoadKeyShare func(context.Context) (K, error)
	// SessionIDSource returns the externally coordinated unique session ID for
	// the next run. Every participant in one run must receive the same ID.
	SessionIDSource func(context.Context, K) (SessionID, error)
	// ClaimSessionID durably and atomically records first use of a session ID.
	// A claimed ID remains unavailable even if this refresh later fails.
	ClaimSessionID func(context.Context, SessionID) error
	// CommitKeyShare is the sole durable commit boundary for a scheduler run. It
	// atomically persists and installs refreshed if previous is still current.
	// The Runner and RefreshSession must not perform this commit themselves. A
	// nil result transfers ownership of refreshed to the callback. On a normal
	// error the scheduler destroys refreshed. If the error wraps
	// ErrRefreshCommitOutcomeUnknown, the callback retains ownership because the
	// durable commit may have succeeded.
	CommitKeyShare func(context.Context, K, K) error
}

RefreshSchedulerOptions configures periodic proactive key-share refresh.

type RefreshSession

type RefreshSession[K KeyShare] interface {
	// Handle validates and applies one inbound refresh envelope.
	Handle(context.Context, InboundEnvelope) ([]Envelope, error)
	// KeyShare returns an independent caller-owned share after completion. The
	// returned share must remain valid after Close is called on the session.
	KeyShare() (K, bool)
	// Close clears secret material retained by the session and reports cleanup failures.
	Close(context.Context) error
}

RefreshSession is the protocol-independent surface needed to drive one externally committed key-share refresh session. Implementations must not install or otherwise durably commit their candidate share themselves.

type ReplayCache

type ReplayCache interface {
	CheckAndStore(slot MessageSlotKey, payloadHash [32]byte) error
	RetireSession(protocol ProtocolID, sessionID SessionID) error
}

ReplayCache detects replayed and equivocating protocol messages. CheckAndStore atomically checks whether a message slot has been seen and:

  • Stores the payload hash and returns nil when the slot is new.
  • Returns ErrDuplicateMessage when the slot exists with the same payload hash.
  • Returns ErrEquivocation when the slot exists with a different payload hash.

RetireSession removes replay state only after the identified session is terminal and its session ID is durably unavailable for reuse.

type SLogger

type SLogger struct{ *slog.Logger }

SLogger adapts log/slog.Logger to the Logger interface.

func NewSLogger

func NewSLogger(sl *slog.Logger) *SLogger

NewSLogger returns an SLogger that wraps sl.

func (*SLogger) Debug

func (l *SLogger) Debug(ctx context.Context, msg string, fields ...any)

Debug logs at debug level.

func (*SLogger) Error

func (l *SLogger) Error(ctx context.Context, msg string, fields ...any)

Error logs at error level.

func (*SLogger) Info

func (l *SLogger) Info(ctx context.Context, msg string, fields ...any)

Info logs at info level.

func (*SLogger) Warn

func (l *SLogger) Warn(ctx context.Context, msg string, fields ...any)

Warn logs at warn level.

type SessionConfig

type SessionConfig struct {
	Self        PartyID
	Parties     PartySet
	SessionID   SessionID
	PolicySet   PolicySet
	ReplayCache ReplayCache
}

SessionConfig carries the security configuration required to construct a protocol session.

type SessionID

type SessionID [sessionIDSize]byte

SessionID is a 32-byte nonce that separates independent protocol executions.

func NewSessionID

func NewSessionID(reader io.Reader) (SessionID, error)

NewSessionID returns a random session identifier from reader or crypto/rand.

Example

ExampleNewSessionID demonstrates how to generate a unique session identifier from a cryptographic random source. A nil reader uses crypto/rand.Reader. Session IDs are used to bind all messages in a protocol run together, preventing cross-session replay attacks.

package main

import (
	"bytes"
	"fmt"

	"github.com/islishude/tss"
)

func main() {
	sessionID, err := tss.NewSessionID(bytes.NewReader(bytes.Repeat([]byte{0x11}, 32)))
	if err != nil {
		panic(err)
	}

	fmt.Println(sessionID.String())
}
Output:
1111111111111111111111111111111111111111111111111111111111111111

func SessionIDFromBytes

func SessionIDFromBytes(in []byte) (SessionID, error)

SessionIDFromBytes parses a 32-byte session identifier.

func (SessionID) Bytes

func (id SessionID) Bytes() []byte

Bytes returns a copy of the session identifier bytes.

func (SessionID) MarshalText

func (id SessionID) MarshalText() ([]byte, error)

MarshalText encodes the session identifier as hex text.

func (SessionID) String

func (id SessionID) String() string

String returns the hex encoding of the session identifier.

func (*SessionID) UnmarshalText

func (id *SessionID) UnmarshalText(text []byte) error

UnmarshalText decodes a hex session identifier.

func (SessionID) Valid

func (id SessionID) Valid() bool

Valid reports whether the session identifier is non-zero.

type SignIntent

type SignIntent struct {
	SessionID SessionID
	Context   SigningContext
	Message   []byte
	Signers   PartySet
}

SignIntent is the protocol-independent shared intent that signers authorize before producing protocol messages.

func (SignIntent) Clone

func (i SignIntent) Clone() SignIntent

Clone returns an independently owned copy of the signing intent.

func (SignIntent) Request

func (i SignIntent) Request() SignRequest

Request returns the context-bound request represented by the intent.

type SignRequest

type SignRequest struct {
	Context SigningContext `json:"context"`
	Message []byte         `json:"message"`
}

SignRequest is a context-bound message supplied for signature creation or verification. Protocols decide how the context and message are hashed.

func (SignRequest) Clone

func (r SignRequest) Clone() SignRequest

Clone returns an independently owned copy of the signing request.

type SigningContext

type SigningContext struct {
	KeyID         string            `json:"key_id" wire:"1,string"`
	ChainID       string            `json:"chain_id" wire:"2,string"`
	Derivation    DerivationRequest `json:"derivation" wire:"3,record"`
	PolicyDomain  string            `json:"policy_domain" wire:"4,string"`
	MessageDomain string            `json:"message_domain" wire:"5,string"`
}

SigningContext binds a signing request to key, chain, derivation, policy, and message domains without changing the message bytes being signed.

func (SigningContext) Clone

func (c SigningContext) Clone() SigningContext

Clone returns a caller-owned copy of the context.

func (SigningContext) DerivationPath

func (c SigningContext) DerivationPath() DerivationPath

DerivationPath returns a caller-owned copy of the requested path.

func (SigningContext) MarshalBinary

func (c SigningContext) MarshalBinary() ([]byte, error)

MarshalBinary encodes the signing context using canonical TLV.

func (*SigningContext) UnmarshalBinary

func (c *SigningContext) UnmarshalBinary(in []byte) error

UnmarshalBinary decodes a canonical signing context.

func (SigningContext) Validate

func (c SigningContext) Validate() error

Validate checks required context fields and the non-hardened derivation path.

func (SigningContext) WireType

func (SigningContext) WireType() string

WireType returns the canonical wire type identifier for SigningContext.

func (SigningContext) WireVersion

func (SigningContext) WireVersion() uint16

WireVersion returns the wire format version for SigningContext.

type TLVLimits

type TLVLimits struct {
	MaxFields     int
	MaxFieldBytes int
}

TLVLimits caps wire-level TLV field counts and per-field sizes.

type ThresholdConfig

type ThresholdConfig struct {
	Threshold      int
	Parties        PartySet
	Self           PartyID
	SessionID      SessionID
	Rand           io.Reader       `json:"-"`
	Context        context.Context `json:"-"`
	Log            Logger          `json:"-"`
	EnvelopeSigner EnvelopeSigner  `json:"-"`
}

ThresholdConfig contains local participant configuration for a protocol run.

func (ThresholdConfig) Ctx

Ctx returns the configuration context or context.Background when unset.

func (ThresholdConfig) Logger

func (c ThresholdConfig) Logger() Logger

Logger returns the configured Logger or a no-op implementation when unset.

func (ThresholdConfig) Reader

func (c ThresholdConfig) Reader() io.Reader

Reader returns the configured randomness source or crypto/rand.

func (ThresholdConfig) SortedParties

func (c ThresholdConfig) SortedParties() PartySet

SortedParties returns the configured party set in ascending order.

func (ThresholdConfig) Validate

func (c ThresholdConfig) Validate() error

Validate checks threshold, party-set, and local-party invariants using conservative default limits. Callers that know the algorithm should prefer ValidateWithLimits with algorithm-specific limits.

func (ThresholdConfig) ValidateWithLimits

func (c ThresholdConfig) ValidateWithLimits(l ThresholdLimits) error

ValidateWithLimits checks threshold, party-set, and local-party invariants against the provided ThresholdLimits. It enforces hard caps on party count and threshold to prevent unbounded resource consumption.

type ThresholdLimits

type ThresholdLimits struct {
	MaxParties              int
	MaxThreshold            int
	MaxSigners              int
	MinProductionThreshold  int
	AllowOneOfOne           bool
	AllowOversizedSignerSet bool
}

ThresholdLimits defines finite caps for threshold protocol parameters.

func (ThresholdLimits) ValidateThreshold

func (l ThresholdLimits) ValidateThreshold(threshold, nParties int) error

ValidateThreshold checks that threshold and party count comply with the configured production minimum and AllowOneOfOne policy.

type Transport

type Transport interface {
	// Send delivers a direct (point-to-point) envelope to its recipient.
	Send(ctx context.Context, env Envelope) error

	// Broadcast delivers an envelope to all parties.
	Broadcast(ctx context.Context, env Envelope) error

	// Receive blocks until the next envelope is available and returns it
	// with transport-verified receive facts bound to the wire envelope.
	Receive(ctx context.Context) (InboundEnvelope, error)
}

Transport abstracts the network layer used to deliver protocol envelopes. Implementations receive raw wire bytes, authenticate the peer, classify the actual channel protection, and return an InboundEnvelope opened with ReceiveInfo.

Directories

Path Synopsis
cggmp21
secp256k1
Package secp256k1 exposes the CGGMP21/secp256k1 threshold ECDSA API.
Package secp256k1 exposes the CGGMP21/secp256k1 threshold ECDSA API.
frost
ed25519
Package ed25519 implements a FROST-style threshold Ed25519 flow with dealerless DKG, explicitly authorized trusted-dealer import, and threshold secret reconstruction.
Package ed25519 implements a FROST-style threshold Ed25519 flow with dealerless DKG, explicitly authorized trusted-dealer import, and threshold secret reconstruction.
internal
clone
Package clone provides internal helpers for making independently owned copies.
Package clone provides internal helpers for making independently owned copies.
fiat/secp256k1field
Code generated by Fiat Cryptography.
Code generated by Fiat Cryptography.
fiat/secp256k1scalar
Code generated by Fiat Cryptography.
Code generated by Fiat Cryptography.
inmemoryrun
Package inmemoryrun provides a private authenticated router for production helpers that deliberately execute a complete multi-party protocol in one process.
Package inmemoryrun provides a private authenticated router for production helpers that deliberately execute a complete multi-party protocol in one process.
mta
oneuse
Package oneuse provides small lifecycle guards for secret-bearing values that may be claimed once and must be destroyed when consumed.
Package oneuse provides small lifecycle guards for secret-bearing values that may be claimed once and must be destroyed when consumed.
paillier/paillierct
Package paillierct provides constant-time modular exponentiation for Paillier private-key operations.
Package paillierct provides constant-time modular exponentiation for Paillier private-key operations.
plantranscript
Package plantranscript centralizes transcript fragments shared by protocol plans without sharing protocol-specific transcript domains or field order.
Package plantranscript centralizes transcript fragments shared by protocol plans without sharing protocol-specific transcript domains or field order.
planvalidation
Package planvalidation centralizes lifecycle-plan validation shared by protocol packages.
Package planvalidation centralizes lifecycle-plan validation shared by protocol packages.
secret
Package secret provides fixed-length scalar types for cryptographic secrets.
Package secret provides fixed-length scalar types for cryptographic secrets.
shamir
Package shamir implements Shamir secret sharing over the secp256k1 scalar field for CGGMP21.
Package shamir implements Shamir secret sharing over the secp256k1 scalar field for CGGMP21.
testharness
Package testharness provides reusable test infrastructure for TSS protocol tests: deterministic RNG, party factories, envelope mutation, network fault simulation, state snapshots, protocol runners, and crash-store helpers.
Package testharness provides reusable test infrastructure for TSS protocol tests: deterministic RNG, party factories, envelope mutation, network fault simulation, state snapshots, protocol runners, and crash-store helpers.
testutil
Package testutil provides shared test helpers used across TSS protocol tests.
Package testutil provides shared test helpers used across TSS protocol tests.
testutil/cmd/testbudget command
testbudget parses `go test -json` output from stdin and flags individual tests that exceed their tier's runtime budget.
testbudget parses `go test -json` output from stdin and flags individual tests that exceed their tier's runtime budget.
testvectors
Package testvectors provides shared helpers for reading, locating, and validating the repository's committed test-vector files.
Package testvectors provides shared helpers for reading, locating, and validating the repository's committed test-vector files.
transcript
Package transcript provides canonical labeled SHA-256 transcripts.
Package transcript provides canonical labeled SHA-256 transcripts.
wire
Package wire provides a strict canonical TLV binary encoding for cryptographic protocol messages.
Package wire provides a strict canonical TLV binary encoding for cryptographic protocol messages.
zk/challenge
Package challenge derives canonical Fiat-Shamir challenges from transcript roots.
Package challenge derives canonical Fiat-Shamir challenges from transcript roots.
zk/paillier
Package paillier contains Paillier zero-knowledge proofs used by the CGGMP21-style secp256k1 signing path.
Package paillier contains Paillier zero-knowledge proofs used by the CGGMP21-style secp256k1 signing path.
zk/schnorred25519
Package schnorred25519 implements non-interactive Schnorr proofs of knowledge in the prime-order Ed25519 subgroup.
Package schnorred25519 implements non-interactive Schnorr proofs of knowledge in the prime-order Ed25519 subgroup.
Package tssrun defines the production integration contract for TSS protocol runs.
Package tssrun defines the production integration contract for TSS protocol runs.
conformance
Package conformance provides reusable tests for tssrun integration stores.
Package conformance provides reusable tests for tssrun integration stores.

Jump to

Keyboard shortcuts

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