Markazlashtirilmagan messenjer blokcheynda qanday ishlaydi?

2017 yil boshida klassik P2P messenjerlariga nisbatan afzalliklarini muhokama qilib, blokcheynda [ism va havola profilda] messenjer yaratishni boshladik.

Ketdi 2.5 yil va biz kontseptsiyamizni tasdiqlay oldik: messenjer ilovalari endi iOS, Web PWA, Windows, GNU/Linux, Mac OS va Android uchun mavjud.

Bugun biz sizga blockchain messenjeri qanday ishlashini va mijoz ilovalari uning API bilan qanday ishlashini aytib beramiz.
Markazlashtirilmagan messenjer blokcheynda qanday ishlaydi?

Biz blokcheyn klassik P2P messenjerlarining xavfsizlik va maxfiylik muammolarini hal qilishini xohladik:

  • Hisob yaratish uchun bir marta bosish - telefonlar yoki elektron pochta xabarlari yo'q, manzillar kitoblariga yoki geolokatsiyalarga kirish imkoni yo'q.
  • Suhbatdoshlar hech qachon to'g'ridan-to'g'ri aloqa o'rnatmaydilar, barcha aloqalar taqsimlangan tugunlar tizimi orqali amalga oshiriladi. Foydalanuvchilarning IP manzillari bir-biriga kira olmaydi.
  • Barcha xabarlar End-to-End curve25519xsalsa20poly1305 shifrlangan. Bu hech kimni ajablantirmasa kerak, ammo bizning manba kodimiz ochiq.
  • MITM hujumi bundan mustasno - har bir xabar tranzaksiya hisoblanadi va Ed25519 EdDSA tomonidan imzolanadi.
  • Xabar o'z blokida tugaydi. Muvofiqlik va timestamp Siz bloklarni va shuning uchun xabarlar tartibini tuzata olmaysiz.
  • "Men buni aytmadim" blokcheyndagi xabarlar bilan ishlamaydi.
  • Xabarning "haqiqiyligini" tekshiradigan markaziy tuzilma yo'q. Bu konsensusga asoslangan taqsimlangan tugunlar tizimi tomonidan amalga oshiriladi va u foydalanuvchilarga tegishli.
  • Tsenzuraning mumkin emasligi - hisoblarni bloklab bo'lmaydi va xabarlarni o'chirib bo'lmaydi.
  • Blockchain 2FA SMS orqali do'zax 2FAga muqobildir, ko'p sog'lig'ini buzdi.
  • Istalgan vaqtda istalgan qurilmadan barcha suhbatlaringizni olish imkoniyati siz suhbatlarni umuman mahalliy saqlashingiz shart emasligini anglatadi.
  • Xabarni yetkazib berishni tasdiqlash. Foydalanuvchi qurilmasiga emas, balki tarmoqqa. Aslida, bu qabul qiluvchining sizning xabaringizni o'qish qobiliyatini tasdiqlaydi. Bu muhim bildirishnomalarni yuborish uchun foydali xususiyatdir.

Blokcheynning afzalliklari, shuningdek, Ethereum, Dogecoin, Lisk, Dash, Bitcoin kriptovalyutalari bilan yaqin integratsiyani (bu hali ham davom etmoqda) va chatlarda tokenlarni yuborish qobiliyatini o'z ichiga oladi. Biz hatto o'rnatilgan kripto almashinuvchini ham yaratdik.

Va keyin - hammasi qanday ishlaydi.

Xabar - bu tranzaksiya

Hamma allaqachon blokcheyndagi tranzaktsiyalar tokenlarni (tangalarni) bir foydalanuvchidan boshqasiga o'tkazishiga o'rganib qolgan. Bitcoin kabi. Biz xabarlarni uzatish uchun maxsus tranzaksiya turini yaratdik.

Blockchain-da messenjerda xabar yuborish uchun siz bir necha bosqichdan o'tishingiz kerak:

  1. Xabar matnini shifrlash
  2. Tranzaktsiyaga shifrlangan matn qo'ying
  3. Tranzaktsiyani imzolang
  4. Har qanday tarmoq tuguniga tranzaktsiyani yuboring
  5. Tarqalgan tugunlar tizimi xabarning "haqiqiyligini" aniqlaydi
  6. Agar hamma narsa yaxshi bo'lsa, xabar bilan operatsiya keyingi blokga kiritiladi
  7. Qabul qiluvchi xabar tranzaksiyasini oladi va shifrini ochadi

1-3 va 7-qadamlar mijozda mahalliy, 5-6-bosqichlar esa xostlarda bajariladi.

