С последней статьи о Hidden Lake прошло больше года. За это время сеть успела достаточно сильно измениться - были переименованы и структурированы сервисы, была переосмыслена концепция адаптеров и прикладных приложений, был написан клиент для работы с узлом HL, было улучшено покрытие тестами, многократно модифицировался сервис файлообмена, упрощался сервис обмена сообщениями и т.д. и т.п.

Пу-пу-пу

Скорее всего, за это время я бы мог сделать ещё куда больше, но чёртовы souls-like игры Бабадзаки затянули меня в своё PvP с созданием множества вариаций билдов на несколько сотен часов.

В этой статье я хотел бы отразить вкратце основной список изменений (с 1.7.7 по 1.10.2), привести актуальную версию запуска узла анонимной сети и сопутствующего ей клиента для комфортной работы, а также описать будущее видение развития данного проекта.

Вкратце об анонимной сети «Hidden Lake»

Анонимная сеть Hidden Lake (HL) - это децентрализованная F2F (friend-to-friend) анонимная сеть с теоретической доказуемостью на базе очередей (QB-задача). В отличие от известных анонимных сетей, подобия Tor, I2P, Mixminion, Crowds и т.п., сеть HL способна противостоять атакам глобального наблюдателя. Сети Hidden Lake для анонимизации своего трафика не важны такие критерии как: 1) уровень сетевой централизации, 2) количество узлов, 3) расположение узлов и 4) связь между узлами в сети.

Более подробный анализ сети Hidden Lake можно найти в работе:
-> Анонимная сеть «Hidden Lake».

Репозиторий Hidden Lake: https://github.com/number571/hidden-lake
Репозиторий проекта go-peer: https://github.com/number571/go-peer

QB-задача

Задача на базе очередей может быть описана следующим списком действий:

  1. Каждое сообщение m шифруется ключом получателя k: c = Ek(m),

  2. Сообщение c отправляется в период = T всем участникам сети,

  3. Период T одного участника независим от периодов T1, T2, ..., Tn других участников,

  4. Если на период T сообщения не существует, то в сеть отправляется ложное сообщение v без получателя (со случайным ключом r): c = Er(v),

  5. Каждый участник пытается расшифровать принятое им сообщение из сети: m = Dk(c).

QB-сеть с тремя узлами A, B, C
QB-сеть с тремя узлами A, B, C

Для любых пассивных наблюдателей, включая и глобального наблюдателя, QB-задача считается трудновыполнимой, потому как она скрывает не только связь между узлами, но и состояние таковых узлов: 1) отправляет ли анализируемый узел какие-нибудь сообщения?; 2) принимает их?; 3) или вовсе бездействует? - таковые вопросы порождает задача.

Основной список изменений

1| Структуризация сервисов

Данное изменение является небольшим, простым в реализации, но и не менее важным. Ранее в Hidden Lake существовало множество сервисов: HLC, HLE, HLF, HLL, HLM, HLR, HLS, HLT. Понять из этих аббревиатур, что означает тот или иной сервис, а также к чему / к какой категории он относится можно было лишь из прочтения его README.

Некоторые сервисы из данного списка лишь косвенно относились к анонимности / анонимизации трафика как таковой. Так например, сервисы HLL (loader), HLE (encryptor) являлись побочными, вспомогательными приложениями. Целью HLL была подгрузка ранее сгенерированного трафика с ретранслятора, который хранил N-ое количество шифртекстов. Целью HLE являлось шифрование и расшифрование сообщений, при этом его функции также дублировались в HLS (service) - ранее называемом ядре анонимной сети. Сервисы HLF (filesharer), HLM (messenger), HLR (remoter) - являлись прикладными сервисами. HLT (traffic) был сервисом транспортировки шифртекстов между узлами сети.

