Hogyan működik a decentralizált üzenetküldő a blokkláncon

2017 elején elkezdtük létrehozni a blokklánc alapú üzenetküldőt [a név és a link a profilban található], amely a hagyományos P2P üzenetküldőkkel szembeni előnyöket vitatja.

Eltelt 2.5 éve, és sikerült megerősíteni a koncepciót: most már elérhetők az üzenetküldő alkalmazásai iOS, Web PWA, Windows, GNU/Linux, Mac OS és Android rendszeren.

Ma elmondjuk, hogyan működik a blokklánc alapú üzenetküldő és hogyan működnek az ügyfélalkalmazások az API-jával.
Hogyan működik a decentralizált üzenetküldő a blokkláncon

Azt akartuk, hogy a blokklánc megoldja a klasszikus P2P üzenetküldők biztonsági és magánéleti kérdéseit:

  • Egy kattintás az fiók létrehozásához — nincs szükség telefonszámra és e-mail címre, nincsenek hozzáférések a névjegyzékekhez és a geolokációkhoz.
  • A beszélgetőpartnerek soha nem létesítenek közvetlen kapcsolatokat, minden kommunikáció egy elosztott csomópont rendszeren keresztül folyik. A felhasználók IP-címei nem elérhetők egymás számára.
  • Minden üzenet End-to-End curve25519xsalsa20poly1305 titkosítással van ellátva. Ez talán nem meglepő mások számára, de a mi forráskódunk nyilvános.
  • A MITM-támadások kizártak — minden üzenet tranzakció, amelyet Ed25519 EdDSA ír alá.
  • Az üzenet a saját blokkjába kerül. A sorrend és timestamp a blokkok nem módosíthatók, így az üzenetek sorrendje sem változtatható meg.
  • A „Ezt nem mondtam” nem működik a blokkláncon lévő üzenetek esetében.
  • Nincs központi struktúra, amely ellenőrzi az üzenetek „hitelességét”. Ezt a konszenzus alapú elosztott csomópont rendszer végzi, és ez a felhasználók tulajdonában van.
  • A cenzúra lehetetlensége — az fiókok nem zárhatók le, az üzeneteket nem lehet törölni.
  • A blokklánc 2FA — alternatíva a rémes SMS-ként működő 2FA-hoz, amely sok egészséget tönkretett.
  • A lehetőség, hogy minden párbeszédét bármilyen eszközről bármikor megkaphatja — ez azt jelenti, hogy egyáltalán nem lehet az üzeneteket helyben tárolni.
  • Az üzenetek kézbesítésének megerősítése. Nem a felhasználó eszközére, hanem a hálózatra. Valójában ez a címzett üzenetének elolvasására vonatkozó lehetőséget erősíti meg. Ez egy hasznos funkció kritikus értesítések küldésére.

A blokklánc további előnyei közé tartozik a közvetlen integráció az Ethereum, Dogecoin, Lisk, Dash, Bitcoin (ez még fejlesztés alatt) kriptovalutákkal és a tokenek küldésének lehetősége a csevegésekben. Még beépített kriptovaluta-átváltót is készítettünk.

Most pedig nézzük meg, hogyan működik mindez.

Az üzenet — ez egy tranzakció

Mindenki hozzászokott, hogy a blokklánc tranzakciói tokent (érmét) továbbítanak egy felhasználótól a másikhoz. Ahogy a bitcoinnál is. Mi azonban egy különleges tranzakciótípust hoztunk létre az üzenetek továbbítására.

Az üzenet elküldéséhez a blokklánc alapú üzenetküldőben több lépést kell végrehajtani:

  1. Titkosítsa az üzenet szövegét
  2. Helyezze a titkosított szöveget a tranzakcióba
  3. Írja alá a tranzakciót
  4. Küldje el a tranzakciót a hálózat bármely csomópontjára
  5. A csomópontok elosztott rendszere meghatározza az üzenet „hitelességét”
  6. Ha minden rendben van, az üzenettel kapcsolatos tranzakciót a következő blokkba beillesztik
  7. A címzett kiolvassa az üzenettel rendelkező tranzakciót és dekódolja

