Технический разбор

Призрак: децентрализованный мессенджер, который на проводе выглядит как обычный HTTPS

F Foxeevich · автор Prizrak · ·~22 мин чтения
TL;DR. Я собрал мессенджер, у которого нет главного сервера, нет привязки к номеру телефона, есть сквозное шифрование и транспорт, который на проводе выглядит как обычный поход на сайт по HTTPS. Если два сервера перестают видеть друг друга — сообщения едут через промежуточные «тайники», у которых нет ключа от содержимого. Плюс встроенный двухпрыжковый VPN: движок готов и покрыт тестами, боевая обвязка ещё дошивается — об этом честно в конце. Всё открыто под AGPL-3.0.
Сайт проекта prizrak.im
Главная страница prizrak.im — клиенты для Android, Windows, macOS и Linux лежат там же.

Зачем ещё один мессенджер

Обычно на этот вопрос отвечают лозунгами. Я попробую ответить инженерно — через то, что ломается в существующих решениях.

Первое: центр. У Telegram, WhatsApp и Signal есть организация, у которой можно что-то потребовать, и инфраструктура, которую можно заблокировать целиком. Даже если переписка зашифрована, сам факт «кто с кем и когда» лежит в одном месте, и это место можно выключить. Проблема не в злом умысле компании — проблема в том, что такая точка вообще существует.

Второе: номер телефона. Номер — это ваш паспорт, привязанный к SIM-карте, которая куплена по документам. Мессенджер, который требует номер, по построению не может быть анонимным.

Третье: транспорт. Даже идеально зашифрованный мессенджер бесполезен, если DPI видит его на проводе и режет соединение. Здесь важна деталь, которую часто упускают: шифрование и незаметность — это разные задачи. Можно зашифровать всё идеально и всё равно быть опознанным по первым восьми байтам пакета.

Prizrak («Призрак») — попытка закрыть все три пункта сразу, не жертвуя удобством: чаты, группы, каналы, звонки, голосовые, «кружочки», реакции, подарки — всё, к чему люди привыкли в Telegram.


Что получилось: коротко

Что Как сделано
Идентификатор имя:домен, без номера телефона и без почты
Шифрование OpenPGP-паспорт + X3DH + Double Ratchet; для больших групп спроектирован MLS (RFC 9420)
Федерация Свой homeserver на своём домене, серверы находят друг друга сами
Транспорт Настоящий TLS 1.3 к настоящему домену, мультипорт, страница-обманка при зондировании
Обход блокировок Сеть «тайников» — промежуточных узлов, которые не могут прочитать содержимое
Звонки Свой нативный медиастек, свой аналог STUN, P2P или релей
VPN Встроенный, в два прыжка, со своим протоколом на проводе (движок готов, обвязка в работе)
Клиенты Electron (macOS / Windows / Linux) и React Native (Android, iOS в работе)
Лицензия AGPL-3.0
Интерфейс десктоп-клиента
Десктоп-клиент. Снаружи — обычный мессенджер: чаты, группы, каналы, звонки, голосовые, галочки доставки и прочтения.

Три опоры

Вся система стоит на трёх вещах. Их нельзя «выключить по требованию» — они вшиты в архитектуру.

Общая архитектура Prizrak
Два независимых канала: сообщения через homeserver'ы, звонки — напрямую или через релей. И то и другое — внутри stealth-транспорта.

1. Федерация без центра

Нет главного сервера. Любой поднимает свой homeserver на своём домене, и его пользователи сразу общаются с пользователями других серверов. Ровно как электронная почта: серверов много, сеть одна.

Пользователь адресуется как alice:a.org — имя и домен домашнего сервера. Когда alice:a.org пишет bob:b.org, сервер a.org смотрит на домен получателя, находит сервер b.org и передаёт ему конверт.

2. Сквозное шифрование

Сервер — тупой ретранслятор запечатанных конвертов. Он видит маршрут (от кого, кому, когда) и шифртекст. Больше ничего. Ни владелец сервера, ни провайдер, ни тот, кто сервер изъял, не прочитают переписку: ключи есть только у собеседников.

Это не декларация, а свойство кода: сервер хранит поле payload, в котором лежит шифртекст, и у него нет ключей, чтобы его открыть.

3. Невидимость для DPI

Трафик мессенджера и звонков должен выглядеть как обычный веб-сёрфинг. Не «похоже на HTTPS», а буквально HTTPS: настоящий TLS 1.3-хендшейк с настоящим сертификатом сервера. Обнаруживать нечего, потому что ничего не имитируется — рукопожатие честное.


