layer 0.4.0

Ergonomic Telegram MTProto library โ€” auto-generated TL types, raw API access, session management
Documentation

โšก layer

A modular, production-grade async Rust implementation of the Telegram MTProto protocol.

Crates.io License: MIT OR Apache-2.0 Rust TL Layer Build Docs Channel Chat

Written from the ground up to understand Telegram's internals at the lowest level.


๐Ÿงฉ What is layer?

layer is a hand-crafted, bottom-up async Rust implementation of the Telegram MTProto protocol โ€” built not to reinvent the wheel, but to understand it.

The core protocol pieces โ€” the .tl schema parser, the AES-IGE cipher, the Diffie-Hellman key exchange, the MTProto session, the async update stream โ€” are all written from scratch. The async runtime and a handful of well-known utilities (tokio, flate2, getrandom) are borrowed from the ecosystem, because that's just good engineering. The architecture draws inspiration from the excellent grammers library.

The goal was never "yet another Telegram SDK." It was: what happens if you sit down and build every piece yourself, and actually understand why it works?

๐ŸŽ“ Personal use & learning project โ€” layer was built as a personal exploration: learning by building. The goal is to deeply understand Telegram's protocol by implementing every layer from scratch, not to ship a polished production SDK. Feel free to explore, learn from it, or hack on it!

โš ๏ธ Pre-production (0.x.x) โ€” This library is still in early development. APIs will change without notice. Not production-ready โ€” use at your own risk!


๐Ÿ’ฌ Community

Link
๐Ÿ“ข Channel (updates & releases) @layer_rs
๐Ÿ’ฌ Chat (questions & discussion) @layer_chat

๐Ÿ—๏ธ Crate Overview

Crate Description
layer-tl-parser Parses .tl schema text into an AST
layer-tl-gen Generates Rust code from the AST at build time
layer-tl-types All Layer 224 constructors, functions and enums
layer-crypto AES-IGE, RSA, SHA, DH key derivation
layer-mtproto MTProto session, DH exchange, message framing
layer-client High-level async client โ€” auth, bots, updates, 2FA, media
layer-app Interactive demo binary (not published)
layer-connect Raw DH connection demo (not published)
layer/
โ”œโ”€โ”€ layer-tl-parser/   โ”€โ”€ Parses .tl schema text โ†’ AST
โ”œโ”€โ”€ layer-tl-gen/      โ”€โ”€ AST โ†’ Rust source (build-time)
โ”œโ”€โ”€ layer-tl-types/    โ”€โ”€ Auto-generated types, functions & enums (Layer 224)
โ”œโ”€โ”€ layer-crypto/      โ”€โ”€ AES-IGE, RSA, SHA, auth key derivation
โ”œโ”€โ”€ layer-mtproto/     โ”€โ”€ MTProto session, DH, framing, transport
โ”œโ”€โ”€ layer-client/      โ”€โ”€ High-level async Client API
โ”œโ”€โ”€ layer-connect/     โ”€โ”€ Demo: raw DH + getConfig
โ””โ”€โ”€ layer-app/         โ”€โ”€ Demo: interactive login + update stream

๐Ÿ†• What's New in v0.4.0

TL Schema โ€” Layer 223 โ†’ 224

  • Updated api.tl from Layer 223 to Layer 224 (2,329 definitions, up from 2,295)
  • All generated types, functions and enums in layer-tl-types reflect Layer 224

MTProto Core Fixes

  • bad_msg auto-resend โ€” messages rejected by the server are automatically re-queued
  • seq_no correction for error codes 32/33
  • Outgoing MsgsAck handling with periodic flush
  • Message container batching for lower round-trip overhead
  • gzip_packed support for large outgoing requests
  • future_salts prefetch and rotation before expiry
  • time_offset correction applied to all outgoing msg_id values
  • msg_resend_req handling from a sent-body cache

Connection / Session

  • Sent message body tracking for resend
  • pending_ack batching system
  • new_session_created / DestroySession lifecycle handling
  • New disconnect() method for graceful teardown

Update Engine

  • pts / seq / qts tracking with gap detection
  • Per-channel getChannelDifference loop
  • Update deadline detection triggers getDifference on stale sequences
  • PossibleGapBuffer for out-of-order update recovery