Xabarni shifrlash

Xabar jo'natuvchining shaxsiy kaliti va qabul qiluvchining ochiq kaliti bilan shifrlangan. Biz ochiq kalitni tarmoqdan olamiz, ammo buning uchun qabul qiluvchining hisobi ishga tushirilishi kerak, ya'ni kamida bitta tranzaktsiyaga ega bo'lishi kerak. REST so'rovidan foydalanishingiz mumkin GET /api/accounts/getPublicKey?address={ADAMANT address}, va chatlarni yuklashda suhbatdoshlarning ochiq kalitlari allaqachon mavjud bo'ladi.

Markazlashtirilmagan messenjer blokcheynda qanday ishlaydi?

Messenjer xabarlarni curve25519xsalsa20poly1305 algoritmi yordamida shifrlaydi (NaCl qutisi). Hisobda Ed25519 kalitlari mavjud bo'lganligi sababli, quti yaratish uchun kalitlar avval Curve25519 Diffie-Hellmanga aylantirilishi kerak.

Mana JavaScript-dagi misol:

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

Xabar bilan tranzaktsiyani shakllantirish

Bitim quyidagi umumiy tuzilishga ega:

{
  "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": {}
}

Xabar tranzaksiyasi uchun eng muhimi asset - ob'ektga xabar joylashtirishingiz kerak chat tuzilishi bilan:

  • message - shifrlangan xabarni saqlang
  • own_message -bir marta
  • type - xabar turi

Xabarlar ham turlarga bo'linadi. Asosan, parametr type qanday tushunish kerakligini aytadi message. Siz shunchaki matn yuborishingiz mumkin yoki ichida qiziqarli narsalar bo'lgan ob'ektni yuborishingiz mumkin - masalan, messenjer chatlarda kriptovalyuta o'tkazmalarini shunday amalga oshiradi.

Natijada biz tranzaksiya yaratamiz:

{
  "transaction": {
    "type": 8,
    "amount": 0,
    "senderId": "U12499126640447739963",
    "senderPublicKey": "e9cafb1e7b403c4cf247c94f73ee4cada367fcc130cb3888219a0ba0633230b6",
    "asset": {
      "chat": {
        "message": "cb682accceef92d7cddaaddb787d1184ab5428",
        "own_message": "e7d8f90ddf7d70efe359c3e4ecfb5ed3802297b248eacbd6",
        "type": 1
      }
    },
    "recipientId": "U15677078342684640219",
    "timestamp": 63228087,
    "signature": "тут будет подпись"
  }
}

Tranzaksiya imzosi

Har bir inson jo'natuvchi va qabul qiluvchining haqiqiyligiga, jo'natish vaqtiga va xabar mazmuniga ishonch hosil qilish uchun bitim imzolanadi. Raqamli imzo ochiq kalit yordamida tranzaktsiyaning haqiqiyligini tekshirish imkonini beradi - buning uchun shaxsiy kalit kerak emas.

Ammo imzoning o'zi shaxsiy kalit yordamida amalga oshiriladi:

Markazlashtirilmagan messenjer blokcheynda qanday ishlaydi?

Diagramma shuni ko'rsatadiki, biz avval SHA-256 bilan tranzaktsiyani xeshlab, keyin imzolaymiz Ed25519 EdDSA va imzo oling signature, va tranzaksiya identifikatori SHA-256 xeshining bir qismidir.

Amalga oshirish misoli:

1 — Maʼlumotlar blokini, jumladan, xabarni shakllantirish

