go_i2cp

package module
v0.1.59999 Latest Latest
Warning

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

Go to latest
Published: Jun 8, 2026 License: MIT Imports: 37 Imported by: 10

README

go-i2cp

A low-level Go implementation of the I2P Client Protocol (I2CP) for building anonymous services and applications.

Features

  • 87% I2CP Protocol Compliance (22/24 message types)
  • Session management, messaging, and destination lookup
  • TLS authentication with mutual TLS support
  • Modern cryptography: Ed25519, X25519, ChaCha20-Poly1305
  • LeaseSet2 and encrypted LeaseSet support
  • Automatic reconnection with circuit breaker
  • Context-aware operations (cancellation, timeouts)
  • Comprehensive error handling

Requirements

  • Go 1.25+
  • Running I2P router with I2CP enabled (default port 7654)

Installation

go get github.com/go-i2p/go-i2cp

Quick Start

client := go_i2cp.NewClient(nil)
ctx := context.Background()

if err := client.Connect(ctx); err != nil {
    log.Fatal(err)
}
defer client.Close()

session := go_i2cp.NewSession(client, go_i2cp.SessionCallbacks{})
if err := client.CreateSession(ctx, session); err != nil {
    log.Fatal(err)
}

See examples/ for complete working examples.

Authentication

Username/Password
client.SetProperty(go_i2cp.CLIENT_PROP_USERNAME, "myuser")
client.SetProperty(go_i2cp.CLIENT_PROP_PASSWORD, "mypassword")
client.SetProperty(go_i2cp.CLIENT_PROP_TLS_ENABLED, "true")
client.SetProperty(go_i2cp.CLIENT_PROP_TLS_CERT_FILE, "/path/to/client-cert.pem")
client.SetProperty(go_i2cp.CLIENT_PROP_TLS_KEY_FILE, "/path/to/client-key.pem")
client.SetProperty(go_i2cp.CLIENT_PROP_TLS_CA_FILE, "/path/to/ca-cert.pem")

Session Callbacks

session := go_i2cp.NewSession(client, go_i2cp.SessionCallbacks{
    OnBlindingInfo: func(sess *go_i2cp.Session, scheme, flags uint16, params []byte) {
        // Handle blinding for encrypted LeaseSets
    },
    OnLeaseSet2: func(sess *go_i2cp.Session, leaseSet *go_i2cp.LeaseSet2) {
        // Called when YOUR session's LeaseSet2 is published to the network.
        // NOTE: This is NOT triggered when receiving a remote destination's LeaseSet.
        // Use DestLookup callbacks (OnDestination) for remote LeaseSet retrieval.
    },
    OnMessageStatusUpdate: func(sess *go_i2cp.Session, messageId, status uint32) {
        // Track message delivery status
    },
})

Message Sending

Basic Message
payload := go_i2cp.NewStream()
payload.WriteString("Hello I2P")

err := session.SendMessage(dest, protocol, srcPort, destPort, payload)
Message with Expiration and Flags
// Build flags (modern I2P uses ECIES-Ratchet, tag flags are obsolete)
flags := go_i2cp.BuildSendMessageFlags(0, 0) // Use defaults

// Optionally prevent LeaseSet bundling
flags |= go_i2cp.SEND_MSG_FLAG_NO_LEASESET

// Send with 60 second expiration
err := session.SendMessageExpires(dest, protocol, srcPort, destPort, payload, flags, 60)

Available Flags:

  • SEND_MSG_FLAG_NO_LEASESET - Don't bundle LeaseSet with message (bit 8)
  • Tag threshold/count flags (bits 7-0) - Obsolete for modern ECIES-Ratchet encryption

Helper Functions:

  • BuildSendMessageFlags(threshold, count) - Construct flags (tag params ignored with ECIES-Ratchet)
  • ParseSendMessageFlags(flags) - Extract flag components
  • ValidateSendMessageFlags(flags) - Validate flags per I2CP spec

Error Recovery

// Enable auto-reconnect
client.EnableAutoReconnect(5, time.Second)

// Circuit breaker
cb := go_i2cp.NewCircuitBreaker(5, 30*time.Second)
err := cb.Execute(func() error {
    return client.Connect(ctx)
})

// Retry with backoff
err = go_i2cp.RetryWithBackoff(ctx, 3, time.Second, func() error {
    return client.CreateSession(ctx, session)
})

Bandwidth Management

Monitor and control bandwidth usage with callback-based rate limiting:

import "golang.org/x/time/rate"

// Create client with bandwidth callback
client := go_i2cp.NewClient(&go_i2cp.ClientCallbacks{
    OnBandwidthLimits: func(c *go_i2cp.Client, limits *go_i2cp.BandwidthLimits) {
        log.Printf("Bandwidth limits: %s", limits.String())
        
        // Configure rate limiter using router burst limits
        // RouterInboundBurst and RouterOutboundBurst are in KBps
        inboundRate := float64(limits.RouterInboundBurst * 1024)
        outboundRate := float64(limits.RouterOutboundBurst * 1024)
        
        inboundLimiter := rate.NewLimiter(rate.Limit(inboundRate), int(inboundRate))
        outboundLimiter := rate.NewLimiter(rate.Limit(outboundRate), int(outboundRate))
        
        // Use limiters before sending/receiving data
    },
})

See examples/bandwidth-limits/ for complete rate limiting implementation.

Session Configuration

Configure session properties for privacy tuning:

// Security settings
config := session.Destination().config
config.SetProperty(go_i2cp.SESSION_CONFIG_PROP_INBOUND_LENGTH, "3")          // Tunnel length (hops)
config.SetProperty(go_i2cp.SESSION_CONFIG_PROP_OUTBOUND_LENGTH, "3")         
config.SetProperty(go_i2cp.SESSION_CONFIG_PROP_INBOUND_QUANTITY, "4")        // Number of tunnels
config.SetProperty(go_i2cp.SESSION_CONFIG_PROP_OUTBOUND_QUANTITY, "4")
config.SetProperty(go_i2cp.SESSION_CONFIG_PROP_INBOUND_BACKUP_QUANTITY, "2") // Backup tunnels
config.SetProperty(go_i2cp.SESSION_CONFIG_PROP_OUTBOUND_BACKUP_QUANTITY, "2")

Privacy vs Performance Tuning:

Setting High Privacy Balanced Low Latency
Tunnel Length 3 hops 3 hops 1-2 hops
Tunnel Quantity 6-8 4 2-3
Backup Quantity 3-4 2 1

Note: Shorter tunnels and fewer backups improve performance but reduce anonymity.

Error Handling

if err := client.Connect(); err != nil {
    if errors.Is(err, go_i2cp.ErrConnectionClosed) {
        // Handle connection closed
    }
}

// Check if retryable
if go_i2cp.IsTemporary(err) {
    // Retry operation
}

Protocol Compliance & Implementation Status

I2CP Protocol Coverage: 87% (22/24 Message Types)

✅ Fully Implemented:

  • ✅ Session Management (CreateSession, DestroySession, SessionStatus, ReconfigureSession)
  • ✅ Messaging (SendMessage, SendMessageExpires, MessagePayload, MessageStatus)
  • ✅ Destination Services (DestLookup, DestReply, GetBandwidthLimits)
  • ✅ Authentication (TLS certificates, username/password, none)
  • ✅ Modern Features:
    • LeaseSet2 support (standard, encrypted types; meta type is experimental/preliminary spec)
    • Blinding support (message parsing; crypto operations require application implementation)
    • Offline signing support
    • Message batching for improved throughput
    • Buffer pooling for reduced allocations
    • Automatic reconnection with circuit breaker
    • Message tracking and delivery confirmation
    • Bandwidth management callbacks
  • ✅ Cryptography:
    • Ed25519 signatures (I2CP 0.9.15+)
    • X25519 key exchange (I2CP 0.9.46+)
    • ChaCha20-Poly1305 encryption (I2CP 0.9.46+)
  • ✅ Context-Aware Operations (cancellation, timeouts, graceful shutdown)
  • ✅ Comprehensive Error Handling (20+ typed errors, 96.2% error-handling path coverage)

📊 Test Coverage:

  • 1290+ passing tests covering all major features
  • 75% code coverage across core library
  • Integration tests with real I2P router
  • 70+ benchmarks for performance validation
  • Error-handling path coverage >96% (measured across error return branches specifically)

🔄 Future Enhancements (Phase 4):

  • DH/PSK authentication (methods 3-4) - Implemented, pending integration testing
  • Observability (Prometheus metrics export, OpenTelemetry tracing)
  • MetaLeaseSet support (preliminary spec)

❌ Excluded by Design:

  • ReportAbuse message (never implemented in I2CP spec)
  • ElGamal encryption (deprecated, security concerns)
  • DSA signatures (legacy, removed in favor of Ed25519)
Version Compatibility
  • I2CP Protocol Versions: 0.6.5 - 0.9.66
  • Recommended I2P Router: 2.0.0+
  • Go Version: 1.25+

Testing

go test -v ./...
go test -race ./...
go test -bench=. -benchmem

Contributing

See CONTRIBUTING.md.

License

MIT License - See LICENSE file

Documentation

Overview

Blinding Crypto Implementation for I2CP

This file implements blinding key derivation and cryptographic operations for accessing encrypted LeaseSets via I2CP BlindingInfoMessage.

The implementation delegates to github.com/go-i2p/crypto/kdf and ed25519 packages which provide I2P-compliant blinding operations per Proposal 123.

Blinding workflow:

  1. Service publishes encrypted LeaseSet with blinded destination
  2. Client derives blinding factor from secret + date
  3. Client blinds destination's public key with the factor
  4. Router uses blinded key to locate encrypted LeaseSet
  5. Client decrypts LeaseSet using derived keys

Since: I2CP 0.9.43+ Reference: I2P Proposal 123 - Encrypted LeaseSet

DH/PSK Authentication Implementation for I2CP Encrypted LeaseSets

This file implements Diffie-Hellman and Pre-Shared Key authentication for accessing encrypted LeaseSets via I2CP BlindingInfoMessage.

Per I2P Proposal 123 and 149, encrypted LeaseSets can require client authentication using either:

  • DH (BLINDING_AUTH_SCHEME_DH = 0): X25519 Diffie-Hellman key exchange
  • PSK (BLINDING_AUTH_SCHEME_PSK = 1): Pre-shared symmetric key

The authentication produces a 32-byte decryption key that is sent in the BlindingInfoMessage to enable the router to decrypt the LeaseSet.

Workflow for DH:

  1. Client has X25519 private key (client identity)
  2. Client knows server's X25519 public key (from blinded b32 address)
  3. Client performs DH: sharedSecret = X25519(clientPrivKey, serverPubKey)
  4. Client derives decryptionKey = HKDF(sharedSecret, salt, info)
  5. Client sends decryptionKey in BlindingInfoMessage

Workflow for PSK:

  1. Client and server share a 32-byte pre-shared key
  2. Client derives decryptionKey = HKDF(psk, salt, info)
  3. Client sends decryptionKey in BlindingInfoMessage

Since: I2CP 0.9.43+ Reference: I2P Proposal 123 - Encrypted LeaseSet, Proposal 149 - Per-Client Auth

meta_leaseset.go - MetaLeaseSet creation and management for I2CP per I2CP specification 0.9.38+ - MetaLeaseSet (type 7)

SessionCallbacks struct definition Moved from: session.go

Session struct definition Moved from: session.go

SignatureKeyPair struct definition Moved from: crypto.go

Index

Constants

View Source
const (
	// ProtoStreaming is reserved for I2P streaming connections.
	// Do not use this for datagrams.
	ProtoStreaming uint8 = 6

	// ProtoDatagram (Datagram1) is for repliable, authenticated datagrams.
	// The sender's Destination is included and signed for authentication.
	// WARNING: Does NOT support offline signatures. Use ProtoDatagram2 for offline keys.
	ProtoDatagram uint8 = 17

	// ProtoDatagramRaw is for raw, non-repliable datagrams.
	// No sender information is included - the receiver cannot reply.
	ProtoDatagramRaw uint8 = 18

	// ProtoDatagram2 is for repliable datagrams with replay prevention.
	// Includes sender Destination, authentication, and timestamp for replay protection.
	// Supports offline signatures (LS2 offline keys).
	ProtoDatagram2 uint8 = 19

	// ProtoDatagram3 is for repliable datagrams without authentication.
	// Includes sender Destination but no signature verification.
	ProtoDatagram3 uint8 = 20
)

I2P Application Protocol Number Constants

These protocol numbers identify the application-layer protocol within I2P messages. They are passed in the protocol field of SendMessage/SendMessageExpires messages and received in payload messages. These constants match the Java I2PSession interface.

