I2P Client Protocol (I2CP)

How applications negotiate sessions, tunnels, and LeaseSets with the I2P router.

Overview

I2CP is the low-level control protocol between an I2P router and any client process. It defines a strict separation of responsibilities:

  • Router: Manages routing, cryptography, tunnel lifecycles, and network database operations
  • Client: Selects anonymity properties, configures tunnels, and submits/receives messages

All communication flows over a single TCP socket (optionally TLS-wrapped), enabling asynchronous, full-duplex operations.

Protocol Version: I2CP uses a protocol version byte 0x2A (42 decimal) sent during initial connection establishment. This version byte has remained stable since the protocol’s inception.

Current Status: This specification is accurate for router version 0.9.67 (API version 0.9.67), released 2025-09.

Implementation Context

Java Implementation

The reference implementation is in Java I2P:

  • Client SDK: i2p.jar package
  • Router implementation: router.jar package
  • Javadocs

When client and router run in the same JVM, I2CP messages are passed as Java objects without serialization. External clients use the serialized protocol over TCP.

C++ Implementation

i2pd (the C++ I2P router) also implements I2CP externally for client connections.

Non-Java Clients

There are no known non-Java implementations of a complete I2CP client library. Non-Java applications should use higher-level protocols instead:

  • SAM (Simple Anonymous Messaging) v3: Socket-based interface with libraries in multiple languages
  • BOB (Basic Open Bridge): Simpler alternative to SAM

These higher-level protocols handle I2CP complexity internally and also provide the streaming library (for TCP-like connections) and datagram library (for UDP-like connections).

Connection Establishment

1. TCP Connection

Connect to the router’s I2CP port:

  • Default: 127.0.0.1:7654
  • Configurable via router settings
  • Optional TLS wrapper (strongly recommended for remote connections)

2. Protocol Handshake

Step 1: Send protocol version byte 0x2A

Step 2: Clock Synchronization

Client → Router: GetDateMessage
Router → Client: SetDateMessage

The router returns its current timestamp and I2CP API version string (since 0.8.7).

Step 3: Authentication (if enabled)

As of 0.9.11, authentication may be included in GetDateMessage via a Mapping containing:

  • i2cp.username
  • i2cp.password

As of 0.9.16, when authentication is enabled, it must be completed via GetDateMessage before any other messages are sent.

Step 4: Session Creation

Client → Router: CreateSessionMessage (contains SessionConfig)
Router → Client: SessionStatusMessage (status=Created)

Step 5: Tunnel Ready Signal

Router → Client: RequestVariableLeaseSetMessage

This message signals that inbound tunnels have been built. The router will NOT send this until at least one inbound AND one outbound tunnel exist.

Step 6: LeaseSet Publication

Client → Router: CreateLeaseSet2Message

At this point, the session is fully operational for sending and receiving messages.

Message Flow Patterns

Outgoing Message (Client sends to remote destination)

With i2cp.messageReliability=none:

Client → Router: SendMessageMessage (nonce=0)
[No acknowledgments]

With i2cp.messageReliability=BestEffort:

Client → Router: SendMessageMessage (nonce>0)
Router → Client: MessageStatusMessage (status=Accepted)
Router → Client: MessageStatusMessage (status=Success or Failure)

Incoming Message (Router delivers to client)

With i2cp.fastReceive=true (default since 0.9.4):

Router → Client: MessagePayloadMessage
[No acknowledgment required]

With i2cp.fastReceive=false (DEPRECATED):

Router → Client: MessageStatusMessage (status=Available)
Client → Router: ReceiveMessageBeginMessage
Router → Client: MessagePayloadMessage
Client → Router: ReceiveMessageEndMessage

Modern clients should always use fast receive mode.

Common Data Structures

I2CP Message Header

All I2CP messages use this common header:

+----+----+----+----+----+----+----+----+
| Body Length (4 bytes)                 |
+----+----+----+----+----+----+----+----+
|Type|  Message Body (variable)        |
+----+----+----+----+----+----+----+----+
  • Body Length: 4-byte integer, length of message body only (excludes header)
  • Type: 1-byte integer, message type identifier
  • Message Body: 0+ bytes, format varies by message type