/**
 * 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 - ma'lumotlar blokidan SHA-256 ni hisoblang

/**
 * 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 - tranzaktsiyani imzolash

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'))
}

Tranzaktsiyani xabar bilan tarmoq tuguniga yuborish

Tarmoq markazlashtirilmaganligi sababli, ochiq API bilan tugunlarning har biri buni amalga oshiradi. Oxirgi nuqtaga POST so'rovini yuborish api/transactions:

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

Bunga javoban biz bunday turdagi tranzaksiya identifikatorini olamiz

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

Tranzaksiyani tekshirish

Konsensusga asoslangan taqsimlangan tugunlar tizimi tranzaksiya xabarining "haqiqiyligini" aniqlaydi. Kimdan va kimga, qachon, xabar boshqasi bilan almashtirilganmi va jo'natish vaqti to'g'ri ko'rsatilganmi. Bu blokcheynning juda muhim afzalligi – tekshirish uchun mas’ul bo‘lgan markaziy tuzilma yo‘q, xabarlar ketma-ketligi va ularning mazmunini soxtalashtirish mumkin emas.

Birinchidan, bitta tugun aniqlikni tekshiradi va keyin uni boshqalarga yuboradi - agar ko'pchilik hamma narsa tartibda ekanligini aytsa, tranzaktsiya zanjirning keyingi blokiga kiritiladi - bu konsensus.

Markazlashtirilmagan messenjer blokcheynda qanday ishlaydi?

Tekshiruvlar uchun mas'ul bo'lgan tugun kodining qismini GitHub-da ko'rish mumkin - validator.js и verify.js. Ha, tugun Node.js da ishlaydi.

Blokdagi xabar bilan tranzaktsiyani o'z ichiga oladi

Agar konsensusga erishilsa, bizning xabarimiz bilan tranzaksiya boshqa amaldagi tranzaktsiyalar bilan birga keyingi blokga kiritiladi.

Bloklar qat'iy ketma-ketlikka ega va har bir keyingi blok oldingi bloklarning xeshlari asosida tuziladi.

Markazlashtirilmagan messenjer blokcheynda qanday ishlaydi?

Gap shundaki, bizning xabarimiz ham ushbu ketma-ketlikka kiritilgan va uni "qayta tartibga solish" mumkin emas. Agar bir nechta xabarlar blokga tushsa, ularning tartibi belgilanadi timestamp xabarlar.

Xabarlarni o'qish

Messenjer ilovasi blokcheyndan qabul qiluvchiga yuborilgan tranzaktsiyalarni oladi. Buning uchun biz yakuniy nuqta qildik api/chatrooms.

Barcha tranzaktsiyalar hamma uchun mavjud - siz shifrlangan xabarlarni olishingiz mumkin. Ammo faqat qabul qiluvchi o'zining shaxsiy kaliti va jo'natuvchining ochiq kaliti yordamida shifrni ochishi mumkin:

**
 * 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) : ''
}

Yana nima?

Xabarlar shu tarzda taxminan 5 soniyada yetkazilganligi sababli - bu yangi tarmoq bloki paydo bo'ladigan vaqt - biz mijozdan tugunga va tugundan tugunga rozetkaga ulanishni o'ylab topdik. Tugun yangi tranzaktsiyani qabul qilganda, uning haqiqiyligini tekshiradi va uni boshqa tugunlarga yuboradi. Tranzaktsiya messenjer mijozlari uchun konsensus yuzaga kelmasdan va blokga kiritilgunga qadar mavjud. Shunday qilib, biz oddiy messenjerlar kabi bir zumda xabarlarni yetkazib beramiz.

Manzillar kitobini saqlash uchun biz KVS-ni yaratdik - Key-value Storage - bu tranzaksiyaning yana bir turi. asset shifrlangan NaCl-box emas, balki NaCl-maxfiy quti. Messenjer shu tarzda boshqa ma'lumotlarni saqlaydi.

Fayl/tasvirni uzatish va guruh suhbatlari hali ham ko'p mehnat talab qiladi. Albatta, qo'pol va qo'pol formatda buni tezda "buzish" mumkin, ammo biz bir xil darajadagi maxfiylikni saqlamoqchimiz.

Ha, hali qilinishi kerak bo'lgan ish bor - ideal holda, haqiqiy maxfiylik foydalanuvchilar umumiy tarmoq tugunlariga ulanmaydi, balki o'zlarini ko'taradi. Sizningcha, foydalanuvchilarning necha foizi buni amalga oshiradi? To'g'ri, 0. Biz messenjerning Tor versiyasi bilan bu masalani qisman hal qilishga muvaffaq bo'ldik.

Biz blokcheyndagi messenjer mavjud bo'lishi mumkinligini isbotladik. Ilgari, 2012 yilda faqat bitta urinish bo'lgan - bit xabar, bu uzoq xabarlarni yetkazib berish vaqtlari, protsessor yuklanishi va mobil ilovalarning yo'qligi sababli muvaffaqiyatsiz tugadi.

Ishonchsizlik esa blokcheyndagi messenjerlarning o‘z vaqtidan oldinda ekani bilan bog‘liq – odamlar o‘z akkauntlari uchun mas’uliyatni o‘z zimmalariga olishga tayyor emaslar, shaxsiy ma’lumotlarga egalik qilish hali trend emas, texnologiya esa blokcheynda yuqori tezlikka yo‘l qo‘ymaydi. Kelgusida loyihamizning ko'proq texnologik analoglari paydo bo'ladi. Ko'rasiz.

Manba: www.habr.com

a Izoh qo'shish