Per I2P Datagram Specification (https://geti2p.net/spec/datagrams):

  • Protocol 6 (Streaming) is reserved for streaming connections
  • Protocol 17 (Datagram) is for repliable, authenticated datagrams (Datagram1)
  • Protocol 18 (DatagramRaw) is for raw, non-repliable datagrams
  • Protocol 19 (Datagram2) is for repliable datagrams with replay prevention
  • Protocol 20 (Datagram3) is for repliable datagrams without authentication

IMPORTANT: Datagram1 (protocol 17) does NOT support offline signatures (LS2 offline keys). If Session.IsOffline() returns true, use Datagram2 (protocol 19) instead.

View Source
const (
	I2CP_CLIENT_VERSION                 = "0.9.66"
	I2CP_PROTOCOL_INIT            uint8 = 0x2a
	I2CP_MESSAGE_SIZE                   = 0xffff
	I2CP_MAX_MESSAGE_PAYLOAD_SIZE       = 65536 // 64KB max payload per I2CP spec (spec says "about 64 KB")
	I2CP_SAFE_MESSAGE_SIZE              = 64000 // Conservative limit for universal router compatibility
	I2CP_MAX_SESSIONS                   = 0xffff
	I2CP_MAX_SESSIONS_PER_CLIENT        = 32
	// Session ID 0xFFFF is reserved per I2CP spec for "no session" operations
	// Used for hostname lookups and other operations that don't require a session
	I2CP_SESSION_ID_NONE uint16 = 0xFFFF
)

I2CP Client Constants Moved from: client.go

View Source
const (
	I2CP_MSG_ANY                       uint8 = 0
	I2CP_MSG_BANDWIDTH_LIMITS          uint8 = 23
	I2CP_MSG_CREATE_LEASE_SET          uint8 = 4
	I2CP_MSG_CREATE_LEASE_SET2         uint8 = 41
	I2CP_MSG_CREATE_SESSION            uint8 = 1
	I2CP_MSG_DEST_LOOKUP               uint8 = 34
	I2CP_MSG_DEST_REPLY                uint8 = 35
	I2CP_MSG_DESTROY_SESSION           uint8 = 3
	I2CP_MSG_DISCONNECT                uint8 = 30
	I2CP_MSG_GET_BANDWIDTH_LIMITS      uint8 = 8
	I2CP_MSG_GET_DATE                  uint8 = 32
	I2CP_MSG_HOST_LOOKUP               uint8 = 38
	I2CP_MSG_HOST_REPLY                uint8 = 39
	I2CP_MSG_MESSAGE_STATUS            uint8 = 22
	I2CP_MSG_PAYLOAD_MESSAGE           uint8 = 31
	I2CP_MSG_RECEIVE_MESSAGE_BEGIN     uint8 = 6 // DEPRECATED: Not used in fastReceive mode (default since 0.9.4)
	I2CP_MSG_RECEIVE_MESSAGE_END       uint8 = 7 // DEPRECATED: Not used in fastReceive mode (default since 0.9.4)
	I2CP_MSG_RECONFIGURE_SESSION       uint8 = 2
	I2CP_MSG_REPORT_ABUSE              uint8 = 29 // DEPRECATED: Never fully implemented, unsupported
	I2CP_MSG_REQUEST_LEASESET          uint8 = 21
	I2CP_MSG_REQUEST_VARIABLE_LEASESET uint8 = 37
	I2CP_MSG_SEND_MESSAGE              uint8 = 5
	I2CP_MSG_SEND_MESSAGE_EXPIRES      uint8 = 36
	I2CP_MSG_SESSION_STATUS            uint8 = 20
	I2CP_MSG_SET_DATE                  uint8 = 33
	I2CP_MSG_BLINDING_INFO             uint8 = 42
)

I2CP Message Type Constants Moved from: client.go

View Source
const (
	AUTH_METHOD_NONE           uint8 = 0 // No authentication required
	AUTH_METHOD_USERNAME_PWD   uint8 = 1 // Username/password authentication (0.9.11+)
	AUTH_METHOD_SSL_TLS        uint8 = 2 // SSL/TLS certificate authentication (0.8.3+)
	AUTH_METHOD_PER_CLIENT_DH  uint8 = 3 // Per-client DH for BlindingInfo (0.9.43+) - NOT for session auth
	AUTH_METHOD_PER_CLIENT_PSK uint8 = 4 // Per-client PSK for BlindingInfo (0.9.43+) - NOT for session auth
)

Authentication Method Constants per I2CP specification for GetDateMessage protocol initialization authentication

IMPORTANT: Methods 0-2 are I2CP session authentication methods for GetDateMessage. Methods 3-4 are NOT I2CP session auth methods - they are for encrypted LeaseSet per-client authentication via BlindingInfoMessage (see per_client_auth.go).

Support Status in go-i2cp:

  • AUTH_METHOD_NONE (0): ✅ Fully supported
  • AUTH_METHOD_USERNAME_PWD (1): ✅ Fully supported (via i2cp.username, i2cp.password)
  • AUTH_METHOD_SSL_TLS (2): ✅ Fully supported (via i2cp.SSL configuration)
  • AUTH_METHOD_PER_CLIENT_DH (3): ✅ Supported via BlindingInfoMessage (see per_client_auth.go)
  • AUTH_METHOD_PER_CLIENT_PSK (4): ✅ Supported via BlindingInfoMessage (see per_client_auth.go)

For per-client authentication to encrypted LeaseSets, use:

  • NewPerClientAuthDH() for DH authentication
  • NewPerClientAuthPSK() for PSK authentication
  • BlindingInfo.SetPerClientAuth() to configure
View Source
const (
	HOST_REPLY_SUCCESS                   uint8 = 0 // Lookup successful
	HOST_REPLY_FAILURE                   uint8 = 1 // General lookup failure
	HOST_REPLY_PASSWORD_REQUIRED         uint8 = 2 // Password required for encrypted LeaseSet (since 0.9.43)
	HOST_REPLY_PRIVATE_KEY_REQUIRED      uint8 = 3 // Private key required for per-client auth (since 0.9.43)
	HOST_REPLY_PASSWORD_AND_KEY_REQUIRED uint8 = 4 // Both password and key required (since 0.9.43)
	HOST_REPLY_DECRYPTION_FAILURE        uint8 = 5 // Failed to decrypt LeaseSet (since 0.9.43)
	HOST_REPLY_LEASESET_LOOKUP_FAILURE   uint8 = 6 // LeaseSet not found in network database (since 0.9.66)
	HOST_REPLY_LOOKUP_TYPE_UNSUPPORTED   uint8 = 7 // Lookup type not supported by router (since 0.9.66)
)

HostReply Error Codes (I2CP Proposal 167) per I2CP specification for HostReplyMessage error handling

View Source
const (
	LEASESET_TYPE_LEGACY    uint8 = 1 // Legacy LeaseSet (deprecated)
	LEASESET_TYPE_STANDARD  uint8 = 3 // Standard LeaseSet2
	LEASESET_TYPE_ENCRYPTED uint8 = 5 // EncryptedLeaseSet
	LEASESET_TYPE_META      uint8 = 7 // MetaLeaseSet (preliminary)
)

LeaseSet Type Constants per I2CP specification for CreateLeaseSet2Message

View Source
const (
	BLINDING_AUTH_SCHEME_DH  uint8 = 0 // Diffie-Hellman client authentication (or no per-client auth)
	BLINDING_AUTH_SCHEME_PSK uint8 = 1 // Pre-Shared Key client authentication
)

Blinding Authentication Scheme Constants per I2CP specification for BlindingInfoMessage authentication

Blinding is used for encrypted LeaseSet access (I2CP 0.9.43+). The client sends BlindingInfoMessage to advise the router about blinded destinations with optional lookup passwords and/or private keys for decryption.

Support Status in go-i2cp:

  • BLINDING_AUTH_SCHEME_DH (0): ✅ Supported via msgBlindingInfo()
  • BLINDING_AUTH_SCHEME_PSK (1): ✅ Supported via msgBlindingInfo()

Blinding workflow:

  1. Client sends BlindingInfoMessage to router before messaging a blinded destination
  2. Router uses the info to look up and decrypt the destination's LeaseSet
  3. Router does NOT reply to this message

Per SPEC.md § BlindingInfoMessage: "Before a client sends a message to a blinded destination, it must either lookup the 'b33' in a Host Lookup message, or send a Blinding Info message."

View Source
const (
	BLINDING_ENDPOINT_HASH        uint8 = 0 // 32-byte SHA-256 hash of destination
	BLINDING_ENDPOINT_HOSTNAME    uint8 = 1 // hostname String (address book lookup)
	BLINDING_ENDPOINT_DESTINATION uint8 = 2 // full binary Destination
	BLINDING_ENDPOINT_SIGKEY      uint8 = 3 // 2-byte sig type + SigningPublicKey
)

Blinding Endpoint Type Constants per I2CP specification for BlindingInfoMessage endpoint identification

The endpoint identifies which blinded destination the blinding info applies to. Different types allow specifying the destination by hash, hostname, full destination, or signing key.

View Source
const (
	BLINDING_FLAG_PER_CLIENT    uint8 = 0x01 // Bit 0: per-client authentication enabled
	BLINDING_FLAG_SECRET        uint8 = 0x10 // Bit 4: lookup password required
	BLINDING_FLAG_AUTH_DH       uint8 = 0x00 // Bits 3-1: DH authentication (000)
	BLINDING_FLAG_AUTH_PSK      uint8 = 0x02 // Bits 3-1: PSK authentication (001)
	BLINDING_FLAG_AUTH_MASK     uint8 = 0x0E // Bits 3-1: authentication scheme mask
	BLINDING_FLAG_RESERVED_MASK uint8 = 0xE0 // Bits 7-5: reserved, must be 0
)

Blinding Flag Constants per I2CP specification for BlindingInfoMessage flags field

Flags field is 1 byte with bit layout: 76543210

  • Bit 0: 0=everybody, 1=per-client authentication
  • Bits 3-1: Auth scheme (if bit 0 is 1), otherwise 000
  • Bit 4: 1=secret (lookup password) required
  • Bits 7-5: Reserved, must be 0
View Source
const (
	// Bit masks for validation
	SEND_MSG_FLAGS_RESERVED_MASK    uint16 = 0xF800 // Bits 15-11: reserved, must be 0
	SEND_MSG_FLAGS_RELIABILITY_MASK uint16 = 0x0600 // Bits 10-9: deprecated reliability override
	SEND_MSG_FLAGS_TAG_THRESHOLD    uint16 = 0x00F0 // Bits 7-4: low tag threshold (ElGamal only)
	SEND_MSG_FLAGS_TAG_COUNT        uint16 = 0x000F // Bits 3-0: tags to send (ElGamal only)

	// Bit 8: LeaseSet bundling control (the only modern flag still used)
	SEND_MSG_FLAG_NO_LEASESET uint16 = 0x0100 // Don't bundle LeaseSet with message
)

SendMessageExpires Flag Constants per I2CP specification § SendMessageExpiresMessage (I2CP 0.8.4+)

These flags control message delivery options for SendMessageExpiresMessage (type 36). The flags field is 2 bytes (16 bits) with the following layout (bit order 15...0):

Bits 15-11: Reserved, must be 0
Bits 10-9:  Message Reliability Override (DEPRECATED - unimplemented, to be removed)
Bit 8:      Don't bundle LeaseSet (SEND_MSG_FLAG_NO_LEASESET)
Bits 7-4:   Low tag threshold (ElGamal only, ignored for ECIES-Ratchet)
Bits 3-0:   Tags to send (ElGamal only, ignored for ECIES-Ratchet)

IMPORTANT: ElGamal-specific flags (bits 7-0) are obsolete in modern I2P. As of I2CP 0.9.39+, all encryption uses ECIES-Ratchet, which does not use session tags. These flags are kept for backward compatibility but have no effect with ECIES-Ratchet.

Usage Example:

flags := SEND_MSG_FLAG_NO_LEASESET | BuildSendMessageFlags(0, 0)
session.SendMessageExpires(dest, protocol, srcPort, destPort, payload, flags, expiration)
View Source
const (
	SEND_MSG_TAG_THRESHOLD_DEFAULT uint8 = 0  // Use session key manager settings
	SEND_MSG_TAG_THRESHOLD_2       uint8 = 1  // Threshold: 2 tags
	SEND_MSG_TAG_THRESHOLD_3       uint8 = 2  // Threshold: 3 tags
	SEND_MSG_TAG_THRESHOLD_6       uint8 = 3  // Threshold: 6 tags
	SEND_MSG_TAG_THRESHOLD_9       uint8 = 4  // Threshold: 9 tags
	SEND_MSG_TAG_THRESHOLD_14      uint8 = 5  // Threshold: 14 tags
	SEND_MSG_TAG_THRESHOLD_20      uint8 = 6  // Threshold: 20 tags
	SEND_MSG_TAG_THRESHOLD_27      uint8 = 7  // Threshold: 27 tags
	SEND_MSG_TAG_THRESHOLD_35      uint8 = 8  // Threshold: 35 tags
	SEND_MSG_TAG_THRESHOLD_45      uint8 = 9  // Threshold: 45 tags
	SEND_MSG_TAG_THRESHOLD_57      uint8 = 10 // Threshold: 57 tags
	SEND_MSG_TAG_THRESHOLD_72      uint8 = 11 // Threshold: 72 tags
	SEND_MSG_TAG_THRESHOLD_92      uint8 = 12 // Threshold: 92 tags
	SEND_MSG_TAG_THRESHOLD_117     uint8 = 13 // Threshold: 117 tags
	SEND_MSG_TAG_THRESHOLD_147     uint8 = 14 // Threshold: 147 tags
	SEND_MSG_TAG_THRESHOLD_192     uint8 = 15 // Threshold: 192 tags
)

SendMessageExpires Tag Threshold Values (ElGamal Only - OBSOLETE) per I2CP specification § SendMessageExpiresMessage Flags Field

NOTE: These are only relevant for ElGamal encryption, which is deprecated. Modern ECIES-Ratchet encryption ignores these values. These constants are provided for completeness but should not be used in new code.

Tag threshold: if there are fewer than this many tags available, send more. This is advisory and does not force tags to be delivered.

View Source
const (
	SEND_MSG_TAG_COUNT_DEFAULT uint8 = 0  // Use session key manager settings
	SEND_MSG_TAG_COUNT_2       uint8 = 1  // Send 2 tags
	SEND_MSG_TAG_COUNT_4       uint8 = 2  // Send 4 tags
	SEND_MSG_TAG_COUNT_6       uint8 = 3  // Send 6 tags
	SEND_MSG_TAG_COUNT_8       uint8 = 4  // Send 8 tags
	SEND_MSG_TAG_COUNT_12      uint8 = 5  // Send 12 tags
	SEND_MSG_TAG_COUNT_16      uint8 = 6  // Send 16 tags
	SEND_MSG_TAG_COUNT_24      uint8 = 7  // Send 24 tags
	SEND_MSG_TAG_COUNT_32      uint8 = 8  // Send 32 tags
	SEND_MSG_TAG_COUNT_40      uint8 = 9  // Send 40 tags
	SEND_MSG_TAG_COUNT_51      uint8 = 10 // Send 51 tags
	SEND_MSG_TAG_COUNT_64      uint8 = 11 // Send 64 tags
	SEND_MSG_TAG_COUNT_80      uint8 = 12 // Send 80 tags
	SEND_MSG_TAG_COUNT_100     uint8 = 13 // Send 100 tags
	SEND_MSG_TAG_COUNT_125     uint8 = 14 // Send 125 tags
	SEND_MSG_TAG_COUNT_160     uint8 = 15 // Send 160 tags
)

SendMessageExpires Tags to Send Values (ElGamal Only - OBSOLETE) per I2CP specification § SendMessageExpiresMessage Flags Field

NOTE: These are only relevant for ElGamal encryption, which is deprecated. Modern ECIES-Ratchet encryption ignores these values. These constants are provided for completeness but should not be used in new code.

Number of tags to send if required. This is advisory and does not force tags to be delivered.

View Source
const (
	HOST_LOOKUP_TYPE_HASH                  = 0 // Basic hash lookup (since 0.9.11)
	HOST_LOOKUP_TYPE_HOSTNAME              = 1 // Basic hostname lookup (since 0.9.11)
	HOST_LOOKUP_TYPE_HASH_WITH_OPTIONS     = 2 // Hash + LeaseSet options mapping (since 0.9.66)
	HOST_LOOKUP_TYPE_HOSTNAME_WITH_OPTIONS = 3 // Hostname + LeaseSet options mapping (since 0.9.66)
	HOST_LOOKUP_TYPE_DEST_WITH_OPTIONS     = 4 // Destination + LeaseSet options mapping (since 0.9.66)
)

Host Lookup Type Constants (I2CP § HostLookupMessage)

Per I2CP 0.9.11+, extended in 0.9.66 with options mappings (Proposal 167 - Service Records).

Basic lookups (types 0-1) resolve an I2P destination from either a hash or hostname. Service record lookups (types 2-4) additionally return the LeaseSet's options Mapping, which can contain service-specific metadata like protocol information.

Router Version Requirements:

  • Types 0-1: Require I2CP 0.9.11+ router
  • Types 2-4: Require I2CP 0.9.66+ router (Proposal 167)

Note: If the router does not support the requested lookup type, it returns HOST_REPLY_LOOKUP_TYPE_UNSUPPORTED (code 7).

View Source
const (
	CERTIFICATE_NULL     uint8 = 0
	CERTIFICATE_HASHCASH uint8 = 1
	CERTIFICATE_SIGNED   uint8 = 2
	CERTIFICATE_MULTIPLE uint8 = 3
	CERTIFICATE_KEY      uint8 = 5
)

Certificate Type Constants Moved from: certificate.go

View Source
const (
	PUB_KEY_SIZE = 256
	DIGEST_SIZE  = 32 // SHA-256 digest size for Ed25519
	DEST_SIZE    = 4096
)

Destination Size Constants Moved from: destination.go

View Source
const (
	HASH_SHA1   uint8 = iota
	HASH_SHA256 uint8 = iota
)

Hash Algorithm Constants Moved from: crypto.go

View Source
const (
	CODEC_BASE32 uint8 = iota
	CODEC_BASE64 uint8 = iota
)

Codec Algorithm Constants Moved from: crypto.go

View Source
const (
	PROTOCOL = 1 << 0
	LOGIC    = 1 << 1

	DEBUG   = 1 << 4
	INFO    = 1 << 5
	WARNING = 1 << 6
	ERROR   = 1 << 7
	FATAL   = 1 << 8

	STRINGMAP      = 1 << 9
	INTMAP         = 1 << 10
	QUEUE          = 1 << 11
	STREAM         = 1 << 12
	CRYPTO         = 1 << 13
	TCP            = 1 << 14
	CLIENT         = 1 << 15
	CERTIFICATE    = 1 << 16
	LEASE          = 1 << 17
	DESTINATION    = 1 << 18
	SESSION        = 1 << 19
	SESSION_CONFIG = 1 << 20
	TEST           = 1 << 21
	DATAGRAM       = 1 << 22
	CONFIG_FILE    = 1 << 23
	VERSION        = 1 << 24

	TAG_MASK       = 0x0000000f
	LEVEL_MASK     = 0x000001f0
	COMPONENT_MASK = 0xfffffe00

	ALL = 0xffffffff
)

Logger Level Constants Moved from: logger.go

View Source
const (
	MSG_STATUS_AVAILABLE              uint8 = 0  // DEPRECATED: Message available for pickup
	MSG_STATUS_ACCEPTED               uint8 = 1  // Message accepted by router
	MSG_STATUS_BEST_EFFORT_SUCCESS    uint8 = 2  // Best-effort delivery succeeded
	MSG_STATUS_BEST_EFFORT_FAILURE    uint8 = 3  // Best-effort delivery failed
	MSG_STATUS_GUARANTEED_SUCCESS     uint8 = 4  // Guaranteed delivery succeeded
	MSG_STATUS_GUARANTEED_FAILURE     uint8 = 5  // Guaranteed delivery failed
	MSG_STATUS_LOCAL_SUCCESS          uint8 = 6  // Local delivery succeeded
	MSG_STATUS_LOCAL_FAILURE          uint8 = 7  // Local delivery failed
	MSG_STATUS_ROUTER_FAILURE         uint8 = 8  // Router error
	MSG_STATUS_NETWORK_FAILURE        uint8 = 9  // Network error
	MSG_STATUS_BAD_SESSION            uint8 = 10 // Invalid session ID
	MSG_STATUS_BAD_MESSAGE            uint8 = 11 // Malformed message
	MSG_STATUS_BAD_OPTIONS            uint8 = 12 // Invalid message options or expiration (I2CP 0.9.5+)
	MSG_STATUS_OVERFLOW_FAILURE       uint8 = 13 // Queue overflow
	MSG_STATUS_MESSAGE_EXPIRED        uint8 = 14 // Message expired
	MSG_STATUS_BAD_LOCAL_LEASESET     uint8 = 15 // Local LeaseSet invalid
	MSG_STATUS_NO_LOCAL_TUNNELS       uint8 = 16 // No local tunnels available
	MSG_STATUS_UNSUPPORTED_ENCRYPTION uint8 = 17 // Encryption type unsupported
	MSG_STATUS_BAD_DESTINATION        uint8 = 18 // Destination invalid
	MSG_STATUS_BAD_LEASESET           uint8 = 19 // Remote LeaseSet invalid
	MSG_STATUS_EXPIRED_LEASESET       uint8 = 20 // Remote LeaseSet expired
	MSG_STATUS_NO_LEASESET            uint8 = 21 // Remote LeaseSet not found
	MSG_STATUS_META_LEASESET          uint8 = 22 // MetaLeaseSet received (since 0.9.41)
	MSG_STATUS_LOOPBACK_DENIED        uint8 = 23 // Loopback message denied (since 0.9.62)
)

MessageStatus Codes (I2CP MessageStatusMessage) Complete status codes 0-23 per I2CP specification Used in MessageStatusMessage (type 22) to report delivery status

View Source
const (
	// ELS2AuthInfo is the HKDF info string for Encrypted LeaseSet2 per-client auth
	// per I2P Proposal 149
	ELS2AuthInfo = "ELS2_L1K"

	// ELS2AuthSalt is the default salt for ELS2 auth derivation
	// (empty per specification - salt comes from blinding factor)
	ELS2AuthSalt = ""
)

I2P context strings for HKDF derivation

View Source
const (
	META_LEASE_TYPE_UNKNOWN   uint8 = 0 // Unknown type
	META_LEASE_TYPE_LEASESET  uint8 = 1 // Legacy LeaseSet
	META_LEASE_TYPE_LEASESET2 uint8 = 3 // LeaseSet2
	META_LEASE_TYPE_META      uint8 = 5 // Nested MetaLeaseSet
)

MetaLeaseSet type constants for the Flags field

View Source
const (
	CHACHA20_POLY1305 uint32 = 4
)

Encryption Algorithm Constants

View Source
const (
	ED25519_SHA256 uint32 = 7
)

Signature Algorithm Constants Moved from: crypto.go Modern I2CP uses Ed25519 (type 7) exclusively

View Source
const ROUTER_CAN_HOST_LOOKUP uint32 = 1

Router Capabilities Constants Moved from: client.go

View Source
const (
	TAG = CLIENT
)

Tag Constants Moved from: crypto.go, destination.go, client.go

View Source
const (
	X25519 uint32 = 4
)

Key Exchange Algorithm Constants

Variables

View Source
var (
	// ErrSessionInvalid indicates an operation was attempted on an invalid or closed session.
	// This typically occurs when trying to use a session ID that doesn't exist or has been destroyed.
	// I2CP spec: SessionStatusMessage status code 3 (Invalid)
	ErrSessionInvalid = errors.New("i2cp: session invalid or closed")

	// ErrConnectionClosed indicates the TCP connection to the I2P router was closed.
	// This may occur due to network issues, router shutdown, or explicit disconnect.
	ErrConnectionClosed = errors.New("i2cp: connection closed")

	// ErrMessageTooLarge indicates a message exceeds the I2CP protocol size limit.
	// I2CP spec: Maximum message size is approximately 64 KB (0xFFFF bytes)
	ErrMessageTooLarge = errors.New("i2cp: message exceeds size limit")

	// ErrAuthenticationFailed indicates authentication with the router failed.
	// This may occur with username/password, TLS certificate, or per-client authentication.
	// I2CP spec: Authentication support added in protocol version 0.9.11+
	ErrAuthenticationFailed = errors.New("i2cp: authentication failed")

	// ErrProtocolVersion indicates an unsupported I2CP protocol version was detected.
	// The client should gracefully degrade or refuse connection.
	// I2CP spec: Supports versions 0.6.5 through 0.9.66
	ErrProtocolVersion = errors.New("i2cp: unsupported protocol version")

	// ErrTimeout indicates an operation exceeded its allowed time limit.
	// Operations should respect context.Context deadlines when provided.
	ErrTimeout = errors.New("i2cp: operation timed out")

	// ErrNoPrimarySession indicates a subsession operation was attempted without a primary session.
	// I2CP spec: Multi-session support added in protocol version 0.9.21+
	ErrNoPrimarySession = errors.New("i2cp: no primary session exists for subsession creation")

	// ErrMultiSessionUnsupported indicates the router doesn't support multiple sessions.
	// I2CP spec: Check router version >= 0.9.21 before creating subsessions
	ErrMultiSessionUnsupported = errors.New("i2cp: router does not support multi-session")

	// ErrInvalidDestination indicates a malformed or invalid destination was provided.
	// Destinations must contain valid cryptographic keys and certificates.
	ErrInvalidDestination = errors.New("i2cp: invalid destination format")

	// ErrInvalidLeaseSet indicates a malformed or invalid LeaseSet was received.
	// LeaseSets must contain valid leases, signatures, and cryptographic data.
	ErrInvalidLeaseSet = errors.New("i2cp: invalid leaseset format")

	// ErrMessageParsing indicates a failure to parse an incoming I2CP message.
	// This typically indicates protocol violations or corrupted data.
	ErrMessageParsing = errors.New("i2cp: message parsing failed")

	// ErrInvalidSessionID indicates an invalid session ID was used.
	// Session IDs must be 2-byte integers assigned by the router.
	// Session ID 0xFFFF is reserved for no-session operations.
	ErrInvalidSessionID = errors.New("i2cp: invalid session id")

	// ErrSessionRefused indicates the router refused to create the session.
	// This may occur due to resource limits or configuration issues.
	// I2CP spec: SessionStatusMessage status code 4 (Refused) added in 0.9.12
	ErrSessionRefused = errors.New("i2cp: session creation refused by router")

	// ErrNotConnected indicates an operation requires an active connection but none exists.
	ErrNotConnected = errors.New("i2cp: not connected to router")

	// ErrAlreadyConnected indicates Connect() was called on an already-connected client.
	ErrAlreadyConnected = errors.New("i2cp: already connected")

	// ErrInvalidConfiguration indicates the session configuration is invalid.
	// Configuration must include valid destination, options, and signature.
	ErrInvalidConfiguration = errors.New("i2cp: invalid session configuration")

	// ErrDestinationLookupFailed indicates a destination lookup operation failed.
	// This is equivalent to a DNS lookup failure in the I2P network.
	// I2CP spec: MessageStatusMessage status code 21 (No Leaseset)
	ErrDestinationLookupFailed = errors.New("i2cp: destination lookup failed")

	// ErrBlindingRequired indicates a blinded destination requires BlindingInfo.
	// Blinded destinations (b33 addresses) need authentication parameters.
	// I2CP spec: BlindingInfoMessage support added in protocol version 0.9.43+
	ErrBlindingRequired = errors.New("i2cp: blinding info required for encrypted leaseset")

	// ErrUnsupportedCrypto indicates an unsupported cryptographic algorithm was encountered.
	// The library supports Ed25519 signatures, X25519 key exchange, and ChaCha20-Poly1305 AEAD.
	ErrUnsupportedCrypto = errors.New("i2cp: unsupported cryptographic algorithm")

	// ErrInvalidSignature indicates a cryptographic signature verification failed.
	// This typically indicates data corruption or a security issue.
	ErrInvalidSignature = errors.New("i2cp: invalid signature")

	// ErrOfflineSignatureExpired indicates an offline signature has expired.
	// Offline signatures have an expiration timestamp and must be rejected after expiry.
	// I2CP spec: LeaseSet2 § Offline Signatures
	ErrOfflineSignatureExpired = errors.New("i2cp: offline signature expired")

	// ErrOfflineSignatureInvalid indicates offline signature cryptographic verification failed.
	// The signature over [signingKey||expires||transientKey] did not match.
	// I2CP spec: LeaseSet2 § Offline Signatures
	ErrOfflineSignatureInvalid = errors.New("i2cp: offline signature verification failed")

	// ErrMaxSessionsReached indicates the maximum number of sessions per client has been reached.
	// I2CP spec: Maximum sessions per client is defined by I2CP_MAX_SESSIONS_PER_CLIENT
	ErrMaxSessionsReached = errors.New("i2cp: maximum sessions per client reached")

	// ErrClientClosed indicates an operation was attempted on a closed client.
	// All operations will fail after Close() has been called.
	ErrClientClosed = errors.New("i2cp: client is closed")

	// ErrClientNotInitialized indicates an operation was attempted on an uninitialized client.
	// Clients must be created using NewClient() to ensure proper initialization.
	// Zero-value Client{} instances are not safe to use.
	ErrClientNotInitialized = errors.New("i2cp: client not initialized (use NewClient)")

	// ErrSessionNotInitialized indicates an operation was attempted on an uninitialized session.
	// Sessions must be created using NewSession() or NewSessionWithContext() to ensure proper initialization.
	// Zero-value Session{} instances are not safe to use.
	ErrSessionNotInitialized = errors.New("i2cp: session not initialized (use NewSession)")

	// ErrInvalidArgument indicates a nil or invalid argument was passed to a public API method.
	// All public methods validate their parameters and return this error for nil values.
	ErrInvalidArgument = errors.New("i2cp: invalid argument (nil or empty value)")
)

Sentinel errors for common I2CP protocol violations and failures

View Source
var (
	// VersionFastReceive is the minimum version for fast receive mode (deprecates ReceiveMessageBegin/End)
	VersionFastReceive = Version{/* contains filtered or unexported fields */}

	// VersionHostLookup is the minimum version for HostLookup/HostReply (deprecates DestLookup/DestReply)
	VersionHostLookup = Version{/* contains filtered or unexported fields */}

	// VersionMultiSession is the minimum version for multi-session support
	VersionMultiSession = Version{/* contains filtered or unexported fields */}

	// VersionCreateLeaseSet2 is the minimum version for CreateLeaseSet2Message (type 41)
	VersionCreateLeaseSet2 = Version{/* contains filtered or unexported fields */}

	// VersionBlindingInfo is the minimum version for BlindingInfoMessage (type 42)
	VersionBlindingInfo = Version{/* contains filtered or unexported fields */}

	// VersionProposal167 is the minimum version for Proposal 167 (HostReply options mapping)
	VersionProposal167 = Version{/* contains filtered or unexported fields */}
)

Predefined router version requirements for I2CP features. These match the I2CP spec version notes and can be used with SupportsVersion().

Functions

func BlindPrivateKey

func BlindPrivateKey(privateKey [64]byte, alpha [32]byte) ([64]byte, error)

BlindPrivateKey blinds an Ed25519 private key using a blinding factor. The blinding operation: d' = d + alpha (mod L)

The blinded private key can sign on behalf of the blinded public key. Both the public and private key must be blinded with the same alpha.

Parameters:

  • privateKey: 64-byte Ed25519 private key to blind
  • alpha: 32-byte blinding factor from DeriveBlindingFactor

Returns:

  • Blinded 64-byte value [scalar][pubkey]
  • Error if private key is invalid or alpha is invalid

func BlindPublicKey

func BlindPublicKey(publicKey, alpha [32]byte) ([32]byte, error)

BlindPublicKey blinds an Ed25519 public key using a blinding factor. The blinding operation: P' = P + [alpha]B

This is used to create unlinkable blinded destinations for EncryptedLeaseSet. The same alpha applied to different public keys produces different blinded keys, ensuring destinations cannot be correlated.

Parameters:

  • publicKey: 32-byte Ed25519 public key to blind
  • alpha: 32-byte blinding factor from DeriveBlindingFactor

Returns:

  • Blinded 32-byte public key
  • Error if public key is invalid or alpha is invalid

func BuildSendMessageFlags

func BuildSendMessageFlags(tagThreshold, tagCount uint8) uint16

BuildSendMessageFlags constructs the flags field for SendMessageExpiresMessage per I2CP specification § SendMessageExpiresMessage (I2CP 0.8.4+)

IMPORTANT: Tag threshold and tag count are OBSOLETE parameters. They are only relevant for ElGamal encryption (deprecated). Modern I2P uses ECIES-Ratchet encryption which does not use session tags. These parameters are kept for backward compatibility but have no effect with ECIES-Ratchet.

Modern usage should use:

flags := BuildSendMessageFlags(0, 0)  // Use defaults (tag params ignored)
flags |= SEND_MSG_FLAG_NO_LEASESET    // Optionally prevent LeaseSet bundling

Parameters:

  • tagThreshold: Low tag threshold (0-15), ElGamal only. Use 0 for default.
  • tagCount: Tags to send (0-15), ElGamal only. Use 0 for default.

Returns the flags value suitable for use with Session.SendMessageExpires()

func CertLength added in v0.1.52

func CertLength(cert *Certificate) uint16

CertLength is a helper that returns the certificate data length as uint16. Returns 0 if length extraction fails.

func CertType added in v0.1.52

func CertType(cert *Certificate) uint8

CertType is a helper that returns the certificate type as uint8. Returns 0 (CERTIFICATE_NULL) if type extraction fails.

func Debug

func Debug(message string, args ...interface{})

Debug logs a debug message with optional arguments. Deprecated: Use github.com/go-i2p/logger directly for new code. The tags parameter has been removed; use logger.Debug() or logger.Debugf() instead.

func DeriveBlindingFactor

func DeriveBlindingFactor(secret []byte, date string) ([32]byte, error)

DeriveBlindingFactor derives a blinding factor (alpha) from a secret and date. This creates a unique per-day blinding factor for EncryptedLeaseSet rotation.

The derivation uses HKDF-SHA256 with the date as salt, producing a 32-byte canonical Ed25519 scalar suitable for key blinding.

Parameters:

  • secret: Secret key material (at least 32 bytes, typically from private key seed)
  • date: Date in "YYYY-MM-DD" format (use kdf.GetCurrentBlindingDate() for today)

Returns:

  • alpha: 32-byte blinding factor
  • error: If secret is too short or date format is invalid

Example:

secret := privateKey.Seed()
alpha, err := DeriveBlindingFactor(secret, "2025-11-24")
if err != nil {
    return err
}

func DeriveBlindingFactorForToday

func DeriveBlindingFactorForToday(secret []byte) ([32]byte, error)

DeriveBlindingFactorForToday derives a blinding factor for the current UTC date. This is a convenience wrapper for DeriveBlindingFactor with today's date.

func DeriveBlindingFactorWithTimestamp

func DeriveBlindingFactorWithTimestamp(secret []byte, unixTimestamp int64) ([32]byte, error)

DeriveBlindingFactorWithTimestamp derives a blinding factor from a Unix timestamp. The timestamp is converted to a UTC date in YYYY-MM-DD format.

func DerivePerClientAuthKey

func DerivePerClientAuthKey(scheme uint8, clientKey, serverKey [32]byte) ([32]byte, error)

DerivePerClientAuthKey is a convenience function that derives the decryption key for per-client authentication. It handles both DH and PSK schemes.

For DH: clientKey is your X25519 private key, serverKey is server's public key For PSK: clientKey is the pre-shared key, serverKey is ignored (can be zero)

Returns the 32-byte decryption key to use in BlindingInfoMessage.

func DerivePerClientAuthKeyWithOptions

func DerivePerClientAuthKeyWithOptions(scheme uint8, clientKey, serverKey [32]byte, salt, info []byte) ([32]byte, error)

DerivePerClientAuthKeyWithOptions derives the decryption key with custom HKDF parameters.

func DisableBufferPool

func DisableBufferPool()

DisableBufferPool disables global buffer pooling. After calling this, NewStream will allocate fresh buffers.

func Ed25519PublicKeyFromStream

func Ed25519PublicKeyFromStream(stream *Stream) (ed25519.PublicKey, error)

Ed25519PublicKeyFromStream reads only the public key from a stream. Returns stdlib ed25519.PublicKey for backward compatibility.

func EnableBufferPool

func EnableBufferPool()

EnableBufferPool enables global buffer pooling for Stream allocations. This reduces GC pressure by reusing byte slices across Stream instances.

func Error

func Error(message string, args ...interface{})

Error logs an error message with optional arguments. Deprecated: Use github.com/go-i2p/logger directly for new code. The tags parameter has been removed; use logger.Error() or logger.Errorf() instead.

func Fatal

func Fatal(message string, args ...interface{})

Fatal logs a fatal message with optional arguments. Deprecated: Use github.com/go-i2p/logger directly for new code. The tags parameter has been removed; use logger.Error() or logger.Errorf() instead. Note: Fatal maps to Error level in the logger and sets WARNFAIL_I2P.

func FormatDateForBlinding

func FormatDateForBlinding(t time.Time) string

FormatDateForBlinding formats a time.Time as YYYY-MM-DD for blinding factor derivation.

func GenerateRandomPrivateKey

func GenerateRandomPrivateKey() ([32]byte, error)

GenerateRandomPrivateKey generates a random 32-byte private key for DH authentication. This can be used to create a new client identity for accessing encrypted LeaseSets.

func GetCurrentBlindingDate

func GetCurrentBlindingDate() string

GetCurrentBlindingDate returns today's date in UTC formatted for blinding (YYYY-MM-DD).

func GetMessageStatusCategory

func GetMessageStatusCategory(status SessionMessageStatus) string

GetMessageStatusCategory returns a human-readable category for the message status. Categories: "success", "failure", "retriable", "pending", or "unknown"

func HandleHostReplyAuthError

func HandleHostReplyAuthError(errorCode uint8) (message, action string)

HandleHostReplyAuthError processes HostReply error codes related to authentication. Returns a descriptive error message and suggested action based on the error code.

Error codes 2-5 indicate authentication requirements for encrypted LeaseSets:

  • Code 2: Lookup password required
  • Code 3: Private key required (per-client auth)
  • Code 4: Both password and private key required
  • Code 5: Decryption failure (credentials may be incorrect)

func Info

func Info(message string, args ...interface{})

Info logs an info message with optional arguments. Deprecated: Use github.com/go-i2p/logger directly for new code. The tags parameter has been removed; use logger.Warn() or logger.Warnf() instead. Note: Info maps to Warn level in the logger.

func IsBufferPoolEnabled

func IsBufferPoolEnabled() bool

IsBufferPoolEnabled returns whether buffer pooling is currently enabled.

func IsFatal

func IsFatal(err error) bool

IsFatal returns true if the error is fatal and the connection should be closed. Fatal errors indicate serious protocol violations or unrecoverable states.

func IsMessageStatusFailure

func IsMessageStatusFailure(status SessionMessageStatus) bool

IsMessageStatusFailure returns true if the message status indicates a delivery failure. This includes all failure codes except transient/retriable failures.

func IsMessageStatusRetriable

func IsMessageStatusRetriable(status SessionMessageStatus) bool

IsMessageStatusRetriable returns true if the message status indicates a transient failure that may succeed if retried later. This includes queue overflow, network failures, and temporary tunnel unavailability.

func IsMessageStatusSuccess

func IsMessageStatusSuccess(status SessionMessageStatus) bool

IsMessageStatusSuccess returns true if the message status indicates successful delivery. Success statuses include accepted, best-effort success, guaranteed success, and local success.

func IsTemporary

func IsTemporary(err error) bool

IsTemporary returns true if the error is temporary and the operation can be retried. This checks for specific error types that indicate transient failures.

func LogInit

func LogInit(level int)

LogInit initializes the logger with the specified level Deprecated: Use github.com/go-i2p/logger directly for new code

func NewMessageError

func NewMessageError(messageType uint8, operation string, err error) error

NewMessageError creates a MessageError with the given parameters. Use this to wrap errors that occur during message processing.

Example:

if err := parseMessage(stream); err != nil {
    return NewMessageError(I2CP_MSG_CREATE_SESSION, "parsing", err)
}

func NewProtocolError

func NewProtocolError(message string, code int, fatal bool) error

NewProtocolError creates a ProtocolError for serious protocol violations.

Example:

if msgType > 42 {
    return NewProtocolError("unknown message type", int(msgType), false)
}

func NewSessionError

func NewSessionError(sessionID uint16, operation string, err error) error

NewSessionError creates a SessionError with the given parameters. Use this to wrap errors that occur during session operations.

Example:

if err := session.sendMessage(); err != nil {
    return NewSessionError(session.id, "send message", err)
}

func ParseConfig

func ParseConfig(s string, cb func(string, string))

ParseConfig parses a configuration file and calls the callback for each key-value pair

func ParseSendMessageFlags

func ParseSendMessageFlags(flags uint16) (noLeaseSet bool, tagThreshold, tagCount uint8, err error)

ParseSendMessageFlags extracts flag components from a SendMessageExpires flags field per I2CP specification § SendMessageExpiresMessage (I2CP 0.8.4+)

Returns:

  • noLeaseSet: true if LeaseSet bundling is disabled (bit 8)
  • tagThreshold: ElGamal tag threshold value (bits 7-4) - OBSOLETE
  • tagCount: ElGamal tags to send value (bits 3-0) - OBSOLETE
  • err: error if reserved or deprecated bits are set

func ReleaseStream

func ReleaseStream(s *Stream)

ReleaseStream returns a Stream's buffer to the pool for reuse. After calling this, the Stream should not be used. If buffer pooling is disabled, this is a no-op.

func ResolveAddr

func ResolveAddr(address string) (net.Addr, error)

func RetryWithBackoff

func RetryWithBackoff(ctx context.Context, maxRetries int, initialBackoff time.Duration, fn func() error) error

func UnblindPublicKey

func UnblindPublicKey(blindedPublicKey, alpha [32]byte) ([32]byte, error)

UnblindPublicKey reverses the blinding operation on a public key. The operation: P = P' - [alpha]B

This is used for verification: given a blinded key P' and alpha, recover P.

Parameters:

  • blindedPublicKey: 32-byte blinded Ed25519 public key
  • alpha: 32-byte blinding factor used to create the blinded key

Returns:

  • Original unblinded 32-byte public key
  • Error if inputs are invalid

func ValidateSendMessageFlags

func ValidateSendMessageFlags(flags uint16) error

ValidateSendMessageFlags validates SendMessageExpires flags per I2CP specification per I2CP specification § SendMessageExpiresMessage (I2CP 0.8.4+)

This function checks that:

  • Reserved bits (15-11) are not set
  • Deprecated reliability override bits (10-9) are not set
  • Tag threshold and count are in valid range (0-15)

Returns an error if validation fails.

func ValidateX25519PublicKey

func ValidateX25519PublicKey(publicKey [32]byte) bool

ValidatePublicKey checks if a public key is valid for X25519

func VerifyBlindedDestination

func VerifyBlindedDestination(blindedPubKey, expectedPubKey, alpha [32]byte) bool

VerifyBlindedDestination verifies that a blinded public key matches the expected unblinded public key when the same alpha is applied.

This is useful for verifying that a router-provided blinded destination corresponds to a known destination.

Parameters:

  • blindedPubKey: The blinded public key to verify
  • expectedPubKey: The expected unblinded public key
  • alpha: The blinding factor that was used

Returns:

  • true if the blinded key corresponds to the expected key
  • false otherwise

func VerifyDHSharedSecret

func VerifyDHSharedSecret(clientPrivateKey, serverPublicKey [32]byte) (bool, error)

VerifyDHSharedSecret verifies that a DH shared secret can be derived from the given keys. This is useful for testing and debugging authentication issues.

func VerifyPSKDerivation

func VerifyPSKDerivation(preSharedKey [32]byte) (bool, error)

VerifyPSKDerivation verifies that a PSK can be used to derive a decryption key.

func Warning

func Warning(message string, args ...interface{})

Warning logs a warning message with optional arguments. Deprecated: Use github.com/go-i2p/logger directly for new code. The tags parameter has been removed; use logger.Warn() or logger.Warnf() instead.

func WriteCertificateToMessage added in v0.1.52

func WriteCertificateToMessage(cert *Certificate, stream *Stream) error

WriteCertificateToMessage writes a Certificate to an I2CP message stream.

func WriteCertificateToStream added in v0.1.52

func WriteCertificateToStream(cert *Certificate, stream *Stream) error

WriteCertificateToStream is an alias for WriteCertificateToMessage.

func WriteLeaseToLeaseSet2 added in v0.1.52

func WriteLeaseToLeaseSet2(l *Lease, stream *Stream) error

WriteLeaseToLeaseSet2 writes a Lease in Lease2 format (40 bytes) for LeaseSet2. Lease2 format: gateway (32 bytes) + tunnel_id (4 bytes) + end_date (4 bytes, seconds) This differs from the I2CP Lease format which uses 8-byte millisecond timestamps.

func WriteLeaseToMessage added in v0.1.52

func WriteLeaseToMessage(l *Lease, stream *Stream) error

WriteLeaseToMessage writes a Lease to an I2CP Stream (44-byte format).

func X25519PublicKeyFromStream

func X25519PublicKeyFromStream(stream *Stream) ([32]byte, error)

X25519PublicKeyFromStream reads only the public key from a stream

Types

type AuthResult

type AuthResult struct {
	// DecryptionKey is the 32-byte key for BlindingInfoMessage
	DecryptionKey [32]byte

	// SharedSecret is the intermediate DH shared secret (DH only)
	// Empty for PSK authentication
	SharedSecret [32]byte

	// Scheme indicates which auth scheme was used (DH=0, PSK=1)
	Scheme uint8
}

AuthResult holds the result of DH or PSK authentication.

type BandwidthLimits

type BandwidthLimits struct {
	// ClientInbound is the maximum inbound bandwidth for the client in kilobytes per second (KBps).
	// This limit applies to data received by the client application.
	ClientInbound uint32

	// ClientOutbound is the maximum outbound bandwidth for the client in kilobytes per second (KBps).
	// This limit applies to data sent by the client application.
	ClientOutbound uint32

	// RouterInbound is the router's maximum inbound bandwidth in kilobytes per second (KBps).
	// This is the router's overall limit, shared across all clients.
	RouterInbound uint32

	// RouterInboundBurst is the maximum burst bandwidth for inbound router traffic in kilobytes per second (KBps).
	// This allows temporary exceeding of the RouterInbound baseline rate during the BurstTime window.
	// Per I2CP spec § BandwidthLimitsMessage: This is a RATE (KBps), not a size (bytes).
	RouterInboundBurst uint32

	// RouterOutbound is the router's maximum outbound bandwidth in kilobytes per second (KBps).
	// This is the router's overall limit, shared across all clients.
	RouterOutbound uint32

	// RouterOutboundBurst is the maximum burst bandwidth for outbound router traffic in kilobytes per second (KBps).
	// This allows temporary exceeding of the RouterOutbound baseline rate during the BurstTime window.
	// Per I2CP spec § BandwidthLimitsMessage: This is a RATE (KBps), not a size (bytes).
	RouterOutboundBurst uint32

	// BurstTime is the time window in seconds over which burst limits are calculated.
	// For example, if BurstTime=10 and RouterInboundBurst=100, the router can
	// burst up to 100 KBps over any 10-second window before throttling.
	BurstTime uint32

	// Undefined contains 9 reserved 32-bit fields for future protocol extensions.
	//
	// Per I2CP BandwidthLimitsMessage specification, these fields are currently
	// undefined and reserved for future protocol versions. They must be:
	//   - Parsed by clients for forward compatibility
	//   - Set to 0 by routers in current protocol versions
	//   - Ignored by clients until a future I2CP version defines their meaning
	//
	// Possible future uses (speculative, not in current spec):
	//   - Per-destination bandwidth limits
	//   - Quality of service parameters
	//   - Tunnel-specific bandwidth allocation
	//   - Congestion control hints
	//
	// Applications should NOT rely on these fields until officially specified.
	Undefined [9]uint32
}

BandwidthLimits represents bandwidth limitation parameters received from the I2P router. This structure contains both client-side and router-side bandwidth limits, plus burst parameters that control how bandwidth constraints are enforced.

I2CP Specification: BandwidthLimitsMessage (type 23) Introduced in I2CP 0.9.3+ to communicate bandwidth constraints from router to client.

Fields represent bytes/second unless otherwise noted. Burst parameters allow temporary exceeding of base limits for bursty traffic patterns.

func (*BandwidthLimits) InboundBytesPerSecond

func (b *BandwidthLimits) InboundBytesPerSecond() int

InboundBytesPerSecond returns the client inbound limit in bytes per second. Converts from KBps (as transmitted in I2CP protocol) to bytes/sec.

func (*BandwidthLimits) OutboundBytesPerSecond

func (b *BandwidthLimits) OutboundBytesPerSecond() int

OutboundBytesPerSecond returns the client outbound limit in bytes per second. Converts from KBps (as transmitted in I2CP protocol) to bytes/sec.

func (*BandwidthLimits) RouterInboundBurstBytesPerSecond

func (b *BandwidthLimits) RouterInboundBurstBytesPerSecond() int

RouterInboundBurstBytesPerSecond returns the router inbound burst limit in bytes per second. Converts from KBps (as transmitted in I2CP protocol) to bytes/sec.

func (*BandwidthLimits) RouterInboundBytesPerSecond

func (b *BandwidthLimits) RouterInboundBytesPerSecond() int

RouterInboundBytesPerSecond returns the router inbound limit in bytes per second. Converts from KBps (as transmitted in I2CP protocol) to bytes/sec.

func (*BandwidthLimits) RouterOutboundBurstBytesPerSecond

func (b *BandwidthLimits) RouterOutboundBurstBytesPerSecond() int

RouterOutboundBurstBytesPerSecond returns the router outbound burst limit in bytes per second. Converts from KBps (as transmitted in I2CP protocol) to bytes/sec.

func (*BandwidthLimits) RouterOutboundBytesPerSecond

func (b *BandwidthLimits) RouterOutboundBytesPerSecond() int

RouterOutboundBytesPerSecond returns the router outbound limit in bytes per second. Converts from KBps (as transmitted in I2CP protocol) to bytes/sec.

func (*BandwidthLimits) String

func (b *BandwidthLimits) String() string

String returns a human-readable representation of the bandwidth limits. Format: BandwidthLimits{Client: inbound/outbound KBps, Router: inbound(burst)/outbound(burst) KBps, Burst: Ns}

type BlindingInfo

type BlindingInfo struct {
	// EndpointType specifies how the destination is identified (0-3)
	// Use BLINDING_ENDPOINT_* constants
	EndpointType uint8

	// Endpoint is the destination identifier, format depends on EndpointType:
	//   Type 0: 32-byte hash
	//   Type 1: hostname string (will be length-prefixed)
	//   Type 2: full Destination bytes
	//   Type 3: 2-byte sig type + SigningPublicKey bytes
	Endpoint []byte

	// BlindedSigType is the signature type used for blinding (2 bytes)
	BlindedSigType uint16

	// Expiration is the expiration time in seconds since epoch
	Expiration uint32

	// PerClientAuth indicates if per-client authentication is required
	// When true, DecryptionKey must be provided
	PerClientAuth bool

	// AuthScheme specifies the authentication scheme when PerClientAuth is true
	// Use BLINDING_AUTH_SCHEME_DH (0) or BLINDING_AUTH_SCHEME_PSK (1)
	AuthScheme uint8

	// DecryptionKey is the 32-byte ECIES_X25519 private key (little-endian)
	// Only required when PerClientAuth is true
	DecryptionKey []byte

	// LookupPassword is the optional password for encrypted LeaseSet lookup
	// Only include if the destination requires a secret
	LookupPassword string
}

BlindingInfo represents the parameters for a BlindingInfoMessage. This structure encapsulates all the fields needed to advise the router about a blinded destination per I2CP specification 0.9.43+.

func CreateDHBlindingInfo

func CreateDHBlindingInfo(
	destHash []byte,
	clientPrivateKey, serverPublicKey [32]byte,
	blindedSigType uint16,
	expiration uint32,
) (*BlindingInfo, error)

Returns BlindingInfo ready to send via Session.SendBlindingInfo().

func CreateDHBlindingInfoForHostname

func CreateDHBlindingInfoForHostname(
	hostname string,
	clientPrivateKey, serverPublicKey [32]byte,
	blindedSigType uint16,
	expiration uint32,
) (*BlindingInfo, error)

CreateDHBlindingInfoForHostname creates BlindingInfo with DH auth for a hostname endpoint.

func CreatePSKBlindingInfo

func CreatePSKBlindingInfo(
	destHash []byte,
	preSharedKey [32]byte,
	blindedSigType uint16,
	expiration uint32,
) (*BlindingInfo, error)

CreatePSKBlindingInfo creates a complete BlindingInfo with PSK authentication for a hash-based endpoint.

Parameters:

  • destHash: 32-byte hash of the blinded destination
  • preSharedKey: The 32-byte pre-shared key
  • blindedSigType: Signature type used for blinding
  • expiration: Expiration time (seconds since epoch)

Returns BlindingInfo ready to send via Session.SendBlindingInfo().

func CreatePSKBlindingInfoForHostname

func CreatePSKBlindingInfoForHostname(
	hostname string,
	preSharedKey [32]byte,
	blindedSigType uint16,
	expiration uint32,
) (*BlindingInfo, error)

CreatePSKBlindingInfoForHostname creates BlindingInfo with PSK auth for a hostname endpoint.

func NewBlindingInfoWithDestination

func NewBlindingInfoWithDestination(destBytes []byte, blindedSigType uint16, expiration uint32) (*BlindingInfo, error)

NewBlindingInfoWithDestination creates BlindingInfo for a full destination. The destination bytes must be at least 387 bytes.

func NewBlindingInfoWithHash

func NewBlindingInfoWithHash(hash []byte, blindedSigType uint16, expiration uint32) (*BlindingInfo, error)

NewBlindingInfoWithHash creates BlindingInfo for a destination identified by its hash. The hash must be 32 bytes (SHA-256 of the destination).

func NewBlindingInfoWithHostname

func NewBlindingInfoWithHostname(hostname string, blindedSigType uint16, expiration uint32) (*BlindingInfo, error)

NewBlindingInfoWithHostname creates BlindingInfo for a destination identified by hostname. The hostname must be non-empty and at most 255 bytes.

func NewBlindingInfoWithSigningKey

func NewBlindingInfoWithSigningKey(sigType uint16, signingPublicKey []byte, blindedSigType uint16, expiration uint32) (*BlindingInfo, error)

NewBlindingInfoWithSigningKey creates BlindingInfo for a signing key. The sigKey bytes must include 2-byte sig type + SigningPublicKey.

func (*BlindingInfo) ClearPerClientAuth

func (info *BlindingInfo) ClearPerClientAuth()

ClearPerClientAuth removes per-client authentication from BlindingInfo.

func (*BlindingInfo) GetAuthSchemeName

func (info *BlindingInfo) GetAuthSchemeName() string

GetAuthSchemeName returns a human-readable name for the auth scheme.

func (*BlindingInfo) IsPerClientAuthEnabled

func (info *BlindingInfo) IsPerClientAuthEnabled() bool

IsPerClientAuthEnabled returns true if per-client authentication is configured.

func (*BlindingInfo) SetLookupPassword

func (info *BlindingInfo) SetLookupPassword(password string)

SetLookupPassword sets the lookup password for accessing encrypted LeaseSets. This can be used independently of per-client auth.

func (*BlindingInfo) SetPerClientAuth

func (info *BlindingInfo) SetPerClientAuth(config *PerClientAuthConfig) error

SetPerClientAuth configures per-client authentication on BlindingInfo. This enables DH or PSK authentication for accessing the encrypted LeaseSet.

func (*BlindingInfo) String

func (info *BlindingInfo) String() string

String returns a human-readable representation of the BlindingInfo.

type BlindingKeyDerivation

type BlindingKeyDerivation struct {
	// Alpha is the 32-byte blinding factor derived from secret + date
	Alpha [32]byte

	// BlindedPublicKey is the destination's public key after blinding
	BlindedPublicKey [32]byte

	// BlindedPrivateKey is the private key after blinding (if available)
	// This is only populated when calling DeriveBlindingKeysWithPrivate
	BlindedPrivateKey [64]byte

	// Date is the date used for derivation (for verification/debugging)
	Date string

	// HasPrivateKey indicates whether BlindedPrivateKey is populated
	HasPrivateKey bool
}

BlindingKeyDerivation holds derived blinding keys for accessing encrypted LeaseSets. This structure contains all the cryptographic material needed to access a blinded destination.

func DeriveBlindingKeys

func DeriveBlindingKeys(secret []byte, publicKey [32]byte, date string) (*BlindingKeyDerivation, error)

DeriveBlindingKeys derives blinding factor and blinds a public key. This is a convenience function that combines DeriveBlindingFactor and BlindPublicKey.

Parameters:

  • secret: Secret key material (at least 32 bytes)
  • publicKey: 32-byte Ed25519 public key to blind
  • date: Date in "YYYY-MM-DD" format (or empty for today)

Returns:

  • BlindingKeyDerivation containing alpha and blinded public key
  • Error if derivation fails

func DeriveBlindingKeysWithPrivate

func DeriveBlindingKeysWithPrivate(secret []byte, publicKey [32]byte, privateKey [64]byte, date string) (*BlindingKeyDerivation, error)

DeriveBlindingKeysWithPrivate derives blinding keys including the blinded private key. This is used by services that need to sign with blinded keys.

Parameters:

  • secret: Secret key material (at least 32 bytes)
  • publicKey: 32-byte Ed25519 public key
  • privateKey: 64-byte Ed25519 private key
  • date: Date in "YYYY-MM-DD" format (or empty for today)

Returns:

  • BlindingKeyDerivation containing alpha, blinded public and private keys
  • Error if derivation fails

type BufferPoolStats

type BufferPoolStats struct {
	Gets512       uint64
	Gets1K        uint64
	Gets4K        uint64
	Gets16K       uint64
	GetsOversized uint64
	Puts512       uint64
	Puts1K        uint64
	Puts4K        uint64
	Puts16K       uint64
}

BufferPoolStats returns statistics about buffer pool usage. Returns nil if buffer pooling is disabled.

func GetBufferPoolStats

func GetBufferPoolStats() *BufferPoolStats

GetBufferPoolStats returns current buffer pool statistics. Returns nil if buffer pooling is disabled.

type Certificate

type Certificate = certificate.Certificate

Certificate is a type alias for certificate.Certificate from the common package. All certificate operations (Type, Length, Data, Bytes, IsValid) are provided by the common package. I2CP-specific stream helpers are defined as package functions.

func CopyCertificate added in v0.1.52

func CopyCertificate(cert *Certificate) *Certificate

CopyCertificate creates a deep copy of a Certificate by re-parsing its bytes.

func NewCertificate

func NewCertificate(typ uint8) *Certificate

NewCertificate creates a new Certificate with the specified type using the common package.

func NewCertificateFromMessage

func NewCertificateFromMessage(stream *Stream) (*Certificate, error)

NewCertificateFromMessage reads a Certificate from an I2CP message stream. Uses common/certificate.ReadCertificate for parsing.

func NewCertificateFromStream

func NewCertificateFromStream(stream *Stream) (*Certificate, error)

NewCertificateFromStream is an alias for NewCertificateFromMessage.

type ChaCha20Poly1305Cipher

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

ChaCha20Poly1305Cipher provides authenticated encryption using ChaCha20-Poly1305 Wraps github.com/go-i2p/crypto/chacha20poly1305.AEAD

func ChaCha20Poly1305CipherFromStream

func ChaCha20Poly1305CipherFromStream(stream *Stream) (*ChaCha20Poly1305Cipher, error)

ChaCha20Poly1305CipherFromStream reads a ChaCha20-Poly1305 cipher from a stream

func NewChaCha20Poly1305Cipher

func NewChaCha20Poly1305Cipher() (*ChaCha20Poly1305Cipher, error)

NewChaCha20Poly1305Cipher creates a new ChaCha20-Poly1305 cipher with a random key Delegates to github.com/go-i2p/crypto/chacha20poly1305.GenerateKey() and NewAEAD()

func NewChaCha20Poly1305CipherWithKey

func NewChaCha20Poly1305CipherWithKey(key [32]byte) (*ChaCha20Poly1305Cipher, error)

NewChaCha20Poly1305CipherWithKey creates a new ChaCha20-Poly1305 cipher with the provided key Delegates to github.com/go-i2p/crypto/chacha20poly1305.NewAEAD()

func (*ChaCha20Poly1305Cipher) AlgorithmType

func (c *ChaCha20Poly1305Cipher) AlgorithmType() uint32

AlgorithmType returns the algorithm type constant

func (*ChaCha20Poly1305Cipher) Decrypt

func (c *ChaCha20Poly1305Cipher) Decrypt(ciphertext, additionalData []byte) ([]byte, error)

Decrypt decrypts ciphertext with optional associated data using ChaCha20-Poly1305 Expects [nonce][ciphertext+tag] format for I2CP compatibility Uses github.com/go-i2p/crypto/chacha20poly1305.AEAD.Decrypt()

func (*ChaCha20Poly1305Cipher) DecryptStream

func (c *ChaCha20Poly1305Cipher) DecryptStream(src, dst *Stream, additionalData []byte) error

DecryptStream decrypts data from source stream and writes to destination stream

func (*ChaCha20Poly1305Cipher) Encrypt

func (c *ChaCha20Poly1305Cipher) Encrypt(plaintext, additionalData []byte) ([]byte, error)

Encrypt encrypts plaintext with optional associated data using ChaCha20-Poly1305 Returns [nonce][ciphertext+tag] format for I2CP compatibility Uses github.com/go-i2p/crypto/chacha20poly1305.AEAD.Encrypt()

func (*ChaCha20Poly1305Cipher) EncryptStream

func (c *ChaCha20Poly1305Cipher) EncryptStream(src, dst *Stream, additionalData []byte) error

EncryptStream encrypts data from source stream and writes to destination stream

func (*ChaCha20Poly1305Cipher) Key

func (c *ChaCha20Poly1305Cipher) Key() [32]byte

Key returns a copy of the encryption key

func (*ChaCha20Poly1305Cipher) NonceSize

func (c *ChaCha20Poly1305Cipher) NonceSize() int

NonceSize returns the nonce size used by the cipher

func (*ChaCha20Poly1305Cipher) Overhead

func (c *ChaCha20Poly1305Cipher) Overhead() int

Overhead returns the authentication tag overhead

func (*ChaCha20Poly1305Cipher) WriteToStream

func (c *ChaCha20Poly1305Cipher) WriteToStream(stream *Stream) error

WriteToStream writes the cipher key to a stream

type CircuitBreaker

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

CircuitBreaker implements the circuit breaker pattern to prevent cascading failures. It monitors operation failures and automatically opens the circuit after a threshold, preventing additional attempts that are likely to fail. After a timeout period, it transitions to half-open state to test if the service has recovered.

States:

  • Closed: Normal operation, failures are counted
  • Open: Circuit is tripped, all operations fail fast without attempting
  • Half-Open: Testing recovery, limited operations allowed

This is particularly useful for I2CP router connections to prevent hammering a router that is down or overloaded.

func NewCircuitBreaker

func NewCircuitBreaker(maxFailures int, resetTimeout time.Duration) *CircuitBreaker

NewCircuitBreaker creates a new circuit breaker with the specified parameters.

Parameters:

  • maxFailures: Number of consecutive failures before opening the circuit
  • resetTimeout: Duration to wait in open state before attempting half-open

Example:

// Open circuit after 3 failures, try recovery after 30 seconds
cb := NewCircuitBreaker(3, 30*time.Second)

func (*CircuitBreaker) Execute

func (cb *CircuitBreaker) Execute(fn func() error) error

Execute runs the given function if the circuit breaker allows it. Returns an error if the circuit is open or if the function fails.

The circuit breaker tracks the success/failure of the operation and automatically manages state transitions.

Example:

err := circuitBreaker.Execute(func() error {
    return client.Connect(ctx)
})
if err != nil {
    if circuitBreaker.IsOpen() {
        // Circuit is open, don't retry immediately
    }
}

func (*CircuitBreaker) Failures

func (cb *CircuitBreaker) Failures() int

Failures returns the current failure count.

func (*CircuitBreaker) IsClosed

func (cb *CircuitBreaker) IsClosed() bool

IsClosed returns true if the circuit is currently closed.

func (*CircuitBreaker) IsHalfOpen

func (cb *CircuitBreaker) IsHalfOpen() bool

IsHalfOpen returns true if the circuit is currently half-open.

func (*CircuitBreaker) IsOpen

func (cb *CircuitBreaker) IsOpen() bool

IsOpen returns true if the circuit is currently open.

func (*CircuitBreaker) RecordFailure added in v0.1.52

func (cb *CircuitBreaker) RecordFailure()

RecordFailure records an external failure in the circuit breaker. This is used for operations not wrapped with Execute(), such as receive errors.

func (*CircuitBreaker) Reset

func (cb *CircuitBreaker) Reset()

Reset manually resets the circuit breaker to closed state with zero failures. This is useful for testing or manual intervention.

func (*CircuitBreaker) State

func (cb *CircuitBreaker) State() CircuitState

State returns the current state of the circuit breaker.

func (*CircuitBreaker) String

func (cb *CircuitBreaker) String() string

String returns a human-readable representation of the circuit breaker state.

type CircuitState

type CircuitState string

CircuitState represents the current state of a circuit breaker.

const (
	// CircuitClosed means the circuit is allowing requests through normally.
	CircuitClosed CircuitState = "closed"

	// CircuitOpen means the circuit is blocking requests due to too many failures.
	CircuitOpen CircuitState = "open"

	// CircuitHalfOpen means the circuit is testing if the service has recovered.
	CircuitHalfOpen CircuitState = "half-open"
)

type Client

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

func NewClient

func NewClient(callbacks *ClientCallBacks) (c *Client)

NewClient creates a new i2p client with the specified callbacks

func (*Client) Close

func (c *Client) Close() error

func (*Client) Connect

func (c *Client) Connect(ctx context.Context) error

Connect establishes a connection to the I2P router with context support. The context can be used to cancel the connection attempt or set a timeout. Implements proper error path cleanup with defer pattern per PLAN.md section 1.3. Supports TLS connections per I2CP 0.8.3+ specification (authentication method 2).

Example:

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err := client.Connect(ctx)

func (*Client) CreateSession

func (c *Client) CreateSession(ctx context.Context, sess *Session) error

CreateSession creates a new I2CP session with the router. This initiates session establishment which completes asynchronously via ProcessIO.

Parameters:

  • ctx: Context for cancellation and timeouts
  • sess: Session configuration and callbacks

Returns error if validation fails or message cannot be sent. Success is confirmed via OnStatus callback with I2CP_SESSION_STATUS_CREATED.

I2CP Spec: CreateSessionMessage (type 1), I2CP 0.9.21+ for multi-session support

func (*Client) CreateSessionSync

func (c *Client) CreateSessionSync(ctx context.Context, sess *Session) error

CreateSessionSync creates a session and waits synchronously for confirmation from the router. This is a convenience wrapper around CreateSession that handles the ProcessIO loop internally and blocks until the session is confirmed or the timeout expires.

IMPORTANT: This function will block until:

  1. The router confirms the session (I2CP_SESSION_STATUS_CREATED), OR
  2. The context expires/is cancelled, OR
  3. The router rejects the session (I2CP_SESSION_STATUS_INVALID)

This function is suitable for simple applications and testing. For production use with multiple sessions or complex I/O patterns, use the async CreateSession with manual ProcessIO.

Parameters:

  • ctx: Context for timeout/cancellation (recommended: 30 second timeout)
  • sess: Session to create (must have callbacks configured if needed)

Returns:

  • nil if session created successfully
  • error if creation failed, timed out, or context cancelled

Example:

session := NewSession(client, SessionCallbacks{
    OnMessage: func(s *Session, srcDest *Destination, protocol uint8, srcPort, destPort uint16, payload *Stream) {
        fmt.Println("Received message!")
    },
})

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

if err := client.CreateSessionSync(ctx, session); err != nil {
    log.Fatalf("Session creation failed: %v", err)
}

fmt.Println("Session created successfully!")

func (*Client) DestinationLookup

func (c *Client) DestinationLookup(ctx context.Context, session *Session, address string) (uint32, error)

func (*Client) DisableAllDebugging

func (c *Client) DisableAllDebugging()

DisableAllDebugging disables all debugging features.

func (*Client) DisableAutoReconnect

func (c *Client) DisableAutoReconnect()

DisableAutoReconnect disables automatic reconnection.

func (*Client) DisableBatching

func (c *Client) DisableBatching() error

DisableBatching disables message batching and stops the flush timer. Any pending messages in the queue will be flushed before disabling.

func (*Client) DisableMessageStats

func (c *Client) DisableMessageStats()

DisableMessageStats disables message statistics tracking.

func (*Client) Disconnect

func (c *Client) Disconnect()

Disconnect is deprecated. Use Close() instead. Kept for backward compatibility.

func (*Client) EnableAllDebugging

func (c *Client) EnableAllDebugging() error

EnableAllDebugging enables all debugging features on a client with default config.

func (*Client) EnableAutoReconnect

func (c *Client) EnableAutoReconnect(maxRetries int, initialBackoff time.Duration)

func (*Client) EnableBatching

func (c *Client) EnableBatching(flushTimer time.Duration, sizeThreshold int)

EnableBatching enables message batching with the specified flush timer and size threshold. flushTimer: duration to wait before flushing batch (e.g., 10ms) sizeThreshold: size in bytes to trigger immediate flush (e.g., 16KB) This starts a background goroutine that periodically flushes the output queue.

func (*Client) EnableDebugging

func (c *Client) EnableDebugging(config *DebugConfig) error

EnableDebugging enables debugging features based on the provided config.

func (*Client) EnableMessageStats

func (c *Client) EnableMessageStats()

EnableMessageStats enables message statistics tracking for diagnostic purposes. This should be enabled when troubleshooting I2CP protocol issues.

func (*Client) GetCircuitBreakerState

func (c *Client) GetCircuitBreakerState() CircuitState

GetCircuitBreakerState returns the current state of the circuit breaker. Returns CircuitClosed if circuit breaker is disabled (nil).

This allows applications to monitor circuit breaker state and implement custom behavior based on router connectivity health.

Example:

if client.GetCircuitBreakerState() == CircuitOpen {
    // Router is unreachable, wait before retrying
    time.Sleep(30 * time.Second)
}

func (*Client) GetConnectionState

func (c *Client) GetConnectionState() *ConnectionState

GetConnectionState returns the current connection state for diagnostic purposes.

func (*Client) GetMessageStats

func (c *Client) GetMessageStats() *MessageStats

GetMessageStats returns the current message statistics for diagnostic purposes. Returns nil if message statistics tracking is not enabled.

func (*Client) GetMetrics

func (c *Client) GetMetrics() MetricsCollector

GetMetrics returns the current metrics collector, or nil if disabled.

func (*Client) GetProtocolDebugger

func (c *Client) GetProtocolDebugger() *ProtocolDebugger

GetProtocolDebugger returns the protocol debugger.

func (*Client) GetStateTracker

func (c *Client) GetStateTracker() *SessionStateTracker

GetStateTracker returns the session state tracker.

func (*Client) IsAutoReconnectEnabled

func (c *Client) IsAutoReconnectEnabled() bool

IsAutoReconnectEnabled returns whether auto-reconnect is currently enabled.

func (*Client) IsBatchingEnabled

func (c *Client) IsBatchingEnabled() bool

IsBatchingEnabled returns whether message batching is currently enabled.

func (*Client) IsConnected

func (c *Client) IsConnected() bool

func (*Client) PrintDiagnostics

func (c *Client) PrintDiagnostics()

PrintDiagnostics prints a comprehensive diagnostic report to help troubleshoot I2CP issues. This is particularly useful when debugging session creation timeouts.

func (*Client) PrintFullDiagnostics

func (c *Client) PrintFullDiagnostics()

PrintFullDiagnostics prints comprehensive diagnostics including all debug info.

func (*Client) ProcessIO

func (c *Client) ProcessIO(ctx context.Context) error

ProcessIO processes pending I/O operations with context support. This method processes the output queue and receives messages from the router. It respects context cancellation and shutdown signals.

Example:

ctx, cancel := context.WithCancel(context.Background())
defer cancel()
err := client.ProcessIO(ctx)

func (*Client) ReconnectAttempts

func (c *Client) ReconnectAttempts() int

ReconnectAttempts returns the current number of reconnection attempts.

func (*Client) ResetCircuitBreaker

func (c *Client) ResetCircuitBreaker() error

ResetCircuitBreaker manually resets the circuit breaker to closed state. This is useful for manual recovery after fixing router connectivity issues.

Returns ErrClientNotInitialized if the client was not properly initialized.

Example:

// After fixing router configuration
if err := client.ResetCircuitBreaker(); err != nil {
    log.Printf("Failed to reset circuit breaker: %v", err)
}

func (*Client) RouterCapabilities

func (c *Client) RouterCapabilities() uint32

RouterCapabilities returns the router's capability flags as a bitmask. Returns 0 if the client is not initialized or not connected.

Known capability flags:

  • ROUTER_CAN_HOST_LOOKUP (1): Router supports hostname resolution (I2CP 0.9.10+)

This method is safe to call before connecting to the router, but will return meaningful data only after a successful connection.

I2CP Spec: Capabilities are determined from router version during connection.

Example:

caps := client.RouterCapabilities()
if (caps & ROUTER_CAN_HOST_LOOKUP) != 0 {
    fmt.Println("Router supports hostname lookups")
}

func (*Client) RouterDate

func (c *Client) RouterDate() uint64

RouterDate returns the router's timestamp in I2P time format (milliseconds since epoch). Returns 0 if the client is not initialized or not connected.

This timestamp is used for time synchronization and lease expiration calculations. The router date is typically close to the current system time but may differ if the router's clock is skewed.

I2CP Spec: Router date is exchanged during GetDateMessage (type 32) response.

Example:

date := client.RouterDate()
routerTime := time.Unix(int64(date/1000), int64((date%1000)*1000000))
fmt.Printf("Router time: %v\n", routerTime)

func (*Client) RouterVersion

func (c *Client) RouterVersion() Version

RouterVersion returns the I2P router's version information. Returns a zero-value Version struct if the client is not initialized or not connected.

This method is safe to call before connecting to the router, but will return meaningful data only after a successful connection (after Connect() completes).

I2CP Spec: Router version is exchanged during GetDateMessage (type 32) response.

Example:

version := client.RouterVersion()
fmt.Printf("Router version: %d.%d.%d\n", version.major, version.minor, version.micro)

func (*Client) SetMetrics

func (c *Client) SetMetrics(metrics MetricsCollector)

SetMetrics enables metrics collection with the provided collector. Pass nil to disable metrics collection. This method is safe to call on a running client.

func (*Client) SetProperty

func (c *Client) SetProperty(name, value string)

EnableAutoReconnect enables automatic reconnection with exponential backoff. When enabled, the client will automatically attempt to reconnect if the connection is lost unexpectedly (not via explicit Close()).

Parameters:

  • maxRetries: Maximum reconnection attempts (0 = infinite retries)
  • initialBackoff: Starting delay between reconnect attempts (doubles each time)

The backoff strategy uses exponential backoff capped at 5 minutes. Set maxRetries to 0 for infinite retry attempts.

Example:

// Retry indefinitely with 1 second initial backoff
client.EnableAutoReconnect(0, time.Second)

// Retry up to 5 times with 2 second initial backoff
client.EnableAutoReconnect(5, 2*time.Second)

func (*Client) SupportsHostLookup

func (c *Client) SupportsHostLookup() bool

SupportsHostLookup returns whether the router supports hostname resolution. Returns false if the client is not initialized or not connected.

Hostname lookup capability was added in I2CP protocol version 0.9.10. Applications should check this capability before calling DestinationLookup with hostname strings (non-base64 destinations).

I2CP Spec: HostLookupMessage (type 38) requires router version >= 0.9.10.

Example:

if !client.SupportsHostLookup() {
    return fmt.Errorf("router does not support hostname lookups")
}
client.DestinationLookup(ctx, session, "example.i2p")

func (*Client) SupportsMultiSession

func (c *Client) SupportsMultiSession() bool

SupportsMultiSession returns whether the router supports multi-session contexts. Returns false if the client is not initialized or not connected.

Multi-session support (primary sessions with subsessions) was added in I2CP protocol version 0.9.21. Subsessions share the tunnel pool of their primary session, enabling efficient resource usage for related services.

Applications should check this capability before creating subsessions. Attempting to create subsessions on routers that don't support this feature will result in ErrMultiSessionUnsupported errors.

I2CP Spec: Multi-session support requires router version >= 0.9.21.

Example:

if !client.SupportsMultiSession() {
    return fmt.Errorf("router does not support multi-session contexts")
}
// Safe to create subsessions

func (*Client) SupportsVersion

func (c *Client) SupportsVersion(minVersion Version) bool

SupportsVersion returns true if the connected router version is at least minVersion. Returns false if the client is not initialized or not connected.

This method should be used to check feature availability before sending version-specific messages. Per I2CP spec § Version Notes: "Clients and routers should not send messages that are unsupported by the other side"

Common version checks (use predefined Version* constants):

  • VersionFastReceive (0.9.4+): Fast receive mode
  • VersionHostLookup (0.9.11+): HostLookup/HostReply messages
  • VersionMultiSession (0.9.21+): Multi-session support
  • VersionCreateLeaseSet2 (0.9.39+): CreateLeaseSet2Message
  • VersionBlindingInfo (0.9.43+): BlindingInfoMessage
  • VersionProposal167 (0.9.66+): HostReply options mapping

Example:

if client.SupportsVersion(VersionBlindingInfo) {
    client.msgBlindingInfo(session, info, true)
} else {
    return errors.New("router does not support blinding (requires 0.9.43+)")
}

func (*Client) ValidatePerClientAuthSupport

func (c *Client) ValidatePerClientAuthSupport() error

ValidatePerClientAuthSupport checks if the router supports per-client authentication. Per-client auth requires I2CP 0.9.43+ (BlindingInfoMessage support).

type ClientCallBacks

type ClientCallBacks struct {
	// Opaque is user-defined data passed to disconnect callback.
	// Can be used to store custom context or state information.
	Opaque *interface{}

	// OnConnect is called when the client successfully connects to the I2P router.
	// This is invoked after the initial GetDate handshake completes.
	// Parameter:
	//   - client: The client that connected
	OnConnect func(*Client)

	// OnDisconnect is called when the client disconnects from the I2P router.
	// This may be triggered by network errors, router shutdown, or explicit disconnection.
	// Parameters:
	//   - client: The client that disconnected
	//   - reason: Reason for disconnection (e.g., "connection closed", "router shutdown")
	//   - opaque: User-defined data from Opaque field
	OnDisconnect func(*Client, string, *interface{})

	// OnLog is called for logging events with structured tags.
	// Allows custom log handling and integration with external logging systems.
	// Parameters:
	//   - client: The client generating the log
	//   - tags: Structured log tags (Debug, Info, Warn, Error)
	//   - message: Log message string
	OnLog func(*Client, LoggerTags, string)

	// OnBandwidthLimits is called when the router sends bandwidth limitation parameters.
	// I2CP 0.9.3+ - Enables rate limiting and traffic shaping based on router capacity.
	// Parameters:
	//   - client: The client receiving bandwidth limits
	//   - limits: Bandwidth limit parameters (inbound/outbound, burst, etc.)
	//
	// Example:
	//
	//	OnBandwidthLimits: func(c *Client, limits *BandwidthLimits) {
	//	    log.Printf("Router limits: inbound=%d, outbound=%d",
	//	               limits.RouterInbound, limits.RouterOutbound)
	//	    // Apply rate limiting using limits.ClientInbound/ClientOutbound
	//	}
	OnBandwidthLimits func(*Client, *BandwidthLimits)

	// OnHostLookupWithOptions is called when the router responds to a HostLookup request
	// that included options mapping (I2CP 0.9.66+, types 2-4).
	// This enables service record retrieval per Proposal 167.
	// Parameters:
	//   - client: The client receiving the response
	//   - requestID: Lookup request ID for correlation
	//   - destination: The resolved destination (nil if lookup failed)
	//   - options: Service record options (e.g., service ports, endpoints, metadata)
	//
	// Example:
	//
	//	OnHostLookupWithOptions: func(c *Client, reqID uint32, dest *Destination, opts map[string]string) {
	//	    if smtpPort, ok := opts["service.smtp.port"]; ok {
	//	        log.Printf("Destination has SMTP service on port %s", smtpPort)
	//	    }
	//	}
	OnHostLookupWithOptions func(*Client, uint32, *Destination, map[string]string)
}

ClientCallBacks defines callback functions for client-level events. All callbacks are optional and can be set to nil if not needed. Callbacks may be invoked from different goroutines, so implementations should be thread-safe.

Example:

callbacks := &ClientCallBacks{
    OnConnect: func(c *Client) {
        log.Println("Connected to I2P router")
    },
    OnDisconnect: func(c *Client, reason string, opaque *interface{}) {
        log.Printf("Disconnected: %s", reason)
    },
    OnBandwidthLimits: func(c *Client, limits *BandwidthLimits) {
        log.Printf("Bandwidth limits: %s", limits.String())
    },
}
client := NewClient(callbacks)

type ClientProperty

type ClientProperty int
const (
	CLIENT_PROP_ROUTER_ADDRESS ClientProperty = iota
	CLIENT_PROP_ROUTER_PORT
	CLIENT_PROP_ROUTER_USE_TLS
	CLIENT_PROP_USERNAME
	CLIENT_PROP_PASSWORD
	CLIENT_PROP_TLS_CERT_FILE
	CLIENT_PROP_TLS_KEY_FILE
	CLIENT_PROP_TLS_CA_FILE
	CLIENT_PROP_TLS_INSECURE
	NR_OF_I2CP_CLIENT_PROPERTIES
)

type ConnectionState

type ConnectionState struct {
	Connected       bool
	RouterVersion   string
	RouterDate      time.Time
	SessionsActive  int
	PrimarySessions int
	SubSessions     int
	LastError       error
	LastErrorTime   time.Time
	ConnectedSince  time.Time
}

ConnectionState represents the current state of the I2CP connection.

type CreateSessionDump

type CreateSessionDump struct {
	Timestamp       time.Time
	TotalSize       int
	DestinationSize int
	MappingSize     int
	TimestampValue  uint64
	SignatureSize   int
	HexDump         string
	FilePath        string // Path to dumped file
}

CreateSessionDump captures CreateSession message for analysis.

type Crypto

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

Crypto provides cryptographic operations for I2CP protocol message handling.

This type is an I2CP protocol adapter that coordinates cryptographic operations for I2CP messages. It maintains state required for protocol operations but delegates all actual cryptographic work to specialized packages.

Fields:

  • rng: Random number generator (crypto/rand.Reader) for protocol operations

Usage Example:

crypto := NewCrypto()
keyPair, err := crypto.Ed25519SignatureKeygen()

See Also:

  • NewCrypto(): Constructor function in crypto.go
  • Ed25519SignatureKeygen(): Ed25519 key generation
  • X25519KeyExchangeKeygen(): X25519 key exchange

func NewCrypto

func NewCrypto() *Crypto

NewCrypto creates a new Crypto instance

func NewCryptoInstance

func NewCryptoInstance() *Crypto

NewCryptoInstance creates a new crypto instance

func (*Crypto) ChaCha20Poly1305CipherKeygen

func (c *Crypto) ChaCha20Poly1305CipherKeygen() (*ChaCha20Poly1305Cipher, error)

ChaCha20Poly1305CipherKeygen generates a new ChaCha20-Poly1305 cipher

func (*Crypto) Ed25519SignatureKeygen

func (c *Crypto) Ed25519SignatureKeygen() (*Ed25519KeyPair, error)

Ed25519SignatureKeygen generates a new Ed25519 signature key pair

func (*Crypto) Random32

func (c *Crypto) Random32() uint32

Random32 generates a cryptographically secure random uint32. Used for I2CP message nonces and request IDs per protocol specification

func (*Crypto) SignatureKeygen

func (c *Crypto) SignatureKeygen(algorithmTyp uint32) (sgk SignatureKeyPair, err error)

Generate a signature keypair

func (*Crypto) WriteEd25519SignatureToStream

func (c *Crypto) WriteEd25519SignatureToStream(kp *Ed25519KeyPair, stream *Stream) error

WriteEd25519SignatureToStream writes an Ed25519 signature keypair to stream

func (*Crypto) X25519KeyExchangeKeygen

func (c *Crypto) X25519KeyExchangeKeygen() (*X25519KeyPair, error)

X25519KeyExchangeKeygen generates a new X25519 key exchange key pair

type DHAuthenticator

type DHAuthenticator struct {
	// ClientPrivateKey is the client's X25519 private key (32 bytes)
	ClientPrivateKey [32]byte

	// ServerPublicKey is the server's X25519 public key (32 bytes)
	// This is typically extracted from the blinded b32 address
	ServerPublicKey [32]byte

	// Salt is optional salt for HKDF derivation (can be nil)
	Salt []byte

	// Info is contextual info for HKDF (I2P uses "ELS2_L1K" for per-client auth)
	Info []byte
}

DHAuthenticator performs DH-based authentication for encrypted LeaseSets. It uses X25519 key exchange to derive a shared secret, then HKDF to derive the decryption key.

func NewDHAuthenticator

func NewDHAuthenticator(clientPrivateKey, serverPublicKey [32]byte) *DHAuthenticator

NewDHAuthenticator creates a new DH authenticator with the given keys. The clientPrivateKey is your X25519 private key. The serverPublicKey is extracted from the blinded destination.

func (*DHAuthenticator) Authenticate

func (d *DHAuthenticator) Authenticate() (*AuthResult, error)

Authenticate performs DH key exchange and derives the decryption key.

The process:

  1. Validate the server's public key
  2. Perform X25519 DH: sharedSecret = X25519(clientPriv, serverPub)
  3. Derive decryptionKey = HKDF-SHA256(sharedSecret, salt, info)

Returns AuthResult containing the decryption key for BlindingInfoMessage.

func (*DHAuthenticator) WithInfo

func (d *DHAuthenticator) WithInfo(info []byte) *DHAuthenticator

WithInfo sets custom info for HKDF derivation.

func (*DHAuthenticator) WithSalt

func (d *DHAuthenticator) WithSalt(salt []byte) *DHAuthenticator

WithSalt sets a custom salt for HKDF derivation.

type DebugConfig

type DebugConfig struct {
	EnableMessageStats     bool   // Enable message statistics tracking
	EnableStateTracking    bool   // Enable session state tracking
	EnableProtocolDebug    bool   // Enable protocol debugging
	DumpDirectory          string // Directory for debug dumps
	LogMessageHex          bool   // Log message hex dumps to console
	LogCreateSessionDetail bool   // Extra logging for CreateSession
}

DebugConfig holds debugging configuration options.

func DefaultDebugConfig

func DefaultDebugConfig() *DebugConfig

DefaultDebugConfig returns sensible debug defaults.

type Destination

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

func NewDestination

func NewDestination(crypto *Crypto) (dest *Destination, err error)

func NewDestinationFromBase64

func NewDestinationFromBase64(base64Str string, crypto *Crypto) (dest *Destination, err error)

func NewDestinationFromFile

func NewDestinationFromFile(file *os.File, crypto *Crypto) (*Destination, error)

func NewDestinationFromMessage

func NewDestinationFromMessage(stream *Stream, crypto *Crypto) (dest *Destination, err error)

NewDestinationFromMessage reads a destination from an I2CP message stream. NOTE: This function supports Ed25519 destinations with KEY certificates only. Legacy DSA destinations are no longer supported.

func NewDestinationFromStream

func NewDestinationFromStream(stream *Stream, crypto *Crypto) (dest *Destination, err error)

NewDestinationFromStream reads a destination from a configuration stream. This format includes the full keypair, not just public keys. NOTE: Only Ed25519 destinations with KEY certificates are supported.

func (*Destination) Base32

func (dest *Destination) Base32() string

Base32 returns the Base32 address of the destination (e.g., "abc123....xyz.b32.i2p")

func (*Destination) Base64

func (dest *Destination) Base64() string

Base64 returns the Base64 address of the destination

func (*Destination) Copy

func (dest *Destination) Copy() (newDest Destination)

func (*Destination) Hash added in v0.1.1

func (dest *Destination) Hash() [32]byte

Hash returns the SHA-256 hash of the destination's canonical wire format serialization. This matches Java I2P's Destination.calculateHash() method.

The hash is computed over the wire format (WriteToMessage):

  • pubKey: 256 bytes (encryption public key)
  • signingPubKey: 128 bytes (Ed25519 key right-aligned at bytes 96-127)
  • certificate: 7+ bytes (KEY certificate with sig/crypto type)

USE CASES:

  • Datagram2: Target destination hash for replay prevention
  • Datagram3: Sender's fromhash for repliability
  • LeaseSet addressing and lookup
  • Any protocol requiring canonical destination identification

INTEROPERABILITY: This produces the same hash as Java I2P's calculateHash(), enabling cross-implementation compatibility for datagram protocols.

Returns the 32-byte SHA-256 hash, or a zero hash if serialization fails.

func (*Destination) SigningKeyPair

func (dest *Destination) SigningKeyPair() (*Ed25519KeyPair, error)

SigningKeyPair returns the Ed25519 signing key pair for this destination. This provides access to both signing (with private key) and verification (with public key). For verification-only use cases (without private key access), use SigningPublicKey() instead.

Returns error if the destination has no Ed25519 keypair available.

func (*Destination) SigningPublicKey

func (dest *Destination) SigningPublicKey() *Ed25519KeyPair

SigningPublicKey returns the Ed25519 public key for signature verification. This allows verification of signatures without needing the private key. Returns nil if no Ed25519 keypair is available.

func (*Destination) VerifySignature

func (dest *Destination) VerifySignature(message, signature []byte) bool

VerifySignature verifies a signature against the given message using this destination's signing public key. This is useful for offline signature verification without access to the private key.

Returns true if the signature is valid, false otherwise.

func (*Destination) WriteForSignature

func (dest *Destination) WriteForSignature(stream *Stream) (err error)

WriteForSignature writes the destination in the format used by Java I2P for SIGNATURE COMPUTATION.

SIGNATURE FORMAT (295 bytes for Ed25519):

  • pubKey: 256 bytes (same as wire format)
  • signingPubKey: 32 bytes (TRUNCATED, not padded to 128 bytes)
  • certificate: 7+ bytes (same as wire format)

CRITICAL DIFFERENCE FROM WriteToMessage: When Java reads a Destination from the wire (128-byte signing key field), it extracts the actual key based on the certificate's declared sizes. When re-serializing for signature verification, Java writes the EXTRACTED key sizes, not the padded wire format.

For Ed25519:

  • Wire format (WriteToMessage): 128-byte field with 32-byte key at bytes 96-127
  • Signature format (WriteForSignature): just 32 bytes

USE THIS METHOD FOR:

  • Computing data-to-sign for datagram authentication
  • Signature verification (must match sender's computation)

DO NOT USE FOR:

  • Transmitting destinations over the network (use WriteToMessage)
  • Building datagram envelopes (use WriteToMessage)

See Java I2P: SigningPublicKey.writeTruncatedBytes() for reference implementation.

func (*Destination) WriteToFile

func (dest *Destination) WriteToFile(filename string) (err error)

func (*Destination) WriteToMessage

func (dest *Destination) WriteToMessage(stream *Stream) (err error)

WriteToMessage writes the destination in I2CP/I2NP WIRE FORMAT. This is the format used for transmitting destinations over the network and in datagram envelopes.

WIRE FORMAT (391+ bytes for Ed25519):

  • pubKey: 256 bytes (encryption public key, zeros for modern crypto)
  • signingPubKey: 128 bytes (Ed25519 key right-aligned at bytes 96-127)
  • certificate: 7+ bytes (KEY certificate with sig/crypto type)

USE THIS METHOD FOR:

  • Building datagram envelopes (sender destination in Datagram1/2/3)
  • Any I2CP message that transmits a destination over the wire
  • Hash computation for replay prevention (Datagram2)

The I2P specification says destinations are "387+ bytes" for DSA, but for Ed25519 with KEY certificates, the wire format is 391+ bytes (256 + 128 + 7). The apparent discrepancy is because DSA-SHA1 keys fit exactly in the legacy fields while Ed25519 requires padding and a KEY certificate.

See also:

  • WriteForSignature: for signature computation (different signing key format)
  • WriteToStream: for file storage (compact format, not wire-compatible)
  • NewDestinationFromMessage: reads this format

func (*Destination) WriteToStream

func (dest *Destination) WriteToStream(stream *Stream) (err error)

WriteToStream writes the destination in a COMPACT STORAGE FORMAT. This format is used for saving destinations to files (e.g., .dat files).

STORAGE FORMAT (varies):

  • certificate: 3+ bytes
  • algorithmType: 4 bytes
  • signingKeyPair: algorithm-specific size
  • encryptionPubKey: 256 bytes

This format differs from the wire format (WriteToMessage) and is NOT compatible with I2CP/I2NP message parsing. Use WriteToFile() for file operations.

USE THIS METHOD FOR:

  • Saving destinations to disk for later loading
  • Internal storage operations

DO NOT USE FOR:

  • Network transmission (use WriteToMessage)
  • Datagram envelopes (use WriteToMessage)
  • Signature computation (use WriteForSignature)

See also:

  • WriteToFile: convenience wrapper for file I/O
  • NewDestinationFromFile: reads this format

type DisconnectInfo

type DisconnectInfo struct {
	Timestamp time.Time
	Reason    string
	RawBytes  []byte
	HexDump   string
}

DisconnectInfo captures disconnect message details.

type Ed25519KeyPair

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

Ed25519KeyPair represents an Ed25519 signature key pair for modern I2P cryptography. This type wraps github.com/go-i2p/crypto/ed25519 keys to provide I2CP-specific functionality while delegating cryptographic operations to the specialized crypto package.

func Ed25519KeyPairFromStream

func Ed25519KeyPairFromStream(stream *Stream) (*Ed25519KeyPair, error)

Ed25519KeyPairFromStream reads an Ed25519 key pair from a stream. Uses github.com/go-i2p/crypto/ed25519 for key reconstruction.

func NewEd25519KeyPair

func NewEd25519KeyPair() (*Ed25519KeyPair, error)

NewEd25519KeyPair generates a new Ed25519 key pair using github.com/go-i2p/crypto. This function delegates to the crypto package for secure key generation.

func (*Ed25519KeyPair) AlgorithmType

func (kp *Ed25519KeyPair) AlgorithmType() uint32

AlgorithmType returns the algorithm type constant

func (*Ed25519KeyPair) PrivateKey

func (kp *Ed25519KeyPair) PrivateKey() ed25519.PrivateKey

PrivateKey returns the private key as stdlib ed25519.PrivateKey for backward compatibility.

func (*Ed25519KeyPair) PublicKey

func (kp *Ed25519KeyPair) PublicKey() ed25519.PublicKey

PublicKey returns the public key as stdlib ed25519.PublicKey for backward compatibility.

func (*Ed25519KeyPair) Sign

func (kp *Ed25519KeyPair) Sign(message []byte) ([]byte, error)

Sign creates a signature for the given message using Ed25519. Uses github.com/go-i2p/crypto/ed25519 Signer interface for cryptographic operations.

func (*Ed25519KeyPair) SignStream

func (kp *Ed25519KeyPair) SignStream(stream *Stream) error

SignStream creates a signature for stream data and appends it to the stream

func (*Ed25519KeyPair) Verify

func (kp *Ed25519KeyPair) Verify(message, signature []byte) bool

Verify verifies a signature against the given message using Ed25519. Uses standard Ed25519 verification which handles SHA-512 hashing internally.

func (*Ed25519KeyPair) VerifyStream

func (kp *Ed25519KeyPair) VerifyStream(stream *Stream) (bool, error)

VerifyStream verifies a signature embedded in the stream data

func (*Ed25519KeyPair) WritePublicKeyToStream

func (kp *Ed25519KeyPair) WritePublicKeyToStream(stream *Stream) error

WritePublicKeyToStream writes only the public key to a stream. Uses crypto package's Bytes() method for key serialization.

func (*Ed25519KeyPair) WriteToStream

func (kp *Ed25519KeyPair) WriteToStream(stream *Stream) error

WriteToStream writes the complete Ed25519 key pair to a stream

type InMemoryMetrics

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

InMemoryMetrics provides a simple in-memory implementation of MetricsCollector. Suitable for development, testing, and applications that want basic metrics without external dependencies.

All operations are thread-safe using atomic operations and minimal locking.

func NewInMemoryMetrics

func NewInMemoryMetrics() *InMemoryMetrics

NewInMemoryMetrics creates a new in-memory metrics collector.

func (*InMemoryMetrics) ActiveSessions

func (m *InMemoryMetrics) ActiveSessions() int

ActiveSessions returns the current count of active sessions.

func (*InMemoryMetrics) AddBytesReceived

func (m *InMemoryMetrics) AddBytesReceived(bytes uint64)

AddBytesReceived adds to the total bytes received.

func (*InMemoryMetrics) AddBytesSent

func (m *InMemoryMetrics) AddBytesSent(bytes uint64)

AddBytesSent adds to the total bytes sent.

func (*InMemoryMetrics) AllErrors

func (m *InMemoryMetrics) AllErrors() map[string]uint64

AllErrors returns a copy of all error counts by type.

func (*InMemoryMetrics) AvgLatency

func (m *InMemoryMetrics) AvgLatency(messageType uint8) time.Duration

AvgLatency returns the average latency for a message type in nanoseconds. Returns 0 if no measurements have been recorded.

func (*InMemoryMetrics) BytesReceived

func (m *InMemoryMetrics) BytesReceived() uint64

BytesReceived returns the total bytes received.

func (*InMemoryMetrics) BytesSent

func (m *InMemoryMetrics) BytesSent() uint64

BytesSent returns the total bytes sent.

func (*InMemoryMetrics) ConnectionState

func (m *InMemoryMetrics) ConnectionState() string

ConnectionState returns the current connection state.

func (*InMemoryMetrics) Errors

func (m *InMemoryMetrics) Errors(errorType string) uint64

Errors returns the total count of errors by type.

func (*InMemoryMetrics) IncrementError

func (m *InMemoryMetrics) IncrementError(errorType string)

IncrementError increments the error counter for the given error type.

func (*InMemoryMetrics) IncrementMessageReceived

func (m *InMemoryMetrics) IncrementMessageReceived(messageType uint8)

IncrementMessageReceived increments the received message counter for the given type.

func (*InMemoryMetrics) IncrementMessageSent

func (m *InMemoryMetrics) IncrementMessageSent(messageType uint8)

IncrementMessageSent increments the sent message counter for the given type.

func (*InMemoryMetrics) MaxLatency

func (m *InMemoryMetrics) MaxLatency(messageType uint8) time.Duration

MaxLatency returns the maximum latency for a message type. Returns 0 if no measurements have been recorded.

func (*InMemoryMetrics) MessagesReceived

func (m *InMemoryMetrics) MessagesReceived(messageType uint8) uint64

MessagesReceived returns the total count of received messages by type.

func (*InMemoryMetrics) MessagesSent

func (m *InMemoryMetrics) MessagesSent(messageType uint8) uint64

MessagesSent returns the total count of sent messages by type.

func (*InMemoryMetrics) MinLatency

func (m *InMemoryMetrics) MinLatency(messageType uint8) time.Duration

MinLatency returns the minimum latency for a message type. Returns 0 if no measurements have been recorded.

func (*InMemoryMetrics) RecordMessageLatency

func (m *InMemoryMetrics) RecordMessageLatency(messageType uint8, duration time.Duration)

RecordMessageLatency records the latency for a message type.

func (*InMemoryMetrics) Reset

func (m *InMemoryMetrics) Reset()

Reset clears all metrics. Useful for testing.

func (*InMemoryMetrics) SetActiveSessions

func (m *InMemoryMetrics) SetActiveSessions(count int)

SetActiveSessions updates the active sessions gauge.

func (*InMemoryMetrics) SetConnectionState

func (m *InMemoryMetrics) SetConnectionState(state string)

SetConnectionState updates the connection state.

type Lease

type Lease = lease.Lease

Lease is a type alias for lease.Lease from the common package. All lease operations (TunnelGateway, TunnelID, Time, Date, Bytes) are provided by the common package. I2CP-specific stream helpers are defined as package functions.

func NewLeaseFromStream

func NewLeaseFromStream(stream *Stream) (*Lease, error)

NewLeaseFromStream reads a Lease from an I2CP Stream. Uses common/lease.ReadLease for parsing after reading the 44-byte lease data.

type LeaseSet2

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

LeaseSet2 represents a modern I2CP LeaseSet2 structure (I2CP 0.9.38+). LeaseSet2 supports multiple types: standard (3), encrypted (5), and meta (7). It uses Lease2 structures with 4-byte second timestamps for efficiency.

I2CP Specification: CreateLeaseSet2Message (type 41), section 3.4 Reference: https://geti2p.net/spec/common-structures#leaseset2

func NewLeaseSet2FromStream

func NewLeaseSet2FromStream(stream *Stream, crypto *Crypto) (*LeaseSet2, error)

NewLeaseSet2FromStream parses a LeaseSet2 structure from an I2CP Stream. This function is called when receiving a CreateLeaseSet2Message from the router.

Stream format (all multi-byte integers in big-endian):

  • LeaseSet type (1 byte): 3=standard, 5=encrypted, 7=meta
  • Destination (387+ bytes): standard I2CP destination
  • Published timestamp (4 bytes): seconds since epoch
  • Expires timestamp (4 bytes): seconds since epoch
  • Flags (2 bytes): bit 0=offline signature present
  • Properties (variable): I2CP mapping structure
  • Lease count (1 byte): number of leases (max 16)
  • Leases (40 bytes each): Lease2 structures
  • [Optional] Offline signature (variable): if flags bit 0 set
  • Signature (variable): signature over all previous data

Parameters:

stream - I2CP Stream containing the LeaseSet2 data
crypto - Crypto instance for parsing destination

Returns:

LeaseSet2 structure and any error encountered

I2CP Spec: CreateLeaseSet2Message format, I2CP 0.9.38+

func (*LeaseSet2) Destination

func (ls *LeaseSet2) Destination() *Destination

Destination returns the destination this LeaseSet is for

func (*LeaseSet2) Expires

func (ls *LeaseSet2) Expires() time.Time

Expires returns the expiration timestamp as time.Time

func (*LeaseSet2) ExpiresSeconds

func (ls *LeaseSet2) ExpiresSeconds() uint32

ExpiresSeconds returns the expiration timestamp in seconds since epoch

func (*LeaseSet2) Flags

func (ls *LeaseSet2) Flags() uint16

Flags returns the flags field

func (*LeaseSet2) HasOfflineSignature

func (ls *LeaseSet2) HasOfflineSignature() bool

HasOfflineSignature returns true if the LeaseSet2 has an offline signature

func (*LeaseSet2) IsExpired

func (ls *LeaseSet2) IsExpired() bool

IsExpired checks if the LeaseSet2 has expired based on current time

func (*LeaseSet2) LeaseCount

func (ls *LeaseSet2) LeaseCount() int

LeaseCount returns the number of leases

func (*LeaseSet2) Leases

func (ls *LeaseSet2) Leases() []*lease.Lease2

Leases returns the array of Lease2 structures

func (*LeaseSet2) OfflineSignature

func (ls *LeaseSet2) OfflineSignature() *OfflineSignature

OfflineSignature returns the offline signature (may be nil)

func (*LeaseSet2) Properties

func (ls *LeaseSet2) Properties() map[string]string

Properties returns the properties mapping

func (*LeaseSet2) Published

func (ls *LeaseSet2) Published() time.Time

Published returns the published timestamp as time.Time

func (*LeaseSet2) PublishedSeconds

func (ls *LeaseSet2) PublishedSeconds() uint32

PublishedSeconds returns the published timestamp in seconds since epoch

func (*LeaseSet2) Signature

func (ls *LeaseSet2) Signature() []byte

Signature returns the signature bytes

func (*LeaseSet2) String

func (ls *LeaseSet2) String() string

String returns a debug-friendly string representation of the LeaseSet2

func (*LeaseSet2) Type

func (ls *LeaseSet2) Type() uint8

Type returns the LeaseSet2 type (3=standard, 5=encrypted, 7=meta)

func (*LeaseSet2) VerifySignature

func (ls *LeaseSet2) VerifySignature() bool

VerifySignature verifies the LeaseSet2 cryptographic signature. Uses the destination's signing public key to verify the signature over all LeaseSet2 data preceding the signature field.

I2CP 0.9.38+ - Supports DSA-SHA1 (legacy) and Ed25519-SHA512 (modern) signatures.

Returns true if signature is cryptographically valid, false otherwise. Basic validation (non-empty signature, correct length) is performed first.

type LeaseSetWaitInfo

type LeaseSetWaitInfo struct {
	SessionID   uint16
	StartedAt   time.Time
	Timeout     time.Duration
	Received    bool
	ReceivedAt  time.Time
	TunnelCount uint8
}

LeaseSetWaitInfo tracks waiting for RequestVariableLeaseSet message.

type LoggerTags

type LoggerTags = uint32

LoggerTags defines the type for logger tags Deprecated: Tags are now formatted as strings using fmt.Sprintf

type LookupEntry

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

LookupEntry represents a destination lookup request entry. Stores the original lookup parameters to support processing the HostReply response.

I2CP Specification:

  • Basic lookups (types 0-1): Only address/session tracked
  • Service record lookups (types 2-4): Also tracks lookupType for parsing optional Mapping

I2CP 0.9.66+ Proposal 167: Service Record Support

type MaxRetriesExceededError

type MaxRetriesExceededError struct {
	Attempts int
	LastErr  error
}

MaxRetriesExceededError is returned when the maximum number of retries is exceeded.

func (*MaxRetriesExceededError) Error

func (e *MaxRetriesExceededError) Error() string

func (*MaxRetriesExceededError) Unwrap

func (e *MaxRetriesExceededError) Unwrap() error

type MessageError

type MessageError struct {
	MessageType uint8  // I2CP message type constant
	Operation   string // What operation failed (e.g., "parsing", "sending")
	Err         error  // Underlying error
}

MessageError represents an error related to I2CP message processing. It includes the message type and additional context about what failed.

func (*MessageError) Error

func (e *MessageError) Error() string

func (*MessageError) Unwrap

func (e *MessageError) Unwrap() error

type MessageStats

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

MessageStats tracks sent and received message counts by type for diagnostic purposes. This is useful for debugging I2CP protocol interactions and identifying message flow issues.

func NewMessageStats

func NewMessageStats() *MessageStats

NewMessageStats creates a new message statistics tracker.

func (*MessageStats) DiagnosticReport

func (ms *MessageStats) DiagnosticReport() string

DiagnosticReport generates a diagnostic report for troubleshooting session creation issues. This is particularly useful when debugging "no SessionCreated response" problems.

func (*MessageStats) Disable

func (ms *MessageStats) Disable()

Disable disables message statistics tracking.

func (*MessageStats) Enable

func (ms *MessageStats) Enable()

Enable enables message statistics tracking.

func (*MessageStats) GetLastReceived

func (ms *MessageStats) GetLastReceived(msgType uint8) (time.Time, bool)

GetLastReceived returns the timestamp of the last received message of the given type.

func (*MessageStats) GetLastSent

func (ms *MessageStats) GetLastSent(msgType uint8) (time.Time, bool)

GetLastSent returns the timestamp of the last sent message of the given type.

func (*MessageStats) GetReceivedCount

func (ms *MessageStats) GetReceivedCount(msgType uint8) uint64

GetReceivedCount returns the number of received messages of the given type.

func (*MessageStats) GetSentCount

func (ms *MessageStats) GetSentCount(msgType uint8) uint64

GetSentCount returns the number of sent messages of the given type.

func (*MessageStats) IsEnabled

func (ms *MessageStats) IsEnabled() bool

IsEnabled returns whether statistics tracking is enabled.

func (*MessageStats) RecordReceived

func (ms *MessageStats) RecordReceived(msgType uint8, size uint64)

RecordReceived records a received message of the given type.

func (*MessageStats) RecordSent

func (ms *MessageStats) RecordSent(msgType uint8, size uint64)

RecordSent records a sent message of the given type.

func (*MessageStats) Reset

func (ms *MessageStats) Reset()

Reset clears all statistics.

func (*MessageStats) Summary

func (ms *MessageStats) Summary() string

Summary returns a human-readable summary of message statistics.

type MetaLease

type MetaLease struct {
	Hash    [32]byte // SHA256 hash of the target LeaseSet destination
	Flags   uint32   // 3 bytes of flags (bits 0-3 = LeaseSet type)
	Cost    uint8    // Priority cost, 0-255, lower is better
	EndDate uint32   // Expiration in seconds since epoch
}

MetaLease represents a single entry in a MetaLeaseSet. Unlike regular Lease2, MetaLease contains references to other LeaseSets rather than tunnel information.

Format (40 bytes):

  • Hash (32 bytes): SHA256 hash of the target destination/LeaseSet
  • Flags (3 bytes): bit 0-3 = type (0=unknown, 1=LeaseSet, 3=LeaseSet2, 5=MetaLeaseSet)
  • Cost (1 byte): 0-255, lower value = higher priority
  • EndDate (4 bytes): seconds since epoch

I2CP Specification: MetaLease structure

func NewMetaLease

func NewMetaLease(hash [32]byte, leaseSetType, cost uint8, endDate uint32) *MetaLease

NewMetaLease creates a new MetaLease entry with the given parameters.

Parameters:

  • hash: SHA256 hash of the target destination
  • leaseSetType: Type of LeaseSet (1=LeaseSet, 3=LeaseSet2, 5=MetaLeaseSet)
  • cost: Priority cost (0=highest priority, 255=lowest)
  • endDate: Expiration timestamp in seconds since epoch

func ReadMetaLeaseFromStream

func ReadMetaLeaseFromStream(stream *Stream) (*MetaLease, error)

ReadMetaLeaseFromStream reads a MetaLease from an I2CP stream. Returns the MetaLease and any error encountered.

func (*MetaLease) SetType

func (ml *MetaLease) SetType(leaseSetType uint8)

SetType sets the LeaseSet type in the flags field.

func (*MetaLease) Type

func (ml *MetaLease) Type() uint8

Type returns the LeaseSet type from the flags field (bits 0-3).

func (*MetaLease) WriteToStream

func (ml *MetaLease) WriteToStream(stream *Stream) error

WriteToStream writes the MetaLease to an I2CP stream in the spec format. Format: hash(32) + flags(3) + cost(1) + endDate(4) = 40 bytes

type MetaLeaseSetConfig

type MetaLeaseSetConfig struct {
	MetaLeases  []*MetaLease // References to other LeaseSets (max 16)
	Revocations [][32]byte   // Hashes of revoked LeaseSets
	Properties  map[string]string
}

MetaLeaseSetConfig holds the configuration for creating a MetaLeaseSet. Used when calling msgCreateMetaLeaseSet.

func NewMetaLeaseSetConfig

func NewMetaLeaseSetConfig() *MetaLeaseSetConfig

NewMetaLeaseSetConfig creates a new MetaLeaseSetConfig with default values.

func (*MetaLeaseSetConfig) AddMetaLease

func (c *MetaLeaseSetConfig) AddMetaLease(ml *MetaLease) error

AddMetaLease adds a MetaLease entry to the configuration. Returns an error if the maximum of 16 entries would be exceeded.

func (*MetaLeaseSetConfig) AddRevocation

func (c *MetaLeaseSetConfig) AddRevocation(hash [32]byte)

AddRevocation adds a revocation hash to the configuration.

type MetricsCollector

type MetricsCollector interface {

	// IncrementMessageSent increments the count of messages sent by type.
	// messageType should be an I2CP message type constant (e.g., I2CP_MSG_SEND_MESSAGE).
	IncrementMessageSent(messageType uint8)

	// IncrementMessageReceived increments the count of messages received by type.
	// messageType should be an I2CP message type constant (e.g., I2CP_MSG_PAYLOAD_MESSAGE).
	IncrementMessageReceived(messageType uint8)

	// SetActiveSessions updates the gauge of currently active sessions.
	SetActiveSessions(count int)

	// IncrementError increments the error counter by error type.
	// errorType should describe the error category (e.g., "network", "protocol", "timeout").
	IncrementError(errorType string)

	// RecordMessageLatency records the latency of a message send operation.
	// messageType is the I2CP message type, duration is the operation time.
	RecordMessageLatency(messageType uint8, duration time.Duration)

	// SetConnectionState updates the current connection state.
	// state should be "connected", "disconnected", or "reconnecting".
	SetConnectionState(state string)

	// AddBytesSent adds to the total bytes sent counter.
	AddBytesSent(bytes uint64)

	// AddBytesReceived adds to the total bytes received counter.
	AddBytesReceived(bytes uint64)
}

MetricsCollector defines the interface for collecting I2CP client metrics. This interface allows applications to plug in custom metrics implementations (e.g., Prometheus, StatsD, custom logging) for production monitoring.

All methods are safe for concurrent use and should be non-blocking.

type OfflineSignature

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

OfflineSignature represents offline signing data for LeaseSet2. Offline signatures allow separation of online and offline keys for enhanced security.

The offline signature proves that the long-term signing key authorized a transient key for a limited time period. This allows the long-term key to remain offline while the transient key signs LeaseSets.

Signature Format (signed data):

signingKeyType (2 bytes) || signingKeyLen (2 bytes) || signingKey (variable) ||
expires (4 bytes) || transientKeyType (2 bytes) || transientKeyLen (2 bytes) || transientKey (variable)

The signature field contains the signature over the above data, signed by the long-term key.

Validation:

  • ✅ Expiration checking via IsExpired()
  • ✅ Cryptographic verification via Verify()
  • ✅ Transient key validation via signature verification

I2CP Specification: LeaseSet2 § Offline Signatures

func (*OfflineSignature) Expires

func (os *OfflineSignature) Expires() time.Time

Expires returns the expiration timestamp as time.Time

func (*OfflineSignature) ExpiresSeconds

func (os *OfflineSignature) ExpiresSeconds() uint32

ExpiresSeconds returns the expiration timestamp in seconds since epoch

func (*OfflineSignature) GetExpires

func (sig *OfflineSignature) GetExpires() uint32

GetExpires returns the expiration timestamp (seconds since epoch)

func (*OfflineSignature) GetTransientKey

func (sig *OfflineSignature) GetTransientKey() []byte

GetTransientKey returns the transient public key bytes. This key should be used to verify the LeaseSet2 signature, not the signing key.

func (*OfflineSignature) IsExpired

func (sig *OfflineSignature) IsExpired() bool

IsExpired checks if the offline signature has expired. Returns true if the current time is past the expiration timestamp.

I2CP Spec: Offline signatures must be rejected if expired to prevent unauthorized use of transient keys beyond their authorized period.

func (*OfflineSignature) Signature

func (os *OfflineSignature) Signature() []byte

Signature returns the signature bytes

func (*OfflineSignature) SigningKey

func (os *OfflineSignature) SigningKey() []byte

SigningKey returns the signing public key

func (*OfflineSignature) SigningKeyType

func (os *OfflineSignature) SigningKeyType() uint16

SigningKeyType returns the signing key type

func (*OfflineSignature) String

func (os *OfflineSignature) String() string

String returns a debug-friendly string representation

func (*OfflineSignature) TransientKey

func (os *OfflineSignature) TransientKey() []byte

TransientKey returns the transient public signing key

func (*OfflineSignature) TransientKeyType

func (os *OfflineSignature) TransientKeyType() uint16

TransientKeyType returns the transient signing key type

func (*OfflineSignature) Verify

func (sig *OfflineSignature) Verify() error

Verify cryptographically verifies the offline signature. This validates that the long-term signing key actually authorized the transient key.

Verification process:

  1. Reconstruct signed data: signingKeyType || signingKeyLen || signingKey || expires || transientKeyType || transientKeyLen || transientKey
  2. Verify signature over this data using the signing key

Returns:

  • nil if signature is valid
  • ErrOfflineSignatureInvalid if verification fails
  • ErrUnsupportedCrypto if signature type is not supported

I2CP Spec: LeaseSet2 § Offline Signatures

type PSKAuthenticator

type PSKAuthenticator struct {
	// PreSharedKey is the 32-byte secret shared between client and server
	PreSharedKey [32]byte

	// Salt is optional salt for HKDF derivation (can be nil)
	Salt []byte

	// Info is contextual info for HKDF (I2P uses "ELS2_L1K" for per-client auth)
	Info []byte
}

PSKAuthenticator performs PSK-based authentication for encrypted LeaseSets. It uses HKDF to derive the decryption key from a pre-shared secret.

func NewPSKAuthenticator

func NewPSKAuthenticator(preSharedKey [32]byte) *PSKAuthenticator

NewPSKAuthenticator creates a new PSK authenticator with the given pre-shared key.

func (*PSKAuthenticator) Authenticate

func (p *PSKAuthenticator) Authenticate() (*AuthResult, error)

Authenticate derives the decryption key from the pre-shared key.

The process:

  1. Derive decryptionKey = HKDF-SHA256(psk, salt, info)

Returns AuthResult containing the decryption key for BlindingInfoMessage.

func (*PSKAuthenticator) WithInfo

func (p *PSKAuthenticator) WithInfo(info []byte) *PSKAuthenticator

WithInfo sets custom info for HKDF derivation.

func (*PSKAuthenticator) WithSalt

func (p *PSKAuthenticator) WithSalt(salt []byte) *PSKAuthenticator

WithSalt sets a custom salt for HKDF derivation.

type PendingMessage

type PendingMessage struct {
	Nonce       uint32               // Message nonce (unique identifier)
	Destination *Destination         // Target destination
	Protocol    uint8                // Protocol identifier
	SrcPort     uint16               // Source port
	DestPort    uint16               // Destination port
	PayloadSize uint32               // Payload size in bytes
	SentAt      time.Time            // When message was sent
	Status      SessionMessageStatus // Current delivery status (0 if pending)
	CompletedAt time.Time            // When status was received (zero if pending)
	Flags       uint16               // Message flags (for SendMessageExpires)
	Expiration  uint64               // Expiration time in seconds (0 if no expiration)
}

PendingMessage represents a message awaiting delivery status Tracks messages from SendMessage call to MessageStatus callback

type PerClientAuthConfig

type PerClientAuthConfig struct {
	// AuthScheme specifies the authentication scheme to use.
	// Use BLINDING_AUTH_SCHEME_DH (0) for Diffie-Hellman or
	// BLINDING_AUTH_SCHEME_PSK (1) for Pre-Shared Key.
	AuthScheme uint8

	// PrivateKey is the 32-byte ECIES_X25519 private key (little-endian).
	// This key is used to derive the shared secret for decrypting the LeaseSet.
	// For DH scheme: This is your X25519 private key for DH exchange.
	// For PSK scheme: This is the pre-shared secret key.
	PrivateKey [32]byte

	// LookupPassword is an optional password for encrypted LeaseSet lookup.
	// Some destinations require both per-client auth AND a lookup password.
	LookupPassword string
}

PerClientAuthConfig holds configuration for per-client authentication when accessing encrypted LeaseSets via BlindingInfoMessage.

func AuthenticateForBlindedDestination

func AuthenticateForBlindedDestination(scheme uint8, clientKey, serverPublicKey [32]byte) (*PerClientAuthConfig, error)

AuthenticateForBlindedDestination performs per-client authentication for accessing a blinded destination and returns a configured PerClientAuthConfig.

Parameters:

  • scheme: BLINDING_AUTH_SCHEME_DH (0) or BLINDING_AUTH_SCHEME_PSK (1)
  • clientKey: For DH: your X25519 private key. For PSK: the pre-shared key.
  • serverPublicKey: For DH: server's X25519 public key. For PSK: ignored.

Returns a PerClientAuthConfig ready to use with BlindingInfo.

func NewPerClientAuthDH

func NewPerClientAuthDH(privateKey []byte) (*PerClientAuthConfig, error)

NewPerClientAuthDH creates a new per-client authentication config using Diffie-Hellman key exchange. The provided private key must be 32 bytes.

Usage:

privKey := generateX25519PrivateKey() // Your X25519 private key
authConfig, err := NewPerClientAuthDH(privKey)
if err != nil {
    return err
}
blindingInfo := NewBlindingInfoWithAuth(endpoint, authConfig)
session.SendBlindingInfo(blindingInfo)

func NewPerClientAuthPSK

func NewPerClientAuthPSK(presharedKey []byte) (*PerClientAuthConfig, error)

NewPerClientAuthPSK creates a new per-client authentication config using Pre-Shared Key. The provided key must be 32 bytes.

Usage:

psk := getPresharedKey() // The pre-shared key from the destination owner
authConfig, err := NewPerClientAuthPSK(psk)
if err != nil {
    return err
}
blindingInfo := NewBlindingInfoWithAuth(endpoint, authConfig)
session.SendBlindingInfo(blindingInfo)

func (*PerClientAuthConfig) WithLookupPassword

func (c *PerClientAuthConfig) WithLookupPassword(password string) *PerClientAuthConfig

WithLookupPassword sets the optional lookup password for the auth config. Some destinations require both per-client auth AND a lookup password.

type ProtocolDebugger

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

ProtocolDebugger provides enhanced protocol debugging capabilities.

func NewProtocolDebugger

func NewProtocolDebugger() *ProtocolDebugger

NewProtocolDebugger creates a new protocol debugger.

func (*ProtocolDebugger) DiagnosticReport

func (pd *ProtocolDebugger) DiagnosticReport() string

DiagnosticReport generates a comprehensive debug report.

func (*ProtocolDebugger) Disable

func (pd *ProtocolDebugger) Disable()

Disable disables protocol debugging.

func (*ProtocolDebugger) DumpCreateSessionMessage

func (pd *ProtocolDebugger) DumpCreateSessionMessage(data []byte, destSize, mappingSize int, timestamp uint64, sigSize int)

DumpCreateSessionMessage saves a CreateSession message for analysis.

func (*ProtocolDebugger) Enable

func (pd *ProtocolDebugger) Enable()

Enable enables protocol debugging.

func (*ProtocolDebugger) GetDisconnectInfo

func (pd *ProtocolDebugger) GetDisconnectInfo() *DisconnectInfo

GetDisconnectInfo returns the last disconnect information.

func (*ProtocolDebugger) GetMessageLog

func (pd *ProtocolDebugger) GetMessageLog(limit int) []ProtocolMessage

GetMessageLog returns recent message log.

func (*ProtocolDebugger) IsEnabled

func (pd *ProtocolDebugger) IsEnabled() bool

IsEnabled returns whether debugging is enabled.

func (*ProtocolDebugger) LogMessage

func (pd *ProtocolDebugger) LogMessage(direction string, msgType uint8, size uint32, data []byte, sessionID uint16)

LogMessage records a protocol message.

func (*ProtocolDebugger) RecordDisconnect

func (pd *ProtocolDebugger) RecordDisconnect(reason string, rawBytes []byte)

RecordDisconnect records disconnect message details.

func (*ProtocolDebugger) SetDumpDir

func (pd *ProtocolDebugger) SetDumpDir(dir string)

SetDumpDir sets the directory for hex dumps.

type ProtocolError

type ProtocolError struct {
	Message string // Human-readable error description
	Code    int    // Optional error code for programmatic handling
	Fatal   bool   // Whether this error should terminate the connection
}

ProtocolError represents a protocol-level error with detailed information. Use this for serious protocol violations that may indicate bugs or attacks.

func (*ProtocolError) Error

func (e *ProtocolError) Error() string

type ProtocolMessage

type ProtocolMessage struct {
	Timestamp time.Time
	Direction string // "SENT" or "RECEIVED"
	Type      uint8
	TypeName  string
	Size      uint32
	HexDump   string // First 256 bytes as hex
	SessionID uint16 // If applicable
}

ProtocolMessage records an I2CP message for debugging.

type RetryableFunc

type RetryableFunc func() error

RetryableFunc is a function that can be retried. It should return an error implementing Temporary() for retry control.

type RouterInfo

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

RouterInfo contains information about the I2P router. Moved from: client.go

MINOR FIX: Router Version Tracking Documentation Per I2CP § Set Date (0.8.7+) and § Version Notes: The router sends its I2CP API version string in SetDateMessage, which clients should use for feature detection and compatibility checks.

Router Version Features by Release:

  • 0.8.7+: Version exchange in Get/Set Date messages
  • 0.9.4+: Fast receive mode (deprecates ReceiveMessageBegin/End)
  • 0.9.7+: RequestVariableLeaseSet (deprecates RequestLeaseSet)
  • 0.9.11+: HostLookup/HostReply with session IDs (deprecates DestLookup/DestReply)
  • 0.9.21+: Enhanced bandwidth limits, session reconfiguration
  • 0.9.38+: ECIES-X25519 encryption support
  • 0.9.46+: BlindingInfoMessage, offline signature keys
  • 0.9.56+: MetaLeaseSet support

The Client uses router.version for automatic feature detection:

  • HostLookup vs DestLookup selection (0.9.11+ check)
  • Authentication method validation (0.9.46+ for auth 3-4)
  • Bandwidth limits interpretation (0.9.21+ enhanced features)

This enables graceful degradation when connecting to older routers and prevents use of unsupported features that would cause protocol errors.

type Session

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

Session represents an I2CP session with modern concurrency and lifecycle management per I2CP specification - supports primary/subsession relationships and proper resource cleanup

func NewSession

func NewSession(client *Client, callbacks SessionCallbacks) *Session

NewSession creates a new I2CP session with the specified client and callbacks per I2CP specification - creates session with proper initialization and error handling This is the exported version of the session constructor for public API usage

func NewSessionWithContext

func NewSessionWithContext(ctx context.Context, client *Client, callbacks SessionCallbacks) (*Session, error)

NewSessionWithContext creates a new I2CP session with context support for timeout control per I2CP specification 0.9.21+ - supports multi-session contexts and cancellation

func (*Session) BlindingFlags

func (session *Session) BlindingFlags() uint16

BlindingFlags returns the current blinding flags per I2CP specification 0.9.43+

func (*Session) BlindingParams

func (session *Session) BlindingParams() []byte

BlindingParams returns a copy of the current blinding parameters per I2CP specification 0.9.43+ - returns nil if no parameters set

func (*Session) BlindingScheme

func (session *Session) BlindingScheme() uint16

BlindingScheme returns the current blinding cryptographic scheme per I2CP specification 0.9.43+ - returns 0 if blinding is disabled

func (*Session) ClearBlinding

func (session *Session) ClearBlinding()

ClearBlinding clears all blinding parameters per I2CP specification 0.9.43+ - resets to non-blinded state

func (*Session) ClearPendingMessages

func (session *Session) ClearPendingMessages() int

ClearPendingMessages removes all pending messages per I2CP specification - called on session close or reset Returns the number of messages that were pending

func (*Session) Close

func (session *Session) Close() error

Close gracefully closes the session and releases resources per I2CP specification - implements proper session lifecycle management with cleanup Sends DestroySession message to router and waits for cleanup completion

func (*Session) ClosedAt

func (session *Session) ClosedAt() time.Time

ClosedAt returns the session closure time (zero if not closed)

func (*Session) CompleteMessage

func (session *Session) CompleteMessage(nonce uint32, status SessionMessageStatus) (*PendingMessage, bool)

CompleteMessage marks a message as completed with the given status per I2CP specification - called when MessageStatusMessage (type 22) is received Returns the pending message and true if found, nil and false otherwise

func (*Session) Config

func (session *Session) Config() *SessionConfig

Config returns the session's configuration. Returns nil if the session was not properly initialized.

The returned SessionConfig contains tunnel settings, cryptographic options, and the destination identity for this session.

I2CP Spec: Session configuration is sent during CreateSessionMessage (type 1).

Example:

config := session.Config()
if config != nil {
    fmt.Printf("Session destination: %s\n", config.destination.Base64())
}

func (*Session) CreateMetaLeaseSet

func (s *Session) CreateMetaLeaseSet(config *MetaLeaseSetConfig) error

CreateMetaLeaseSet creates and sends a MetaLeaseSet for this session. This allows the session's destination to act as an aggregation point for multiple other destinations.

Parameters:

  • config: MetaLeaseSetConfig containing the MetaLease entries

Returns an error if the session is not connected or if sending fails.

func (*Session) CreateMetaLeaseSetQueued

func (s *Session) CreateMetaLeaseSetQueued(config *MetaLeaseSetConfig) error

CreateMetaLeaseSetQueued creates a MetaLeaseSet and queues it for sending. Use this when not yet connected to the router.

func (*Session) CreatedAt

func (session *Session) CreatedAt() time.Time

CreatedAt returns the session creation time

func (*Session) DeriveBlindingKeysForDestination

func (s *Session) DeriveBlindingKeysForDestination(date string) (*BlindingKeyDerivation, error)

DeriveBlindingKeysForDestination derives blinding keys for this session's destination. This is used by services to create blinded versions of their destination for publication.

The secret is derived from the session's signing key pair seed.

Parameters:

  • date: Date in "YYYY-MM-DD" format (or empty for today)

Returns:

  • BlindingKeyDerivation with alpha and blinded keys
  • Error if session has no destination or derivation fails

func (*Session) Destination

func (session *Session) Destination() *Destination

Destination returns the session's destination per I2CP specification - provides access to session destination for addressing

func (*Session) GetPendingMessage

func (session *Session) GetPendingMessage(nonce uint32) (*PendingMessage, bool)

GetPendingMessage returns a pending message by nonce without completing it per I2CP specification - used for status queries and debugging Returns the pending message and true if found, nil and false otherwise

func (*Session) GetPendingMessages

func (session *Session) GetPendingMessages() map[uint32]*PendingMessage

GetPendingMessages returns a snapshot of all pending messages per I2CP specification - used for monitoring and cleanup Returns a copy of the pending messages map to prevent external modification

func (*Session) GetProperty

func (session *Session) GetProperty(prop SessionConfigProperty) string

GetProperty returns the value of a specific session configuration property. Returns an empty string if the session is not properly initialized or the property is not set.

Available properties include tunnel configuration (quantity, length, variance), cryptographic options (tagsToSend, lowTagThreshold), and I2CP protocol settings (fastReceive, gzip, messageReliability).

See SessionConfigProperty constants for the full list of available properties.

I2CP Spec: Session properties are sent as a mapping in CreateSessionMessage (type 1).

Example:

fastReceive := session.GetProperty(SESSION_CONFIG_PROP_I2CP_FAST_RECEIVE)
if fastReceive == "true" {
    fmt.Println("Fast receive mode enabled")
}

nickname := session.GetProperty(SESSION_CONFIG_PROP_INBOUND_NICKNAME)
fmt.Printf("Inbound tunnel nickname: %s\n", nickname)

func (*Session) GetTunnelLength

func (session *Session) GetTunnelLength(inbound bool) int

GetTunnelLength returns the hop count (length) for tunnels in this session. The inbound parameter determines which direction: true for inbound, false for outbound. Returns 0 if the session is not properly initialized or the property is not set.

Tunnel length affects anonymity and latency:

  • Higher values (3+): Stronger anonymity, higher latency
  • Lower values (1-2): Lower latency, weaker anonymity
  • Default (from client properties): 3 hops for strong anonymity

I2CP Spec: Tunnel configuration is part of session properties mapping.

Example:

inboundLength := session.GetTunnelLength(true)
outboundLength := session.GetTunnelLength(false)
fmt.Printf("Tunnel lengths: %d inbound hops, %d outbound hops\n",
    inboundLength, outboundLength)

func (*Session) GetTunnelQuantity

func (session *Session) GetTunnelQuantity(inbound bool) int

GetTunnelQuantity returns the number of tunnels configured for this session. The inbound parameter determines which direction: true for inbound, false for outbound. Returns 0 if the session is not properly initialized or the property is not set.

Tunnel quantity affects anonymity and performance:

  • Higher values (3-5): Better anonymity and reliability, more overhead
  • Lower values (1-2): Lower latency, less anonymity
  • Default (from client properties): 3 tunnels for balanced anonymity/performance

I2CP Spec: Tunnel configuration is part of session properties mapping.

Example:

inboundCount := session.GetTunnelQuantity(true)
outboundCount := session.GetTunnelQuantity(false)
fmt.Printf("Tunnels: %d inbound, %d outbound\n", inboundCount, outboundCount)

func (*Session) ID

func (session *Session) ID() uint16

ID returns the session ID assigned by the router per I2CP specification - unique identifier for session within I2CP connection

func (*Session) IsBlindingEnabled

func (session *Session) IsBlindingEnabled() bool

IsBlindingEnabled returns true if blinding is currently enabled per I2CP specification 0.9.43+ - checks if scheme is non-zero

func (*Session) IsClosed

func (session *Session) IsClosed() bool

IsClosed returns whether the session has been closed

func (*Session) IsOffline added in v0.1.1

func (session *Session) IsOffline() bool

IsOffline returns true if this session uses offline keys (LS2 offline signing). per I2CP specification § SessionConfig - Offline Signatures

Sessions with offline keys have a transient signing key that is time-limited, while the master signing key remains offline (not accessible to the I2CP client).

IMPORTANT: Datagram1 (protocol 17) does NOT support offline signatures. If this method returns true, applications should use Datagram2 (protocol 19) instead of Datagram1 for repliable authenticated datagrams.

The Java reference implementation (I2PDatagramMaker.java) throws IllegalArgumentException if session.isOffline() returns true when attempting to create Datagram1 messages.

Example usage:

if session.IsOffline() {
    // Use Datagram2 for repliable authenticated datagrams
    protocol = go_i2cp.ProtoDatagram2
} else {
    // Use Datagram1 (traditional repliable datagram)
    protocol = go_i2cp.ProtoDatagram
}

func (*Session) IsPrimary

func (session *Session) IsPrimary() bool

IsPrimary returns whether this is a primary session or subsession per I2CP specification 0.9.21+ - primary sessions own tunnel pools, subsessions share them

func (*Session) LookupDestination

func (session *Session) LookupDestination(address string, timeout time.Duration) error

LookupDestination initiates an asynchronous destination lookup using HostLookupMessage per I2CP specification 0.9.11+ - implements destination and hostname resolution. The resolved destination is delivered via the OnDestination callback; this method only returns an error if the request itself cannot be sent.

func (*Session) LookupDestinationWithContext

func (session *Session) LookupDestinationWithContext(ctx context.Context, address string, timeout time.Duration) error

LookupDestinationWithContext initiates an asynchronous destination lookup with context support per I2CP specification 0.9.11+ - implements context-aware destination resolution. The resolved destination is delivered via the OnDestination callback.

func (*Session) PendingMessageCount

func (session *Session) PendingMessageCount() int

PendingMessageCount returns the number of messages awaiting status per I2CP specification - used for monitoring queue depth

func (*Session) PrimarySession

func (session *Session) PrimarySession() *Session

PrimarySession returns the primary session for this subsession per I2CP specification 0.9.21+ - subsessions reference their primary for tunnel sharing

func (*Session) ReconfigureSession

func (session *Session) ReconfigureSession(properties map[string]string) error

ReconfigureSession updates session configuration with new properties per I2CP specification section 7.1 - supports dynamic tunnel and crypto parameter updates Returns error if reconfiguration fails or properties are invalid

func (*Session) ReconfigureSessionWithContext

func (session *Session) ReconfigureSessionWithContext(ctx context.Context, properties map[string]string) error

ReconfigureSessionWithContext updates session configuration with context support per I2CP specification section 7.1 - implements context-aware reconfiguration with timeout

func (*Session) SendBlindingInfo

func (session *Session) SendBlindingInfo(info *BlindingInfo) error

SendBlindingInfo is a convenience method on Session to send blinding info for a destination. This is the primary API for applications to use when messaging blinded destinations.

Example usage:

info := &go_i2cp.BlindingInfo{
    EndpointType:   go_i2cp.BLINDING_ENDPOINT_HASH,
    Endpoint:       destHash[:],
    BlindedSigType: 11, // Ed25519-SHA512
    Expiration:     uint32(time.Now().Add(24*time.Hour).Unix()),
    LookupPassword: "optional-secret",
}
err := session.SendBlindingInfo(info)

func (*Session) SendBlindingInfoForHash

func (s *Session) SendBlindingInfoForHash(
	hash []byte,
	blindedSigType uint16,
	expiration uint32,
	authConfig *PerClientAuthConfig,
) error

SendBlindingInfoForHash is a convenience method to send BlindingInfo for a hash endpoint.

func (*Session) SendBlindingInfoForHostname

func (s *Session) SendBlindingInfoForHostname(
	hostname string,
	blindedSigType uint16,
	expiration uint32,
	authConfig *PerClientAuthConfig,
) error

SendBlindingInfoForHostname is a convenience method to send BlindingInfo for a hostname.

func (*Session) SendBlindingInfoWithAuth

func (s *Session) SendBlindingInfoWithAuth(
	endpointType uint8,
	endpoint []byte,
	blindedSigType uint16,
	expiration uint32,
	authConfig *PerClientAuthConfig,
) error

SendBlindingInfoWithAuth is a convenience method to send BlindingInfo with per-client auth. It creates the BlindingInfo, configures auth, and sends it to the router.

Parameters:

  • endpointType: BLINDING_ENDPOINT_HASH, BLINDING_ENDPOINT_HOSTNAME, etc.
  • endpoint: The endpoint data (hash, hostname, destination bytes, or sigkey)
  • blindedSigType: The signature type used for blinding
  • expiration: Expiration time in seconds since epoch
  • authConfig: Per-client authentication configuration (can be nil)

func (*Session) SendMessage

func (session *Session) SendMessage(destination *Destination, protocol uint8, srcPort, destPort uint16, payload *Stream, nonce uint32) error

SendMessage sends a basic message without expiration control per I2CP specification - implements basic message delivery via SendMessageMessage (type 5)

func (*Session) SendMessageExpires

func (session *Session) SendMessageExpires(dest *Destination, protocol uint8, srcPort, destPort uint16, payload *Stream, flags uint16, expirationSeconds uint64) error

SendMessageExpires sends a message with expiration time and flags for delivery options per I2CP specification 0.7.1+ - implements SendMessageExpiresMessage (type 36) for enhanced delivery control Supports per-message reliability override and tag management

func (*Session) SendMessageExpiresWithContext

func (session *Session) SendMessageExpiresWithContext(ctx context.Context, dest *Destination, protocol uint8, srcPort, destPort uint16, payload *Stream, flags uint16, expirationSeconds uint64) error

SendMessageExpiresWithContext sends an expiring message with context support per I2CP specification 0.7.1+ - implements context-aware expiring message delivery

func (*Session) SendMessageWithContext

func (session *Session) SendMessageWithContext(ctx context.Context, destination *Destination, protocol uint8, srcPort, destPort uint16, payload *Stream, nonce uint32) error

SendMessageWithContext sends a message with context support for timeout control per I2CP specification - implements context-aware message delivery with cancellation

func (*Session) SessionID

func (session *Session) SessionID() uint16

SessionID returns the session ID assigned by the router per I2CP specification - unique identifier for session within I2CP connection This is an idiomatic alias for ID() following Go naming conventions

func (*Session) SetBlindingFlags

func (session *Session) SetBlindingFlags(flags uint16)

SetBlindingFlags sets the blinding flags per I2CP specification 0.9.43+

func (*Session) SetBlindingParams

func (session *Session) SetBlindingParams(params []byte)

SetBlindingParams sets the blinding parameters per I2CP specification 0.9.43+ - stores a copy of the provided data

func (*Session) SetBlindingScheme

func (session *Session) SetBlindingScheme(scheme uint16)

SetBlindingScheme sets the blinding cryptographic scheme per I2CP specification 0.9.43+ - use 0 to disable blinding

func (*Session) SetID

func (session *Session) SetID(id uint16)

SetID sets the session ID (internal use only) per I2CP specification - called by client when session is created by router

func (*Session) SetPrimary

func (session *Session) SetPrimary(isPrimary bool)

SetPrimary sets the primary session flag (internal use only) per I2CP specification 0.9.21+ - used for multi-session support

func (*Session) SetPrimarySession

func (session *Session) SetPrimarySession(primary *Session) error

SetPrimarySession sets the primary session reference (internal use only) per I2CP specification 0.9.21+ - links subsession to primary for resource sharing

func (*Session) SigningKeyPair

func (session *Session) SigningKeyPair() (*Ed25519KeyPair, error)

SigningKeyPair returns the Ed25519 key pair used for this session. Returns the key pair that corresponds to the session's destination. This key pair is used to sign I2P Streaming Protocol packets and other cryptographic operations requiring the session's signing key.

Returns:

  • *Ed25519KeyPair: The signing key pair if available
  • error: ErrSessionNotInitialized if session not properly initialized, or an error describing why the key pair is unavailable

Example usage for packet signing:

keyPair, err := session.SigningKeyPair()
if err != nil {
    return err
}
signature, err := keyPair.Sign(packetData)

func (*Session) StoreBlindingInfo

func (s *Session) StoreBlindingInfo(scheme, flags uint16, params []byte)

StoreBlindingInfo stores received blinding parameters in the session. This is called when the router sends BlindingInfoMessage to provide parameters for accessing an encrypted LeaseSet.

The stored parameters can be retrieved with BlindingParams() and used for key derivation with DeriveBlindingFactor.

func (*Session) TrackMessage

func (session *Session) TrackMessage(nonce uint32, dest *Destination, protocol uint8, srcPort, destPort uint16, payloadSize uint32, flags uint16, expiration uint64) error

TrackMessage registers a message for delivery tracking per I2CP specification - tracks messages from send to status callback (type 22) Returns error if nonce is already being tracked

func (*Session) TransientSigningKeyPair added in v0.1.1

func (session *Session) TransientSigningKeyPair() (*Ed25519KeyPair, error)

TransientSigningKeyPair returns the transient Ed25519 signing key pair for offline sessions. This is used for signing Datagram2 payloads when the session uses offline keys.

Per I2P Proposal 163 (Datagram2), offline signature block construction requires:

  • Authorization: Sign(expires||sigtype||transient_pubkey) with destination key
  • Payload: Sign(target_hash||flags||options||offline_sig||payload) with transient key

This method returns the transient key pair needed for the payload signature. Use SigningKeyPair() to get the destination key for authorization signatures.

Returns:

  • The transient Ed25519 key pair if offline signing is configured
  • Error if session is not offline or no transient key pair is configured

Example usage for Datagram2 offline signature construction:

if session.IsOffline() {
    transientKP, err := session.TransientSigningKeyPair()
    if err != nil {
        return err
    }
    payloadSig, err := transientKP.Sign(payloadData)
}

func (*Session) ValidateProtocol added in v0.1.1

func (session *Session) ValidateProtocol(protocol uint8) error

ValidateProtocol checks if the given protocol is compatible with this session's configuration. Returns an error if the protocol cannot be used with this session.

Currently validates:

  • ProtoDatagram (17) is not used with offline-signed sessions

This provides a clear error message instead of cryptographic failures when users attempt incompatible protocol/session combinations.

type SessionCallbacks

type SessionCallbacks struct {
	// OnMessage is called when a message is received from another I2P destination.
	// Parameters:
	//   - session: The session that received the message
	//   - srcDest: Source I2P destination that sent the message
	//   - protocol: Protocol number (application-defined)
	//   - srcPort: Source port (application-defined)
	//   - destPort: Destination port (application-defined)
	//   - payload: Message payload as a Stream (can be read with ReadUint*/ReadBytes methods)
	OnMessage func(session *Session, srcDest *Destination, protocol uint8, srcPort, destPort uint16, payload *Stream)

	// OnStatus is called when the session status changes.
	// Parameters:
	//   - session: The session whose status changed
	//   - status: New session status (e.g., SessionCreated, SessionDestroyed)
	OnStatus func(session *Session, status SessionStatus)

	// OnDestination is called when a destination lookup completes.
	// Parameters:
	//   - session: The session that requested the lookup
	//   - requestId: Request identifier from the original lookup call
	//   - address: Destination address that was looked up (Base32 or Base64)
	//   - dest: Resolved destination, or nil if lookup failed
	OnDestination func(session *Session, requestId uint32, address string, dest *Destination)

	// OnMessageStatus is called when a sent message's delivery status is updated.
	// Useful for tracking message delivery and implementing reliable messaging.
	// Parameters:
	//   - session: The session that sent the message
	//   - messageId: Message nonce/identifier from SendMessage
	//   - status: Delivery status (e.g., SendSuccess, SendFailure)
	//   - size: Message size in bytes
	//   - nonce: Message nonce (same as messageId)
	OnMessageStatus func(session *Session, messageId uint32, status SessionMessageStatus, size, nonce uint32)

	// OnLeaseSet2 is called when the router requests LeaseSet publication via RequestVariableLeaseSetMessage.
	// I2CP 0.9.38+ - The router provides lease information; the client creates and publishes the LeaseSet2.
	// Note: This is NOT triggered when receiving a remote destination's LeaseSet - use DestLookup for that.
	// Parameters:
	//   - session: The session that received the LeaseSet request
	//   - leaseSet: The LeaseSet2 structure with destination, leases, and signature to publish
	//
	// Example:
	//
	//	OnLeaseSet2: func(sess *Session, ls *LeaseSet2) {
	//	    log.Printf("LeaseSet2: type=%d, expires=%s", ls.Type(), ls.Expires())
	//	    if ls.IsExpired() {
	//	        log.Println("WARNING: LeaseSet expired")
	//	    }
	//	}
	OnLeaseSet2 func(session *Session, leaseSet *LeaseSet2)

	// OnBlindingInfo is called when the router provides blinding information for encrypted LeaseSet access.
	// I2CP 0.9.43+ - Used for password-protected or key-protected destinations.
	// Parameters:
	//   - session: The session that received blinding info
	//   - blindingScheme: Authentication scheme (0=DH, 1=PSK)
	//   - blindingFlags: Flags indicating required authentication
	//   - blindingParams: Blinding parameters (store securely for future access)
	//
	// Important: Store blindingParams securely - they're required to access encrypted destinations.
	//
	// Example:
	//
	//	OnBlindingInfo: func(sess *Session, scheme, flags uint16, params []byte) {
	//	    log.Printf("Blinding enabled: scheme=%d, flags=%d", scheme, flags)
	//	    // Store params securely for future connections
	//	    if err := storeBlindingParams(params); err != nil {
	//	        log.Printf("Failed to store blinding params: %v", err)
	//	    }
	//	}
	OnBlindingInfo func(session *Session, blindingScheme, blindingFlags uint16, blindingParams []byte)

	// OnMetaLeaseSet is called when a send attempt fails because the destination uses a MetaLeaseSet.
	// I2CP 0.9.41+ (MessageStatus code 22) - Indicates multi-homed destination requiring resolution.
	// Parameters:
	//   - session: The session that attempted to send
	//   - originalDest: The MetaLeaseSet destination that was targeted
	//   - messageNonce: Nonce of the failed message (for retry tracking)
	//
	// Recovery procedure:
	//  1. Call session.LookupDestination() with the originalDest hash to retrieve MetaLeaseSet contents
	//  2. Parse the MetaLeaseSet to extract available destination hashes
	//  3. Select one hash (application logic - e.g., random, round-robin, or preference-based)
	//  4. Retry SendMessage using the selected destination hash
	//
	// Example:
	//
	//	OnMetaLeaseSet: func(sess *Session, dest *Destination, nonce uint32) {
	//	    log.Printf("Destination is MetaLeaseSet, resolving...")
	//	    // Request MetaLeaseSet contents via HostLookup
	//	    sess.LookupDestination(dest.Base64())
	//	    // In OnDestination callback, parse meta and select actual destination
	//	}
	OnMetaLeaseSet func(session *Session, originalDest *Destination, messageNonce uint32)
}

SessionCallbacks provides callback functions for session events. All callbacks are optional and can be set to nil if not needed. Callbacks may be invoked concurrently, so implementations should be thread-safe.

Example:

callbacks := SessionCallbacks{
    OnMessage: func(sess *Session, proto uint8, src, dest uint16, payload *Stream) {
        log.Printf("Received message: protocol=%d, ports=%d->%d", proto, src, dest)
    },
    OnMessageStatus: func(sess *Session, msgId uint32, status SessionMessageStatus, size, nonce uint32) {
        log.Printf("Message %d status: %v", msgId, status)
    },
}
session := NewSession(client, callbacks)

type SessionConfig

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

func NewSessionConfig

func NewSessionConfig() (*SessionConfig, error)

NewSessionConfig creates a new SessionConfig with auto-generated destination. This is the simplest way to create a session configuration without loading from a file. The destination is created using standard cryptography (currently Ed25519 by default).

Example:

config := NewSessionConfig()
// config is ready to use with default settings

If you need to load a destination from a file, use NewSessionConfigFromDestinationFile instead.

func NewSessionConfigFromDestinationFile

func NewSessionConfigFromDestinationFile(filename string, crypto *Crypto) (config SessionConfig)

func (*SessionConfig) GetOfflineSignatureBytes

func (config *SessionConfig) GetOfflineSignatureBytes() []byte

GetOfflineSignatureBytes returns the offline signature bytes. Returns nil if offline signing is not configured or the signature is invalid.

func (*SessionConfig) GetOfflineSignatureExpiration

func (config *SessionConfig) GetOfflineSignatureExpiration() uint32

GetOfflineSignatureExpiration returns the offline signature expiration timestamp. Returns 0 if offline signing is not configured.

func (*SessionConfig) GetOfflineSignatureTransientKey

func (config *SessionConfig) GetOfflineSignatureTransientKey() []byte

GetOfflineSignatureTransientKey returns the transient public key for offline signing. Returns nil if offline signing is not configured or the key is invalid.

func (*SessionConfig) GetProperty

func (config *SessionConfig) GetProperty(prop SessionConfigProperty) string

func (*SessionConfig) GetTransientKeyPair added in v0.1.1

func (config *SessionConfig) GetTransientKeyPair() *Ed25519KeyPair

GetTransientKeyPair returns the transient signing key pair for offline sessions. Returns nil if no transient key pair has been configured.

This method provides access to the transient private key needed for signing Datagram2 payloads when the session is offline (IsOffline() returns true).

func (*SessionConfig) HasOfflineSignature

func (config *SessionConfig) HasOfflineSignature() bool

HasOfflineSignature returns true if the session is configured for offline-signed operation. Per I2CP § SessionConfig - Offline Signatures, all three properties must be set.

func (*SessionConfig) SetOfflineSignature

func (config *SessionConfig) SetOfflineSignature(expiration uint32, transientPublicKey, signature []byte) error

SetOfflineSignature configures the session for offline-signed destination operation. Per I2CP § SessionConfig - Offline Signatures: "If the Destination is offline signed, the Mapping must contain:

  • i2cp.leaseSetOfflineExpiration
  • i2cp.leaseSetTransientPublicKey
  • i2cp.leaseSetOfflineSignature"

Parameters:

  • expiration: Unix timestamp in seconds when the offline signature expires
  • transientPublicKey: The transient signing public key (raw bytes, will be base64 encoded)
  • signature: The offline signature (raw bytes, will be base64 encoded)

The signature is generated by signing [signingKeyType||signingKey||expires||transientKeyType||transientKey] with the long-term signing private key. The session then uses the transient private key for all subsequent signatures (e.g., LeaseSet signing).

This enables enhanced security by keeping the long-term private key offline and only using a time-limited transient key for active operations.

func (*SessionConfig) SetProperty

func (config *SessionConfig) SetProperty(prop SessionConfigProperty, value string)

func (*SessionConfig) SetTransientKeyPair added in v0.1.1

func (config *SessionConfig) SetTransientKeyPair(keyPair *Ed25519KeyPair) error

SetTransientKeyPair sets the transient signing key pair for offline-signed sessions. This key pair is used for Datagram2 payload signing when the session is offline.

The transient key pair should be generated separately and the public key should also be passed to SetOfflineSignature() along with the authorization signature.

Per I2P Proposal 163 (Datagram2), offline signature block construction requires:

  • Authorization: Sign(expires||sigtype||transient_pubkey) with destination key
  • Payload: Sign(target_hash||flags||options||offline_sig||payload) with transient key

This method stores the transient private key needed for the payload signature. Returns an error if the key pair is nil.

func (*SessionConfig) ValidateOfflineSignature

func (config *SessionConfig) ValidateOfflineSignature() error

ValidateOfflineSignature validates the offline signature configuration. Per I2CP § SessionConfig - Offline Signatures, all three properties must be set together.

This function validates:

  • All three properties are set (or none are set)
  • The expiration timestamp is not in the past
  • The transient public key and signature are valid base64

Returns nil if the configuration is valid or if offline signing is not configured.

func (*SessionConfig) ValidateTimestamp

func (config *SessionConfig) ValidateTimestamp() error

ValidateTimestamp validates that the session config timestamp is within ±30 seconds of the current time, as required by the I2CP specification.

Per I2CP § SessionConfig Notes: "The creation date must be within +/- 30 seconds of the current time when processed by the router, or the config will be rejected."

This validation should be called before sending CreateSessionMessage to ensure early detection of clock synchronization issues.

type SessionConfigProperty

type SessionConfigProperty int
const (
	SESSION_CONFIG_PROP_CRYPTO_LOW_TAG_THRESHOLD SessionConfigProperty = iota
	SESSION_CONFIG_PROP_CRYPTO_TAGS_TO_SEND

	SESSION_CONFIG_PROP_I2CP_DONT_PUBLISH_LEASE_SET
	SESSION_CONFIG_PROP_I2CP_FAST_RECEIVE
	SESSION_CONFIG_PROP_I2CP_GZIP
	SESSION_CONFIG_PROP_I2CP_LEASESET_ENC_TYPE
	SESSION_CONFIG_PROP_I2CP_MESSAGE_RELIABILITY
	SESSION_CONFIG_PROP_I2CP_PASSWORD
	SESSION_CONFIG_PROP_I2CP_USERNAME

	// Offline Signature Properties (I2CP § SessionConfig - Offline Signatures)
	// These three properties must ALL be set together if the Destination uses offline signing.
	// Per SPEC.md: "If the Destination is offline signed, the Mapping must contain:
	//   - i2cp.leaseSetOfflineExpiration
	//   - i2cp.leaseSetTransientPublicKey
	//   - i2cp.leaseSetOfflineSignature"
	SESSION_CONFIG_PROP_I2CP_LEASESET_OFFLINE_EXPIRATION   // Unix timestamp in seconds when offline signature expires
	SESSION_CONFIG_PROP_I2CP_LEASESET_TRANSIENT_PUBLIC_KEY // Base64-encoded transient signing public key
	SESSION_CONFIG_PROP_I2CP_LEASESET_OFFLINE_SIGNATURE    // Base64-encoded offline signature

	SESSION_CONFIG_PROP_INBOUND_ALLOW_ZERO_HOP
	SESSION_CONFIG_PROP_INBOUND_BACKUP_QUANTITY
	SESSION_CONFIG_PROP_INBOUND_IP_RESTRICTION
	SESSION_CONFIG_PROP_INBOUND_LENGTH
	SESSION_CONFIG_PROP_INBOUND_LENGTH_VARIANCE
	SESSION_CONFIG_PROP_INBOUND_NICKNAME
	SESSION_CONFIG_PROP_INBOUND_QUANTITY

	SESSION_CONFIG_PROP_OUTBOUND_ALLOW_ZERO_HOP
	SESSION_CONFIG_PROP_OUTBOUND_BACKUP_QUANTITY
	SESSION_CONFIG_PROP_OUTBOUND_IP_RESTRICTION
	SESSION_CONFIG_PROP_OUTBOUND_LENGTH
	SESSION_CONFIG_PROP_OUTBOUND_LENGTH_VARIANCE
	SESSION_CONFIG_PROP_OUTBOUND_NICKNAME
	SESSION_CONFIG_PROP_OUTBOUND_PRIORITY
	SESSION_CONFIG_PROP_OUTBOUND_QUANTITY

	NR_OF_SESSION_CONFIG_PROPERTIES
)

type SessionError

type SessionError struct {
	SessionID uint16 // I2CP session ID (2-byte integer)
	Operation string // What operation failed
	Err       error  // Underlying error
}

SessionError represents an error related to session operations. It includes the session ID for debugging and tracing.

func (*SessionError) Error

func (e *SessionError) Error() string

func (*SessionError) Unwrap

func (e *SessionError) Unwrap() error

type SessionMessageStatus

type SessionMessageStatus = uint8

Legacy type alias for backward compatibility DEPRECATED: Use uint8 MSG_STATUS_* constants directly

type SessionState

type SessionState uint8

SessionState represents the lifecycle state of an I2CP session. This helps diagnose where in the protocol flow issues occur.

const (
	// SessionStatePending - CreateSession sent, awaiting response
	SessionStatePending SessionState = iota
	// SessionStateCreated - SessionStatus received with CREATED status
	SessionStateCreated
	// SessionStateAwaitingLeaseSet - Waiting for RequestVariableLeaseSet from router
	SessionStateAwaitingLeaseSet
	// SessionStateLeaseSetRequested - Router requested LeaseSet (type 37 received)
	SessionStateLeaseSetRequested
	// SessionStateLeaseSetSent - CreateLeaseSet2 sent to router
	SessionStateLeaseSetSent
	// SessionStateActive - Session fully established and active
	SessionStateActive
	// SessionStateDestroying - DestroySession sent
	SessionStateDestroying
	// SessionStateDestroyed - Session destroyed
	SessionStateDestroyed
	// SessionStateRejected - Session was rejected by router
	SessionStateRejected
	// SessionStateDisconnected - Connection lost
	SessionStateDisconnected
)

func (SessionState) String

func (s SessionState) String() string

String returns a human-readable name for the session state.

type SessionStateTracker

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

SessionStateTracker tracks the lifecycle state of I2CP sessions for debugging.

func NewSessionStateTracker

func NewSessionStateTracker() *SessionStateTracker

NewSessionStateTracker creates a new session state tracker.

func (*SessionStateTracker) DiagnosticReport

func (sst *SessionStateTracker) DiagnosticReport() string

DiagnosticReport generates a comprehensive session state report.

func (*SessionStateTracker) Disable

func (sst *SessionStateTracker) Disable()

Disable disables session state tracking.

func (*SessionStateTracker) Enable

func (sst *SessionStateTracker) Enable()

Enable enables session state tracking.

func (*SessionStateTracker) GetLeaseSetWaitDiagnostics

func (sst *SessionStateTracker) GetLeaseSetWaitDiagnostics() string

GetLeaseSetWaitDiagnostics returns diagnostic info about LeaseSet waits.

func (*SessionStateTracker) GetState

func (sst *SessionStateTracker) GetState(sessionID uint16) (SessionState, bool)

GetState returns the current state of a session.

func (*SessionStateTracker) IsEnabled

func (sst *SessionStateTracker) IsEnabled() bool

IsEnabled returns whether state tracking is enabled.

func (*SessionStateTracker) RecordLeaseSetReceived

func (sst *SessionStateTracker) RecordLeaseSetReceived(sessionID uint16, tunnelCount uint8)

RecordLeaseSetReceived records that RequestVariableLeaseSet was received.

func (*SessionStateTracker) SetState

func (sst *SessionStateTracker) SetState(sessionID uint16, newState SessionState, reason string)

SetState sets the state for a session and records the transition.

func (*SessionStateTracker) StartLeaseSetWait

func (sst *SessionStateTracker) StartLeaseSetWait(sessionID uint16, timeout time.Duration)

StartLeaseSetWait records that a session is waiting for RequestVariableLeaseSet.

type SessionStatus

type SessionStatus int

Session Status Constants I2CP specification: SessionStatusMessage (type 20) status field values Per https://geti2p.net/spec/i2cp#sessionstatusmessage:

0 = Destroyed - The session with the given ID is terminated
1 = Created - In response to CreateSessionMessage, a new session is now active
2 = Updated - In response to ReconfigureSessionMessage
3 = Invalid - The configuration is invalid
4 = Refused - Router was unable to create the session (0.9.12+)
const (
	I2CP_SESSION_STATUS_DESTROYED SessionStatus = 0 // 0 - Session destroyed
	I2CP_SESSION_STATUS_CREATED   SessionStatus = 1 // 1 - Session created successfully
	I2CP_SESSION_STATUS_UPDATED   SessionStatus = 2 // 2 - Session configuration updated
	I2CP_SESSION_STATUS_INVALID   SessionStatus = 3 // 3 - Session invalid (see errors.go: ErrSessionInvalid)
	I2CP_SESSION_STATUS_REFUSED   SessionStatus = 4 // 4 - Session creation refused (0.9.12+, see errors.go: ErrSessionRefused)
)

type SignatureKeyPair

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

SignatureKeyPair represents an Ed25519 signature key pair. This struct is maintained for backward compatibility. New code should use Ed25519KeyPair directly.

type StateTransition

type StateTransition struct {
	From      SessionState
	To        SessionState
	Timestamp time.Time
	Reason    string
}

StateTransition records a state change for diagnostic purposes.

type Stream

type Stream struct {
	*bytes.Buffer
}

Stream provides I2CP-specific message serialization operations. It wraps bytes.Buffer and adds methods for reading/writing I2CP protocol data structures.

The Stream type focuses on I2CP protocol serialization including:

  • Binary integer encoding (big-endian uint16/32/64)
  • Length-prefixed strings
  • I2CP property mappings (key=value; format)

For general binary operations outside I2CP, use encoding/binary directly.

func NewStream

func NewStream(buf []byte) *Stream

NewStream creates a new Stream from a byte slice. The Stream wraps a bytes.Buffer initialized with the provided data.

func NewStreamPooled

func NewStreamPooled(size int) *Stream

NewStreamPooled creates a new Stream using a buffer from the pool. When the Stream is no longer needed, call ReleaseStream() to return the buffer. If buffer pooling is disabled, this behaves identically to NewStream().

func (*Stream) ReadMapping

func (stream *Stream) ReadMapping() (map[string]string, error)

ReadMapping reads an I2CP property mapping from the stream. Format: [size:uint16][key1_len:1][key1][=][value1_len:1][value1][;]...[keyN_len:1][keyN][=][valueN_len:1][valueN][;]

Returns a map of key-value pairs. If the mapping is empty (size=0), returns an empty map. Returns an error if the mapping data is malformed or incomplete.

func (*Stream) ReadUint16

func (s *Stream) ReadUint16() (uint16, error)

ReadUint16 reads a big-endian uint16 from the stream. This is commonly used for I2CP session IDs and length prefixes.

func (*Stream) ReadUint32

func (s *Stream) ReadUint32() (uint32, error)

ReadUint32 reads a big-endian uint32 from the stream. This is commonly used for I2CP message IDs, sizes, and tunnel IDs.

func (*Stream) ReadUint64

func (s *Stream) ReadUint64() (uint64, error)

ReadUint64 reads a big-endian uint64 from the stream. This is commonly used for I2CP timestamps.

func (*Stream) Seek

func (s *Stream) Seek(offset int64, whence int) (int64, error)

Seek provides limited support for repositioning within the stream. Currently only supports Seek(0, 0) to reset to the beginning. This is used internally for I2CP message processing.

For full io.Seeker support, use bytes.Reader instead.

func (*Stream) WriteLenPrefixedString

func (stream *Stream) WriteLenPrefixedString(s string) error

WriteLenPrefixedString writes a string prefixed by its length as a single byte. Format: [length:1 byte][string data] This limits strings to 255 bytes, which is sufficient for I2CP property keys/values.

func (*Stream) WriteMapping

func (stream *Stream) WriteMapping(m map[string]string) error

WriteMapping writes an I2CP property mapping to the stream. Format: [size:uint16][key1_len:1][key1][=][value1_len:1][value1][;]...[keyN_len:1][keyN][=][valueN_len:1][valueN][;]

The mapping is a collection of key=value pairs separated by semicolons. Keys are sorted alphabetically for deterministic serialization. Empty keys are skipped to avoid malformed output.

This format is used throughout I2CP for session configuration properties.

func (*Stream) WriteUint16

func (s *Stream) WriteUint16(i uint16) error

WriteUint16 writes a big-endian uint16 to the stream. This is commonly used for I2CP session IDs and length prefixes.

func (*Stream) WriteUint32

func (s *Stream) WriteUint32(i uint32) error

WriteUint32 writes a big-endian uint32 to the stream. This is commonly used for I2CP message IDs, sizes, and tunnel IDs.

func (*Stream) WriteUint64

func (s *Stream) WriteUint64(i uint64) error

WriteUint64 writes a big-endian uint64 to the stream. This is commonly used for I2CP timestamps.

type Tcp

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

func (*Tcp) CanRead

func (tcp *Tcp) CanRead() bool

func (*Tcp) Connect

func (tcp *Tcp) Connect() (err error)

Connect establishes a TCP or TLS connection to the I2P router. Initializes the connection address if needed, then establishes either a TLS connection (if configured) or plain TCP connection.

func (*Tcp) Disconnect

func (tcp *Tcp) Disconnect()

func (*Tcp) GetProperty

func (tcp *Tcp) GetProperty(property TcpProperty) string

func (*Tcp) Init

func (tcp *Tcp) Init(routerAddress ...string) (err error)

func (*Tcp) IsConnected

func (tcp *Tcp) IsConnected() bool

func (*Tcp) Receive

func (tcp *Tcp) Receive(buf *Stream) (i int, err error)

func (*Tcp) Send

func (tcp *Tcp) Send(buf *Stream) (i int, err error)

func (*Tcp) SetProperty

func (tcp *Tcp) SetProperty(property TcpProperty, value string)

func (*Tcp) SetupTLS

func (tcp *Tcp) SetupTLS(certFile, keyFile, caFile string, insecure bool) error

SetupTLS configures TLS for the TCP connection per I2CP 0.8.3+ specification. It loads client certificates, CA certificates, and configures TLS settings. The insecure parameter allows skipping certificate verification (development only).

Parameters:

  • certFile: Path to client certificate file (PEM format)
  • keyFile: Path to client private key file (PEM format)
  • caFile: Path to CA certificate file (PEM format, optional)
  • insecure: If true, skip certificate verification (NOT for production)

Returns error if certificate loading fails or TLS configuration is invalid.

type TcpProperty

type TcpProperty int
const (
	TCP_PROP_ADDRESS TcpProperty = iota
	TCP_PROP_PORT
	TCP_PROP_USE_TLS
	TCP_PROP_TLS_CLIENT_CERTIFICATE
	NR_OF_TCP_PROPERTIES
)

type Version

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

func (*Version) AtLeast

func (v *Version) AtLeast(other Version) bool

AtLeast returns true if v >= other. This is a convenience method for version comparison.

func (*Version) String

func (v *Version) String() string

String returns the version as a string (e.g., "0.9.67").

type X25519KeyPair

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

X25519KeyPair represents an X25519 key exchange key pair for modern I2P ECDH Wraps github.com/go-i2p/crypto/curve25519 types

func NewX25519KeyPair

func NewX25519KeyPair() (*X25519KeyPair, error)

NewX25519KeyPair generates a new X25519 key pair for ECDH operations Delegates to github.com/go-i2p/crypto/curve25519.GenerateX25519KeyPair()

func X25519KeyPairFromPrivateKey

func X25519KeyPairFromPrivateKey(privateKey [32]byte) (*X25519KeyPair, error)

X25519KeyPairFromPrivateKey creates an X25519KeyPair from just the private key. The public key is derived from the private key.

func X25519KeyPairFromStream

func X25519KeyPairFromStream(stream *Stream) (*X25519KeyPair, error)

X25519KeyPairFromStream reads an X25519 key pair from a stream Uses go.step.sm/crypto/x25519 for key reconstruction and validation

func (*X25519KeyPair) AlgorithmType

func (kp *X25519KeyPair) AlgorithmType() uint32

AlgorithmType returns the algorithm type constant

func (*X25519KeyPair) GenerateSharedSecret

func (kp *X25519KeyPair) GenerateSharedSecret(peerPublicKey [32]byte) ([32]byte, error)

GenerateSharedSecret performs ECDH to generate a shared secret with the peer's public key Uses go.step.sm/crypto/x25519 PrivateKey.SharedKey() for ECDH

func (*X25519KeyPair) PrivateKey

func (kp *X25519KeyPair) PrivateKey() [32]byte

PrivateKey returns a copy of the private key as [32]byte for backward compatibility

func (*X25519KeyPair) PublicKey

func (kp *X25519KeyPair) PublicKey() [32]byte

PublicKey returns a copy of the public key as [32]byte for backward compatibility

func (*X25519KeyPair) WritePublicKeyToStream

func (kp *X25519KeyPair) WritePublicKeyToStream(stream *Stream) error

WritePublicKeyToStream writes only the public key to a stream

func (*X25519KeyPair) WriteToStream

func (kp *X25519KeyPair) WriteToStream(stream *Stream) error

WriteToStream writes the complete X25519 key pair to a stream

Directories

Path Synopsis
examples
context-usage command
Package main demonstrates context-aware operations in go-i2cp
Package main demonstrates context-aware operations in go-i2cp
debug_leaseset command
diagnostics command
Package main demonstrates go-i2cp diagnostic capabilities for troubleshooting I2CP protocol interactions, particularly useful for debugging session creation timeouts with Java I2P routers.
Package main demonstrates go-i2cp diagnostic capabilities for troubleshooting I2CP protocol interactions, particularly useful for debugging session creation timeouts with Java I2P routers.
metrics command
modern-crypto command
session-creation-fix command
Package main demonstrates the CORRECT way to create I2CP sessions This example shows the fix for the "CreateSession hangs with Java I2P router" bug.
Package main demonstrates the CORRECT way to create I2CP sessions This example shows the fix for the "CreateSession hangs with Java I2P router" bug.
signature-fix-test command
Example program to test CreateSession signature fix This verifies that the signature is now valid according to I2CP specification
Example program to test CreateSession signature fix This verifies that the signature is now valid according to I2CP specification
tls-connection command

Jump to

Keyboard shortcuts

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