Message Size Limit: Approximately 64 KB maximum.

Session ID

2-byte integer uniquely identifying a session on a router.

Special Value: 0xFFFF indicates “no session” (used for hostname lookups without an established session).

Message ID

4-byte integer generated by the router to uniquely identify a message within a session.

Important: Message IDs are not globally unique, only unique within a session. They are also distinct from the nonce generated by the client.

Payload Format

Message payloads are gzip-compressed with a standard 10-byte gzip header:

  • Starts with: 0x1F 0x8B 0x08 (RFC 1952)
  • Since 0.7.1: Unused portions of gzip header contain protocol, from-port, and to-port information
  • This enables streaming and datagrams on the same destination

Compression Control: Set i2cp.gzip=false to disable compression (sets gzip effort to 0). The gzip header is still included, but with minimal compression overhead.

SessionConfig Structure

Defines configuration for a client session:

+----------------------------------+
| Destination                      |
+----------------------------------+
| Mapping (configuration options)  |
+----------------------------------+
| Creation Date                    |
+----------------------------------+
| Signature                        |
+----------------------------------+

Critical Requirements:

  1. Mapping must be sorted by key for signature validation
  2. Creation Date must be within ±30 seconds of router’s current time
  3. Signature is created by the SigningPrivateKey of the Destination

Offline Signatures (as of 0.9.38):

If using offline signing, the Mapping must contain:

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

The Signature is then generated by the transient SigningPrivateKey.

Core Configuration Options

Tunnel Configuration

OptionDefaultDescription
inbound.length3Number of hops for inbound tunnels
outbound.length3Number of hops for outbound tunnels
inbound.lengthVariance0Random variance in hop count (since 0.7.6)
outbound.lengthVariance0Random variance in hop count (since 0.7.6)
inbound.quantity2Number of concurrent inbound tunnels
outbound.quantity2Number of concurrent outbound tunnels
inbound.backupQuantity0Standby inbound tunnels (hot spares)
outbound.backupQuantity0Standby outbound tunnels (hot spares)
inbound.allowZeroHoptrueAllow 0-hop tunnels (disable for full anonymity)
outbound.allowZeroHoptrueAllow 0-hop tunnels (disable for full anonymity)

Notes:

  • Values for quantity > 6 require peers running 0.9.0+ and significantly increase resource usage
  • Set backupQuantity to 1-2 for high-availability services
  • Zero-hop tunnels sacrifice anonymity for latency but are useful for testing

Message Handling

OptionDefaultDescription
clientMessageTimeout60000 msLegacy timeout for message delivery
i2cp.messageReliabilityBestEffortNone, BestEffort, or Guaranteed
i2cp.fastReceivetrueSkip ReceiveMessageBegin/End handshake (default since 0.9.4)
i2cp.gziptrueEnable gzip compression of message payloads
outbound.priority0Priority for outbound scheduling (-25 to +25)

Message Reliability:

  • None: No router acknowledgments (streaming library default since 0.8.1)
  • BestEffort: Router sends acceptance + success/failure notifications
  • Guaranteed: Unimplemented (currently behaves like BestEffort)

Per-Message Override (since 0.9.14):

  • In a session with messageReliability=none, setting a nonzero nonce requests delivery notification for that specific message
  • Setting nonce=0 in a BestEffort session disables notifications for that message

LeaseSet Configuration

OptionDefaultDescription
i2cp.dontPublishLeaseSetfalseDisable automatic LeaseSet publication (for client-only destinations)
i2cp.leaseSetType1LeaseSet variant: 1 = standard, 3 = LS2, 5 = encrypted, 7 = meta
i2cp.leaseSetEncType0Comma-separated encryption type codes (see below)

Legacy ElGamal/AES Session Tags

These options are relevant only for legacy ElGamal encryption:

OptionDefaultDescription
crypto.lowTagThreshold30Minimum session tags before replenishing
crypto.tagsToSend40Number of tags to send in a batch

Note: ECIES-X25519 clients use a different ratchet mechanism and ignore these options.

Encryption Types

I2CP supports multiple end-to-end encryption schemes via the i2cp.leaseSetEncType option. Multiple types can be specified (comma-separated) to support both modern and legacy peers.