Федерация: как это работает на самом деле

Идея взята у Matrix, но сознательно упрощена.

Discovery. Классический путь — GET https://домен/.well-known/prizrak/server, который отдаёт базовый URL. Но я пошёл дальше: прописывать чужие серверы в конфиг не нужно вообще. Сервер сам сканирует стандартные порты соседа — 443, 8801, 80, 993, 995, 587, 465, 143, 110, 25 — и находит рабочую точку входа, кэшируя результат на 5 минут. Строчка resolver в конфиге осталась только как необязательный пин, если у соседа нестандартный адрес.

Почему это важно: любой обязательный конфиг — это точка отказа и ручная работа. Сменился адрес узла — и надо править файлы на всех серверах сети. Живое обнаружение снимает эту боль полностью.

Два API. Клиент-серверное и сервер-серверное:

Уровень Метод Путь Назначение
Клиент POST /_prizrak/client/v1/register опубликовать профиль и prekey-bundle
Клиент GET /_prizrak/client/v1/bundle?userId= взять ключи собеседника (в т.ч. с чужого домена)
Клиент POST /_prizrak/client/v1/send отправить запечатанный конверт
Сервер POST /_prizrak/federation/v1/send принять конверт для своего пользователя
Сервер GET /_prizrak/federation/v1/bundle?userId= отдать ключи своего пользователя

Чем проще Matrix. Matrix реплицирует между серверами полный граф состояния комнаты с разрешением конфликтов (state resolution). Это мощно и тяжело. Для мессенджера «как Telegram» это избыточно: сообщения — это поток запечатанных событий с доставкой store-and-forward, а состояние группы решается на уровне E2E-группы, а не открытого серверного стейта.

Хранилище — SQLite в режиме WAL с нормальными таблицами и индексами (раньше был JSON-файл; миграция прошла с автопереносом и 34 тестами на стор).


Шифрование: почему «чистый PGP-мессенджер» — плохая идея

Изначально хотелось «просто PGP»: открытый ключ, закрытый ключ, всё понятно. Это правильная интуиция про асимметричную криптографию — и неправильное решение для потока сообщений. Разберём честно.

Криптографический стек

Что не так с PGP как транспортом переписки:

Что при этом PGP делает отлично — и за что он остался в проекте:

Итоговая схема:

OpenPGP-ключ (долговременный)  ──подписывает──▶  X25519 identity + prekeys
                                                          │
                                             X3DH: первый общий секрет
                                                          │
                                              Double Ratchet (поток 1:1)
                                    forward secrecy + post-compromise security

Под капотом: X25519 для DH-ратчета, HKDF-SHA256 для root-цепочки, HMAC-SHA256 для symmetric-цепочек, ChaCha20-Poly1305 как AEAD. Доставка не по порядку поддержана (skipped message keys) — иначе мобильная сеть развалит переписку на первом же переключении вышки.

Для больших групп попарные сессии не масштабируются: O(n) шифрований на каждое сообщение. Для этого в архитектуру заложен MLS (RFC 9420) — групповой E2E, где сообщение шифруется один раз независимо от размера группы, а смена состава стоит O(log n). MLS рассчитан на недоверенную службу доставки, что ложится на федеративную модель идеально. Оговорка: MLS спроектирован, но пока не интегрирован — сегодня группы работают через per-device fan-out (см. раздел про ограничения).

Про защиту от подмены ключей честно. Защита многослойная: подпись prekeys паспортом, сверка отпечатка вживую, а для продакшена нужен публичный key transparency-лог (append-only, как CONIKS), чтобы подмена ключа была публично обнаружима. KT-лога пока нет — это в планах, и я это не скрываю.


Транспорт: почему обычный звонок ловится DPI за один пакет

Это самая недооценённая часть. Люди думают: «Раз всё зашифровано, DPI ничего не увидит». Увидит. DPI смотрит не в содержимое, а в форму.

Что видит DPI

У обычного WebRTC-звонка есть две сигнатуры, обе открытым текстом:

Вывод, который мне пришлось принять на старте: маскировать надо не «сигналинг», а весь транспорт целиком. Прятать управляющий канал бессмысленно, если сам медиапоток кричит о себе первыми байтами.

Решение: не имитировать HTTPS, а быть им

