How the MTProto Protocol Is Implemented in TelegramCore for iOS: A Deep Dive into MtProtoKit
The MTProto protocol in Telegram-iOS is implemented through the MtProtoKit sub-module, featuring a central MTProto state machine in MTProto.m that manages sessions, auth keys, and transport layers, while modular message services handle time synchronization and message resend operations.
The MTProto protocol serves as the encrypted transport layer powering all API calls, message exchanges, and file uploads within the Telegram ecosystem. In the TelegramMessenger/Telegram-iOS repository, this implementation lives inside the MtProtoKit sub-module, written in Objective-C and designed to isolate cryptographic operations, network transport, and session management into discrete, testable components.
Core Architecture of MTProto in Telegram-iOS
The implementation follows a layered architecture where a central state machine coordinates between persistence, transport, and cryptographic services. Understanding how these components interact is essential for working with the low-level protocol code.
The MTProto State Machine
At the heart of the implementation lies the MTProto class defined in submodules/MtProtoKit/Sources/MTProto.m. This object maintains an internal bitfield _mtState (enumerated as MTProtoState) that tracks the connection lifecycle through specific flags:
AwaitingDatacenterScheme– Indicates no transport scheme is known, triggering a request toMTContextfor endpoint details.AwaitingDatacenterAuthorization– Signals that authentication keys must be generated or retrieved.AwaitingTimeFixAndSalts– Activates when client-server clock drift requires correction or salt sets need replenishment.StoppedandPaused– Control user-initiated shutdown or network suspension.
State transitions occur through the setMtState: method, which automatically notifies registered message services and delegates via mtProtoServiceTasksStateChanged:isPerformingServiceTasks:. When you call resume on an MTProto instance, the method clears the paused flag, instantiates a fresh MTTcpTransport if needed, and immediately invokes requestTransportTransaction to begin queued operations.
MTProtoEngine and Persistence Layer
The MTProtoEngine class in MTProtoEngine.m acts as a lightweight wrapper around the MTProtoPersistenceInterface protocol. Rather than handling raw SQLite operations, the engine delegates storage concerns to the host application, which implements methods such as:
authInfoForDatacenterWithId:selector:– Retrieves stored authentication keys and salts.updateAuthInfoForDatacenterWithId:authInfo:selector:– Persists new keys after successful Diffie-Hellman exchanges.
This separation allows MTProto instances to remain stateless regarding storage while ensuring that sensitive cryptographic material survives application restarts.
Transport Layer Implementation
Network communication is handled by MTTcpTransport (see MTTcpTransport.m), which manages low-level socket connections, proxy support, and automatic reconnection logic. When resetTransport is called, the system builds a transport instance using MTTransportScheme objects provided by MTContext, determining whether to use SOCKS5 proxies with MTProto-proxy secrets or extended padding configurations.
Cryptographic and Session Management
The MTProto protocol relies on precise cryptographic primitives and monotonic message identification to ensure security and delivery guarantees.
Message Encryption and AES-IGE
Outgoing messages follow a strict preparation pipeline before transmission:
- Message ID Generation –
MTSessionInfogenerates monotonic identifiers viagenerateClientMessageId:and sequence numbers throughtakeSeqNo:. - Auth Key Resolution –
getAuthKeyForCurrentScheme:retrieves either persistent or ephemeral keys based on theuseTempAuthKeysconfiguration. - Payload Construction – Raw data is wrapped in an
MTPreparedMessageobject containing the current salt fromMTDatacenterSaltInfo. - Encryption – The static helper
+[MTProto _manuallyEncryptedMessage:messageId:authKey:]applies AES-IGE encryption with 16-byte padding.
Cryptographic utilities reside in MTEncryption.m, which handles Diffie-Hellman key exchange, proxy secret parsing, and optional extended padding for MTProto-proxy connections.
Session Info and Message IDs
The MTSessionInfo class ensures that every message carries a unique, temporally ordered identifier. This prevents replay attacks and enables the server to detect gaps in message sequences, triggering resend requests when necessary.
Message Services and Protocol Operations
TelegramCore implements auxiliary protocol functions through pluggable message services that conform to the MTMessageService protocol. These services are added via addMessageService: and execute alongside user transactions.
Time Synchronization Service
When the state machine enters AwaitingTimeFixAndSalts, MTProto automatically instantiates MTTimeSyncMessageService (see MTTimeSyncMessageService.m). This service transmits msgs_state_req and msgs_state_info handshakes to calculate clock offset and retrieve fresh salts. The service updates the internal MTTimeFixContext and removes itself upon completion, allowing normal message flow to resume.
Resend and Reliability Services
If the server reports a missing message ID, the core creates MTResendMessageService (see MTResendMessageService.m) through the requestMessageWithId: method. This service constructs a msg_resend_req TL object and automatically destroys itself after the server acknowledges the retransmission, ensuring reliable delivery without blocking the main transport queue.
These services are processed within transportReadyForTransaction:, which aggregates pending operations into a single msg_container respecting MTMaxContainerSize limits and prioritizing high-priority messages.
Practical Implementation Examples
Initializing an MTProto Connection
The following Objective-C snippet demonstrates the standard initialization sequence for establishing a connection to datacenter 2:
#import <MtProtoKit/MTProtoKit.h>
@interface MyController () <MTProtoDelegate>
@property (nonatomic, strong) MTProto *proto;
@end
@implementation MyController
- (void)setupProto {
// 1️⃣ Context – holds datacenter list, proxy, etc.
MTContext *context = [[MTContext alloc] initWithApiEnvironment:[MTApiEnvironment sharedInstance]];
// 2️⃣ Persistence – simple SQLite wrapper (provided by the app)
id<MTProtoPersistenceInterface> persistence = [[MTProtoPersistence alloc] initWithPath:@"/tmp/mtproto.db"];
// 3️⃣ Engine – ties persistence to the core (optional, used by higher‑level layers)
MTProtoEngine *engine = [[MTProtoEngine alloc] initWithPersistenceInterface:persistence];
// 4️⃣ Create the core MTProto instance for DC 2 (main Telegram DC)
self.proto = [[MTProto alloc] initWithContext:context
datacenterId:2
usageCalculationInfo:nil
requiredAuthToken:nil
authTokenMasterDatacenterId:0];
self.proto.delegate = self;
// 5️⃣ Start the connection
[self.proto resume];
}
#pragma mark - MTProtoDelegate
- (void)mtProtoConnectionStateChanged:(MTProto *)mtProto state:(MTProtoConnectionState *)state {
NSLog(@"Connection state – connected: %d, proxy issues: %d", state.isConnected, state.proxyHasConnectionIssues);
}
- (void)mtProtoNetworkAvailabilityChanged:(MTProto *)mtProto isNetworkAvailable:(bool)isNetworkAvailable {
NSLog(@"Network available: %d", isNetworkAvailable);
}
@end
Sending an RPC Request
To transmit a ping request (or any TL-method), wrap the payload in an MTOutgoingMessage and attach it via a transaction:
#import <MtProtoKit/MTMessageTransaction.h>
#import <MtProtoKit/MTOutgoingMessage.h>
#import <MtProtoKit/MTBuffer.h>
- (void)sendPing {
// Build the raw TL‑object for “ping#7abe77ec ping_id:long = Pong”
MTBuffer *buf = [[MTBuffer alloc] init];
[buf appendInt32:0x7abe77ec]; // constructor id
int64_t pingId = (int64_t)arc4random(); // random 64‑bit ping_id
[buf appendInt64:pingId];
MTOutgoingMessage *msg = [[MTOutgoingMessage alloc] initWithData:buf.data
metadata:@"ping"
additionalDebugDescription:nil
shortMetadata:@"ping"];
msg.requiresConfirmation = true; // we want a server response
// Wrap the outgoing message in a transaction
MTMessageTransaction *tx = [[MTMessageTransaction alloc] initWithMessagePayload:@[msg]
prepared:nil
failed:nil
completion:^(NSDictionary *msgIdToTxId,
NSDictionary *msgIdToPrepared,
NSDictionary *msgIdToQuickAck) {
NSLog(@"Ping transaction completed");
}];
// Attach a lightweight service that will forward the response to us
[self.proto addMessageService:tx];
// Request the transport to flush the pending messages
[self.proto requestTransportTransaction];
}
Handling Lost Messages
When the server indicates a missing message ID, trigger the automatic resend mechanism:
- (void)handleMissingMessageId:(int64_t)msgId {
// The core offers a tiny helper – it will create the resend service for us
[self.proto requestMessageWithId:msgId];
}
This call spawns an MTResendMessageService that constructs and transmits a msg_resend_req without manual intervention.
Summary
- MtProtoKit serves as the dedicated sub-module implementing the MTProto protocol in Telegram-iOS, isolating network, cryptographic, and state management concerns.
- The
MTProtoclass inMTProto.moperates as a central state machine tracking connection status through bitfield flags likeAwaitingDatacenterAuthorizationandAwaitingTimeFixAndSalts. MTProtoEnginedelegates persistence to the host application via theMTProtoPersistenceInterface, ensuring auth keys and salts survive app restarts.MTTcpTransportmanages raw TCP sockets, proxy configurations, and automatic reconnection logic.- Message services such as
MTTimeSyncMessageServiceandMTResendMessageServiceprovide modular, self-contained implementations of protocol-level reliability features. - All outgoing traffic undergoes AES-IGE encryption via
MTEncryption.mafter being prepared with unique message IDs generated byMTSessionInfo.
Frequently Asked Questions
What is the role of MTProtoKit in Telegram-iOS?
MTProtoKit is the dedicated sub-module that encapsulates the entire MTProto protocol implementation, providing the cryptographic primitives, transport layers, and session management required for secure communication with Telegram servers. According to the TelegramMessenger/Telegram-iOS source code, this module lives in submodules/MtProtoKit and exposes Objective-C interfaces for initializing connections, managing auth keys, and encrypting payloads.
How does Telegram-iOS handle message encryption in MTProto?
Messages are encrypted using AES-IGE mode with auth keys retrieved via getAuthKeyForCurrentScheme:, as implemented in MTProto.m. The encryption process involves generating unique message IDs through MTSessionInfo, wrapping payloads in MTPreparedMessage objects with current salts, and calling the static helper +[MTProto _manuallyEncryptedMessage:messageId:authKey:] which applies the cipher with 16-byte padding.
What happens when the client and server clocks are out of sync?
The MTTimeSyncMessageService automatically initiates a time-fix handshake when the MTProto state machine enters AwaitingTimeFixAndSalts. This service, defined in MTTimeSyncMessageService.m, transmits msgs_state_req and msgs_state_info messages to calculate clock offset and retrieve fresh salts, updating the internal MTTimeFixContext before removing itself from the active service queue.
How does the protocol ensure reliable message delivery?
Reliability is ensured through the MTResendMessageService and sequence number tracking, as defined in MTResendMessageService.m. When the server reports a missing message ID, the requestMessageWithId: method spawns a temporary service that constructs a msg_resend_req and automatically destroys itself upon server acknowledgment, ensuring gaps in message sequences are filled without blocking other operations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →