Kako decentralizirani messenger deluje na blockchainu?

V začetku leta 2017 smo začeli ustvarjati messenger na blockchainu [ime in povezava sta v profilu] z razpravo o prednostih pred klasičnimi P2P messengerji.

opravljeno 2.5 letu in lahko smo potrdili naš koncept: aplikacije za sporočila so zdaj na voljo za iOS, Web PWA, Windows, GNU/Linux, Mac OS in Android.

Danes vam bomo povedali, kako deluje blockchain messenger in kako lahko odjemalske aplikacije delujejo z njegovim API-jem.
Kako decentralizirani messenger deluje na blockchainu?

Želeli smo, da bi veriga blokov rešila vprašanja varnosti in zasebnosti klasičnih sporočil P2P:

  • En klik za ustvarjanje računa – brez telefonov ali e-pošte, brez dostopa do imenikov ali geolokacij.
  • Sogovorniki nikoli ne vzpostavijo neposrednih povezav, vsa komunikacija poteka prek porazdeljenega sistema vozlišč. IP naslovi uporabnikov med seboj niso dostopni.
  • Vsa sporočila so šifrirana Curve25519xsalsa20poly1305 od konca do konca. Zdi se, da to nikogar ne bo presenetilo, vendar je naša izvorna koda odprta.
  • Napad MITM je izključen – vsako sporočilo je transakcija in je podpisano z Ed25519 EdDSA.
  • Sporočilo se konča v svojem bloku. Doslednost in timestamp Ne morete popraviti blokov in s tem vrstnega reda sporočil.
  • »Nisem rekel tega« ne bo deloval s sporočili v verigi blokov.
  • Ni centralne strukture, ki bi preverjala "pristnost" sporočila. To izvaja porazdeljen sistem vozlišč, ki temelji na soglasju, in je v lasti uporabnikov.
  • Nemožnost cenzure - računov ni mogoče blokirati in sporočil ni mogoče izbrisati.
  • Blockchain 2FA je alternativa peklenskemu 2FA prek SMS-a, uničil veliko zdravja.
  • Možnost, da kadar koli dobite vse svoje pogovore iz katere koli naprave, pomeni, da vam pogovorov sploh ni treba shranjevati lokalno.
  • Potrditev dostave sporočila. Ne v uporabnikovo napravo, ampak v omrežje. V bistvu je to potrditev sposobnosti prejemnika, da prebere vaše sporočilo. To je uporabna funkcija za pošiljanje kritičnih obvestil.

Prednosti blokovne verige vključujejo tudi tesno integracijo s kriptovalutami Ethereum, Dogecoin, Lisk, Dash, Bitcoin (ta še poteka) in možnost pošiljanja žetonov v klepetih. Naredili smo celo vgrajen kripto izmenjevalnik.

In potem - kako vse skupaj deluje.

Sporočilo je transakcija

Vsi so že navajeni, da transakcije v blockchainu prenašajo žetone (kovance) od enega uporabnika do drugega. Kot Bitcoin. Ustvarili smo posebno vrsto transakcije za prenos sporočil.

Če želite poslati sporočilo v messengerju v blockchainu, morate opraviti več korakov:

  1. Šifrirajte besedilo sporočila
  2. Vnesite šifrirano besedilo v transakcijo
  3. Podpišite transakcijo
  4. Pošljite transakcijo v katero koli omrežno vozlišče
  5. Porazdeljeni sistem vozlišč določa "avtentičnost" sporočila
  6. Če je vse v redu, je transakcija s sporočilom vključena v naslednji blok
  7. Prejemnik pridobi transakcijo sporočila in jo dešifrira

Koraki 1–3 in 7 se izvedejo lokalno na odjemalcu, koraki 5–6 pa na gostiteljih.

Šifriranje sporočil

Sporočilo je šifrirano z zasebnim ključem pošiljatelja in javnim ključem prejemnika. Javni ključ bomo vzeli iz omrežja, vendar mora biti za to prejemnikov račun inicializiran, torej imeti vsaj eno transakcijo. Uporabite lahko zahtevo REST GET /api/accounts/getPublicKey?address={ADAMANT address}, pri nalaganju klepetov pa bodo že na voljo javni ključi sogovornikov.

Kako decentralizirani messenger deluje na blockchainu?

Messenger šifrira sporočila z algoritmom curve25519xsalsa20poly1305 (Škatla NaCl). Ker račun vsebuje ključe Ed25519, je treba za oblikovanje škatle ključe najprej pretvoriti v Curve25519 Diffie-Hellman.

Tukaj je primer v JavaScriptu:

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

Oblikovanje transakcije s sporočilom

Transakcija ima naslednjo splošno strukturo:

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

Za transakcijo sporočila je najpomembnejše asset - v predmet morate postaviti sporočilo chat s strukturo:

  • message - shranite šifrirano sporočilo
  • own_message - enkrat
  • type — vrsto sporočila

Sporočila so razdeljena tudi na vrste. V bistvu parameter type vam pove, kako razumeti message. Lahko pošljete samo besedilo ali pa predmet z zanimivimi stvarmi - na primer, tako messenger izvaja prenose kriptovalut v klepetih.