New Client APIs

  • send_reaction() โ€” send a message reaction
  • set_admin_rights() โ€” promote a user with AdminRightsBuilder
  • set_banned_rights() โ€” restrict a user with BanRights
  • iter_participants() โ€” lazy async iterator over all members
  • get_profile_photos() โ€” fetch a user's profile photo list
  • get_permissions() โ€” retrieve effective permissions of a user
  • edit_inline_message() โ€” edit a message sent via inline mode

Search

  • SearchBuilder โ€” fluent per-peer message search with date filters and limits
  • GlobalSearchBuilder โ€” search across all dialogs

Updates & Keyboard

  • IncomingMessage: new markdown_text(), html_text(), and extended accessors
  • CallbackQuery: typed helpers for game_short_name, chat_instance, data
  • InlineSend::edit_message() support
  • Keyboard: added request_phone, request_geo, request_poll, request_quiz, game, buy, copy_text button constructors
  • Typing: topic typing via optional top_msg_id in send_chat_action

๐Ÿš€ Quick Start

Add to your Cargo.toml:

[dependencies]
layer-client = "0.4.0"
tokio = { version = "1", features = ["full"] }

๐Ÿ‘ค User Account

use layer_client::{Client, Config, SignInError};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (client, _shutdown) = Client::connect(Config {
        session_path: "my.session".into(),
        api_id:       12345,          // https://my.telegram.org
        api_hash:     "abc123".into(),
        ..Default::default()
    }).await?;

    if !client.is_authorized().await? {
        let token = client.request_login_code("+1234567890").await?;
        let code  = "12345"; // read from stdin

        match client.sign_in(&token, code).await {
            Ok(name) => println!("Welcome, {name}!"),
            Err(SignInError::PasswordRequired(t)) => {
                client.check_password(*t, "my_2fa_password").await?;
            }
            Err(e) => return Err(e.into()),
        }
        client.save_session().await?;
    }

    client.send_message("me", "Hello from layer! ๐Ÿ‘‹").await?;
    Ok(())
}

๐Ÿค– Bot

use layer_client::{Client, Config, update::Update};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (client, _shutdown) = Client::connect(Config {
        session_path: "bot.session".into(),
        api_id:       12345,
        api_hash:     "abc123".into(),
        ..Default::default()
    }).await?;

    client.bot_sign_in("1234567890:ABCdef...").await?;
    client.save_session().await?;

    let mut updates = client.stream_updates();
    while let Some(update) = updates.next().await {
        match update {
            Update::NewMessage(msg) if !msg.outgoing() => {
                if let Some(peer) = msg.peer_id() {
                    client.send_message_to_peer(
                        peer.clone(),
                        &format!("Echo: {}", msg.text().unwrap_or("")),
                    ).await?;
                }
            }
            Update::CallbackQuery(cb) => {
                client.answer_callback_query(cb.query_id, Some("Done!"), false).await?;
            }
            _ => {}
        }
    }
    Ok(())
}

โœ… What Is Supported