Все из вышеописанных сервисов были в той или иной мере изменены или вовсе удалены. Больше не существует вспомогательных сервисов (HLL, HLE). Прикладные сервисы сначала сгруппировались в HLS нейминг (ядро анонимной сети было переименовано в HLK (kernel)), HLS=filesharer, HLS=messenger, HLS=remoter (remoter был удалён вследствие своей специфичности и потенциальной опасности), а далее изменили свой принцип работы, перестав выполнять роль клиентских приложений. Сервис HLT и вовсе эволюционировал в обновлённую схему адаптеров (об этом буду писать далее).

Стек протоколов GP/12
Стек протоколов GP/12
Категоризация сервисов по стеку протоколов GP/12. AL - прикладной уровень (запись/чтение сообщений), TL - транспортный уровень (упаковка, добавление заголовков, путей), NL - сетевой уровень (анонимизация/шифрование трафика), CL - канальный уровень (маршрутизация/проверка принадлежности трафика к подсети)
Категоризация сервисов по стеку протоколов GP/12. AL - прикладной уровень (запись/чтение сообщений), TL - транспортный уровень (упаковка, добавление заголовков, путей), NL - сетевой уровень (анонимизация/шифрование трафика), CL - канальный уровень (маршрутизация/проверка принадлежности трафика к подсети)

В результате, неупорядоченное множество сервисов начало наконец вырисовывать более чёткую картину правильной архитектуры взаимодействия приложений между собой. Всего осталось три категории приложений - HLS (прикладные приложения), HLK (ядро сети, производящее анонимизированный трафик) и HLA (адаптеры, отправляющие и принимающие шифртексты в/из внешней среды).

2| Переосмысление адаптеров

Как я упоминал ранее, в Hidden Lake существовал такой сервис, как - HLT, целью которого была транспортировка анонимизирующего (шифрованного) трафика вовне и сопутствующее принятие трафика из вне. По нему или с косвенным его использованием писал также несколько статей на хабр: 1, 2.

Адаптация анонимизирующего трафика при помощи HLT
Адаптация анонимизирующего трафика при помощи HLT

У HLT было несколько способов применения. Первый и самый основной - это выполнять роль ретранслятора. Несколько узлов Hidden Lake (узел - это фактически ядро сети, ранее оно называлось HLS, сейчас - HLK) подключалось к внешнему приложению HLT по TCP протоколу, и оно, в свою очередь, ретранслировало весь входящий трафик с одного узла на всех остальных. Второе и более специфичное применение - это выполнять роль адаптера к среде, в которой сеть, по умолчанию, не могла нормально функционировать. Как например, централизованный сервис в котором имеется возможность читать и оставлять комментарии (более подробно можно посмотреть тут). В таком случае, HLT начинал генерировать HTTP трафик и пересылать его на самописный сервис Sender и принимать сообщения от сервиса Receiver. Такая пара (Sender,Receiver) представляла собой суть адаптер.

Так почему собственно HLT, в конечном счёте, был удалён? Первая причина состояла в привязке HLT к протоколу TCP - не очень хороший выбор, когда архитектура стремится к микросервисной. Вторая причина состояла в вариативности действий - HLT изначально разрабатывался как простой и тупой ретранслятор сообщений, но в конечном итоге у него появились функции конвертировать TCP трафик в HTTP (для адаптации) и у него появлялись ручки для подгрузки трафика (при помощи ранее упомянутого HLL сервиса). Третья причина состояла в том, что само соединение TCP между несколькими узлами HL также является адаптацией анонимизирующего трафика к среде/протоколу ранее не созданному для такого действия. В конечном итоге, даже если мы посмотрим на схему адаптации трафика, представленную выше, то можно обойтись и без HLT, если HLS сможет общаться с Sender/Receiver напрямую. HLT просто становится излишним звеном. Таким образом, схема взаимодействия начала видоизменяться и пришла к следующему виду.

Адаптация трафика без HLT (HLS на момент создания схемы уже был переименован в HLK)
Адаптация трафика без HLT (HLS на момент создания схемы уже был переименован в HLK)

Что изменилось? Первое - основным протоколом коммуникации сервисов между собой становится HTTP-протокол. Второе - у каждого узла HLK (ядра) и HLA (адаптера) существует теперь внутренний (вшитый) HTTP-адаптер - сервис, принимающий и отправляющий шифртексты / анонимизирующий трафик друг к другу. Это позволяет с лёгкостью заменять один адаптер, например "TCP", на другой, например "Радиовещание". Третье - появляется несколько возможных режимов коммуникации узлов между собой.

Классический режим. Узлы соединяются только HTTP-протоколом (HLS в новом именовании - это любые прикладные приложения / сервисы)
Классический режим. Узлы соединяются только HTTP-протоколом (HLS в новом именовании - это любые прикладные приложения / сервисы)
Адаптационный режим. Узлы соединяются посредством выбранного протокола / платформы связи
Адаптационный режим. Узлы соединяются посредством выбранного протокола / платформы связи
Мультипликативный режим. Узлы соединяются посредством нескольких выбранных протоколов. При этом стоит заметить, что все они объединены общим HLA=http адаптером, который служит цели перенаправлять одно сообщение от HLK к множеству различных адаптеров. Если HLA=http использовать как один единственный адаптер, то режим коммуникации будет аналогичен классическому режиму.
Мультипликативный режим. Узлы соединяются посредством нескольких выбранных протоколов. При этом стоит заметить, что все они объединены общим HLA=http адаптером, который служит цели перенаправлять одно сообщение от HLK к множеству различных адаптеров. Если HLA=http использовать как один единственный адаптер, то режим коммуникации будет аналогичен классическому режиму.

3| Переосмысление прикладных сервисов

Ранее (на момент v1.7.7) существовало три прикладных сервиса - HLM, HLF, HLR. Двое из этих сервисов обладали WebGUI интерфейсом - HLM и HLF. HLR не обладал графическим интерфейсом вовсе. Проблема такого подхода крылась в четырёх деталях: 1) каждое прикладное приложение было отделено от другого, в результате чего, чтобы перейти от функции отправки сообщений (HLM) к функции скачивания файла (HLF) приходилось менять порт в строке браузера, что выглядело мягко говоря неудобно, 2) у прикладных приложений с графическим интерфейсом бОльшая часть страниц была одинакова или почти одинакова (список соединений, список друзей, главная страница), что приводило к определённому дублированию функций (в том числе из-за первого пункта), 3) графический интерфейс прикладных приложений, которые не являлись в полной мере P2P-приложениями (по типу HLF, где можно, например, скачивать файлы, но не раздавать их) выглядит странно, т.к. сервис запущен, у него есть "морда", но он не работает в полной мере, давая ложную видимость своего функционирования, 4) некоторые сервисы могли использовать функции других сервисов "под капотом", так например, HLM мог задействовать функции HLP (pinger - сервис, отвечающий за проверку онлайн статуса узла) - такая связь приводила к усложнению общей логики взаимодействия сервисов.

Старая и новая логика взаимодействия сервисов. В первом случае, HLS=messenger (HLM в старом именовании) представлял собой полноценное приложение на базе WebGUI. Во втором случае, HLS=messenger представлен сервисом, у которого есть своё API и к которому обращается клиентское приложение на базе какого-либо UI
Старая и новая логика взаимодействия сервисов. В первом случае, HLS=messenger (HLM в старом именовании) представлял собой полноценное приложение на базе WebGUI. Во втором случае, HLS=messenger представлен сервисом, у которого есть своё API и к которому обращается клиентское приложение на базе какого-либо UI