Supported Encryption Types

TypeAlgorithmKey SizeSinceStatus
0ElGamal/AES+SessionTags2048-bit ElGamalOriginalLegacy
1-3Reserved--Unused
4ECIES-X25519-AEAD-Ratchet32-byte X255190.9.46Current Standard
5ECIES-X25519-AEAD-Ratchet + ML-KEM-768 hybrid32 + PQ0.9.67Beta
6ECIES-X25519-AEAD-Ratchet + ML-KEM-1024 hybrid32 + PQ0.9.67Beta
7Reserved (likely ML-KEM-512 hybrid)32 + PQFuturePlanned

Recommended Configuration:

i2cp.leaseSetEncType=4,0

This provides X25519 (preferred) with ElGamal fallback for compatibility.

Encryption Type Details

Type 0 - ElGamal/AES+SessionTags:

  • 2048-bit ElGamal public keys (256 bytes)
  • AES-256 symmetric encryption
  • 32-byte session tags sent in batches
  • High CPU, bandwidth, and memory overhead
  • Being phased out network-wide

Type 4 - ECIES-X25519-AEAD-Ratchet:

  • X25519 key exchange (32-byte keys)
  • ChaCha20/Poly1305 AEAD
  • Signal-style double ratchet
  • 8-byte session tags (vs 32-byte for ElGamal)
  • Tags generated via synchronized PRNG (not sent in advance)
  • ~92% overhead reduction vs ElGamal
  • Standard for modern I2P (most routers use this)

Types 5-6 - Post-Quantum Hybrid:

  • Combines X25519 with ML-KEM (NIST FIPS 203)
  • Provides quantum-resistant security
  • ML-KEM-768 for balanced security/performance
  • ML-KEM-1024 for maximum security
  • Larger message sizes due to PQ key material
  • Network support still being deployed

Migration Strategy

The I2P network is actively migrating from ElGamal (type 0) to X25519 (type 4):

  • NTCP → NTCP2 (complete)
  • SSU → SSU2 (complete)
  • ElGamal tunnels → X25519 tunnels (complete)
  • ElGamal end-to-end → ECIES-X25519 (majority complete)

LeaseSet2 and Advanced Features

LeaseSet2 Options (since 0.9.38)

OptionSincePurpose
i2cp.leaseSetType0.9.38Specifies LeaseSet variant (1, 3, 5, 7)
i2cp.leaseSetEncType0.9.38Encryption types supported (comma-separated)
i2cp.leaseSetAuthType0.9.41Per-client authentication: 0 = none, 1 = DH, 2 = PSK
i2cp.leaseSetPrivKey0.9.41X25519 private key for decrypting LS2 with auth
i2cp.leaseSetSecret0.9.39Base64 secret for blinded addresses
i2cp.leaseSetTransientPublicKey0.9.38Transient signing key for offline signatures
i2cp.leaseSetPrivateKey0.9.18Persistent LeaseSet encryption keys (type:key pairs)
i2cp.leaseSetOption.nnn0.9.66Service records (proposal 167)
i2cp.leaseSetClient.dh.nnn0.9.41DH client auth material (indexed from 0)
i2cp.leaseSetClient.psk.nnn0.9.41PSK client auth material (indexed from 0)

Blinded Addresses

As of 0.9.39, destinations can use “blinded” addresses (b33 format) that change periodically:

  • Requires i2cp.leaseSetSecret for password protection
  • Optional per-client authentication
  • See proposals 123 and 149 for details

Service Records (since 0.9.66)

LeaseSet2 supports service record options (proposal 167):

i2cp.leaseSetOption.0=_smtp._tcp=1 86400 0 0 25 mail.example.b32.i2p

Format follows DNS SRV record style but adapted for I2P.

Multiple Sessions (since 0.9.21)

A single I2CP connection can maintain multiple sessions:

Primary Session: The first session created on a connection Subsessions: Additional sessions sharing the primary’s tunnel pool

Subsession Characteristics

  1. Shared Tunnels: Use the same inbound/outbound tunnel pools as primary
  2. Shared Encryption Keys: Must use identical LeaseSet encryption keys
  3. Different Signing Keys: Must use distinct Destination signing keys
  4. No Anonymity Guarantee: Clearly linked to primary session (same router, same tunnels)

