X3DH и Double Ratchet: когда нужна новая сессия
Самая дорогая ошибка в интеграции шифрования — считать криптографическую сессию одноразовой обёрткой вокруг HTTP-запроса. Сеть может оборваться и потребовать retry, но из этого не следует, что нужно снова устанавливать отношения между собеседниками.
В ZionVox точка этого решения видна в frontend/src/crypto/directDrSessionSend.ts. Разберу её отдельно от пути доставки из Z03: что переиспользуется, когда запускается X3DH и почему rekey не должен быть универсальной реакцией на любую ошибку.
prepareDirectDrSessionForSend принимает sid, локальный материал идентичности, peerUserId и необязательный forceRekey. Обычная ветка загружает Double Ratchet state и проверяет, что это поддерживаемое v1-состояние.
При отсутствии подходящего состояния код получает prekey bundle через fetchUserPreKeyBundle и проверяет его verifyPreKeyBundleV1. Затем x3dhInitiatorDerive использует identity public key и signed prekey собеседника вместе с локальным материалом инициатора.
Установить состояние недостаточно: оно должно оставаться согласованным с последующими сообщениями. В appDb.ts ratchet state отделён от исходящих и кэша истории. Это разные жизненные циклы, даже если они участвуют в одной отправке.
В коде forceRekey сначала вызывает wipeDoubleRatchetState. Лишь после этого начинается получение bundle и новая инициализация. Этот порядок стоит читать буквально: очистка старого состояния и успешное создание нового — не одна неделимая операция.
В исходящей очереди ZionVox сохраняются ciphertext, iv и protocolMetadata. При повторной перевозке важно удержать тот же логический пакет. На сервере clientMessageId связывает попытки, а другой ciphertext/iv под прежним идентификатором даёт конфликт.
Я бы не ограничивал тестирование утверждением «сообщение расшифровалось один раз». Для orchestration важны отрицательные сценарии: bundle не прошёл проверку, state имеет неподдерживаемую версию, сеть оборвалась при новой установке, повтор транспорта пришёл после записи на сервере.
В полной статье — последовательность операций, разбор отказов и практический чек-лист. Я проектирую такие архитектуры и для клиентских продуктов.
https://arhellist.ru/blog/x3dh-i-double-ratchet-kogda-nuzhna-novaya-sessiya/