В современном цифровом мире мы хотим не просто создавать совместно редактируемые документы и приложения, но и сохранять полную конфиденциальность данных. Классический подход — сквозное (end-to-end) шифрование — хорошо работает, пока вы и ваш коллега находитесь онлайн одновременно. Но что делать, если вам нужна асинхронность? Здесь на сцену выходит гомоморфное шифрование, о котором недавно подробно написал Джейк Лазарофф в своём блоге.
🚀 Что такое гомоморфное шифрование и почему оно важно для CRDT?
Гомоморфное шифрование — это техника, позволяющая выполнять вычисления непосредственно над зашифрованными данными, без их предварительной расшифровки. Это звучит фантастически, но именно так это и работает! Грубо говоря, мы можем:
- 🔑 Зашифровать данные на стороне пользователя.
- ⚙️ Выполнить операции (например, сложение или сравнение) на зашифрованных данных.
- 🔓 Расшифровать результат и получить корректный итог вычислений.
В контексте CRDT (Conflict-free Replicated Data Types), которые используются в распределённых приложениях для объединения изменений от разных пользователей, это открывает интересные возможности. В частности, сервер может объединять изменения, не зная при этом, что именно объединяется.
🧩 Как реализовать CRDT с гомоморфным шифрованием?
В статье Джейк приводит пример реализации простой структуры — last write wins register. Такая структура хранит значение, идентификатор автора и счётчик обновлений. При слиянии изменений выбирается значение с наибольшим счётчиком, а если счётчики равны — используется идентификатор автора.
При гомоморфном шифровании этот алгоритм выглядит совсем иначе:
- 🔐 Все данные (значения, счётчики, идентификаторы) шифруются.
- 📏 Сравнения («больше», «равно») выполняются с использованием логических гейтов (AND, XOR), которые позволяют сохранять секретность исходных данных.
- 🛡️ Результат слияния также остаётся зашифрованным, и сервер не может узнать, какие данные были изменены.
Вот пример «магической» функции слияния в зашифрованном виде (на Rust с библиотекой TFHE-rs):
let higher_clock = self.clock.gt(&other.clock);
let equal_clock = self.clock.eq(&other.clock);
let higher_peer = self.peer.gt(&other.peer);
let keep_self = higher_clock | (equal_clock & higher_peer);
self.peer = keep_self.select(&self.peer, &other.peer);
self.clock = keep_self.select(&self.clock, &other.clock);
self.value = array::from_fn(|i| keep_self.select(&self.value[i], &other.value[i]));
Несмотря на внешнюю простоту, за каждой строкой кода скрывается сложная криптографическая логика.
⚠️ Но есть подвох: почему не всё так гладко?
Однако у гомоморфного шифрования есть серьёзные проблемы:
- 🐢 Производительность: Операции над зашифрованными данными крайне медленные. В эксперименте автора простейшая операция слияния длилась 1 секунду, что в миллиарды раз медленнее, чем на незашифрованных данных!
- 📦 Размер ключей: Чтобы выполнить даже простейшие операции, приходится использовать ключи размером десятки и сотни мегабайт. Например, ключ в эксперименте весил 123 МБ для структуры размером всего 32 байта!
- 📈 Худший случай всегда: Код с гомоморфным шифрованием должен всегда работать так, будто обрабатывает худший возможный сценарий, что сильно увеличивает потребление ресурсов.
Это делает гомоморфное шифрование пока что не самым практичным выбором для большинства приложений.
🤔 Есть ли альтернатива?
Автор указывает, что существуют альтернативные подходы:
- 🔄 Использование операционных CRDT вместо состояний, где сервер просто пересылает обновления, не пытаясь их объединять.
- 📜 Хранение версий зашифрованных данных, пусть и с некоторыми издержками.
Кроме того, Джейк упоминает проекты, которые исследуют другие подходы к защите CRDT:
- 🐝 Keyhive от Ink & Switch — контроль доступа к локальным данным.
- 📚 Работы Мартина Клеппмана о сочетании безопасных мессенджеров и CRDT.
✨ Личное мнение автора статьи
На мой взгляд, подход Джейка Лазароффа прекрасно иллюстрирует современное состояние технологий: гомоморфное шифрование уже не научная фантастика, но пока ещё далека от повседневного применения. Технические ограничения — огромные ключи и низкая производительность — не дают массово внедрять его в текущие приложения.
Тем не менее, его исследование показывает, что эта технология может сыграть важную роль в нишевых областях, где конфиденциальность данных важнее всего, например, в медицине или финансах. Вопрос лишь в том, сможем ли мы дождаться, когда производительность и удобство гомоморфного шифрования подтянутся к нашим ожиданиям.
🔗 Полезные ссылки и материалы:
Технологии шифрования и CRDT всё ещё на раннем этапе развития, но этот эксперимент ясно показывает: будущее уже близко, хоть и требует немалых усилий для своего воплощения.