Subsession Use Case

Enable communication with destinations using different signature types:

  • Primary: EdDSA signature (modern)
  • Subsession: DSA signature (legacy compatibility)

Subsession Lifecycle

Creation:

Client → Router: CreateSessionMessage
Router → Client: SessionStatusMessage (unique Session ID)
Router → Client: RequestVariableLeaseSetMessage (separate for each destination)
Client → Router: CreateLeaseSet2Message (separate for each destination)

Destruction:

  • Destroying a subsession: Leaves primary session intact
  • Destroying primary session: Destroys all subsessions and closes connection
  • DisconnectMessage: Destroys all sessions

Session ID Handling

Most I2CP messages contain a Session ID field. Exceptions:

  • DestLookup / DestReply (deprecated, use HostLookup / HostReply)
  • GetBandwidthLimits / BandwidthLimits (response not session-specific)

Important: Clients should not have multiple CreateSession messages outstanding simultaneously, as responses cannot be definitively correlated to requests.

Message Catalog

Message Type Summary

TypeNameDirectionSinceStatus
1CreateSessionC → ROriginalCurrent
2ReconfigureSessionC → R0.7.1Current
3DestroySessionC → ROriginalCurrent
4CreateLeaseSetC → ROriginalDeprecated
5SendMessageC → ROriginalCurrent
6ReceiveMessageBeginC → ROriginalDeprecated
7ReceiveMessageEndC → ROriginalDeprecated
8GetBandwidthLimitsC → R0.7.2Current
20SessionStatusR → COriginalCurrent
21RequestLeaseSetR → COriginalDeprecated
22MessageStatusR → COriginalCurrent
23BandwidthLimitsR → C0.7.2Current
29ReportAbuseBidirectionalOriginalUnused
30DisconnectBidirectionalOriginalCurrent
31MessagePayloadR → COriginalCurrent
32GetDateC → ROriginalCurrent
33SetDateR → COriginalCurrent
34DestLookupC → R0.7Deprecated
35DestReplyR → C0.7Deprecated
36SendMessageExpiresC → R0.7.1Current
37RequestVariableLeaseSetR → C0.9.7Current
38HostLookupC → R0.9.11Current
39HostReplyR → C0.9.11Current
41CreateLeaseSet2C → R0.9.39Current
42BlindingInfoC → R0.9.43Current

Legend: C = Client, R = Router

Key Message Details

CreateSessionMessage (Type 1)

Purpose: Initiate a new I2CP session

Content: SessionConfig structure

Response: SessionStatusMessage (status=Created or Invalid)

Requirements:

  • Date in SessionConfig must be within ±30 seconds of router time
  • Mapping must be sorted by key for signature validation
  • Destination must not already have an active session

RequestVariableLeaseSetMessage (Type 37)

Purpose: Router requests client authorization for inbound tunnels

Content:

  • Session ID
  • Number of leases
  • Array of Lease structures (each with individual expiration)

Response: CreateLeaseSet2Message

Significance: This is the signal that the session is operational. The router sends this only after:

  1. At least one inbound tunnel is built
  2. At least one outbound tunnel is built

Timeout Recommendation: Clients should destroy the session if this message is not received within 5+ minutes of session creation.

CreateLeaseSet2Message (Type 41)

Purpose: Client publishes LeaseSet to network database

Content:

  • Session ID
  • LeaseSet type byte (1, 3, 5, or 7)
  • LeaseSet or LeaseSet2 or EncryptedLeaseSet or MetaLeaseSet
  • Number of private keys
  • Private key list (one per public key in LeaseSet, same order)

Private Keys: Required for decrypting incoming garlic messages. Format:

Encryption type (2 bytes)
Key length (2 bytes)
Private key data (variable)

Note: Replaces deprecated CreateLeaseSetMessage (type 4), which cannot handle:

  • LeaseSet2 variants
  • Non-ElGamal encryption
  • Multiple encryption types
  • Encrypted LeaseSets
  • Offline signing keys

SendMessageExpiresMessage (Type 36)

Purpose: Send message to destination with expiration and advanced options