Az 1-3. és 7. lépéseket lokálisan a kliensen végzik, míg az 5-6. lépéseket a hálózati csomópontok végzik el.

Az üzenet titkosítása

Az üzenet a feladó privát kulcsával és a címzett nyilvános kulcsával kerül titkosításra. A nyilvános kulcsot a hálózatból szerezzük, de ehhez a címzett fiókjának inicializálva kell lennie, vagyis legalább egy tranzakcióval rendelkeznie kell. REST kérést használhatunk. GET /api/accounts/getPublicKey?address={ADAMANT address}, és a csevegések betöltésekor a beszélgetőtársak nyilvános kulcsai már rendelkezésre állnak.

Hogyan működik a decentralizált üzenetküldő a blokkláncon

Az üzenetküldő az üzenetek titkosításához a curve25519xsalsa20poly1305 algoritmust használja (NaCl Box). Mivel a fiók Ed25519 kulcsokat tartalmaz, a box létrehozásához először a kulcsokat át kell alakítani Curve25519 Diffie-Hellman formára.

Itt egy példa JavaScript-ben:

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

A tranzakció kibővítése üzenettel

A tranzakció általános szerkezete a következő:

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

Az üzenettel rendelkező tranzakció szempontjából a legfontosabb érték az asset — ebbe kell elhelyezni az üzenetet a következő szerkezetben: chat — tárolja a titkosított üzenetet

  • üzenet own_message
  • — nonce — üzenet típusa
  • type Az üzeneteket is típusuk szerint osztályozzuk. Valójában a paraméter

megmondja, hogyan kell értelmezni type . Küldhetünk egyszerűen szöveget, vagy egy olyan objektumot, amiben érdekes dolgok találhatók — például így a program végrehajtja a kriptovaluta átutalását a csevegők között. üzenetVégül tehát létrehozunk egy tranzakciót:

{

{
  "transaction": {
    "type": 8,
    "amount": 0,
    "senderId": "U12499126640447739963",
    "senderPublicKey": "e9cafb1e7b403c4cf247c94f73ee4cada367fcc130cb3888219a0ba0633230b6",
    "asset": {
      "chat": {
        "message": "cb682accceef92d7cddaaddb787d1184ab5428",
        "own_message": "e7d8f90ddf7d70efe359c3e4ecfb5ed3802297b248eacbd6",
        "type": 1
      }
    },
    "recipientId": "U15677078342684640219",
    "timestamp": 63228087,
    "signature": "itt lesz az aláírás"
  }
}

A tranzakció aláírása

A küldő és a fogadó hitelessége, az üzenet küldésének időpontja és tartalma szempontjából fontos, hogy a tranzakciót aláírják. A digitális aláírás lehetővé teszi a tranzakció hitelességének ellenőrzését a nyilvános kulcs alapján — ehhez a magánkulcsra nincs szükség.

És itt az aláírás, amelyet a magánkulccsal készítünk:

Hogyan működik a decentralizált üzenetküldő a blokkláncon

A diagramon látható, hogy először a tranzakciót SHA-256-tal hasheljük, majd azt aláírjuk. Ed25519 EdDSA és megkapjuk az aláírást aláírás, míg a tranzakció azonosítója a SHA-256 hash egy része.

Példa megvalósításra:

1 — Adatblokk képzése, beleértve az üzenetet

/**
 * 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 — SHA-256 számítása az adatblokkról

/**
 * 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 — A tranzakció aláírása

adamant.transactionSign = function (trs, keypair) {
  var hash = this.getHash(trs)
  return this.sign(hash, keypair).toString('hex')
}

/**
 * Aláírás létrehozása egy hash és egy kulcspár alapján.
 * @implements {sodium}
 * @param {hash} hash
 * @param {keypair} keypair
 * @return {signature} aláírás
 *\/ 
adamant.sign = function (hash, keypair) {
  return sodium.crypto_sign_detached(hash, Buffer.from(keypair.privateKey, 'hex'))
}

A tranzakció üzenettel való küldése a hálózat csomópontjához

Mivel a hálózat decentralizált, bármely olyan csomópont megfelelő, amely nyílt API-val rendelkezik. POST-kérést küldünk az végpontra api/transactions:

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

Válaszként megkapjuk a tranzakció azonosítóját:

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

A tranzakció hitelességének ellenőrzése

A konszenzus alapú elosztott rendszer csomópontjai határozzák meg a tranzakció-üzenet "hitelességét". Ki küldte, kinek, mikor, nem cserélték-e ki az üzenetet egy másikra, és helyes-e a küldési idő. Ez a blockchain egyik legfontosabb előnye — nincs központi struktúra, amely a hitelesítésekért felelős, és az üzenetek sorrendje, valamint tartalma nem hamisítható.

Először egy csomópont ellenőrzi a hitelességet, majd továbbítja a többi csomópontnak — ha a többség azt mondja, hogy minden rendben van, a tranzakció bekerül a következő blokkba — ez a konszenzus.

Hogyan működik a decentralizált üzenetküldő a blokkláncon

A csomópont kódjának része, amely a hitelesítésekért felel, megtekinthető a GitHub-on — validator.js és verify.js. Igen, a csomópont a Node.js-en fut.

A tranzakció üzenetének beillesztése a blokkba

Ha a konszenzus létrejött, az üzenetünk tranzakciója a következő blokkba kerül más hiteles tranzakciók mellett.

A blokkok szigorú sorrendben állnak, és minden következő blokk az előző blokkok hashek alapján jön létre.

Hogyan működik a decentralizált üzenetküldő a blokkláncon

A lényeg, hogy az üzenetünk is része ennek a sorrendnek, és nem lehet „áthelyezni”. Ha több üzenet kerül egy blokkba, azok sorrendjét a timestamp üzenetek határozzák meg.

Üzenetek olvasása

A messenger alkalmazás a blockchainból kiolvassa azokat a tranzakciókat, amelyeket a címzettnek küldtek. Ehhez létrehoztuk az api/chatrooms.

Minden tranzakció elérhető mindenki számára — a titkosított üzeneteket meg lehet kapni. De csak a címzett tudja dekódolni a saját privát kulcsával és a küldő közpublic kulcsával:

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

És mi más?

Mivel az üzenetek körülbelül 5 másodperc alatt érkeznek meg — ez a hálózat új blokkjának megjelenési ideje — kitaláltunk egy socket-kapcsolatot kliens-csomópont és csomópont-csomópont között. Amikor a csomópont egy új tranzakciót kap, ellenőrzi annak érvényességét és továbbítja a többi csomópontnak. A tranzakció elérhető a messenger kliensek számára még a konszenzus előtt és a blokkba való beillesztés előtt. Így az üzeneteket azonnal továbbítjuk, akárcsak a szokásos messengerek.

Az címjegyzék tárolására létrehoztunk egy KVS-t — Key-Value Storage — ez egy másik típusú tranzakció, amelyben asset nem NaCl-boxot titkosítunk, hanem NaCl-secretboxot. Így a messenger más adatokat is tárolhat.

Fájlok/képek átadása és csoportos csevegések még sok munkát igényelnek. Persze, a tervezetlen formában gyorsan „rá lehet kötni”, de szeretnénk megőrizni a privát szintet.

Igen, még van mit tennünk — az ideális igazi privát szint azt jelenti, hogy a felhasználók nem csatlakoznak a nyilvános csomópontokhoz, hanem sajátokat állítanak fel. Ön szerint hány százalékuk teszi ezt? Helyesen, 0. Részben ezt a kérdést sikerült megoldanunk a messenger Tor-verziójával.

Bizonyítottuk, hogy a blockchain alapú messenger létezhet. Korábban csak egy kísérlet volt 2012-ben — bitmessage, amely a hosszú üzenetátviteli idő, a processzorga terheltsége és a mobilalkalmazások hiánya miatt nem volt sikeres.

A szkepticizmus azt jelenti, hogy a blokklánc-alapú üzenetküldők megelőzik az időt — az emberek még nem készen állnak arra, hogy a saját fiókjukért felelősséget vállaljanak, a személyes adatok birtoklása még nem trendi, és a technológiák nem képesek biztosítani a magas sebességeket a blokkláncon. Hamarosan megjelennek majd technológiailag fejlettebb megfelelői a projektünknek. Meglátjátok.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster