Bagaimanakah utusan terdesentralisasi berfungsi pada blockchain?

Pada awal tahun 2017, kami mula mencipta utusan pada rantaian blok [nama dan pautan ada dalam profil] dengan membincangkan kelebihan berbanding pemesej P2P klasik.

hilang 2.5 tahun, dan kami dapat mengesahkan konsep kami: aplikasi messenger kini tersedia untuk iOS, Web PWA, Windows, GNU/Linux, Mac OS dan Android.

Hari ini kami akan memberitahu anda cara messenger blockchain berfungsi dan cara aplikasi pelanggan boleh berfungsi dengan APInya.
Bagaimanakah utusan terdesentralisasi berfungsi pada blockchain?

Kami mahu rantaian blok menyelesaikan isu keselamatan dan privasi utusan P2P klasik:

  • Satu klik untuk mencipta akaun - tiada telefon atau e-mel, tiada akses kepada buku alamat atau geolokasi.
  • Interlocutors tidak pernah mewujudkan sambungan langsung; semua komunikasi berlaku melalui sistem nod yang diedarkan. Alamat IP pengguna tidak boleh diakses antara satu sama lain.
  • Semua mesej disulitkan keluk Hujung ke Hujung25519xsalsa20poly1305. Nampaknya ini tidak akan mengejutkan sesiapa pun, tetapi kod sumber kami terbuka.
  • Serangan MITM dikecualikan - setiap mesej adalah transaksi dan ditandatangani oleh Ed25519 EdDSA.
  • Mesej itu berakhir di bloknya sendiri. Konsistensi dan timestamp Anda tidak boleh membetulkan sekatan, dan oleh itu susunan mesej.
  • "Saya tidak mengatakan itu" tidak akan berfungsi dengan mesej pada rantaian blok.
  • Tiada struktur pusat yang memeriksa "ketulenan" mesej. Ini dilakukan oleh sistem pengedaran nod berdasarkan konsensus, dan ia dimiliki oleh pengguna.
  • Kemustahilan penapisan - akaun tidak boleh disekat dan mesej tidak boleh dipadamkan.
  • Blockchain 2FA adalah alternatif kepada 2FA neraka melalui SMS, banyak merosakkan kesihatan.
  • Keupayaan untuk mendapatkan semua perbualan anda daripada sebarang peranti pada bila-bila masa bermakna anda tidak perlu menyimpan perbualan secara setempat sama sekali.
  • Pengesahan penghantaran mesej. Bukan kepada peranti pengguna, tetapi kepada rangkaian. Pada asasnya, ini adalah pengesahan keupayaan penerima untuk membaca mesej anda. Ini adalah ciri yang berguna untuk menghantar pemberitahuan kritikal.

Faedah rantaian blok juga termasuk penyepaduan rapat dengan mata wang kripto Ethereum, Dogecoin, Lisk, Dash, Bitcoin (yang ini masih dalam proses) dan keupayaan untuk menghantar token dalam sembang. Kami juga membuat penukar kripto terbina dalam.

Dan kemudian - bagaimana ia berfungsi.

Mesej adalah transaksi

Semua orang sudah terbiasa dengan fakta bahawa transaksi dalam blockchain memindahkan token (syiling) dari satu pengguna ke pengguna lain. Seperti Bitcoin. Kami mencipta jenis transaksi khas untuk menghantar mesej.

Untuk menghantar mesej dalam messenger pada blockchain, anda perlu melalui beberapa langkah:

  1. Sulitkan teks mesej
  2. Letakkan teks sifir ke dalam transaksi
  3. Tandatangani transaksi
  4. Hantar transaksi ke mana-mana nod rangkaian
  5. Sistem nod yang diedarkan menentukan "ketulenan" mesej
  6. Jika semuanya OK, transaksi dengan mesej disertakan dalam blok seterusnya
  7. Penerima mendapatkan semula transaksi mesej dan menyahsulit

Langkah 1–3 dan 7 dilakukan secara tempatan pada klien, dan langkah 5–6 dilakukan pada hos.

