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

2017 elején elkezdtük egy üzenetküldő létrehozását a blokkláncon [név és link a profilban], megvitatva a klasszikus P2P üzenetküldőkkel szembeni előnyöket.

Elmúlt 2.5 évben, és meg tudtuk erősíteni koncepciónkat: a messenger alkalmazások már elérhetőek iOS, Web PWA, Windows, GNU/Linux, Mac OS és Android rendszerekre.

Ma elmondjuk, hogyan működik a blockchain messenger, és hogyan működhetnek az ügyfélalkalmazások az API-jával.
Hogyan működik egy decentralizált üzenetküldő a blokkláncon?

Azt akartuk, hogy a blokklánc megoldja a klasszikus P2P üzenetküldők biztonsági és adatvédelmi problémáit:

  • Egy kattintással hozhat létre fiókot – nincs telefon vagy e-mail, nincs hozzáférés a címjegyzékekhez vagy a földrajzi helyekhez.
  • A beszélgetőpartnerek soha nem hoznak létre közvetlen kapcsolatot, minden kommunikáció elosztott csomópontrendszeren keresztül történik. A felhasználók IP-címei nem érhetők el egymás számára.
  • Minden üzenet titkosított End-to-End curve25519xsalsa20poly1305. Úgy tűnik, ez senkit nem fog meglepni, de a forráskódunk nyitva van.
  • A MITM támadás kizárt – minden üzenet tranzakció, és az Ed25519 EdDSA aláírja őket.
  • Az üzenet a saját blokkjába kerül. A következetesség és timestamp Nem tudja javítani a blokkokat, így az üzenetek sorrendjét.
  • A „nem mondtam ezt” nem működik a blokkláncon lévő üzenetekkel.
  • Nincs olyan központi struktúra, amely ellenőrizné az üzenet „hitelességét”. Ezt konszenzuson alapuló elosztott csomópontrendszer végzi, és a felhasználók tulajdonában van.
  • A cenzúra lehetetlensége - a fiókokat nem lehet blokkolni, és az üzeneteket nem lehet törölni.
  • A Blockchain 2FA a pokoli 2FA alternatívája SMS-ben, sok egészséget tönkretett.
  • Az a képesség, hogy az összes beszélgetést bármilyen eszközről bármikor lekérheti, azt jelenti, hogy egyáltalán nem kell helyileg tárolnia a beszélgetéseket.
  • Az üzenet kézbesítésének megerősítése. Nem a felhasználó eszközére, hanem a hálózatra. Ez lényegében annak megerősítése, hogy a címzett el tudja olvasni az üzenetet. Ez egy hasznos funkció a kritikus értesítések küldéséhez.

A blokklánc előnyei közé tartozik az Ethereum, Dogecoin, Lisk, Dash, Bitcoin kriptovalutákkal való szoros integráció (ez még folyamatban van), valamint a tokenek chatekben történő küldésének lehetősége. Még egy beépített kriptocserélőt is készítettünk.

És akkor – hogyan működik mindez.

Az üzenet tranzakció

Mindenki megszokta már, hogy a blokkláncban végrehajtott tranzakciók tokeneket (érméket) adnak át egyik felhasználótól a másikhoz. Mint a Bitcoin. Létrehoztunk egy speciális tranzakciótípust az üzenetek továbbítására.

Ha üzenetet szeretne küldeni egy messengerben a blokkláncon, több lépést kell végrehajtania:

  1. Üzenet szövegének titkosítása
  2. Helyezzen titkosított szöveget a tranzakcióba
  3. Írja alá a tranzakciót
  4. Tranzakció küldése bármely hálózati csomópontra
  5. A csomópontok elosztott rendszere határozza meg az üzenet „autentikusságát”.
  6. Ha minden rendben van, akkor az üzenetet tartalmazó tranzakció bekerül a következő blokkba
  7. A címzett lekéri az üzenettranzakciót, és visszafejti a titkosítást

Az 1–3. és 7. lépést helyileg a kliensen, az 5–6. lépéseket pedig a gazdagépeken hajtják végre.

Üzenet titkosítás

Az üzenetet a feladó privát kulcsával és a címzett nyilvános kulcsával titkosítják. Elvesszük a nyilvános kulcsot a hálózatból, de ehhez inicializálni kell a címzett fiókját, azaz legalább egy tranzakciót kell végrehajtani. Használhat REST kérést GET /api/accounts/getPublicKey?address={ADAMANT address}, a chatek betöltésekor pedig már elérhetőek lesznek a beszélgetőpartnerek nyilvános kulcsai.

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

A messenger a curve25519xsalsa20poly1305 algoritmussal titkosítja az üzeneteket (NaCl Box). Mivel a fiók Ed25519 kulcsokat tartalmaz, egy doboz létrehozásához a kulcsokat először Curve25519 Diffie-Hellman formátumra kell konvertálni.

Íme egy példa JavaScriptben:

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

Tranzakció létrehozása üzenettel

A tranzakció általános felépítése 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": {}
}

Üzenet-tranzakciónál a legfontosabb az asset - üzenetet kell elhelyezni az objektumban chat szerkezettel:

  • message - mentse el a titkosított üzenetet
  • own_message -egyszer sem
  • type - üzenet típusa

Az üzeneteket szintén típusokra osztják. Lényegében a paraméter type megmondja, hogyan kell megérteni message. Küldhetsz csak egy szöveget, vagy küldhetsz egy objektumot, amiben érdekes dolgok vannak benne - például chaten a messenger kriptovaluta-átutalásokat hajt végre.

