Как работает децентрализованный мессенджер на блокчейне
В начале 2017 мы начали создавать мессенджер на блокчейне [название и ссылка есть в профиле] с обсуждения преимуществ перед классическими P2P-мессенджерами.
Прошло 2.5 года, и нам удалось подтвердить свой концепт: сейчас доступны приложения мессенджера для iOS, Web PWA, Windows, GNU/Linux, Mac OS и Android.
Сегодня мы расскажем, как устроен мессенджер на блокчейне и как клиентским приложениям работать с его API.
Мы хотели, чтобы блокчейн решил вопросы безопасности и приватности классических P2P-мессенджеров:
Один клик для создания аккаунта — никаких телефонов и электронных почт, нет доступа к адресным книгам и геолокациям.
Собеседники никогда не устанавливают прямых соединений, все общение идет через распределенную систему узлов. IP-адресы пользователей недоступны друг другу.
Все сообщения шифруются End-to-End curve25519xsalsa20poly1305. Вроде бы этим никого не удивишь, но у нас-то исходный код открыт.
MITM-атака исключена — каждое сообщение является транзакцией и подписывается Ed25519 EdDSA.
Сообщение попадает в свой блок. Последовательность и timestamp блоков не исправишь, а следовательно и порядок сообщений.
“Я этого не говорил” не прокатит с сообщениями в блокчейне.
Нет центральной структуры, которая делает проверки на “достоверность” сообщения. Это делает распределенная система узлов на основе консенсуса, а она принадлежит пользователям.
Невозможность цензуры — аккаунты нельзя блокировать, а сообщения удалять.
Возможность получить все свои диалоги с любого устройства в любое время — это возможность не хранить диалоги локально вообще.
Подтверждение доставки сообщений. Не на устройство пользователя, а в сеть. По сути, это подтверждение возможности получателя прочитать ваше сообщение. Это полезная фича для отправки критических уведомлений.
Из плюшек блокчейна также тесная интеграция с криптовалютами Ethereum, Dogecoin, Lisk, Dash, Bitcoin (этот пока в процессе) и возможность отправки токенов в чатах. Мы даже сделали встроенный крипто-обменник.
А дальше — как все это работает.
Сообщение — это транзакция
Все уже привыкли, что транзакции в блокчейне передают токены (монеты) от одного пользователя другому. Как у биткоина. Мы же создали особый тип транзакций для передачи сообщений.
Чтобы отправить сообщение в мессенджере на блокчейне, нужно пройти несколько этапов:
Зашифровать текст сообщения
Поместить зашифрованный текст в транзакцию
Подписать транзакцию
Отправить транзакцию на любой узел сети
Распределенная система узлов определяет “достоверность” сообщения
Если все ОК — транзакция с сообщением включается в следующий блок
Получатель извлекает транзакцию с сообщением и расшифровывает
Этапы 1–3 и 7 выполняются локально на клиенте, а 5–6 — на узлах сети.
Шифрование сообщения
Сообщение шифруется приватным ключом отправителя и публичным ключом получателя. Публичный ключ мы возьмем из сети, но для этого аккаунт получателя должен быть инициализирован, то есть иметь хотя бы одну транзакцию. Можно использовать REST-запрос GET /api/accounts/getPublicKey?address={ADAMANT address}, а при загрузке чатов публичные ключи собеседников уже будут в наличии.
Мессенджер шифрует сообщения алгоритмом curve25519xsalsa20poly1305 (NaCl Box). Поскольку аккаунт содержит ключи Ed25519, для формирования box’а предварительно ключи нужно преобразовать в Curve25519 Diffie-Hellman.
Для транзакции-сообщения самое важное значение имеет asset — в него нужно разместить сообщение в объекте chat со структурой:
message — сохраняем зашифрованное сообщение
own_message — nonce
type — тип сообщения
Сообщения тоже делятся на типы. По сути, параметр type сообщает, как понимать message. Можно отправить просто текст, а можно объект с интересностями внутри — например, так мессенджер делает переводы криптовалют в чатах.
Чтобы все были уверены в достоверности отправителя и получателя, во времени отправки и содержимом сообщения, транзакцию подписывают. Цифровая подпись позволяет проверить достоверность транзакции по публичному ключу — приватный ключ для этого не нужен.
А вот сама подпись как раз выполняется приватным ключом:
Из схемы видно, что транзакцию сначала хешируем SHA-256, а потом подписываем Ed25519 EdDSA и получаем подпись signature, а идентификатор транзакции — это часть SHA-256-хэша.
Пример реализации:
1 — Формируем блок данных, включая сообщение
/**
* Calls `getBytes` based on transaction type
* @see privateTypes
* @implements {ByteBuffer}
* @param {transaction} trs
* @param {boolean} skipSignature
* @param {boolean} skipSecondSignature
* @return {!Array} Contents as an ArrayBuffer.
* @throws {error} If buffer fails.
*/
adamant.getBytes = function (transaction) {
...
switch (transaction.type) {
case constants.Transactions.SEND:
break
case constants.Transactions.CHAT_MESSAGE:
assetBytes = this.chatGetBytes(transaction)
assetSize = assetBytes.length
break
…
default:
alert('Not supported yet')
}
var bb = new ByteBuffer(1 + 4 + 32 + 8 + 8 + 64 + 64 + assetSize, true)
bb.writeByte(transaction.type)
bb.writeInt(transaction.timestamp)
...
bb.flip()
var arrayBuffer = new Uint8Array(bb.toArrayBuffer())
var buffer = []
for (var i = 0; i < arrayBuffer.length; i++) {
buffer[i] = arrayBuffer[i]
}
return Buffer.from(buffer)
}
Распределенная система узлов на основе консенсуса определяет “достоверность” транзакции-сообщения. От кого и кому, когда, не заменили ли сообщение другим, а правильное ли указано время отправки. Это очень важное преимущества блокчейна — нет центральной структуры, которая отвечает за проверки, и последовательность сообщений и их содержимое не подделать.
Сначала достоверность проверяет одна нода, а потом рассылает другим — если большинство говорят, что все в порядке, транзакция будет включена в следующий блок цепи — это и есть консенсус.
Часть кода узла, которая отвечает за проверки, можно посмотреть в GitHub — validator.js и verify.js. Ага, узел работает на Node.js.
Включаем транзакцию с сообщением в блок
Если консенсус достигнут, транзакция с нашим сообщением попадет в следующий блок наряду с другими достоверными транзакциями.
Блоки имеют строгую последовательность, и каждый последующий блок формируется на основе хешей предыдущих блоков.
Суть в том, что наше сообщение также включено в эту последовательность и не может быть “переставлено”. Если в блок попадает несколько сообщений, их порядок будет определен по timestamp сообщений.
Чтение сообщений
Приложение-мессенджер извлекает транзакции из блокчейна, которые отправлены адресату. Для этого мы сделали эндпоинт api/chatrooms.
Все транзакции доступны для каждого — можно получить зашифрованные сообщения. А вот расшифровать сможет только получатель своим приватным ключом и публичным ключом отправителя:
Поскольку сообщения таким способом доставляются около 5 секунд — это время появления нового блока сети — мы придумали сокет-подключение клиент-узел и узел-узел. Когда узел получает новую транзакцию, он проверяет ее валидность и передает на другие узлы. Транзакция доступна клиентам-мессенджерам еще до наступления консенсуса и включения в блок. Так мы будем доставлять сообщения мгновенно, как и привычные мессенджеры.
Чтобы хранить адресную книгу, мы сделали KVS — Key-Value Storage — это еще один тип транзакций, в которых asset шифруется не NaCl-box, а NaCl-secretbox. Так мессенджер хранит и другие данные.
Передача файлов/изображений и групповые чаты требуют еще много работы. Конечно, в формате тяп-ляп это можно “прикрутить” быстро, но мы хотим сохранить тот же уровень приватности.
Да, есть еще над чем работать — в идеале реальная приватность предполагает, что пользователи не будут подключаться к публичным узлам сети, а поднимут свои. Как вы думаете, сколько процентов пользователей так делает? Правильно, 0. Частично этот вопрос нам удалось решить Tor-версией мессенджера.
Мы доказали, что мессенджер на блокчейне может существовать. Ранее была только одна попытка в 2012 году — bitmessage, неудавшаяся из-за большого времени доставки сообщений, нагрузки на процессор и отсутствия мобильных приложений.
А скептицизм связан с тем, что мессенджеры на блокчейне опережают время — люди не готовы брать ответственность за свой аккаунт на себя, владение личной информацией пока не в тренде, а технологии не позволяют обеспечить высокие скорости на блокчейне. Следом будут появляться более технологичные аналоги нашего проекта. Вот увидите.