# How the MTProto Protocol Is Implemented in TelegramCore for iOS: A Deep Dive into MtProtoKit

> Explore the MTProto protocol implementation in TelegramCore for iOS. Discover how MtProtoKit manages sessions, auth keys, and transport layers for secure communication within the app.

- Repository: [TelegramMessenger/Telegram-iOS](https://github.com/TelegramMessenger/Telegram-iOS)
- Tags: deep-dive
- Published: 2026-04-07

---

**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 to `MTContext` for 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.
- **`Stopped`** and **`Paused`** – 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:

1. **Message ID Generation** – `MTSessionInfo` generates monotonic identifiers via `generateClientMessageId:` and sequence numbers through `takeSeqNo:`.
2. **Auth Key Resolution** – `getAuthKeyForCurrentScheme:` retrieves either persistent or ephemeral keys based on the `useTempAuthKeys` configuration.
3. **Payload Construction** – Raw data is wrapped in an **`MTPreparedMessage`** object containing the current salt from `MTDatacenterSaltInfo`.
4. **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:

```objc
#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:

```objc
#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:

```objc
- (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 **`MTProto`** class in `MTProto.m` operates as a central state machine tracking connection status through bitfield flags like `AwaitingDatacenterAuthorization` and `AwaitingTimeFixAndSalts`.
- **`MTProtoEngine`** delegates persistence to the host application via the `MTProtoPersistenceInterface`, ensuring auth keys and salts survive app restarts.
- **`MTTcpTransport`** manages raw TCP sockets, proxy configurations, and automatic reconnection logic.
- **Message services** such as `MTTimeSyncMessageService` and `MTResendMessageService` provide modular, self-contained implementations of protocol-level reliability features.
- All outgoing traffic undergoes **AES-IGE encryption** via `MTEncryption.m` after being prepared with unique message IDs generated by `MTSessionInfo`.

## 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.