๐Ÿ” Cryptography

  • AES-IGE encryption / decryption (MTProto 2.0)
  • RSA encryption with Telegram's public keys
  • SHA-1 and SHA-256 hashing
  • Auth key derivation from DH nonce material
  • PQ factorization (Pollard's rho)
  • Diffie-Hellman shared secret computation

๐Ÿ“ก MTProto

  • Full 3-step DH key exchange handshake
  • MTProto 2.0 encrypted sessions
  • Proper message framing (salt, session_id, msg_id, seq_no)
  • msg_container (multi-message) unpacking
  • gzip-packed response decompression
  • Server salt tracking, pong, bad_server_salt handling
  • bad_msg_notification handling
  • Reconnect with exponential backoff + ยฑ20% jitter
  • Network hint channel (signal_network_restored()) to skip backoff immediately

๐Ÿš‚ Transports

  • Abridged โ€” default, single-byte length prefix (lowest overhead)
  • Intermediate โ€” 4-byte LE length prefix, better proxy compat
  • Obfuscated2 โ€” XOR stream cipher over Abridged, bypasses DPI / MTProxy

๐Ÿ“ฆ TL Type System

  • Full .tl schema parser
  • Build-time Rust code generation
  • All Layer 224 constructors โ€” 2,329 definitions
  • Serializable / Deserializable traits for all types
  • RemoteCall trait for all RPC functions
  • Optional: Debug, serde, name_for_id(u32)

๐Ÿ‘ค Auth

  • Phone code login (request_login_code โ†’ sign_in)
  • 2FA SRP password (check_password)
  • Bot token login (bot_sign_in)
  • Sign out (sign_out)
  • DC migration โ€” PHONE_MIGRATE_*, USER_MIGRATE_*, NETWORK_MIGRATE_*
  • FLOOD_WAIT auto-retry with configurable policy (RetryPolicy trait)
  • Configurable I/O error retry treated as a flood-equivalent delay

๐Ÿ’ฌ Messaging

  • Send text message by username/peer (send_message, send_message_to_peer)
  • Send with full options โ€” reply_to, silent, schedule, no_webpage, entities, markup via InputMessage builder
  • Send to Saved Messages (send_to_self)
  • Edit message (edit_message)
  • Edit inline bot message (edit_inline_message)
  • Forward messages (forward_messages)
  • Delete messages (delete_messages)
  • Get messages by ID (get_messages_by_id)
  • Get / delete scheduled messages
  • Pin / unpin message, unpin all messages
  • Get pinned message
  • Send chat action / typing indicator (send_chat_action)
  • TypingGuard โ€” RAII wrapper, keeps typing alive on an interval, auto-cancels on drop
  • Send reactions (send_reaction)
  • Mark as read, clear mentions

๐Ÿ“Ž Media

  • Upload file from bytes โ€” sequential (upload_file) and concurrent parallel-parts (upload_file_concurrent)
  • Upload from async AsyncRead stream (upload_stream)
  • Send file as document or photo (send_file)
  • Send multiple media in one album (send_multi_media)
  • Download media to file (download_media_to_file)
  • Chunked streaming download (DownloadIter)
  • Photo, Document, Sticker ergonomic wrappers with accessors
  • Downloadable trait for generic media location handling

โŒจ๏ธ Keyboards & Reply Markup

  • InlineKeyboard row builder
  • Button types: callback, url, url_auth, switch_inline, switch_elsewhere, webview, simple_webview, request_phone, request_geo, request_poll, request_quiz, game, buy, copy_text
  • Reply keyboard (standard keyboard) builder
  • Answer callback query, answer inline query

๐Ÿ“‹ Text Parsing

  • Markdown parser โ†’ (plain_text, Vec<MessageEntity>)
  • HTML parser โ†’ (plain_text, Vec<MessageEntity>) (feature html)
  • spec-compliant html5ever tokenizer replacing parse_html (feature html5ever)
  • HTML generator (generate_html) always available, hand-rolled

๐Ÿ‘ฅ Participants & Chat Management

  • Get participants, kick, ban with BanRights builder, promote with AdminRightsBuilder
  • Get profile photos
  • Search peer members
  • Join chat / accept invite link
  • Delete dialog

๐Ÿ” Search

  • Search messages in a peer (SearchBuilder)
  • Global search across all chats (GlobalSearchBuilder)

๐Ÿ“œ Dialogs & Iteration

  • List dialogs (get_dialogs)
  • Lazy dialog iterator (iter_dialogs)
  • Lazy message iterator per peer (iter_messages)

๐Ÿ”— Peer Resolution

  • Resolve username โ†’ peer (resolve_username)
  • Resolve peer string (username, phone, "me") โ†’ InputPeer (resolve_peer)
  • Access-hash cache, restored from session across restarts

๐Ÿ’พ Session Persistence

  • Binary file session (BinaryFileBackend) โ€” default
  • In-memory session (InMemoryBackend) โ€” testing / ephemeral bots
  • SQLite session (SqliteBackend) โ€” feature sqlite
  • SessionBackend trait โ€” plug in any custom backend
  • Catch-up mode (Config::catch_up) โ€” replay missed updates via getDifference on reconnect

๐ŸŒ Networking

  • SOCKS5 proxy (Config::socks5, optional username/password auth)
  • Multi-DC pool โ€” auth keys stored per DC, connections created on demand
  • invoke_on_dc โ€” send a request to a specific DC
  • Raw escape hatch: client.invoke::<R>() for any Layer 224 method not yet wrapped

๐Ÿ”” Updates

  • Typed update stream (stream_updates())
  • Update::NewMessage / MessageEdited / MessageDeleted
  • Update::CallbackQuery / InlineQuery / InlineSend
  • Update::Raw โ€” unmapped TL update passthrough
  • PTS / QTS / seq / date gap detection and fill via getDifference
  • Per-channel PTS tracking

๐Ÿ›‘ Shutdown

  • ShutdownToken returned from Client::connect โ€” call .cancel() to begin graceful shutdown
  • client.disconnect() โ€” disconnect without token

โŒ What Is NOT Supported

These are high level gaps, not planned omissions, just not built yet. Use client.invoke::<R>() with raw TL types as a workaround for any of these.

Feature Notes
Secret chats (E2E) MTProto layer-2 secret chats not implemented
Voice / video calls No call signalling or media transport
Payments SentCode::PaymentRequired returns an error; payment flow not implemented
Group / channel creation createChat, createChannel not wrapped
Channel admin tooling No channel creation, migration, linking, or statistics โ€” admin/ban rights are supported via set_admin_rights / set_banned_rights
Sticker set management No getStickerSet, uploadStickerFile, etc.
Account settings No profile update, privacy settings, notification preferences
Contact management No importContacts, deleteContacts
Poll / quiz creation No InputMediaPoll wrapper
Live location Not wrapped
Bot menu / command registration setMyCommands, setBotInfo not wrapped
IPv6 Config flag exists (allow_ipv6: false) but not tested
MTProxy with proxy secret Obfuscated2 transport works; MTProxy secret mode untested

๐Ÿ”ง Feature Flags

layer-tl-types

Feature Default Description
tl-api โœ… High-level Telegram API schema
tl-mtproto โŒ Low-level MTProto schema
impl-debug โœ… #[derive(Debug)] on generated types
impl-from-type โœ… From<types::T> for enums::E
impl-from-enum โœ… TryFrom<enums::E> for types::T
name-for-id โŒ name_for_id(u32) -> Option<&'static str>
impl-serde โŒ serde::Serialize / Deserialize

layer-client

Feature Default Description
html โŒ Built-in hand-rolled HTML parser (parse_html, generate_html)
html5ever โŒ spec-compliant html5ever tokenizer replaces parse_html
sqlite โŒ SQLite session backend (SqliteBackend)

๐Ÿ“ Updating to a New TL Layer

# 1. Replace the schema
cp new-api.tl layer-tl-types/tl/api.tl

# 2. Build โ€” types regenerate automatically
cargo build

๐Ÿงช Tests

cargo test --workspace

๐Ÿ“„ License

Licensed under either of, at your option:


๐Ÿ‘ค Author

Ankit Chaubey

Built with curiosity, caffeine, and a lot of Rust compiler errors. ๐Ÿฆ€

๐Ÿ™ GitHub github.com/ankit-chaubey
๐ŸŒ Website ankitchaubey.in
๐Ÿ“ฌ Email ankitchaubey.dev@gmail.com
๐Ÿ“ฆ Project github.com/ankit-chaubey/layer
๐Ÿ“ข Channel @layer_rs
๐Ÿ’ฌ Chat @layer_chat

๐Ÿ™ Acknowledgements

  • Lonami for grammers. Portions of this project include code derived from the grammers project, which is dual-licensed under the MIT or Apache-2.0 licenses. The architecture, design decisions, SRP math, and session handling are deeply inspired by grammers. It's a fantastic library and an even better learning resource. Thank you for making it open source! ๐ŸŽ‰

  • Telegram for the detailed MTProto specification.

  • The Rust async ecosystem โ€” tokio, getrandom, flate2, and friends.

  • ๐Ÿค– AI tools used for clearer documentation and better comments across the repo (2026 is a good year to use AI).
    Even regrets ๐Ÿ˜ after making these docs through AI. iykyk. Too lazy to revert and type again, so it stays as is!


โš ๏ธ Telegram Terms of Service

As with any third-party Telegram library, please ensure that your usage complies with Telegram's Terms of Service. Misuse or abuse of the Telegram API may result in temporary limitations or permanent bans of Telegram accounts.


layer.. because sometimes you have to build it yourself to truly understand it.