Content:

  • Session ID
  • Destination
  • Payload (gzipped)
  • Nonce (4 bytes)
  • Flags (2 bytes) - see below
  • Expiration Date (6 bytes, truncated from 8)

Flags Field (2 bytes, bit order 15…0):

Bits 15-11: Unused, must be 0

Bits 10-9: Message Reliability Override (unused, use nonce instead)

Bit 8: Don’t bundle LeaseSet

  • 0: Router may bundle LeaseSet in garlic
  • 1: Don’t bundle LeaseSet

Bits 7-4: Low tag threshold (ElGamal only, ignored for ECIES)

0000 = Use session settings
0001 = 2 tags
0010 = 3 tags
...
1111 = 192 tags

Bits 3-0: Tags to send if needed (ElGamal only, ignored for ECIES)

0000 = Use session settings
0001 = 2 tags
0010 = 4 tags
...
1111 = 160 tags

MessageStatusMessage (Type 22)

Purpose: Notify client of message delivery status

Content:

  • Session ID
  • Message ID (router-generated)
  • Status code (1 byte)
  • Size (4 bytes, only relevant for status=0)
  • Nonce (4 bytes, matches client’s SendMessage nonce)

Status Codes (Outgoing Messages):

CodeNameMeaningResult
1AcceptedRouter accepted messageSuccess
2Best Effort SuccessProbable deliverySuccess
4Guaranteed SuccessProbable deliverySuccess
6Local SuccessDelivered to local clientSuccess
3Best Effort FailureProbable failureFailure
5Guaranteed FailureGeneric failureFailure
7Local FailureLocal delivery failedFailure
8Router FailureRouter shutdown/errorFailure
9Network FailureNo network connectivityFailure
10Bad SessionInvalid/closed sessionFailure
11Bad MessageInvalid payloadFailure
12Bad OptionsInvalid options/expirationFailure
13Overflow FailureQueue/buffer fullFailure
14Message ExpiredExpired before sendFailure
15Bad Local LeaseSetLocal LeaseSet problemFailure
16No Local TunnelsNo tunnels availableFailure
17Unsupported EncryptionIncompatible encryptionFailure
18Bad DestinationInvalid remote destinationFailure
19Bad LeasesetInvalid remote LeaseSetFailure
20Expired LeasesetRemote LeaseSet expiredFailure
21No LeasesetRemote LeaseSet not foundFailure
22Meta LeasesetCannot send to meta LSFailure
23Loopback DeniedSame source and destinationFailure

Success codes: 1, 2, 4, 6 Failure codes: All others

Status Code 0 (DEPRECATED): Available message (incoming, fast receive disabled)

HostLookupMessage (Type 38)

Purpose: Lookup destination by hostname or hash (replaces DestLookup)

Content:

  • Session ID (or 0xFFFF for no session)
  • Request ID (4 bytes)
  • Timeout in milliseconds (4 bytes, min recommended: 10000)
  • Request type (1 byte)
  • Lookup key (Hash, hostname String, or Destination)

Request Types:

TypeLookup KeyReturnsSince
0HashDestinationOriginal
1Hostname StringDestinationOriginal
2HashDestination + Options0.9.66
3Hostname StringDestination + Options0.9.66
4DestinationDestination + Options0.9.66

Types 2-4 return LeaseSet options (proposal 167) if available.

Response: HostReplyMessage

HostReplyMessage (Type 39)

Purpose: Response to HostLookupMessage

Content:

  • Session ID
  • Request ID
  • Result code (1 byte)
  • Destination (present on success, sometimes on specific failures)
  • Mapping (only for lookup types 2-4, may be empty)

Result Codes:

CodeNameMeaning
0SuccessLookup succeeded
1FailureGeneric failure
2Lookup Password RequiredBlinded address requires password
3Private Key RequiredBlinded address requires private key
4Password and Key RequiredBlinded address requires both
5LeaseSet Decryption FailureCannot decrypt LeaseSet
6LeaseSet Lookup FailureLeaseSet not found in netdb
7Lookup Type UnsupportedRouter doesn't support this type

BlindingInfoMessage (Type 42)

Purpose: Inform router about blinded destination authentication requirements (since 0.9.43)

Content:

  • Session ID
  • Flags (1 byte)
  • Endpoint type (1 byte): 0=Hash, 1=hostname, 2=Destination, 3=SigType+Key
  • Blinded signature type (2 bytes)
  • Expiration (4 bytes, seconds since epoch)
  • Endpoint data (varies by type)
  • Private key (32 bytes, only if flag bit 0 set)
  • Lookup password (String, only if flag bit 4 set)

Flags (bit order 76543210):

  • Bit 0: 0=everybody, 1=per-client
  • Bits 3-1: Auth scheme (if bit 0=1): 000=DH, 001=PSK
  • Bit 4: 1=secret required
  • Bits 7-5: Unused, set to 0

No Response: Router processes silently

Use Case: Before sending to a blinded destination (b33 address), client must either:

  1. Lookup the b33 via HostLookup, OR
  2. Send BlindingInfo message

If the destination requires authentication, BlindingInfo is mandatory.

ReconfigureSessionMessage (Type 2)

Purpose: Update session configuration after creation

Content:

  • Session ID
  • SessionConfig (only changed options needed)

Response: SessionStatusMessage (status=Updated or Invalid)

Notes:

  • Router merges new config with existing config
  • Tunnel options (inbound.*, outbound.*) are always applied
  • Some options may be immutable after session creation
  • Date must be within ±30 seconds of router time
  • Mapping must be sorted by key

DestroySessionMessage (Type 3)

Purpose: Terminate a session

Content: Session ID

Expected Response: SessionStatusMessage (status=Destroyed)

Actual Behavior (Java I2P through 0.9.66):

  • Router never sends SessionStatus(Destroyed)
  • If no sessions remain: Sends DisconnectMessage
  • If subsessions remain: No reply

Important: Java I2P behavior deviates from specification. Implementations should be cautious when destroying individual subsessions.

DisconnectMessage (Type 30)

Purpose: Notify that connection is about to be terminated

Content: Reason String

Effect: All sessions on the connection are destroyed, socket closes

Implementation: Primarily router → client in Java I2P

Protocol Version History

Version Detection

The I2CP protocol version is exchanged in Get/SetDate messages (since 0.8.7). For older routers, version information is unavailable.

Version String: Indicates “core” API version, not necessarily router version.

Feature Timeline

VersionKey Features
0.9.67PQ Hybrid ML-KEM (enc types 5-7) in LeaseSet
0.9.66Host lookup/reply extensions (proposal 167), service records
0.9.62MessageStatus loopback error code
0.9.46X25519 (enc type 4) in LeaseSet, ECIES end-to-end
0.9.43BlindingInfo message, extended HostReply failure codes
0.9.41EncryptedLeaseSet options, Meta LS error code
0.9.39CreateLeaseSet2 message, RedDSA Ed25519 support
0.9.38Preliminary LS2 support (format changed in 0.9.39)
0.9.21Multiple sessions on single connection
0.9.20Additional SetDate messages for clock shifts
0.9.16Authentication required before other messages (when enabled)
0.9.15EdDSA Ed25519 signature type
0.9.14Per-message reliability override with nonzero nonce
0.9.12ECDSA P-256/384/521 signature types, RSA support
0.9.11HostLookup/HostReply messages, auth in GetDate
0.9.7RequestVariableLeaseSet message
0.9.5Additional MessageStatus codes
0.9.4Fast receive mode default, nonce=0 allowed
0.9.2SendMessageExpires flag tag bits
0.916 leases per LeaseSet (up from 6)
0.8.7Version strings in Get/SetDate
0.8.4SendMessageExpires flag bits
0.8.3DestLookup in standard session, concurrent lookups
0.8.1messageReliability=none
0.7.2GetBandwidthLimits, BandwidthLimits
0.7.1SendMessageExpires, ReconfigureSession, ports in gzip header
0.7DestLookup, DestReply
0.6.5-Original protocol features

Security Considerations

Authentication

Default: No authentication required Optional: Username/password authentication (since 0.9.11) Required: When enabled, auth must complete before other messages (since 0.9.16)

Remote Connections: Always use TLS (i2cp.SSL=true) to protect credentials and private keys.

Clock Skew