Ennek eredményeként 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": "тут будет подпись"
  }
}

Tranzakció aláírása

Annak érdekében, hogy mindenki biztos legyen a feladó és a címzett hitelességében, a küldés időpontjában és az üzenet tartalmában, a tranzakció aláírásra kerül. A digitális aláírás lehetővé teszi a tranzakció hitelességének ellenőrzését nyilvános kulcs segítségével – ehhez nincs szükség privát kulcsra.

De maga az aláírás a privát kulccsal történik:

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

A diagram azt mutatja, hogy először kivonatolja a tranzakciót az SHA-256-tal, majd aláírjuk Ed25519 EdDSA és kap egy aláírást signature, és a tranzakcióazonosító az SHA-256 hash része.

Példa megvalósításra:

1 — Adatblokk létrehozása, 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 – Számolja ki az SHA-256-ot az adatblokkbó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. Írja alá a tranzakciót

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

Tranzakció küldése üzenettel egy hálózati csomópontnak

Mivel a hálózat decentralizált, bármelyik nyitott API-val rendelkező csomópont megteszi. POST kérés a végponthoz api/transactions:

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

Válaszul egy ilyen típusú tranzakcióazonosítót kapunk

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

Tranzakció érvényesítése

A csomópontok elosztott rendszere konszenzus alapján határozza meg a tranzakciós üzenet „hitelességét”. Kitől és kinek, mikor, lecserélték-e az üzenetet másikra, helyesen lett-e feltüntetve a küldés időpontja. Ez egy nagyon fontos előnye a blokkláncnak - nincs központi struktúra, amely az ellenőrzésért felelős, és az üzenetek sorozata és azok tartalma nem hamisítható.

Először az egyik csomópont ellenőrzi a pontosságot, majd elküldi másoknak - ha a többség szerint minden rendben van, akkor a tranzakció a lánc következő blokkjába kerül - ez konszenzus.

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

A csomópont kódjának az ellenőrzésekért felelős része megtekinthető a GitHubon - validator.js и verify.js. Igen, a csomópont Node.js-en fut.

Üzenetet tartalmazó tranzakció blokkba foglalása

Ha konszenzus születik, az üzenetünket tartalmazó tranzakció a többi érvényes tranzakcióval együtt a következő blokkba kerül.

A blokkoknak szigorú sorrendjük van, és minden további blokk az előző blokkok hash-ei alapján jön létre.

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

A lényeg az, hogy a mi üzenetünk is benne van ebben a sorrendben, és nem lehet „átrendezni”. Ha több üzenet esik egy blokkba, akkor azok sorrendjét a timestamp üzenetek.

Üzenetek olvasása

Az üzenetküldő alkalmazás lekéri a blokkláncból a címzettnek küldött tranzakciókat. Ehhez készítettünk egy végpontot api/chatrooms.

Minden tranzakció mindenki számára elérhető - titkosított üzeneteket fogadhat. De csak a címzett tudja visszafejteni a titkosítást a privát kulcsával és a küldő nyilvános 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) : ''
}

Mi más?

Mivel az üzenetek így kb. 5 másodperc alatt kézbesítenek – ekkor jelenik meg egy új hálózati blokk –, kitaláltunk egy kliens-csomópont és csomópont-csomópont socket kapcsolatot. Amikor egy csomópont új tranzakciót kap, ellenőrzi annak érvényességét, és továbbítja más csomópontoknak. A tranzakció már a konszenzus létrejötte és a blokkba való felvétel előtt is elérhető a messenger ügyfelek számára. Így azonnal kézbesítjük az üzeneteket, akárcsak a hagyományos azonnali üzenetküldők.

A címjegyzék tárolásához KVS-t készítettünk - Key-Value Storage - ez egy másik típusú tranzakció, amelyben asset nem a NaCl-box titkosított, hanem NaCl-titkosdoboz. A messenger így tárol más adatokat.

A fájl-/képátvitel és a csoportos csevegés még mindig sok munkát igényel. Természetesen a baklövés-badulás formátumban ez gyorsan „elcsavarható”, de szeretnénk megőrizni a magánélet azonos szintjét.

Igen, van még tennivaló – ideális esetben a valódi adatvédelem azt feltételezi, hogy a felhasználók nem csatlakoznak nyilvános hálózati csomópontokhoz, hanem felveszik a sajátjukat. Szerinted a felhasználók hány százaléka csinálja ezt? Igaz, 0. Ezt a problémát részben sikerült megoldanunk a messenger Tor verziójával.

Bebizonyítottuk, hogy létezhet üzenetküldő a blokkláncon. Korábban csak egy próbálkozás volt 2012-ben - bitüzenet, amely a hosszú üzenetkézbesítési idő, a CPU terhelés és a mobilalkalmazások hiánya miatt meghiúsult.

A szkepticizmus pedig annak a ténynek köszönhető, hogy a hírnökök a blokkláncon megelőzik korukat – az emberek nem állnak készen arra, hogy felelősséget vállaljanak a fiókjukért, a személyes adatok birtoklása még nem trend, és a technológia nem teszi lehetővé a nagy sebességet a blokkláncon. Legközelebb projektünk további technológiai analógjai jelennek meg. Látni fogod.

Forrás: will.com

Hozzászólás