Penyulitan mesej

Mesej disulitkan dengan kunci peribadi pengirim dan kunci awam penerima. Kami akan mengambil kunci awam daripada rangkaian, tetapi untuk ini, akaun penerima mesti dimulakan, iaitu, mempunyai sekurang-kurangnya satu transaksi. Anda boleh menggunakan permintaan REST GET /api/accounts/getPublicKey?address={ADAMANT address}, dan apabila memuatkan sembang, kunci awam pembicara sudah tersedia.

Bagaimanakah utusan terdesentralisasi berfungsi pada blockchain?

Pengutus menyulitkan mesej menggunakan algoritma curve25519xsalsa20poly1305 (Kotak NaCl). Memandangkan akaun itu mengandungi kunci Ed25519, untuk membentuk kotak, kunci mesti ditukar terlebih dahulu kepada Curve25519 Diffie-Hellman.

Berikut ialah 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)
  }
}

Membentuk transaksi dengan mesej

Urus niaga mempunyai struktur umum 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 transaksi mesej, perkara yang paling penting ialah asset - anda perlu meletakkan mesej dalam objek chat dengan struktur:

  • message - simpan mesej yang disulitkan
  • own_message -tidak pernah
  • type β€” jenis mesej

Mesej juga dibahagikan kepada jenis. Pada asasnya, parameter type memberitahu anda bagaimana untuk memahami message. Anda boleh menghantar hanya teks, atau anda boleh menghantar objek dengan perkara yang menarik di dalamnya - contohnya, ini adalah cara penghantar membuat pemindahan mata wang kripto dalam sembang.

Akibatnya, kami membuat transaksi:

{
  "transaction": {
    "type": 8,
    "amount": 0,
    "senderId": "U12499126640447739963",
    "senderPublicKey": "e9cafb1e7b403c4cf247c94f73ee4cada367fcc130cb3888219a0ba0633230b6",
    "asset": {
      "chat": {
        "message": "cb682accceef92d7cddaaddb787d1184ab5428",
        "own_message": "e7d8f90ddf7d70efe359c3e4ecfb5ed3802297b248eacbd6",
        "type": 1
      }
    },
    "recipientId": "U15677078342684640219",
    "timestamp": 63228087,
    "signature": "Ρ‚ΡƒΡ‚ Π±ΡƒΠ΄Π΅Ρ‚ подпись"
  }
}

Tandatangan urus niaga

Untuk memastikan semua orang yakin dengan ketulenan pengirim dan penerima, masa penghantaran dan kandungan mesej, transaksi ditandatangani. Tandatangan digital membolehkan anda mengesahkan ketulenan transaksi menggunakan kunci awam - kunci peribadi tidak diperlukan untuk ini.

Tetapi tandatangan itu sendiri dilakukan menggunakan kunci peribadi:

Bagaimanakah utusan terdesentralisasi berfungsi pada blockchain?

Rajah menunjukkan bahawa kami mula-mula mencincang transaksi dengan SHA-256 dan kemudian menandatanganinya Ed25519 EdDSA dan dapatkan tandatangan signature, dan ID transaksi adalah sebahagian daripada cincang SHA-256.

Contoh pelaksanaan:

1 β€” Bentuk blok data, termasuk mesej

