Documentation
¶
Index ¶
- Constants
- Variables
- func DeriveSessionSalt(pubA, pubB []byte) []byte
- func MarshalClaim(claim *ReputationClaim) ([]byte, error)
- func TrustLevelString(level TrustLevel) string
- func ValidTrustTransition(from, to TrustLevel) bool
- type BehaviorType
- type MessageValidator
- type ReputationClaim
- type ReputationEntry
- type ReputationGossip
- type ReputationStore
- func (rs *ReputationStore) ApplyGossipScore(peerID string, gossipScore float64, weight float64)
- func (rs *ReputationStore) GetEntry(pubKey string) *ReputationEntry
- func (rs *ReputationStore) GetScore(pubKey string) float64
- func (rs *ReputationStore) IsMalicious(pubKey string) bool
- func (rs *ReputationStore) ListEntries() []ReputationEntry
- func (rs *ReputationStore) LoadFromFile(path string) error
- func (rs *ReputationStore) RecordEvent(pubKey string, behavior BehaviorType)
- func (rs *ReputationStore) SaveToFile(path string) error
- type SessionKey
- func (sk *SessionKey) Decrypt(data []byte) ([]byte, error)
- func (sk *SessionKey) DecryptWithAAD(data, aad []byte) ([]byte, error)
- func (sk *SessionKey) Encrypt(plaintext []byte) ([]byte, error)
- func (sk *SessionKey) EncryptWithAAD(plaintext, aad []byte) ([]byte, error)
- func (sk *SessionKey) PeerID() string
- type TrustChangeCallback
- type TrustEntry
- type TrustLevel
- type TrustStore
- func (ts *TrustStore) Check(pubKey string) TrustLevel
- func (ts *TrustStore) CleanExpired()
- func (ts *TrustStore) Export() ([]byte, error)
- func (ts *TrustStore) Import(data []byte) error
- func (ts *TrustStore) IsAllowed(pubKey string) bool
- func (ts *TrustStore) IsAllowedWithReputation(pubKey string) bool
- func (ts *TrustStore) ListEntries() []TrustEntry
- func (ts *TrustStore) LoadFromFile(path string) error
- func (ts *TrustStore) OnTrustChange(cb TrustChangeCallback)
- func (ts *TrustStore) RemoveEntry(pubKey string) bool
- func (ts *TrustStore) SaveToFile(path string) error
- func (ts *TrustStore) SetAlias(pubKey, alias string)
- func (ts *TrustStore) SetReputationStore(rs *ReputationStore)
- func (ts *TrustStore) SetTrust(pubKey string, level TrustLevel) error
- func (ts *TrustStore) TouchLastSeen(pubKey string)
- func (ts *TrustStore) TrustOnFirstUse(pubKey, firstSeen string) TrustLevel
Constants ¶
const ( // MaxMessageSize is the hard limit for message payload size (1 MB). MaxMessageSize = 1 << 20 // NonceWindowDuration is how long nonces are remembered for replay protection. NonceWindowDuration = 5 * time.Minute // TimestampSkew is the maximum allowed clock difference. TimestampSkew = 2 * time.Minute )
const DefaultSecondHandWeight = 0.3
DefaultSecondHandWeight is the default weight applied to reputation claims from other peers.
const DefaultTOFUExpiry = 30 * 24 * time.Hour // 30 days
DefaultTOFUExpiry is the default duration after which a TOFU trust entry expires.
const HKDFSaltSize = 32
HKDFSaltSize is the size of the random salt used for HKDF key derivation.
const MinTrustForGossip = TrustVerified
MinTrustForGossip is the minimum trust level required to accept gossip from a peer.
const NostrReputationKind = 30078
NostrReputationKind is the Nostr event kind for reputation claims (NIP-78 application-specific data).
Variables ¶
var ErrInvalidTrustTransition = fmt.Errorf("invalid trust level transition")
ErrInvalidTrustTransition is returned when a trust level transition is not allowed.
Functions ¶
func DeriveSessionSalt ¶ added in v0.2.0
DeriveSessionSalt produces a deterministic 32-byte salt from two public keys. Keys are sorted so both sides compute the same salt regardless of call order.
func MarshalClaim ¶
func MarshalClaim(claim *ReputationClaim) ([]byte, error)
MarshalClaim serializes a claim to JSON for Nostr event content.
func TrustLevelString ¶
func TrustLevelString(level TrustLevel) string
TrustLevelString returns a human-readable name for a TrustLevel.
func ValidTrustTransition ¶ added in v0.2.0
func ValidTrustTransition(from, to TrustLevel) bool
ValidTrustTransition checks whether transitioning from one trust level to another is allowed by the trust state machine. Allowed transitions:
- Unknown -> TOFU, Verified, Pinned, Blocked
- TOFU -> Verified, Blocked
- Verified -> Pinned, Blocked
- Pinned -> Blocked
- Blocked -> Unknown (explicit unblock only)
All other transitions are rejected (e.g., Blocked->Verified, Blocked->Pinned, Pinned->TOFU, Verified->TOFU, etc.).
Types ¶
type BehaviorType ¶
type BehaviorType string
BehaviorType represents the type of observed behavior from a peer.
const ( BehaviorSuccess BehaviorType = "success" BehaviorTimeout BehaviorType = "timeout" BehaviorError BehaviorType = "error" BehaviorInvalidSignature BehaviorType = "invalid_signature" BehaviorSpam BehaviorType = "spam" BehaviorProtocolViolation BehaviorType = "protocol_violation" )
type MessageValidator ¶
type MessageValidator struct {
// contains filtered or unexported fields
}
MessageValidator provides message-level security: signature verification, replay protection via nonces, and size limits.
func NewMessageValidator ¶
func NewMessageValidator() *MessageValidator
NewMessageValidator creates a new message validator.
func (*MessageValidator) CleanExpiredNonces ¶
func (v *MessageValidator) CleanExpiredNonces()
CleanExpiredNonces removes nonces older than the window duration.
func (*MessageValidator) ValidateMessage ¶
func (v *MessageValidator) ValidateMessage(env *envelope.Envelope, pubKeyStr string) error
ValidateMessage validates the integrity and freshness of an envelope.
type ReputationClaim ¶
type ReputationClaim struct {
ClaimID string `json:"claim_id"` // unique claim identifier for replay protection
Issuer string `json:"issuer"` // pubkey of the issuer
Subject string `json:"subject"` // pubkey of the rated peer
Score float64 `json:"score"` // 0.0 - 1.0
Reason string `json:"reason"` // brief description
Timestamp time.Time `json:"timestamp"`
}
ReputationClaim represents a reputation assertion published via Nostr.
func UnmarshalClaim ¶
func UnmarshalClaim(data []byte) (*ReputationClaim, error)
UnmarshalClaim deserializes a claim from JSON.
type ReputationEntry ¶
type ReputationEntry struct {
PubKey string `json:"pub_key"`
Score float64 `json:"score"`
EventCount int64 `json:"event_count"`
LastUpdated time.Time `json:"last_updated"`
}
ReputationEntry tracks the reputation of a single peer.
type ReputationGossip ¶
type ReputationGossip struct {
SecondHandWeight float64 // Configurable weight for second-hand reputation claims
// contains filtered or unexported fields
}
ReputationGossip manages publishing and consuming reputation claims via Nostr.
func NewReputationGossip ¶
func NewReputationGossip(store *ReputationStore, trustStore *TrustStore, selfPubKey string) *ReputationGossip
NewReputationGossip creates a new gossip manager with the default second-hand weight.
func (*ReputationGossip) CleanSeenClaims ¶ added in v0.2.0
func (rg *ReputationGossip) CleanSeenClaims()
CleanSeenClaims removes stale entries from seenClaims to prevent unbounded growth. Should be called periodically.
func (*ReputationGossip) CreateClaim ¶
func (rg *ReputationGossip) CreateClaim(subjectPubKey string) *ReputationClaim
CreateClaim creates a reputation claim for publishing.
func (*ReputationGossip) ProcessClaim ¶
func (rg *ReputationGossip) ProcessClaim(claim *ReputationClaim) bool
ProcessClaim processes an incoming reputation claim from another peer. It only accepts claims from peers with TrustVerified or higher, and applies the configurable SecondHandWeight to the score. Returns false if the claim is rejected (untrusted issuer, self-issued, duplicate, stale, or rate-limited).
type ReputationStore ¶
type ReputationStore struct {
// contains filtered or unexported fields
}
ReputationStore tracks per-peer reputation scores using EWMA.
func NewReputationStore ¶
func NewReputationStore() *ReputationStore
NewReputationStore creates a new reputation store with default settings.
func (*ReputationStore) ApplyGossipScore ¶ added in v0.2.0
func (rs *ReputationStore) ApplyGossipScore(peerID string, gossipScore float64, weight float64)
ApplyGossipScore blends a gossip-reported score with the existing score using a weighted EWMA formula. This is the safe way to incorporate external reputation data without allowing direct score overrides.
func (*ReputationStore) GetEntry ¶
func (rs *ReputationStore) GetEntry(pubKey string) *ReputationEntry
GetEntry returns the full reputation entry for a peer, or nil if not found.
func (*ReputationStore) GetScore ¶
func (rs *ReputationStore) GetScore(pubKey string) float64
GetScore returns the reputation score for a peer. Returns 0.5 (neutral) if unknown.
func (*ReputationStore) IsMalicious ¶
func (rs *ReputationStore) IsMalicious(pubKey string) bool
IsMalicious returns true if the peer's reputation is below the malicious threshold.
func (*ReputationStore) ListEntries ¶
func (rs *ReputationStore) ListEntries() []ReputationEntry
ListEntries returns all reputation entries.
func (*ReputationStore) LoadFromFile ¶
func (rs *ReputationStore) LoadFromFile(path string) error
LoadFromFile loads the reputation store from a JSON file.
func (*ReputationStore) RecordEvent ¶
func (rs *ReputationStore) RecordEvent(pubKey string, behavior BehaviorType)
RecordEvent records a behavior event for a peer and updates the EWMA score.
func (*ReputationStore) SaveToFile ¶
func (rs *ReputationStore) SaveToFile(path string) error
SaveToFile persists the reputation store to a JSON file.
type SessionKey ¶
type SessionKey struct {
// contains filtered or unexported fields
}
SessionKey holds the derived symmetric key for encrypting messages between two peers.
func DeriveSessionKey ¶
func DeriveSessionKey(privateKey *ecdh.PrivateKey, peerPublicKey *ecdh.PublicKey, peerID string, salt ...[]byte) (*SessionKey, []byte, error)
DeriveSessionKey computes a shared secret via X25519 ECDH and derives a 32-byte symmetric key using HKDF-SHA256. An optional salt can be provided; if nil, a random 32-byte salt is generated. The salt is returned alongside the session key so it can be exchanged with the peer.
func NewSessionKeyFromBytes ¶
func NewSessionKeyFromBytes(key []byte, peerID string) (*SessionKey, error)
NewSessionKeyFromBytes creates a SessionKey from raw key bytes. Used primarily for testing.
func (*SessionKey) Decrypt ¶
func (sk *SessionKey) Decrypt(data []byte) ([]byte, error)
Decrypt decrypts data produced by Encrypt. Expects input format: nonce (24 bytes) || ciphertext || tag (16 bytes).
func (*SessionKey) DecryptWithAAD ¶ added in v0.2.0
func (sk *SessionKey) DecryptWithAAD(data, aad []byte) ([]byte, error)
DecryptWithAAD decrypts data with additional associated data verification. The AAD must match what was provided during encryption.
func (*SessionKey) Encrypt ¶
func (sk *SessionKey) Encrypt(plaintext []byte) ([]byte, error)
Encrypt encrypts plaintext using XChaCha20-Poly1305 with a random nonce. The nonce is prepended to the ciphertext. Returns: nonce (24 bytes) || ciphertext || tag (16 bytes).
func (*SessionKey) EncryptWithAAD ¶ added in v0.2.0
func (sk *SessionKey) EncryptWithAAD(plaintext, aad []byte) ([]byte, error)
EncryptWithAAD encrypts plaintext with additional associated data (AAD). AAD is authenticated but not encrypted — it binds the ciphertext to context (e.g., envelope Source + Destination + Nonce) preventing ciphertext swapping.
func (*SessionKey) PeerID ¶
func (sk *SessionKey) PeerID() string
PeerID returns the remote peer identifier associated with this session key.
type TrustChangeCallback ¶
type TrustChangeCallback func(pubKey string, oldLevel, newLevel TrustLevel)
TrustChangeCallback is called when a trust entry changes.
type TrustEntry ¶
type TrustEntry struct {
PublicKey string `json:"public_key"`
Level TrustLevel `json:"level"`
FirstSeen string `json:"first_seen"`
LastSeen string `json:"last_seen,omitempty"`
Alias string `json:"alias,omitempty"`
ExpiresAt time.Time `json:"expires_at,omitempty"`
WasBlocked bool `json:"was_blocked,omitempty"` // L-05: tracks if peer was previously blocked
}
TrustEntry records trust information about a peer.
type TrustLevel ¶
type TrustLevel int
TrustLevel represents how much an agent is trusted.
const ( TrustUnknown TrustLevel = 0 TrustTOFU TrustLevel = 1 // Trust On First Use TrustVerified TrustLevel = 2 // Explicitly verified TrustBlocked TrustLevel = 3 // Explicitly blocked TrustPinned TrustLevel = 4 // Permanently pinned (highest trust) )
type TrustStore ¶
type TrustStore struct {
// contains filtered or unexported fields
}
TrustStore manages TOFU trust relationships with peers.
func NewTrustStore ¶
func NewTrustStore() *TrustStore
NewTrustStore creates a new empty trust store.
func (*TrustStore) Check ¶
func (ts *TrustStore) Check(pubKey string) TrustLevel
Check returns the trust level for a public key. If the entry is a TOFU entry that has expired, TrustUnknown is returned.
func (*TrustStore) CleanExpired ¶
func (ts *TrustStore) CleanExpired()
CleanExpired removes expired TOFU entries from the store. Only TOFU entries are subject to expiration; entries at TrustVerified or higher (including TrustBlocked and TrustPinned) are never removed.
func (*TrustStore) Export ¶
func (ts *TrustStore) Export() ([]byte, error)
Export serializes all entries to JSON bytes.
func (*TrustStore) Import ¶
func (ts *TrustStore) Import(data []byte) error
Import merges entries from JSON bytes into the store. Existing entries are NOT overwritten — only new keys are imported. Trust levels are validated; invalid values are rejected.
func (*TrustStore) IsAllowed ¶
func (ts *TrustStore) IsAllowed(pubKey string) bool
IsAllowed returns true if the peer is trusted (TOFU, Verified, or Pinned).
func (*TrustStore) IsAllowedWithReputation ¶
func (ts *TrustStore) IsAllowedWithReputation(pubKey string) bool
IsAllowedWithReputation returns true if the peer passes both trust and reputation checks. If no ReputationStore is set, it falls back to IsAllowed.
func (*TrustStore) ListEntries ¶
func (ts *TrustStore) ListEntries() []TrustEntry
ListEntries returns all trust entries sorted by public key.
func (*TrustStore) LoadFromFile ¶
func (ts *TrustStore) LoadFromFile(path string) error
LoadFromFile loads the trust store from a JSON file.
func (*TrustStore) OnTrustChange ¶
func (ts *TrustStore) OnTrustChange(cb TrustChangeCallback)
OnTrustChange registers a callback invoked when trust levels change.
func (*TrustStore) RemoveEntry ¶
func (ts *TrustStore) RemoveEntry(pubKey string) bool
RemoveEntry removes a trust entry entirely.
func (*TrustStore) SaveToFile ¶
func (ts *TrustStore) SaveToFile(path string) error
SaveToFile persists the trust store to a JSON file using atomic write (write to temp file, then rename) to prevent corruption on crash.
func (*TrustStore) SetAlias ¶
func (ts *TrustStore) SetAlias(pubKey, alias string)
SetAlias sets a human-readable alias for a peer.
func (*TrustStore) SetReputationStore ¶
func (ts *TrustStore) SetReputationStore(rs *ReputationStore)
SetReputationStore associates a ReputationStore with this TrustStore.
func (*TrustStore) SetTrust ¶
func (ts *TrustStore) SetTrust(pubKey string, level TrustLevel) error
SetTrust explicitly sets the trust level for a public key. Returns an error if the transition is not allowed by the trust state machine.
func (*TrustStore) TouchLastSeen ¶
func (ts *TrustStore) TouchLastSeen(pubKey string)
TouchLastSeen updates the LastSeen timestamp for a peer.
func (*TrustStore) TrustOnFirstUse ¶
func (ts *TrustStore) TrustOnFirstUse(pubKey, firstSeen string) TrustLevel
TrustOnFirstUse records a new peer with TOFU trust if not already known. The TOFU entry expires after DefaultTOFUExpiry (30 days). L-05: If the peer was previously blocked (WasBlocked is true), auto-TOFU is denied — the caller must use explicit verification (SetTrust) instead. Returns the trust level (existing or newly created).