По итогу, прикладные сервисы были переделаны таким образом, чтобы предоставлять клиентам исключительно API и не иметь самостоятельно какого-либо пользовательского интерфейса по типу CLI, TUI, GUI и прочего. Эта схема не просто упростила взаимодействие с сервисами, но и добавила новые возможности. Так например, ранее HLS=filesharer (HLF в старом именовании) не имел возможности отправлять файлы, но сейчас при комбинации HLS=messenger + HLS=filesharer таковая возможность появилась. За счёт этого изменения также исключились горизонтальные связи сервисов, по типу HLS=messenger и HLS=pinger (HLP в старом именовании).

Алгоритм отправления файлов при комбинации (HLS=messenger + HLS=filesharer)
  1. Пользователь A загружает в локальное хранилище файл X при помощи HLS=filesharer;

  2. Пользователь A отправляет при помощи HLS=messenger пользователю B информацию о существовании файла X в своём локальном хранилище;

  3. Пользователь B получает сообщение от HLS=messenger и по ссылке начинает скачивать файл при помощи HLS=filesharer с удалённого хранилища пользователя A;

Запуск узла и клиента

Перед запуском необходимо установить все необходимые приложения. В нашем случае - это узел анонимной сети со всеми прилегающими прикладными сервисами (HLC - composite) и клиента (HL-Client). Установить можно двумя способами - либо скачать с релиза (тут и тут) под конкретную архитектуру и платформу, либо установив средствами Go, как показано ниже.

$ go install github.com/number571/hidden-lake/cmd/hlc@latest
$ go install github.com/number571/hl-client@latest

После установки следует запустить узел анонимной сети. В данном случае HLC запускает по умолчанию HLK (ядро сети), HLS=messenger, HLS=filesharer, HLS=pinger и HLA=tcp. Для того чтобы подключиться к продовой среде, необходимо прописать имя сети (network). Полный список сетей можно посмотреть здесь.

$ hlc --network oi4r9NW9Le7fKF9d
Лог после запуска HLC
[INFO] 2026/02/14 04:41:50 HLC is started; ["hlk","hla-tcp","hls-pinger","hls-messenger","hls-filesharer"]
[INFO] 2026/02/14 04:41:50 HLA-TCP is started; {"message_size_bytes":8192,"work_size_bits":8192,"network_key":"oi4r9NW9Le7fKF9d"}
[INFO] 2026/02/14 04:41:50 HLS-PINGER is started; {}
[INFO] 2026/02/14 04:41:50 HLS-MESSENGER is started; {"messages_capacity":2048}
[INFO] 2026/02/14 04:41:50 HLS-FILESHARER is started; {"page_offset":10,"retry_num":2}
[INFO] 2026/02/14 04:41:50 HLK is started; {"message_size_bytes":8192,"work_size_bits":18,"network_key":"oi4r9NW9Le7fKF9d","payload_size_bytes":3615}
[INFO] 2026/02/14 04:41:55 service=HLA-TCP type=RNMSG hash=6264F31D...F047DCC7 proof=0000136596 size=8268B conn=127.0.0.1:58114
[INFO] 2026/02/14 04:41:55 service=HLA-TCP type=SNMSG hash=6264F31D...F047DCC7 proof=0000136596 size=8268B conn=tcp
[INFO] 2026/02/14 04:41:55 service=HLK type=BRDCS hash=6264F31D...F047DCC7 proof=0000136596 size=8268B addr=9368296F...E4BEFB9E
[INFO] 2026/02/14 04:42:00 service=HLA-TCP type=RNMSG hash=CC5ABE64...E444078E proof=0000449692 size=8268B conn=127.0.0.1:58124
[INFO] 2026/02/14 04:42:00 service=HLK type=BRDCS hash=CC5ABE64...E444078E proof=0000449692 size=8268B addr=9368296F...E4BEFB9E
[INFO] 2026/02/14 04:42:00 service=HLA-TCP type=SNMSG hash=CC5ABE64...E444078E proof=0000449692 size=8268B conn=tcp
[INFO] 2026/02/14 04:42:05 service=HLA-TCP type=RNMSG hash=915247DB...0AAED8BB proof=0000333701 size=8268B conn=127.0.0.1:54214
[INFO] 2026/02/14 04:42:05 service=HLK type=BRDCS hash=915247DB...0AAED8BB proof=0000333701 size=8268B addr=9368296F...E4BEFB9E
[INFO] 2026/02/14 04:42:05 service=HLA-TCP type=SNMSG hash=915247DB...0AAED8BB proof=0000333701 size=8268B conn=tcp
[INFO] 2026/02/14 04:42:10 service=HLA-TCP type=RNMSG hash=3C66CEB4...3F903649 proof=0000064681 size=8268B conn=127.0.0.1:54222
[INFO] 2026/02/14 04:42:10 service=HLA-TCP type=SNMSG hash=3C66CEB4...3F903649 proof=0000064681 size=8268B conn=tcp
[INFO] 2026/02/14 04:42:10 service=HLK type=BRDCS hash=3C66CEB4...3F903649 proof=0000064681 size=8268B addr=9368296F...E4BEFB9E
...

Как только был успешно запущен HLC, мы можем запускать клиента. Его основная суть - это вызов функций из HLK API (получение/редактирование списка друзей, соединений, получение публичного ключа) и HLS API (отправка сообщений, пинг друзей, скачивание и просмотр файлов). Клиент подключится к адресам, заданным по умолчанию. Более подробно о запуске можно почитать тут.

$ hl-client
Страница с общей информацией
Страница с общей информацией

HL-Client по функциональности схож со старым HLS=messenger, который был реализован ещё на WebGUI. Но в отличие от него, сам HL-Client является отдельным приложением и не относится к прикладным сервисам. Также он задействует все три сервиса: messenger, filesharer, pinger. Сам HL-Client реализован на Go при помощи библиотеки Fyne.

Другие скриншоты клиентского приложения
Список соединений
Список соединений
Список друзей
Список друзей
Чат с другом
Чат с другом

Для того чтобы начать общение с другом - необходимо обменяться публичными ключами. Как именно будет происходить обмен - зависит от пользователей, анонимная сеть в данном сценарии никак не участвует. С одной стороны - это недостаток сети, который ставит в зависимость использование сторонних сервисов / платформ / сред связи. С другой стороны - это упрощение всей системы и сопутствующее ограничение модели угроз. Наиболее рекомендуемый способ обмена публичными ключами при помощи централизованных сервисов можно найти здесь. После обмена публичными ключами и их добавлении, вы можете начать общение в чате.

Немного об анонимности в HL

Анонимность коммуникации обеспечивается невозможностью (вычислительной сложностью) определения состояния участников сети. Иными словами, провайдер связи или глобальный наблюдатель будут видеть лишь три ваших состояния: 1) когда вы включили анонимную сеть, 2) когда вы находитесь в анонимной сети, 3) когда вы отключили анонимную сеть. Первый и последний пункты необходимо свести к минимуму, т.к. если включение сети всегда связано с отправлением или принятием сообщений - это потенциальный фактор деанонимизации. Поэтому, рекомендуемый способ использования анонимной сети Hidden Lake - это держать HLC по возможности всегда включенным. HL-Client можно включать по необходимости, т.к. все состояния хранят у себя прикладные сервисы или ядро сети, которые уже были запущены процессом HLC.

Заполнение очереди шифртекстами, где k,m - истинный ключ шифрования и сообщение, r, v - ложный ключ шифрования и сообщение
Заполнение очереди шифртекстами, где k,m - истинный ключ шифрования и сообщение, r, v - ложный ключ шифрования и сообщение