Posledično ustvarimo transakcijo:

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

Podpis transakcije

Da bi bili vsi prepričani o pristnosti pošiljatelja in prejemnika, času pošiljanja in vsebini sporočila, je transakcija podpisana. Digitalni podpis omogoča preverjanje pristnosti transakcije z javnim ključem – zasebni ključ za to ni potreben.

Toda sam podpis se izvaja z zasebnim ključem:

Kako decentralizirani messenger deluje na blockchainu?

Diagram prikazuje, da transakcijo najprej zgostimo s SHA-256 in jo nato podpišemo Ed25519 EdDSA in dobi podpis signature, ID transakcije pa je del zgoščene vrednosti SHA-256.

Primer izvedbe:

1 — Oblikujte podatkovni blok, vključno s sporočilom

/**
 * 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 - Štetje SHA-256 iz podatkovnega bloka

/**
 * 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 — Podpišite transakcijo

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

Pošiljanje transakcije s sporočilom omrežnemu vozlišču

Ker je omrežje decentralizirano, bo zadostovalo katero koli od vozlišč z odprtim API-jem. Izdelava zahteve POST do končne točke api/transactions:

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

V odgovor bomo prejeli ID transakcije tipa

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

Validacija transakcije

Porazdeljeni sistem vozlišč, ki temelji na soglasju, določa "avtentičnost" transakcijskega sporočila. Od koga in komu, kdaj, ali je bilo sporočilo zamenjano z drugim in ali je bil pravilno naveden čas pošiljanja. To je zelo pomembna prednost blockchaina – ni centralne strukture, ki bi bila odgovorna za preverjanje, zaporedja sporočil in njihove vsebine pa ni mogoče ponarediti.

Najprej eno vozlišče preveri točnost, nato pa ga pošlje drugim - če večina pravi, da je vse v redu, bo transakcija vključena v naslednji blok verige - to je konsenz.

Kako decentralizirani messenger deluje na blockchainu?

Del kode vozlišča, ki je odgovoren za preverjanja, si lahko ogledate na GitHub - validator.js и verify.js. Ja, vozlišče deluje na Node.js.

Vključitev transakcije s sporočilom v bloku

Če je doseženo soglasje, bo transakcija z našim sporočilom vključena v naslednji blok skupaj z drugimi veljavnimi transakcijami.

Bloki imajo strogo zaporedje, vsak naslednji blok pa je oblikovan na podlagi zgoščenih vrednosti prejšnjih blokov.

Kako decentralizirani messenger deluje na blockchainu?

Gre za to, da je v to zaporedje vključeno tudi naše sporočilo in ga ni mogoče »preurediti«. Če več sporočil pade v blok, bo njihov vrstni red določen z timestamp sporočila.

Branje sporočil

Messenger aplikacija pridobi transakcije iz verige blokov, ki so poslane prejemniku. Za to smo naredili končno točko api/chatrooms.

Vse transakcije so na voljo vsem – prejemate lahko šifrirana sporočila. Toda samo prejemnik lahko dešifrira s svojim zasebnim ključem in pošiljateljevim javnim ključem:

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

In kaj še?

Ker so sporočila na ta način dostavljena v približno 5 sekundah - to je čas, ko se pojavi nov omrežni blok - smo prišli do povezave odjemalca do vozlišča in vtičnice od vozlišča do vozlišča. Ko vozlišče prejme novo transakcijo, preveri njeno veljavnost in jo posreduje drugim vozliščem. Transakcija je na voljo strankam messengerja, še preden pride do soglasja in vključitve v blok. Tako bomo sporočila dostavili takoj, tako kot običajni hitri messengerji.

Za shranjevanje adresarja smo naredili KVS - Key-Value Storage - to je še ena vrsta transakcije, pri kateri asset ni NaCl-box šifriran, ampak NaCl-tajna škatla. Tako messenger shranjuje druge podatke.

Prenosi datotek/slik in skupinski klepeti še vedno zahtevajo veliko dela. Seveda se lahko v formatu kiks in kiks to hitro "pokvari", vendar želimo ohraniti enako raven zasebnosti.

Da, še vedno je treba delati - v idealnem primeru resnična zasebnost predvideva, da se uporabniki ne bodo povezovali z javnimi omrežnimi vozlišči, ampak bodo dvignili svoja. Kaj mislite, kolikšen odstotek uporabnikov to počne? Tako je, 0. To težavo smo lahko delno rešili z različico messengerja Tor.

Dokazali smo, da messenger v blockchainu lahko obstaja. Prej je bil leta 2012 le en poskus - bitno sporočilo, ki ni uspel zaradi dolgih časov dostave sporočil, obremenitve procesorja in pomanjkanja mobilnih aplikacij.

Skepticizem pa je posledica dejstva, da so messengerji na blockchainu pred časom – ljudje niso pripravljeni prevzeti odgovornosti za svoj račun, lastništvo osebnih podatkov še ni trend, tehnologija pa ne omogoča visokih hitrosti na blockchainu. V nadaljevanju se bo pojavilo več tehnoloških analogov našega projekta. Boste videli.

Vir: www.habr.com

Dodaj komentar