Лучшее, что реально работает против современных фильтров, — подход в духе Reality/XTLS. Идея контринтуитивная: не подделывать TLS, а провести настоящий TLS 1.3-хендшейк.

Мультипорт и «клиент сам найдёт дорогу»

Сервер слушает сразу список стабильных портов и молча пропускает те, что заняты или требуют прав. Клиент подключается по адресу без порта и сам сканирует, начиная с 443. Если задан сертификат — 443, 993, 995 и 465 поднимаются как настоящий HTTPS/WSS.

Смысл простой: чем больше независимых точек входа, тем дороже блокировка. И тем меньше вопросов у пользователя, который просто вводит имя:домен и не должен знать слово «порт».

Честная оговорка. Я специально не стал делать «свою обфускацию поверх TLS» и заявлять, что она неотличима. Настоящий TLS на 443 с реальным сертификатом даёт фильтру гораздо меньше зацепок, чем любой самодельный протокол-мимикрия. Но «меньше зацепок» — это не «невидимо»: тайминги и объёмы трафика никуда не деваются, а кастомная мимикрия — отдельный крупный R&D, и называть её невидимой голословно нечестно.


Звонки: как я потратил неделю на 2048 байт

Самая поучительная инженерная история проекта. Держите её как чек-лист, если будете делать своё медиа.

Диагноз на старте. Звонки тормозили и грели телефон. Виновато было не шифрование (аппаратный AES — доли процента CPU), а две вещи:

  1. Каждый видеокадр гонялся через мост React Native в JavaScript как base64. Чудовищные накладные расходы на каждый кадр.
  2. Весь поток шёл только через сервер.

Решение: медиа целиком уходит в натив (Camera2 / MediaCodec / AudioRecord / Opus), JS занимается только сигналингом и UI. Ноль base64 на кадр.

Свой аналог STUN. Публичный STUN не годится — см. magic cookie выше. Вместо него сервер сам работает «зеркалом адресов»: клиент шлёт один UDP-пакет, оформленный по форме как QUIC-initial (long header, случайный connection ID), сервер отвечает, какой публичный ip:port он увидел. Это ровно функция STUN, но без единого узнаваемого байта на проводе. Дальше — обмен кандидатами по уже зашифрованному сигналингу и одновременный hole-punch.

И вот тут была та самая ошибка. После включения прямого P2P-пути звук в видеозвонке стал отличным, а видео посыпалось артефактами и фризами. Разница между звуком и видео — размер пакетов: Opus-кадр это сотни байт, VP8-кадр — десятки килобайт. Приёмный UDP-буфер был 2048 байт. Мелкое аудио проходило целиком, крупные видеокадры обрезались, AEAD не сходился, кадр терялся.

Правки, которые всё починили:

Топология. Прямой P2P, если NAT позволяет; иначе релей через серверы. У мобильных операторов почти всегда CGNAT, поэтому релей — рабочая лошадка, а прямой канал выигрывает на Wi-Fi. Индикатор пути (🔗 / 📡) виден прямо в звонке вместе с потерями и битрейтом.

Про кодеки и iOS честно. Согласование кодека в offer уже есть: по умолчанию VP8 (совместимость с десктопом), H.264 — в тестовом режиме на Android. Осталось научить десктоп принимать H.264 (WebCodecs) и портировать нативный стек на iOS. И там жёсткое ограничение: у iOS нет аппаратного VP8, VideoToolbox умеет H.264/HEVC. Сам iOS-клиент сейчас в состоянии «код написан, на устройстве не проверен» — сборка требует Mac с Xcode, а аудиомодуль писался вслепую и почти наверняка потребует правок.

И честно про текущее состояние на мобильном: видеозвонки сейчас снова выключены. Более поздняя регрессия роняла вместе с видео и аудио (похоже, отрисовка в мёртвый EGL-контекст после уничтожения SurfaceView), и я убрал кнопку до аккуратного пересбора видеопути — с гарантией, что видео не может уронить звук. Аудиозвонки работают.


Сеть тайников: что делать, когда прямой путь перерезан

Ситуация: серверы на доменах Д1 и Д2 не видят друг друга — IP одного забанен у другого. Но оба видят какой-то третий узел. Этого достаточно.

Сеть тайников

Ключевое решение: доставка через pull. Под фильтрацией надёжнее, когда оба конца соединяются исходяще к общему узлу. Д1 кладёт конверт в тайник, Д2 сам его забирает. Никому не нужна входящая достижимость от другого — только исходящая к тайнику.

Тайник ничего не знает. Адрес ящика — это токен HKDF(публичный ключ сервера-получателя, эпоха), а не домен. Узел не знает, чей это ящик, видит только непрозрачный меняющийся идентификатор и шифртекст. Дедупликация — по контент-адресу (msgId = хеш(шифртекста)).

Кто именно доставляет. Конверт кладётся сразу на 4 узла (RF=4). Получатель забирает первую попавшуюся копию и рассылает всем репликам подписанный ACK. Узел, получивший ACK, удаляет блоб. ACK — единственный источник правды о доставке: вернувшийся из офлайна узел спрашивает у живых «есть ACK?» и, если есть, просто удаляет своё протухшее.

Самоисцеление — по мотивам Ceph. Здесь я честно взял проверенную модель RADOS и перенёс её на тайники:

Ceph Тайники Prizrak
CRUSH — детерминированное размещение без центральной таблицы Rendezvous-хеширование (HRW): любой сам вычисляет, где лежит блоб
Cluster map + эпоха Реестр узлов с версией-эпохой, расходится госсипом
size / min_size RF=4 / min_size=2
Placement Group Бакет блобов, реплики сверяются по Merkle-корню бакета
Primary OSD Primary-тайник — первый живой в детерминированном порядке
Backfill / recovery Доливка копий до RF при уходе узла
Peering при возврате OSD Merkle-ресинк: удалить доставленное, сбросить лишнее, подтянуть недостающее

Важная поправка на цензуру: связь «узел↔узел» тоже может быть перерезана. Поэтому базовая гарантия — отправитель сразу кладёт на 4 узла (этот путь заведомо рабочий), самоисцеление — best-effort поверх, а страховка — периодический ре-фан-аут недоставленного отправителем.

Иммутабельность сильно упрощает жизнь по сравнению с Ceph: блобы write-once, удаляются по ACK или TTL (7 дней). Нет мутаций — не нужны версии, строгий порядок записи и кворумы. Только «есть копия / нет копии / есть ACK» плюс anti-entropy.

Закалка. Паддинг длин по вёдрам, PoW-admission против спама, anti-Sybil-диверсити по подписанной метке группы операторов, ротация эпох, jitter. Плюс приватные bridge-узлы, которые не попадают в публичный реестр и раздаются по инвайтам — как мосты Tor.

Проверено. Сеть тайников и федерация через неё покрыты автотестами: 140 зелёных проверок на узле и сервере, включая репликацию, самоисцеление, возврат узла из офлайна и антиэнумерацию листингов.


Обнаружение узлов без «списка в конфиге»

Отдельная проблема, которую пришлось решать: как серверы и узлы находят друг друга, если любой статический список — это подарок цензору? Опубликовал файл со списком узлов — заблокировали все разом.

Принципы, по которым сделано:

  1. Никаких статических списков. Директория — живое gossip-состояние, а не конфиг.
  2. Никакой единой точки. Директория — набор подписанных объектов, которые может отдать кто угодно: другой сервер, тайник, зеркало, CDN, DNS. Блокировка одного домена ничего не значит.
  3. Принцип Керкгоффса. Считаем, что противник знает код и весь публичный каталог. Безопасность — не в секретности списка, а в подписи (нельзя отравить), множестве входов (нельзя заблокировать все) и стелс-транспорте (трафик = обычный HTTPS).
  4. Достаточно одного живого контакта. Дотянулся до любого узла — развернул весь актуальный каталог. Дальше конфиг не нужен никогда.

Каналы холодного старта, любой одного достаточно: живой госсип от известного пира → вшитые ротируемые сиды → DNS-сиды через DoH (обходит подмену DNS) → подписанный bootstrap-бандл через большой CDN → peer exchange → приватные мосты по инвайтам.

Отдельно про анти-энумерацию: реестр отдаётся порционно и с рейт-лимитом (как BridgeDB у Tor), мосты не госсипятся публично вообще.

Честно: холодный старт под тотальным баном не решается магией — нужен хотя бы один канал получения моста извне (как с Tor bridges). Но слои выше делают так, что до этого почти никто не доходит.


Встроенный VPN: два прыжка и свой протокол

Пользователи всё равно ставят VPN отдельно, так что логично встроить его в клиент — тем более что вся стелс-механика уже есть.

Призрак-VPN

Требования были жёсткие и, на мой взгляд, правильные:

Слои технологии (у каждого свои тесты):