Теперь, если мы возьмём на себя роль провайдера связи / глобального наблюдателя, то наша задача деанонимизации будет сводиться к решению одной из двух подзадач: 1) уметь различать истинный шифртекст от ложного, 2) уметь разделять генерацию истинного трафика от ложного. Первая подзадача является вычислительно сложной при условии, что ключи и сам алгоритм шифрования являются безопасными / надёжными. Вторая подзадача сводится к используемому алгоритму генерации последовательности шифртекстов и стави�� вопрос так: "при каком событии x был сгенерирован шифртекст c". Если условие генерации сопоставимо с генерацией шума, то событие x становится независимым от наличия истинного текста. В нашем случае, очередь позволяет откладывать сообщения до наступления периода и вне зависимости от наличия истинного текста, всегда будет сгенерирован шифртекст. Таким образом, событие появления истинного текста скрывается за независимым событием постоянной генерации шума.

Второй пункт наиболее интересен со стороны скрытия трафика, т.к. он непосредственно ссылается на задачу анонимизации сети Hidden Lake (проблема на базе очередей). Суть задачи такова: каждый узел по умолчанию является генератором шифрованного ложного трафика (шума), который создаётся раз в пять секунд и отправляется в сеть (параметры генерации можно изменять в файле конфигурации hlk.yml). Если пользователь хочет отправить сообщение, то оно сначала шифруется, потом помещается в очередь и заменяет собой одно ложное сообщение (которое планировалось отправить). При достижении периода в пять секунд, истинное сообщение будет отправлено в сеть всем действующим участникам. Получателем станет лишь тот, кто сможет расшифровать сообщение своим приватным ключом.

Дальнейшее развитие

Как бы ни были масштабны последние изменения анонимной сети Hidden Lake, основные концепции они никак не затронули. Ядро анонимизации HLK не изменилось вовсе (за исключением лишь своего именования), QB-задача, протокол шифрования, формат шифртекстов остались всё также прежними. Это хорошая новость, потому как это значит, что основной и наиболее важный компонент был хорошо абстрагирован от всех связанных с ним прикладных сервисов и адаптеров связи. Предполагаю, или вернее сказать надеюсь, что в будущем данный процесс будет продолжаться и разрастаться, словно ржавчина, на все остальные сервисы. В результате, получится проект, который будет полностью завершённым и не требующим обновлений. Чтобы этого достичь необходимо свести к минимуму зависимости, а также не увеличивать без надобности количество сервисов.

Перспективы сети

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

РКП пнх
РКП пнх

Скорее всего будет существовать ряд внутренне-российских VPS-сервисов, на которых данный список и будет распространяться. Но даже если таковые ограничат или их вовсе не будет, продолжат существовать убогие Одноклассники, VK, Max и прочие сервисы, которые потенциально можно использовать для внедрения паразитного трафика. Сеть Hidden Lake была спроектирована как раз под такие неблагоприятные условия своего существования, где возможность адаптироваться под конкретные среды коммуникации, абстрагироваться от сетевой топологии и предоставлять при этом анонимность и безопасность пользователей, имеет все шансы сыграть одну из возможных ролей в нашем общем сопротивлении за существование небольшого озерца анонимности вокруг огромного океана цензурного безумия.

Дополнительные проекты

Помимо анонимной сети, есть также идеи в реализации других проектов. Одним из таковых является мессенджер. Скорее всего будет две версии мессенджера, один будет задействовать протокол, применяемый в HL, но с другими параметрами, чтобы сети не могли пересекаться и без анонимизации трафика. В некой степени это будет аналог Bitmessage, но более упрощённый и устанавливаемый помимо десктопа также на телефон. Другой же будет расчитан на групповые чаты и будет иметь иные протоколы. Оба мессенджера планирую реализовать также на Go+Fyne, как это было сделано с HL-Client'ом. Вряд-ли проекты получатся идеальны в плане фронтенда / дизайна, учитывая, что Fyne примерно этакий Bootstrap на минималках для десктопа/мобилки без возможности сильной кастомизации и привязки JS/CSS/HTML. В любом случае, посмотрим...

Заключение

На этом пожалуй всё. С кодом анонимной сети вы можете ознакомиться тут. С её более подробным описанием, анализом, QB-задачей и прочим - здесь.