Bagaimana cara messenger terdesentralisasi di blockchain

Pada awal 2017, kami mulai membuat messenger di blockchain [nama dan tautannya ada di profil] dengan membahas kelebihan dibandingkan dengan messenger P2P klasik.

2.5 tahun berlalu dan kami dapat mengkonfirmasi konsep kami: aplikasi instant messenger untuk iOS, Web PWA, Windows, GNU / Linux, Mac OS dan Android sekarang tersedia.

Hari ini kami akan memberi tahu Anda bagaimana messenger diatur pada blockchain dan bagaimana aplikasi klien dapat bekerja dengan API-nya.


Kami ingin blockchain untuk memecahkan masalah keamanan dan privasi utusan P2P klasik:

  • Satu klik untuk membuat akun - tidak ada telepon dan email, tidak ada akses ke buku alamat dan geolokasi.
  • Lawan bicara tidak pernah membuat koneksi langsung, semua komunikasi melewati sistem node terdistribusi. Alamat IP pengguna tidak dapat diakses satu sama lain.
  • Semua pesan dienkripsi kurva End-to-End25519xsalsa20poly1305. Tampaknya Anda tidak akan mengejutkan siapa pun, tetapi kami memiliki kode sumber terbuka.
  • Serangan MITM tidak termasuk - setiap pesan adalah transaksi dan ditandatangani oleh Ed25519 EdDSA.
  • Pesan jatuh ke bloknya. Urutan dan timestamp blok tidak dapat diperbaiki, dan karena itu urutan pesan.
  • "Saya tidak mengatakan ini" tidak akan berfungsi dengan pesan di blockchain.
  • Tidak ada struktur utama yang memeriksa β€œkeaslian” pesan. Ini dilakukan oleh sistem node terdistribusi berbasis konsensus, dan itu milik pengguna.
  • Tidak mungkin penyensoran - akun tidak dapat diblokir dan pesan dihapus.
  • The 2FA blockchain adalah alternatif untuk 2FA neraka melalui SMS, yang telah merusak banyak kesehatan.
  • Kemampuan untuk mendapatkan semua dialog Anda dari perangkat apa pun kapan saja adalah kemampuan untuk tidak menyimpan dialog sama sekali.
  • Konfirmasi Pengiriman Pesan. Bukan ke perangkat pengguna, tetapi ke jaringan. Sebenarnya, ini adalah konfirmasi kemampuan penerima untuk membaca pesan Anda. Ini adalah fitur yang berguna untuk mengirim pemberitahuan penting.

Dari roti blockchain, ada juga integrasi dekat dengan cryptocurrency Ethereum, Dogecoin, Lisk, Dash, Bitcoin (ini masih dalam proses) dan kemampuan untuk mengirim token dalam obrolan. Kami bahkan membuat exchanger crypto bawaan.

Dan kemudian - cara kerjanya.

Pesan adalah transaksi


Setiap orang sudah terbiasa dengan fakta bahwa transaksi dalam token transfer blockchain (koin) dari satu pengguna ke yang lain. Suka bitcoin. Kami telah membuat jenis transaksi khusus untuk mengirim pesan.

Untuk mengirim pesan di messenger di blockchain, Anda harus melewati beberapa tahapan:

  1. Enkripsi teks pesan
  2. Masukkan ciphertext ke dalam transaksi
  3. Tanda tangani transaksi
  4. Kirim transaksi ke host mana pun
  5. Sistem node terdistribusi menentukan "keandalan" pesan
  6. Jika semuanya baik-baik saja, transaksi dengan pesan tersebut termasuk dalam blok berikutnya.
  7. Penerima mengambil transaksi pesan dan mendekripsi

Tahapan 1-3 dan 7 dilakukan secara lokal pada klien, dan 5-6 pada node jaringan.

Enkripsi pesan


Pesan dienkripsi dengan kunci pribadi pengirim dan kunci publik penerima. Kami akan mengambil kunci publik dari jaringan, tetapi untuk ini akun penerima harus diinisialisasi, yaitu, memiliki setidaknya satu transaksi. Anda dapat menggunakan permintaan REST GET /api/accounts/getPublicKey?address={ADAMANT address} , dan ketika Anda mengunduh obrolan, kunci publik dari teman bicara sudah tersedia.



Utusan mengenkripsi pesan dengan algoritma curve25519xsalsa20poly1305 ( Kotak NaCl ). Karena akun tersebut berisi kunci Ed25519, untuk membentuk sebuah kotak, kunci tersebut terlebih dahulu harus dikonversi ke Curve25519 Diffie-Hellman.