SessionConfig Date must be within ±30 seconds of router time, or session will be rejected. Use Get/SetDate to synchronize.

Private Key Handling

CreateLeaseSet2Message contains private keys for decrypting incoming messages. These keys must be:

  • Transmitted securely (TLS for remote connections)
  • Stored securely by the router
  • Rotated when compromised

Message Expiration

Always use SendMessageExpires (not SendMessage) to set explicit expiration. This:

  • Prevents messages from being queued indefinitely
  • Reduces resource consumption
  • Improves reliability

Session Tag Management

ElGamal (deprecated):

  • Tags must be transmitted in batches
  • Lost tags cause decryption failures
  • High memory overhead

ECIES-X25519 (current):

  • Tags generated via synchronized PRNG
  • No advance transmission needed
  • Resilient to message loss
  • Significantly lower overhead

Best Practices

For Client Developers

  1. Use Fast Receive Mode: Always set i2cp.fastReceive=true (or rely on default)

  2. Prefer ECIES-X25519: Configure i2cp.leaseSetEncType=4,0 for best performance with compatibility

  3. Set Explicit Expiration: Use SendMessageExpires, not SendMessage

  4. Handle Subsessions Carefully: Be aware that subsessions offer no anonymity between destinations

  5. Timeout Session Creation: Destroy session if RequestVariableLeaseSet not received within 5 minutes

  6. Sort Configuration Mappings: Always sort Mapping keys before signing SessionConfig

  7. Use Appropriate Tunnel Counts: Don’t set quantity > 6 unless necessary

  8. Consider SAM/BOB for Non-Java: Implement SAM rather than I2CP directly

For Router Developers

  1. Validate Dates: Enforce ±30 second window on SessionConfig dates

  2. Limit Message Size: Enforce ~64 KB maximum message size

  3. Support Multiple Sessions: Implement subsession support per 0.9.21 spec

  4. Send RequestVariableLeaseSet Promptly: Only after both inbound and outbound tunnels exist

  5. Handle Deprecated Messages: Accept but discourage ReceiveMessageBegin/End

  6. Support ECIES-X25519: Prioritize type 4 encryption for new deployments

Debugging and Troubleshooting

Common Issues

Session Rejected (Invalid):

  • Check clock skew (must be within ±30 seconds)
  • Verify Mapping is sorted by key
  • Ensure Destination not already in use

No RequestVariableLeaseSet:

  • Router may be building tunnels (wait up to 5 minutes)
  • Check for network connectivity issues
  • Verify sufficient peer connections

Message Delivery Failures:

  • Check MessageStatus codes for specific failure reason
  • Verify remote LeaseSet is published and current
  • Ensure compatible encryption types

Subsession Problems:

  • Verify primary session created first
  • Confirm same encryption keys
  • Check for distinct signing keys

Diagnostic Messages

GetBandwidthLimits: Query router capacity HostLookup: Test name resolution and LeaseSet availability MessageStatus: Track message delivery end-to-end

  • Common Structures: /docs/specs/common-structures/
  • I2NP (Network Protocol): /docs/specs/i2np/
  • ECIES-X25519: /docs/specs/ecies/
  • Tunnel Creation: /docs/specs/implementation/
  • Streaming Library: /docs/specs/streaming/
  • Datagram Library: /docs/api/datagrams/
  • SAM v3: /docs/api/samv3/

Proposals Referenced

Javadocs Reference

Deprecation Summary

Deprecated Messages (Do Not Use)

  • CreateLeaseSetMessage (type 4): Use CreateLeaseSet2Message
  • RequestLeaseSetMessage (type 21): Use RequestVariableLeaseSetMessage
  • ReceiveMessageBeginMessage (type 6): Use fast receive mode
  • ReceiveMessageEndMessage (type 7): Use fast receive mode
  • DestLookupMessage (type 34): Use HostLookupMessage
  • DestReplyMessage (type 35): Use HostReplyMessage
  • ReportAbuseMessage (type 29): Never implemented

Deprecated Options

  • ElGamal encryption (type 0): Migrate to ECIES-X25519 (type 4)
  • DSA signatures: Migrate to EdDSA or ECDSA
  • i2cp.fastReceive=false: Always use fast receive mode

Was this page helpful?