Як працює децентралізований месенджер на блокчейні
На початку 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, що невдала через великий час доставки повідомлень, навантаження на процесор та відсутність мобільних додатків.
А скептицизм пов'язаний з тим, що месенджери на блокчейні випереджають час — люди не готові брати відповідальність за свій аккаунт на себе, володіння особистою інформацією поки не в тренді, а технології не дозволяють забезпечити високу швидкість на блокчейні. Далі з'являтимуться більш технологічні аналоги нашого проекту. Ось побачите.