mirror of
https://github.com/luxfi/threshold.git
synced 2026-10-30 15:15:53 +00:00
344 lines
8.8 KiB
Go
344 lines
8.8 KiB
Go
// Package adapters provides chain-specific implementations for threshold signatures
|
|
package adapters
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/luxfi/threshold/pkg/math/curve"
|
|
"github.com/luxfi/threshold/pkg/party"
|
|
)
|
|
|
|
// coerceScalar returns a scalar on the target curve. If src is nil, a fresh
|
|
// zero scalar on the curve is returned. If src already lives on the target
|
|
// curve, it is returned as-is. Otherwise, src is re-encoded onto the curve
|
|
// via MarshalBinary/UnmarshalBinary so cross-curve mock shares do not panic
|
|
// during aggregation.
|
|
func coerceScalar(group curve.Curve, src curve.Scalar) (curve.Scalar, error) {
|
|
if src == nil {
|
|
return group.NewScalar(), nil
|
|
}
|
|
if src.Curve().Name() == group.Name() {
|
|
return src, nil
|
|
}
|
|
bz, err := src.MarshalBinary()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("marshal share scalar: %w", err)
|
|
}
|
|
out := group.NewScalar()
|
|
if err := out.UnmarshalBinary(bz); err != nil {
|
|
return nil, fmt.Errorf("coerce share scalar to %s: %w", group.Name(), err)
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// SignatureType defines the signature algorithm
|
|
type SignatureType int
|
|
|
|
const (
|
|
SignatureECDSA SignatureType = iota
|
|
SignatureEdDSA
|
|
SignatureSchnorr
|
|
SignatureBLS
|
|
SignatureCorona // Post-quantum lattice-based
|
|
SignatureDilithium // Post-quantum ML-DSA (NIST standard)
|
|
)
|
|
|
|
// Share represents a party's secret share
|
|
type Share struct {
|
|
ID party.ID
|
|
Value curve.Scalar
|
|
Index int
|
|
}
|
|
|
|
// PartialSig represents a partial signature from one party
|
|
type PartialSig interface {
|
|
GetPartyID() party.ID
|
|
Serialize() []byte
|
|
}
|
|
|
|
// FullSig represents a complete threshold signature
|
|
type FullSig interface {
|
|
Verify(pubKey curve.Point, message []byte) bool
|
|
Serialize() []byte
|
|
}
|
|
|
|
// SignerAdapter is the common interface for all chain-specific adapters
|
|
type SignerAdapter interface {
|
|
// Digest computes chain-specific message digest
|
|
Digest(tx interface{}) ([]byte, error)
|
|
|
|
// SignEC creates a partial signature with a party's share
|
|
SignEC(digest []byte, share Share) (PartialSig, error)
|
|
|
|
// AggregateEC combines partial signatures into a full signature
|
|
AggregateEC(parts []PartialSig) (FullSig, error)
|
|
|
|
// Encode converts signature to chain-specific wire format
|
|
Encode(full FullSig) ([]byte, error)
|
|
|
|
// ValidateConfig checks if configuration is valid for this chain
|
|
ValidateConfig(config *UnifiedConfig) error
|
|
}
|
|
|
|
// UnifiedConfig represents configuration for unified LSS
|
|
type UnifiedConfig struct {
|
|
// Common fields
|
|
ID party.ID
|
|
Threshold int
|
|
Generation uint64
|
|
PartyIDs []party.ID
|
|
|
|
// Signature type
|
|
SignatureScheme SignatureType
|
|
|
|
// Curve-specific
|
|
Group curve.Curve
|
|
|
|
// Shared secrets (works for both EC and PQ)
|
|
SecretShare interface{} // curve.Scalar for EC, lattice element for PQ
|
|
PublicKey interface{} // curve.Point for EC, lattice public key for PQ
|
|
|
|
// Additional scheme-specific data
|
|
ECDSAConfig *ECDSAExtensions
|
|
EdDSAConfig *EdDSAExtensions
|
|
CoronaConfig *CoronaExtensions
|
|
DilithiumConfig *DilithiumExtensions
|
|
|
|
// Verification shares for all parties
|
|
VerificationShares map[party.ID]interface{}
|
|
}
|
|
|
|
// ECDSAExtensions holds ECDSA-specific configuration
|
|
type ECDSAExtensions struct {
|
|
PaillierKey interface{} // Paillier secret key
|
|
PedersenParams interface{} // Pedersen parameters
|
|
ChainCode []byte // HD wallet chain code
|
|
}
|
|
|
|
// EdDSAExtensions holds EdDSA-specific configuration
|
|
type EdDSAExtensions struct {
|
|
AuxRand []byte // Auxiliary randomness for deterministic nonces
|
|
}
|
|
|
|
// CoronaExtensions holds Corona PQ-specific configuration
|
|
type CoronaExtensions struct {
|
|
// Lattice parameters
|
|
N int // Lattice dimension
|
|
Q int // Modulus
|
|
Sigma float64 // Gaussian parameter
|
|
SecurityLevel int // 128, 192, or 256 bits
|
|
|
|
// Offline preprocessing store
|
|
PreprocessingShares []CoronaPreprocessing
|
|
|
|
// Public parameters
|
|
PublicMatrix interface{} // A matrix for LWE
|
|
}
|
|
|
|
// CoronaPreprocessing represents offline preprocessing for Corona
|
|
type CoronaPreprocessing struct {
|
|
ID string
|
|
Round1 interface{} // Offline round 1 data
|
|
Round2 interface{} // Offline round 2 data
|
|
Consumed bool
|
|
}
|
|
|
|
// DilithiumExtensions holds Dilithium/ML-DSA specific configuration
|
|
type DilithiumExtensions struct {
|
|
// NIST security level (2, 3, or 5)
|
|
SecurityLevel int // Maps to ML-DSA-44, ML-DSA-65, ML-DSA-87
|
|
|
|
// Lattice parameters (auto-configured based on security level)
|
|
K int // Vector dimension
|
|
L int // Matrix dimension
|
|
|
|
// Public seed for deterministic key generation
|
|
PublicSeed []byte
|
|
}
|
|
|
|
// ECDSA signature components
|
|
type ECDSAPartialSig struct {
|
|
PartyID party.ID
|
|
R curve.Scalar
|
|
S curve.Scalar
|
|
}
|
|
|
|
func (e *ECDSAPartialSig) GetPartyID() party.ID { return e.PartyID }
|
|
func (e *ECDSAPartialSig) Serialize() []byte {
|
|
// Serialize R || S
|
|
rBytes, _ := e.R.MarshalBinary()
|
|
sBytes, _ := e.S.MarshalBinary()
|
|
return append(rBytes, sBytes...)
|
|
}
|
|
|
|
type ECDSAFullSig struct {
|
|
R curve.Scalar
|
|
S curve.Scalar
|
|
}
|
|
|
|
func (e *ECDSAFullSig) Verify(pubKey curve.Point, message []byte) bool {
|
|
// ECDSA verification logic
|
|
return true // Placeholder
|
|
}
|
|
|
|
func (e *ECDSAFullSig) Serialize() []byte {
|
|
rBytes, _ := e.R.MarshalBinary()
|
|
sBytes, _ := e.S.MarshalBinary()
|
|
return append(rBytes, sBytes...)
|
|
}
|
|
|
|
// EdDSA signature components
|
|
type EdDSAPartialSig struct {
|
|
PartyID party.ID
|
|
R curve.Point
|
|
Z curve.Scalar
|
|
}
|
|
|
|
func (e *EdDSAPartialSig) GetPartyID() party.ID { return e.PartyID }
|
|
func (e *EdDSAPartialSig) Serialize() []byte {
|
|
rBytes, _ := e.R.MarshalBinary()
|
|
zBytes, _ := e.Z.MarshalBinary()
|
|
return append(rBytes, zBytes...)
|
|
}
|
|
|
|
type EdDSAFullSig struct {
|
|
R curve.Point
|
|
Z curve.Scalar
|
|
}
|
|
|
|
func (e *EdDSAFullSig) Verify(pubKey curve.Point, message []byte) bool {
|
|
// EdDSA verification logic
|
|
return true // Placeholder
|
|
}
|
|
|
|
func (e *EdDSAFullSig) Serialize() []byte {
|
|
rBytes, _ := e.R.MarshalBinary()
|
|
zBytes, _ := e.Z.MarshalBinary()
|
|
return append(rBytes, zBytes...)
|
|
}
|
|
|
|
// Corona PQ signature components
|
|
type CoronaPartialSig struct {
|
|
PartyID party.ID
|
|
Share interface{} // Lattice element
|
|
}
|
|
|
|
func (r *CoronaPartialSig) GetPartyID() party.ID { return r.PartyID }
|
|
func (r *CoronaPartialSig) Serialize() []byte {
|
|
// Serialize lattice element
|
|
return []byte{} // Placeholder
|
|
}
|
|
|
|
type CoronaFullSig struct {
|
|
Signature interface{} // Complete lattice signature
|
|
Size int // Signature size in bytes
|
|
}
|
|
|
|
func (r *CoronaFullSig) Verify(pubKey curve.Point, message []byte) bool {
|
|
// Corona verification logic
|
|
return true // Placeholder
|
|
}
|
|
|
|
func (r *CoronaFullSig) Serialize() []byte {
|
|
// ~13.4KB for 128-bit security as per Corona paper
|
|
return make([]byte, r.Size)
|
|
}
|
|
|
|
// AdapterFactory creates appropriate adapter for a chain
|
|
type AdapterFactory struct{}
|
|
|
|
// NewAdapter creates a chain-specific adapter. Returns nil if the chain
|
|
// is unsupported or the (chain, sigType) pair is invalid. Callers that
|
|
// need the underlying error should construct the adapter directly via
|
|
// the typed New*Adapter functions.
|
|
func (f *AdapterFactory) NewAdapter(chain string, sigType SignatureType) SignerAdapter {
|
|
switch chain {
|
|
case "xrpl":
|
|
a, err := NewXRPLAdapter(sigType, false)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return a
|
|
case "ethereum":
|
|
return NewEthereumAdapter()
|
|
case "bitcoin":
|
|
return NewBitcoinAdapter(sigType)
|
|
case "solana":
|
|
return NewSolanaAdapter()
|
|
case "ton":
|
|
return NewTONAdapter(0) // basechain by default
|
|
case "cardano":
|
|
a, err := NewCardanoAdapter(sigType, 0x01, EraBabbage) // mainnet, current era
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return a
|
|
case "cosmos":
|
|
// Cosmos adapter not yet available.
|
|
return nil
|
|
case "polkadot":
|
|
// Polkadot adapter not yet available.
|
|
return nil
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// GetSupportedChains returns list of supported blockchain networks
|
|
func GetSupportedChains() []string {
|
|
return []string{
|
|
"xrpl",
|
|
"ethereum",
|
|
"bitcoin",
|
|
"solana",
|
|
"ton",
|
|
"cosmos",
|
|
"polkadot",
|
|
"lux",
|
|
"binance",
|
|
"cardano",
|
|
"near",
|
|
"aptos",
|
|
"sui",
|
|
}
|
|
}
|
|
|
|
// GetChainRequirements returns specific requirements for a chain
|
|
func GetChainRequirements(chain string) map[string]interface{} {
|
|
requirements := map[string]map[string]interface{}{
|
|
"xrpl": {
|
|
"signature_types": []SignatureType{SignatureECDSA, SignatureEdDSA},
|
|
"low_s_required": true,
|
|
"max_threshold": 8,
|
|
"prefix_ed25519": true,
|
|
},
|
|
"ethereum": {
|
|
"signature_types": []SignatureType{SignatureECDSA},
|
|
"low_s_required": true,
|
|
"eip155_chainid": true,
|
|
"typed_tx": true,
|
|
},
|
|
"bitcoin": {
|
|
"signature_types": []SignatureType{SignatureECDSA, SignatureSchnorr},
|
|
"low_s_required": true,
|
|
"taproot_support": true,
|
|
"sighash_types": true,
|
|
},
|
|
"solana": {
|
|
"signature_types": []SignatureType{SignatureEdDSA},
|
|
"ed25519_only": true,
|
|
"program_verify": true,
|
|
},
|
|
"polkadot": {
|
|
"signature_types": []SignatureType{SignatureSchnorr},
|
|
"sr25519_native": true,
|
|
"merlin_transcript": true,
|
|
},
|
|
}
|
|
|
|
if req, exists := requirements[chain]; exists {
|
|
return req
|
|
}
|
|
return nil
|
|
}
|