Слой Что делает
Тень Шифрование: Noise NK + X25519, ChaCha20-Poly1305, анти-повтор
Личина Узел снаружи — настоящий сайт с «дверью» для своих
Эстафета Два прыжка, слоистое (луковичное) шифрование A/B/C
Дыхание Форма трафика: DATA/PAD/KEEP, keepalive, автопрофиль
Стая Раздача адресов узлов без публичного списка
Живучесть Контроль доступности изнутри сессии, без пинга; автозамена узла
Экономика Билеты, тариф, делёж выручки с операторами

Три решения, которыми доволен:

Экран VPN в клиенте
Два тумблера: «Замаскироваться» (весь трафик устройства через Призрак) и «Поднять призрак-узел» (стать частью сети и зарабатывать). Ниже — страны со звёздами.

Движок покрыт автотестами — 182 зелёных на пакет VPN. Что осталось до «поля»: реальный TLS-фронт с Let's Encrypt и отпечатком ClientHello под Chrome, реальные сокеты релей↔выход вместо смоделированных в памяти, насос IP-пакетов tun↔движок и полевые проверки на разных операторах. Это я тоже не прячу: движок и слои готовы и покрыты тестами, боевая обвязка — нет.


Мультидевайс без «общего ключа на всех»

Один аккаунт на трёх устройствах — это классическая ловушка. Простое решение «положим один ключ на все устройства» ломает всю модель безопасности: украли планшет — скомпрометирован аккаунт целиком, и отозвать нечего.

Мультидевайс

Как сделано: два уровня ключей. Корень аккаунта — существующий OpenPGP-ключ (он и так лежит в резервной копии и восстанавливается сид-фразой). У каждого устройства — свой X25519 identity и свои prekeys, подписанные корнем и опубликованные в реестре устройств.

Отправитель берёт список устройств получателя и шифрует сообщение отдельно на каждое устройство отдельной ратчет-сессией. Плюс self-sync: свои исходящие и отметки «прочитано» разъезжаются на собственные устройства.

Что это даёт и чем расплачиваемся:

Лимит — 10 устройств на аккаунт, при публикации одиннадцатого вытесняется самое старое. Список устройств и кнопка отзыва — в настройках.


Группы, каналы и поиск

Здесь цель была прозаичной: паритет с Telegram, потому что люди не будут пользоваться тем, где нет привычных вещей.

Реестр поиска публичных групп. Отдельный сервис (tech.prizrak.im): серверы публикуют в него только публичные комнаты, записи подписаны ключом домашнего сервера, домен принимается по модели TOFU и сверяется с .well-known, есть рейт-лимит 60 запросов в минуту на IP, лимит 200 групп на домен и TTL 7 дней. Клиент ходит в реестр через свой сервер, так что поиск работает и за стелс-транспортом.


Bot API: как в Telegram, только проще

Ставится на каждый homeserver. Бот — это настоящий аккаунт Призрака, чьи E2E-ключи живут на сервере, а сторонний разработчик работает по обычному HTTP с токеном (наружу такой эндпоинт стоит выставлять только через свой TLS-терминатор):

POST http://<сервер>:8840/bot<TOKEN>/sendMessage
{"chat_id": "!roomid:example.org", "text": "Сборка зелёная ✅"}

Конверт ответа — как в Telegram: {ok: true, result} либо {ok: false, error_code, description}. Методы v0.1: getMe, sendMessage, getUpdates (long-poll до 30 секунд, подтверждение через offset).

Ботов заводит PrizrakFather — прямой аналог BotFather, который поднимается сам при первом старте сервиса. Пишете ему в личку /newbot, отвечаете на пару вопросов, получаете токен. Есть /mybots, /revoke и /deletebot.

Первая целевая задача была приземлённой: постить в каналы из внешних скриптов и сайтов. Тест на 22 проверки гоняет полный цикл: настоящий homeserver + botapi + живой пользователь, диалог с PrizrakFather, отзыв токена, создание группы и пост в неё через API.


Экономика: призраки, и почему деньги централизованы

В мессенджере есть внутренняя валюта — призраки (👻): подарки, донаты, реакции, оплата VPN, награды операторам узлов.

И здесь возникает вопрос, который стоит задавать любому децентрализованному проекту с валютой: что мешает админу чужого сервера начислить себе миллион? Код-то открытый.

Что децентрализовано, а что нет

Ответ честный и неромантичный: баланс нельзя хранить на самохостящихся серверах. Поэтому граница проведена так:

Три гаранта:

  1. Нельзя начислить себе. Баланс живёт только в Банке. Банк увеличивает его исключительно после подтверждённого платежа — webhook с проверкой HMAC-подписи, идемпотентно по идентификатору транзакции. Rogue-админ может только купить призраки за реальные деньги, что вполне легально.
  2. Нельзя украсть чужие. Каждая операция подписывается отдельным Ed25519-ключом пользователя («ghost-key»), Банк проверяет подпись. У админа домашнего сервера приватного ключа нет. Плюс защита от повтора: метка времени ±5 минут и одноразовый nonce.
  3. Нельзя угнать чужое имя. Ключ привязывается к user:domain по модели TOFU: первый зарегистрировавший задаёт ключ, дальнейшие изменения требуют подписи текущим ключом.

Форк, конечно, может выпустить «свои призраки» — но это будет другая валюта другого банка. Официальные существуют только в официальном Банке, и открытость кода этому не мешает: безопасность держится на секретных платёжных ключах и приватных ключах пользователей, а не на секретности исходников.

Награды операторам. Узел-тайник зарабатывает призраки за аптайм, за доставки и за гигабайт-часы хранения. Доставки пока считаются по самоотчёту узла — криптографический пруф доставки от получателя в планах, и до него владелец сети правит цифры руками. Владелец сети задаёт ставки в админке, видит таблицу операторов и выплачивает накопленное. Аптайм капается на разрыв, выплата идемпотентна.


Из чего это собрано

Карта проекта

Монорепозиторий. Ядро на JavaScript переиспользуется десктопом и мобилкой, натив появляется только там, где без него никак (медиа, VPN-сервис Android).

Поднять свой сервер:

cd packages/server
npm install
./deploy/prizrak-deploy.sh init --domain chat.example.org \
  --admin root --registration on --relay-url stealth://<IP>:8810
./deploy/prizrak-deploy.sh create-admin --password 'PASSWORD'
./deploy/prizrak-deploy.sh start

Поднять узел-тайник (нужен любой сервер или домашний компьютер с Node.js и постоянным интернетом):

cd packages/deaddrop
npm install
node src/node.js
# статус: http://127.0.0.1:8820/status

Порты по умолчанию: homeserver — 8801, релей звонков — 8810, rendezvous — 8811/UDP, узел-тайник — 8820, реестр групп — 8830, Bot API — 8840. Плюс 80/443 и почтовые, если включена TLS-маскировка. UDP 8811 нужно явно открыть в фаерволе — без этого прямой P2P-путь соберётся только внутри одной Wi-Fi.

Клиенты — на prizrak.im: APK для Android, .exe для Windows, .dmg для macOS, AppImage для Linux. Регистрация — логин и пароль, домен подставляется сам.

Страница загрузки

Из мелочей, которые дались дороже, чем ожидалось, но без которых продукт не продукт: резервная копия аккаунта в файл, сид-фраза из 17 слов с контрольной суммой (запасной вход и сброс пароля), автообновление в один клик с проверкой подписи Ed25519, сворачивание в трей, звук входящего (да, тот самый ICQ-шный), кружочки-видеосообщения до 60 секунд, голосовые с волной формы сигнала, галочки доставки и прочтения — причём у голосовых и «кружочков» вторая галочка ставится только по факту прослушивания, как в Telegram.


Что не сделано и где слабые места

Раздел, ради которого стоит читать любую статью про безопасность.

Ничего из этого не мешает пользоваться мессенджером сегодня, но знать об этом стоит.


Юридическое замечание

Средства обхода блокировок защищают свободу слова и приватность, но их легальность различается по юрисдикциям. Проект развивается как опенсорс для приватности и свободы общения; ответственность за соблюдение применимого к вам закона лежит на вас.


Итог

Prizrak — это попытка сделать честный децентрализованный мессенджер без компромиссов в трёх местах сразу: нет центра, нет привязки к личности, нет узнаваемого следа на проводе. Плюс встроенный VPN, потому что все три задачи опираются на один и тот же стелс-транспорт, и было бы странно не переиспользовать его.

Проект открыт, форки и свои серверы приветствуются: чем больше независимых узлов, тем дороже сеть блокировать.

Буду рад разбору по существу — особенно от тех, кто занимался DPI, транспортами и групповой криптографией. Критика по делу здесь полезнее звёздочек.

Попробовать

Клиенты для Android, Windows, macOS и Linux — на странице загрузки. Исходники — на GitHub под AGPL-3.0.