Berikut ini contoh dalam JavaScript:

 /** * Encodes a text message for sending to ADM * @param {string} msg message to encode * @param {*} recipientPublicKey recipient's public key * @param {*} privateKey our private key * @returns {{message: string, nonce: string}} */ adamant.encodeMessage = function (msg, recipientPublicKey, privateKey) { const nonce = Buffer.allocUnsafe(24) sodium.randombytes(nonce) if (typeof recipientPublicKey === 'string') { recipientPublicKey = hexToBytes(recipientPublicKey) } const plainText = Buffer.from(msg) const DHPublicKey = ed2curve.convertPublicKey(recipientPublicKey) const DHSecretKey = ed2curve.convertSecretKey(privateKey) const encrypted = nacl.box(plainText, nonce, DHPublicKey, DHSecretKey) return { message: bytesToHex(encrypted), nonce: bytesToHex(nonce) } } 

Pembentukan transaksi dengan pesan


Suatu transaksi memiliki struktur umum sebagai berikut:

 { "id": "15161295239237781653", "height": 7585271, "blockId": "16391508373936326027", "type": 8, "block_timestamp": 45182260, "timestamp": 45182254, "senderPublicKey": "bd39cc708499ae91b937083463fce5e0668c2b37e78df28f69d132fce51d49ed", "senderId": "U16023712506749300952", "recipientId": "U17653312780572073341", "recipientPublicKey": "23d27f616e304ef2046a60b762683b8dabebe0d8fc26e5ecdb1d5f3d291dbe21", "amount": 204921300000000, "fee": 50000000, "signature": "3c8e551f60fedb81e52835c69e8b158eb1b8b3c89a04d3df5adc0d99017ffbcb06a7b16ad76d519f80df019c930960317a67e8d18ab1e85e575c9470000cf607", "signatures": [], "confirmations": 3660548, "asset": {} } 

Untuk pesan transaksi, asset adalah yang paling penting - Anda perlu menempatkan pesan di dalamnya di objek chat dengan struktur:

  • message - simpan pesan terenkripsi
  • own_message - nonce
  • type - tipe pesan

Pesan juga dibagi menjadi beberapa tipe. Pada dasarnya, parameter type memberi tahu cara memahami message . Anda dapat mengirim hanya teks, atau Anda dapat mengirim objek dengan minat menarik di dalamnya - misalnya, ini adalah cara kurir melakukan transfer cryptocurrency di ruang obrolan.

Sebagai hasilnya, kami membentuk transaksi:

 { "transaction": { "type": 8, "amount": 0, "senderId": "U12499126640447739963", "senderPublicKey": "e9cafb1e7b403c4cf247c94f73ee4cada367fcc130cb3888219a0ba0633230b6", "asset": { "chat": { "message": "cb682accceef92d7cddaaddb787d1184ab5428", "own_message": "e7d8f90ddf7d70efe359c3e4ecfb5ed3802297b248eacbd6", "type": 1 } }, "recipientId": "U15677078342684640219", "timestamp": 63228087, "signature": "  " } } 

Tanda Tangan Transaksi


Agar setiap orang memastikan keaslian pengirim dan penerima, pada saat pengiriman dan isi pesan, transaksi ditandatangani. Tanda tangan digital memungkinkan Anda memverifikasi keaslian transaksi menggunakan kunci publik - kunci pribadi tidak diperlukan untuk ini.

Tetapi tanda tangan itu sendiri hanya dilakukan oleh kunci pribadi:



Dapat dilihat dari diagram bahwa kita pertama kali melakukan hash transaksi dengan SHA-256, dan kemudian kita menandatangani Ed25519 EdDSA dan mendapatkan tanda signature tanda signature , dan pengidentifikasi transaksi adalah bagian dari hash SHA-256.

Contoh Implementasi:


1 - Kami membentuk blok data, termasuk pesan

 /** * 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) } 

2 - Kami menganggap SHA-256 dari blok data

 /** * Creates hash based on transaction bytes. * @implements {getBytes} * @implements {crypto.createHash} * @param {transaction} trs * @return {hash} sha256 crypto hash */ adamant.getHash = function (trs) { return crypto.createHash('sha256').update(this.getBytes(trs)).digest() } 

3 - Kami menandatangani transaksi

 adamant.transactionSign = function (trs, keypair) { var hash = this.getHash(trs) return this.sign(hash, keypair).toString('hex') } /** * Creates a signature based on a hash and a keypair. * @implements {sodium} * @param {hash} hash * @param {keypair} keypair * @return {signature} signature */ adamant.sign = function (hash, keypair) { return sodium.crypto_sign_detached(hash, Buffer.from(keypair.privateKey, 'hex')) } 

Mengirim transaksi dengan pesan ke host


Karena jaringan terdesentralisasi, salah satu dari node dengan API terbuka akan melakukannya. Kami membuat permintaan POST untuk titik api/transactions :

 curl 'api/transactions' -X POST \ -d 'TX_DATA' 

Sebagai tanggapan, kami mendapatkan ID transaksi jenis

 { "success": true, "nodeTimestamp": 63228852, "transactionId": "6146865104403680934" } 

Validasi Transaksi


