Documentation
¶
Overview ¶
Package handshake implements ZK-enhanced peer authentication and session management.
Index ¶
- Constants
- func PreferredProtocols(kemEnabled bool) []string
- func VerifySecp256k1Signature(pubkey, message, signature []byte) error
- type ApprovalFunc
- type BundleAttacher
- type Challenge
- type ChallengeResponse
- type Config
- type Handshaker
- func (h *Handshaker) HandleIncoming(ctx context.Context, s network.Stream) (*Session, error)
- func (h *Handshaker) Initiate(ctx context.Context, s network.Stream, localDID string) (*Session, error)
- func (h *Handshaker) StreamHandler() network.StreamHandler
- func (h *Handshaker) StreamHandlerV11() network.StreamHandler
- func (h *Handshaker) StreamHandlerV12() network.StreamHandler
- type InvalidationReason
- type InvalidationRecord
- type NonceCache
- type PendingHandshake
- type SecurityEventHandler
- type Session
- type SessionAck
- type SessionStore
- func (s *SessionStore) ActiveSessions() []*Session
- func (s *SessionStore) Cleanup() int
- func (s *SessionStore) Create(peerDID string, zkVerified bool) (*Session, error)
- func (s *SessionStore) Get(peerDID string) *Session
- func (s *SessionStore) GetByToken(token string) (string, bool)
- func (s *SessionStore) Invalidate(peerDID string, reason InvalidationReason)
- func (s *SessionStore) InvalidateAll(reason InvalidationReason)
- func (s *SessionStore) InvalidateByCondition(reason InvalidationReason, predicate func(*Session) bool)
- func (s *SessionStore) InvalidationHistory() []InvalidationRecord
- func (s *SessionStore) Remove(peerDID string)
- func (s *SessionStore) SetInvalidationCallback(fn func(peerDID string, reason InvalidationReason))
- func (s *SessionStore) Validate(peerDID, token string) bool
- type SignatureVerifyFunc
- type Signer
- type ZKProverFunc
- type ZKVerifierFunc
Constants ¶
const ( // ProtocolID is the legacy protocol identifier (unsigned challenges). ProtocolID = "/lango/handshake/1.0.0" // ProtocolIDv11 is the signed-challenge protocol (v1.1). ProtocolIDv11 = "/lango/handshake/1.1.0" // ProtocolIDv12 is the PQ KEM handshake protocol (v1.2). ProtocolIDv12 = "/lango/handshake/1.2.0" )
Protocol version constants for handshake negotiation.
const NonceSize = 32
NonceSize is the expected byte length of a nonce.
Variables ¶
This section is empty.
Functions ¶
func PreferredProtocols ¶ added in v0.7.0
PreferredProtocols returns the ordered list of protocol IDs for initiator stream negotiation. When kemEnabled is true, v1.2 is tried first. Returns []string since libp2p protocol.ID is a string alias.
func VerifySecp256k1Signature ¶ added in v0.7.0
VerifySecp256k1Signature is the default verifier using secp256k1+keccak256. It hashes the message with Keccak256, recovers the public key from the 65-byte ECDSA signature (R+S+V), and compares with the claimed compressed key.
Types ¶
type ApprovalFunc ¶
type ApprovalFunc func(ctx context.Context, pending *PendingHandshake) (bool, error)
ApprovalFunc is called to request user approval for an incoming handshake. Uses the callback pattern to avoid import cycles with the approval package.
type BundleAttacher ¶ added in v0.7.0
type BundleAttacher interface {
Bundle() *identity.IdentityBundle
}
BundleAttacher is an optional interface that Signers can implement to provide their IdentityBundle for inclusion in handshake messages.
type Challenge ¶
type Challenge struct {
Nonce []byte `json:"nonce"`
Timestamp int64 `json:"timestamp"`
SenderDID string `json:"senderDid"`
PublicKey []byte `json:"publicKey,omitempty"` // v1.1: initiator's public key
Signature []byte `json:"signature,omitempty"` // v1.1: signature over canonical payload
SignatureAlgorithm string `json:"signatureAlgorithm,omitempty"` // algorithm (empty = secp256k1-keccak256)
Bundle *identity.IdentityBundle `json:"bundle,omitempty"` // v2: initiator's identity bundle
KEMPublicKey []byte `json:"kemPublicKey,omitempty"` // v1.2: ephemeral hybrid KEM public key
KEMAlgorithm string `json:"kemAlgorithm,omitempty"` // v1.2: "X25519-MLKEM768"
}
Challenge is sent by the initiator to start the handshake.
type ChallengeResponse ¶
type ChallengeResponse struct {
Nonce []byte `json:"nonce"`
Signature []byte `json:"signature,omitempty"`
ZKProof []byte `json:"zkProof,omitempty"`
DID string `json:"did"`
PublicKey []byte `json:"publicKey"`
SignatureAlgorithm string `json:"signatureAlgorithm,omitempty"` // algorithm (empty = secp256k1-keccak256)
Bundle *identity.IdentityBundle `json:"bundle,omitempty"` // v2: responder's identity bundle
KEMCiphertext []byte `json:"kemCiphertext,omitempty"` // v1.2: KEM ciphertext
}
ChallengeResponse is the target's reply with proof of identity.
type Config ¶
type Config struct {
Signer Signer
LegacySigner Signer // v1 secp256k1 fallback (optional)
Sessions *SessionStore
ApprovalFn ApprovalFunc
ZKProver ZKProverFunc
ZKVerifier ZKVerifierFunc
ZKEnabled bool
Timeout time.Duration
AutoApproveKnown bool
NonceCache *NonceCache
RequireSignedChallenge bool
Verifiers map[string]SignatureVerifyFunc // nil → default with secp256k1 + ed25519
BundleCache identity.BundleResolver // optional: for caching received bundles
DIDAlias *identity.DIDAlias // optional: v1/v2 DID alias for session continuity
EnablePQKEM bool // enable PQ KEM key exchange (default false)
Logger *zap.SugaredLogger
}
Config configures the Handshaker.
type Handshaker ¶
type Handshaker struct {
// contains filtered or unexported fields
}
Handshaker manages peer authentication using wallet signatures or ZK proofs.
func NewHandshaker ¶
func NewHandshaker(cfg Config) *Handshaker
NewHandshaker creates a new peer authenticator.
func (*Handshaker) HandleIncoming ¶
HandleIncoming processes an incoming handshake request.
func (*Handshaker) Initiate ¶
func (h *Handshaker) Initiate(ctx context.Context, s network.Stream, localDID string) (*Session, error)
Initiate starts a handshake with a remote peer over the given stream.
func (*Handshaker) StreamHandler ¶
func (h *Handshaker) StreamHandler() network.StreamHandler
StreamHandler returns a libp2p stream handler for incoming handshakes.
func (*Handshaker) StreamHandlerV11 ¶
func (h *Handshaker) StreamHandlerV11() network.StreamHandler
StreamHandlerV11 returns a libp2p stream handler for v1.1 (signed challenge) handshakes. Uses the same HandleIncoming logic since it handles both signed and unsigned challenges.
func (*Handshaker) StreamHandlerV12 ¶ added in v0.7.0
func (h *Handshaker) StreamHandlerV12() network.StreamHandler
StreamHandlerV12 returns a libp2p stream handler for v1.2 (PQ KEM) handshakes.
type InvalidationReason ¶
type InvalidationReason string
InvalidationReason describes why a session was invalidated.
const ( ReasonLogout InvalidationReason = "logout" ReasonReputationDrop InvalidationReason = "reputation_drop" ReasonRepeatedFailures InvalidationReason = "repeated_failures" ReasonManualRevoke InvalidationReason = "manual_revoke" ReasonSecurityEvent InvalidationReason = "security_event" )
type InvalidationRecord ¶
type InvalidationRecord struct {
PeerDID string `json:"peerDid"`
Reason InvalidationReason `json:"reason"`
InvalidatedAt time.Time `json:"invalidatedAt"`
}
InvalidationRecord stores details about a session invalidation.
type NonceCache ¶
type NonceCache struct {
// contains filtered or unexported fields
}
NonceCache prevents nonce replay attacks by tracking recently seen nonces.
func NewNonceCache ¶
func NewNonceCache(ttl time.Duration) *NonceCache
NewNonceCache creates a new NonceCache with the given TTL.
func (*NonceCache) CheckAndRecord ¶
func (nc *NonceCache) CheckAndRecord(nonce []byte) bool
CheckAndRecord returns true if the nonce has NOT been seen before (first occurrence). Returns false if the nonce was already recorded (replay detected). The nonce parameter must be exactly 32 bytes.
func (*NonceCache) Cleanup ¶
func (nc *NonceCache) Cleanup()
Cleanup removes expired entries older than TTL.
func (*NonceCache) Start ¶
func (nc *NonceCache) Start()
Start begins periodic cleanup using a ticker goroutine.
type PendingHandshake ¶
type PendingHandshake struct {
PeerID peer.ID `json:"peerId"`
PeerDID string `json:"peerDid"`
RemoteAddr string `json:"remoteAddr"`
Timestamp time.Time `json:"timestamp"`
}
PendingHandshake describes a handshake awaiting user approval.
type SecurityEventHandler ¶
type SecurityEventHandler struct {
// contains filtered or unexported fields
}
SecurityEventHandler tracks tool execution failures and reputation changes to auto-invalidate sessions when thresholds are exceeded.
func NewSecurityEventHandler ¶
func NewSecurityEventHandler( sessions *SessionStore, maxFailures int, minTrustScore float64, logger *zap.SugaredLogger, ) *SecurityEventHandler
NewSecurityEventHandler creates a handler that auto-invalidates sessions after consecutive tool failures or reputation drops below the threshold.
func (*SecurityEventHandler) OnReputationChange ¶
func (h *SecurityEventHandler) OnReputationChange(peerDID string, newScore float64)
OnReputationChange invalidates the peer's session if the new score drops below the minimum trust threshold.
func (*SecurityEventHandler) RecordToolFailure ¶
func (h *SecurityEventHandler) RecordToolFailure(peerDID string)
RecordToolFailure increments the consecutive failure counter for the peer. When the counter reaches maxFailures, the session is auto-invalidated.
func (*SecurityEventHandler) RecordToolSuccess ¶
func (h *SecurityEventHandler) RecordToolSuccess(peerDID string)
RecordToolSuccess resets the consecutive failure counter for the peer.
type Session ¶
type Session struct {
PeerDID string `json:"peerDid"`
Token string `json:"token"`
CreatedAt time.Time `json:"createdAt"`
ExpiresAt time.Time `json:"expiresAt"`
ZKVerified bool `json:"zkVerified"`
Invalidated bool `json:"invalidated"`
InvalidatedReason InvalidationReason `json:"invalidatedReason,omitempty"`
EncryptionKey []byte `json:"-"` // derived from KEM, never serialized
KEMUsed bool `json:"kemUsed"` // true if PQ KEM key exchange succeeded
}
Session represents an authenticated peer session.
type SessionAck ¶
SessionAck is sent by the initiator after verifying the response.
type SessionStore ¶
type SessionStore struct {
// contains filtered or unexported fields
}
SessionStore manages authenticated peer sessions with TTL eviction.
func NewSessionStore ¶
func NewSessionStore(ttl time.Duration) (*SessionStore, error)
NewSessionStore creates a session store with the given TTL.
func (*SessionStore) ActiveSessions ¶
func (s *SessionStore) ActiveSessions() []*Session
ActiveSessions returns all non-expired, non-invalidated sessions.
func (*SessionStore) Cleanup ¶
func (s *SessionStore) Cleanup() int
Cleanup removes all expired and invalidated sessions.
func (*SessionStore) Create ¶
func (s *SessionStore) Create(peerDID string, zkVerified bool) (*Session, error)
Create creates a new session for the given peer DID.
func (*SessionStore) Get ¶
func (s *SessionStore) Get(peerDID string) *Session
Get returns the session for the given peer DID, or nil if not found/expired/invalidated.
func (*SessionStore) GetByToken ¶ added in v0.6.0
func (s *SessionStore) GetByToken(token string) (string, bool)
GetByToken looks up an active session by its token and returns the peer DID.
func (*SessionStore) Invalidate ¶
func (s *SessionStore) Invalidate(peerDID string, reason InvalidationReason)
Invalidate marks a session as invalidated, removes it from active sessions, records the invalidation, and fires the onInvalidate callback.
func (*SessionStore) InvalidateAll ¶
func (s *SessionStore) InvalidateAll(reason InvalidationReason)
InvalidateAll invalidates all active sessions with the given reason.
func (*SessionStore) InvalidateByCondition ¶
func (s *SessionStore) InvalidateByCondition(reason InvalidationReason, predicate func(*Session) bool)
InvalidateByCondition invalidates sessions matching the predicate.
func (*SessionStore) InvalidationHistory ¶
func (s *SessionStore) InvalidationHistory() []InvalidationRecord
InvalidationHistory returns all recorded invalidation events.
func (*SessionStore) Remove ¶
func (s *SessionStore) Remove(peerDID string)
Remove deletes a session, zeroing any encryption key first.
func (*SessionStore) SetInvalidationCallback ¶
func (s *SessionStore) SetInvalidationCallback(fn func(peerDID string, reason InvalidationReason))
SetInvalidationCallback sets a function to be called when a session is invalidated.
func (*SessionStore) Validate ¶
func (s *SessionStore) Validate(peerDID, token string) bool
Validate checks if a session token is valid for the given peer DID.
type SignatureVerifyFunc ¶ added in v0.7.0
SignatureVerifyFunc verifies a signature against a claimed public key. Used for both challenge and response signature verification. pubkey is the claimed public key, message is the raw message (verifier handles algorithm-specific hashing internally), and signature is the raw signature bytes.
type Signer ¶ added in v0.7.0
type Signer interface {
SignMessage(ctx context.Context, message []byte) ([]byte, error)
PublicKey(ctx context.Context) ([]byte, error)
Algorithm() string
DID(ctx context.Context) (string, error)
}
Signer is the minimal interface for identity signing operations. Implementations must declare their algorithm and DID via Algorithm() and DID().
type ZKProverFunc ¶
ZKProverFunc generates a ZK ownership proof for the given challenge.