/**
 * 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 - Kira SHA-256 daripada 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 β€” Tandatangani 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'))
}

Menghantar transaksi dengan mesej ke nod rangkaian

Memandangkan rangkaian tidak berpusat, mana-mana nod dengan API terbuka akan berfungsi. Membuat permintaan POST ke titik akhir api/transactions:

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

Sebagai balasan, kami akan menerima jenis ID transaksi

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

Pengesahan Transaksi

Sistem nod yang diedarkan, berdasarkan konsensus, menentukan "ketulenan" mesej transaksi. Daripada siapa dan kepada siapa, bila, sama ada mesej itu digantikan dengan yang lain, dan sama ada masa penghantaran ditunjukkan dengan betul. Ini adalah kelebihan rantaian yang sangat penting - tidak ada struktur pusat yang bertanggungjawab untuk pengesahan, dan urutan mesej serta kandungannya tidak boleh dipalsukan.

Pertama, satu nod menyemak ketepatan, dan kemudian menghantarnya kepada orang lain - jika majoriti mengatakan bahawa semuanya teratur, transaksi akan dimasukkan ke dalam blok rantai seterusnya - ini adalah konsensus.

Bagaimanakah utusan terdesentralisasi berfungsi pada blockchain?

Bahagian kod nod yang bertanggungjawab untuk semakan boleh dilihat di GitHub - validator.js ΠΈ verify.js. Ya, nod berjalan pada Node.js.

Termasuk transaksi dengan mesej dalam blok

Jika konsensus dicapai, transaksi dengan mesej kami akan dimasukkan ke dalam blok seterusnya bersama-sama dengan transaksi sah yang lain.

Blok mempunyai urutan yang ketat, dan setiap blok berikutnya dibentuk berdasarkan cincang blok sebelumnya.

Bagaimanakah utusan terdesentralisasi berfungsi pada blockchain?

Maksudnya ialah mesej kami juga termasuk dalam urutan ini dan tidak boleh "disusun semula". Jika beberapa mesej jatuh ke dalam blok, pesanan mereka akan ditentukan oleh timestamp mesej.

Membaca mesej

Aplikasi messenger mendapatkan semula transaksi daripada blockchain yang dihantar kepada penerima. Untuk ini kami membuat titik akhir api/chatrooms.

Semua transaksi tersedia untuk semua orang - anda boleh menerima mesej yang disulitkan. Tetapi hanya penerima boleh menyahsulit menggunakan kunci peribadinya dan kunci awam penghantar:

**
 * 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?

Memandangkan mesej dihantar dengan cara ini dalam masa kira-kira 5 saat - inilah masanya blok rangkaian baharu muncul - kami menghasilkan sambungan soket klien-ke-nod dan nod-ke-nod. Apabila nod menerima transaksi baharu, ia menyemak kesahihannya dan meneruskannya kepada nod lain. Urus niaga tersedia untuk pelanggan messenger walaupun sebelum konsensus berlaku dan dimasukkan ke dalam blok. Dengan cara ini kami akan menghantar mesej serta-merta, sama seperti utusan segera biasa.

Untuk menyimpan buku alamat, kami membuat KVS - Penyimpanan Nilai-Kekunci - ini adalah satu lagi jenis transaksi yang asset ia bukan NaCl-box yang disulitkan, tetapi NaCl-secretbox. Beginilah cara messenger menyimpan data lain.

Pemindahan fail/imej dan sembang kumpulan masih memerlukan banyak kerja. Sudah tentu, dalam format kesilapan-dan-kesilapan ini boleh "diselesaikan" dengan cepat, tetapi kami mahu mengekalkan tahap privasi yang sama.

Ya, masih ada kerja yang perlu dilakukan - idealnya, privasi sebenar mengandaikan bahawa pengguna tidak akan menyambung ke nod rangkaian awam, tetapi akan menaikkan nod mereka sendiri. Berapakah peratusan pengguna yang anda fikir melakukan ini? Betul, 0. Kami dapat menyelesaikan sebahagian isu ini dengan versi Tor utusan.

Kami telah membuktikan bahawa utusan pada blockchain boleh wujud. Sebelum ini, hanya terdapat satu percubaan pada tahun 2012 - bitmessage, yang gagal disebabkan oleh masa penghantaran mesej yang lama, beban CPU dan kekurangan aplikasi mudah alih.

Dan keraguan adalah disebabkan oleh fakta bahawa utusan pada blockchain mendahului masa mereka - orang tidak bersedia untuk bertanggungjawab ke atas akaun mereka, memiliki maklumat peribadi belum lagi menjadi trend, dan teknologi tidak membenarkan kelajuan tinggi pada blockchain. Lebih banyak analog teknologi projek kami akan muncul seterusnya. Anda akan melihat.

Sumber: www.habr.com

Tambah komen