Sistem node berbasis konsensus terdistribusi menentukan β€œkeandalan” suatu transaksi pesan. Dari siapa dan kepada siapa, kapan, apakah pesan diganti oleh yang lain, dan apakah waktu pengiriman ditunjukkan dengan benar. Ini adalah keuntungan yang sangat penting dari blockchain - tidak ada struktur pusat yang bertanggung jawab untuk pemeriksaan, dan urutan pesan dan isinya tidak dapat dipalsukan.

Pertama, satu simpul memeriksa keandalan, dan kemudian mengirimkannya ke orang lain - jika sebagian besar mengatakan bahwa semuanya beres, transaksi akan dimasukkan dalam blok rantai berikutnya - ini adalah konsensus.



Bagian dari kode host yang bertanggung jawab untuk validasi dapat dilihat di GitHub - validator.js dan verifikasi.js . Ya, simpul tersebut berjalan di Node.js.

Sertakan transaksi dengan pesan di blokir


Jika konsensus tercapai, transaksi dengan pesan kami akan jatuh ke blok berikutnya, bersama dengan transaksi yang dapat diandalkan lainnya.

Blok memiliki urutan yang ketat, dan setiap blok berikutnya dibentuk berdasarkan hash dari blok sebelumnya.



Intinya adalah bahwa pesan kami juga termasuk dalam urutan ini dan tidak dapat "diatur ulang". Jika beberapa pesan masuk ke dalam blokir, urutannya akan ditentukan oleh timestamp pesan.

Membaca pesan


Aplikasi messenger mengambil transaksi dari blockchain yang dikirim ke penerima. Untuk melakukan ini, kami membuat titik api/chatrooms .

Semua transaksi tersedia untuk semua orang - Anda dapat menerima pesan terenkripsi. Tetapi hanya penerima yang dapat mendekripsi dengan kunci pribadinya dan kunci publik pengirim:

 ** * Decodes the incoming message * @param {any} msg encoded message * @param {string} senderPublicKey sender public key * @param {string} privateKey our private key * @param {any} nonce nonce * @returns {string} */ adamant.decodeMessage = function (msg, senderPublicKey, privateKey, nonce) { if (typeof msg === 'string') { msg = hexToBytes(msg) } if (typeof nonce === 'string') { nonce = hexToBytes(nonce) } if (typeof senderPublicKey === 'string') { senderPublicKey = hexToBytes(senderPublicKey) } if (typeof privateKey === 'string') { privateKey = hexToBytes(privateKey) } const DHPublicKey = ed2curve.convertPublicKey(senderPublicKey) const DHSecretKey = ed2curve.convertSecretKey(privateKey) const decrypted = nacl.box.open(msg, nonce, DHPublicKey, DHSecretKey) return decrypted ? decode(decrypted) : '' } 

Apa lagi


Karena pesan dikirimkan dengan cara ini selama sekitar 5 detik - ini adalah waktu blok jaringan baru muncul - kami datang dengan koneksi socket client-node dan node-to-node. Ketika sebuah node menerima transaksi baru, ia memeriksa validitasnya dan mentransfernya ke node lain. Transaksi ini tersedia untuk klien kurir bahkan sebelum dimulainya konsensus dan dimasukkan dalam blok. Jadi kami akan mengirimkan pesan secara instan, serta pesan biasa.

Untuk menyimpan buku alamat, kami membuat KVS - Key-Value Storage adalah jenis transaksi lain di mana asset dienkripsi bukan dengan NaCl-box, tetapi dengan NaCl-secretbox . Jadi kurir menyimpan data lainnya.

Transfer file / gambar dan obrolan grup masih memerlukan banyak pekerjaan. Tentu saja, dalam format tyap-bloop, ini dapat diikat dengan cepat, tetapi kami ingin mempertahankan tingkat privasi yang sama.

Ya, masih ada pekerjaan yang harus dilakukan - idealnya, privasi nyata menyiratkan bahwa pengguna tidak akan terhubung ke node jaringan publik, tetapi akan meningkatkan sendiri. Bagaimana menurut Anda, berapa persen pengguna yang melakukan ini? Itu benar, 0. Sebagian, kami berhasil menyelesaikan masalah ini dengan versi Tor messenger.

Kami telah membuktikan bahwa seorang messenger di blockchain dapat ada. Sebelumnya, hanya ada satu upaya di 2012 - bitmessage , yang gagal karena waktu pengiriman pesan yang lama, beban CPU dan kurangnya aplikasi mobile.

Dan skeptisisme terkait dengan fakta bahwa para utusan di blockchain ada di depan - orang tidak siap untuk bertanggung jawab atas akun mereka sendiri, kepemilikan informasi pribadi belum menjadi tren, dan teknologi tidak memungkinkan memastikan kecepatan tinggi pada blockchain. Berikut ini akan muncul lebih banyak analog teknologi dari proyek kami. Kamu akan lihat.

Source: https://habr.com/ru/post/id467751/


All Articles