Hoe werk 'n gedesentraliseerde boodskapper op die blokketting?

Aan die begin van 2017 het ons 'n boodskapper op die blokketting begin skep [naam en skakel is in die profiel] deur die voordele bo klassieke P2P-boodskappers te bespreek.

Weg 2.5 jaar, en ons kon ons konsep bevestig: boodskapper-toepassings is nou beskikbaar vir iOS, Web PWA, Windows, GNU/Linux, Mac OS en Android.

Vandag sal ons jou vertel hoe die blockchain-boodskapper werk en hoe kliënttoepassings met sy API kan werk.
Hoe werk 'n gedesentraliseerde boodskapper op die blokketting?

Ons wou hê die blokketting moet die sekuriteits- en privaatheidskwessies van klassieke P2P-boodskappers oplos:

  • Een klik om 'n rekening te skep - geen telefone of e-posse, geen toegang tot adresboeke of geo-liggings nie.
  • Die gespreksgenote vestig nooit direkte verbindings nie; alle kommunikasie vind plaas deur 'n verspreide stelsel van nodusse. Gebruikers se IP-adresse is nie vir mekaar toeganklik nie.
  • Alle boodskappe is geënkripteer End-tot-End curve25519xsalsa20poly1305. Dit blyk dat dit niemand sal verras nie, maar ons bronkode is oop.
  • MITM-aanval is uitgesluit - elke boodskap is 'n transaksie en word deur Ed25519 EdDSA onderteken.
  • Die boodskap beland in sy eie blok. Konsekwentheid en timestamp Jy kan nie die blokke regmaak nie, en dus die volgorde van die boodskappe.
  • "Ek het dit nie gesê nie" sal nie werk met boodskappe op die blokketting nie.
  • Daar is geen sentrale struktuur wat kontroleer vir die "egtheid" van die boodskap nie. Dit word gedoen deur 'n verspreide stelsel van nodusse gebaseer op konsensus, en dit word deur gebruikers besit.
  • Onmoontlikheid van sensuur – rekeninge kan nie geblokkeer word nie en boodskappe kan nie uitgevee word nie.
  • Blockchain 2FA is 'n alternatief vir die helse 2FA via SMS, baie gesondheid verwoes.
  • Die vermoë om al jou gesprekke te eniger tyd van enige toestel af te kry, beteken dat jy glad nie gesprekke plaaslik hoef te stoor nie.
  • Bevestiging van boodskap aflewering. Nie na die gebruiker se toestel nie, maar na die netwerk. In wese is dit bevestiging van die ontvanger se vermoë om jou boodskap te lees. Dit is 'n nuttige kenmerk om kritieke kennisgewings te stuur.

Blockchain-voordele sluit ook noue integrasie met die kripto-geldeenhede Ethereum, Dogecoin, Lisk, Dash, Bitcoin in (hierdie een is nog aan die gang) en die vermoë om tokens in geselsies te stuur. Ons het selfs 'n ingeboude kripto-wisselaar gemaak.

En dan - hoe dit alles werk.

'n Boodskap is 'n transaksie

Almal is reeds gewoond daaraan dat transaksies in die blokketting tokens (munte) van een gebruiker na 'n ander oordra. Soos Bitcoin. Ons het 'n spesiale tipe transaksie geskep vir die oordrag van boodskappe.

Om 'n boodskap in 'n boodskapper op die blokketting te stuur, moet jy deur verskeie stappe gaan:

  1. Enkripteer boodskapteks
  2. Plaas syferteks in 'n transaksie
  3. Teken die transaksie
  4. Stuur 'n transaksie na enige netwerknodus
  5. 'n Verspreide stelsel van nodusse bepaal die "egtheid" van 'n boodskap
  6. As alles reg is, word die transaksie met die boodskap in die volgende blok ingesluit
  7. Die ontvanger haal die boodskaptransaksie op en dekripteer

Stappe 1–3 en 7 word plaaslik op die kliënt uitgevoer, en stappe 5–6 word op die gashere uitgevoer.

Boodskapkodering

Die boodskap word geïnkripteer met die sender se private sleutel en die ontvanger se publieke sleutel. Ons sal die publieke sleutel van die netwerk af neem, maar hiervoor moet die ontvanger se rekening geïnisialiseer word, dit wil sê, ten minste een transaksie hê. Jy kan 'n REST-versoek gebruik GET /api/accounts/getPublicKey?address={ADAMANT address}, en wanneer geselsies gelaai word, sal die publieke sleutels van die gespreksgenote reeds beskikbaar wees.

Hoe werk 'n gedesentraliseerde boodskapper op die blokketting?

Die boodskapper enkripteer boodskappe met behulp van die curve25519xsalsa20poly1305-algoritme (NaCl boks). Aangesien die rekening Ed25519-sleutels bevat, om 'n boks te vorm, moet die sleutels eers na Curve25519 Diffie-Hellman omgeskakel word.

Hier is 'n voorbeeld in 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)
  }
}

Vorm 'n transaksie met 'n boodskap

Die transaksie het die volgende algemene struktuur:

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

Vir 'n boodskaptransaksie is die belangrikste ding asset - jy moet 'n boodskap in die voorwerp plaas chat met struktuur:

  • message - stoor die geïnkripteer boodskap
  • own_message - niks
  • type - tipe boodskap

Boodskappe word ook in tipes verdeel. In wese, die parameter type vertel jou hoe om te verstaan message. Jy kan net 'n teks stuur, of jy kan 'n voorwerp met interessante dinge binne stuur - byvoorbeeld, dit is hoe die boodskapper kripto-geldeenheid-oordragte in geselsies maak.

As gevolg hiervan skep ons 'n transaksie:

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

Transaksie handtekening

Om te verseker dat almal vertroue het in die egtheid van die sender en ontvanger, die tyd van versending en die inhoud van die boodskap, word die transaksie onderteken. 'n Digitale handtekening laat jou toe om die egtheid van 'n transaksie met behulp van 'n publieke sleutel te verifieer - 'n private sleutel is nie hiervoor nodig nie.

Maar die handtekening self word uitgevoer met behulp van die private sleutel:

Hoe werk 'n gedesentraliseerde boodskapper op die blokketting?

Die diagram wys dat ons eers die transaksie met SHA-256 hash en dit dan onderteken Ed25519 EdDSA en kry 'n handtekening signature, en die transaksie-ID is deel van die SHA-256-hash.

Voorbeeld implementering:

1 — Vorm 'n datablok, insluitend 'n boodskap

/**
 * 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 - Tel SHA-256 vanaf die datablok

/**
 * 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 — Teken die transaksie

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

Stuur 'n transaksie met 'n boodskap na 'n netwerknodus

Aangesien die netwerk gedesentraliseerd is, sal enige van die nodusse met 'n oop API werk. Maak 'n POST-versoek na die eindpunt api/transactions:

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

In reaksie sal ons 'n transaksie-ID van die tipe ontvang

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

Transaksie validering

'n Verspreide stelsel van nodusse, gebaseer op konsensus, bepaal die "egtheid" van die transaksieboodskap. Van wie en aan wie, wanneer, of die boodskap met 'n ander vervang is, en of die tyd van versending korrek aangedui is. Dit is 'n baie belangrike voordeel van die blokketting - daar is geen sentrale struktuur wat verantwoordelik is vir verifikasie nie, en die volgorde van boodskappe en hul inhoud kan nie vervals word nie.

Eerstens kontroleer een nodus die akkuraatheid, en stuur dit dan aan ander - as die meerderheid sê dat alles in orde is, sal die transaksie in die volgende blok van die ketting ingesluit word - dit is konsensus.

Hoe werk 'n gedesentraliseerde boodskapper op die blokketting?

Die deel van die noduskode wat verantwoordelik is vir tjeks kan op GitHub gesien word - validator.js и verifieer.js. Ja, die node loop op Node.js.

Insluitend 'n transaksie met 'n boodskap in 'n blok

As konsensus bereik word, sal die transaksie met ons boodskap in die volgende blok ingesluit word saam met ander geldige transaksies.

Blokke het 'n streng volgorde, en elke daaropvolgende blok word gevorm op grond van die hashes van vorige blokke.

Hoe werk 'n gedesentraliseerde boodskapper op die blokketting?

Die punt is dat ons boodskap ook in hierdie volgorde ingesluit is en nie “herrangskik” kan word nie. As verskeie boodskappe in 'n blok val, sal hul volgorde bepaal word deur timestamp boodskappe.

Lees boodskappe

Die messenger-toepassing haal transaksies uit die blokketting wat na die ontvanger gestuur word. Hiervoor het ons 'n eindpunt gemaak api/chatrooms.

Alle transaksies is vir almal beskikbaar - jy kan geënkripteerde boodskappe ontvang. Maar net die ontvanger kan met sy private sleutel en die sender se publieke sleutel dekripteer:

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

En wat nog?

Aangesien boodskappe op hierdie manier in ongeveer 5 sekondes afgelewer word - dit is die tyd wat 'n nuwe netwerkblok verskyn - het ons met 'n kliënt-tot-nodus en node-tot-node-sokverbinding vorendag gekom. Wanneer 'n nodus 'n nuwe transaksie ontvang, kontroleer dit die geldigheid daarvan en stuur dit aan na ander nodusse. Die transaksie is beskikbaar vir boodskapperkliënte selfs voor konsensus plaasvind en insluiting in die blok. Op hierdie manier sal ons boodskappe onmiddellik aflewer, net soos gewone kitsboodskappers.

Om die adresboek te stoor, het ons KVS gemaak - Sleutel-Waarde Berging - dit is nog 'n tipe transaksie waarin asset dit is nie NaCl-boks wat geïnkripteer is nie, maar NaCl-geheimboks. Dit is hoe die boodskapper ander data stoor.

Lêer-/prentoordragte en groepkletse verg nog baie werk. Natuurlik, in die flater-en-flater-formaat kan dit vinnig "opgeskroef" word, maar ons wil dieselfde vlak van privaatheid handhaaf.

Ja, daar is nog werk wat gedoen moet word - ideaal gesproke aanvaar werklike privaatheid dat gebruikers nie aan publieke netwerknodusse sal koppel nie, maar hul eie sal verhoog. Watter persentasie gebruikers dink jy doen dit? Dit is reg, 0. Ons kon hierdie probleem gedeeltelik oplos met die Tor-weergawe van die boodskapper.

Ons het bewys dat 'n boodskapper op die blokketting kan bestaan. Voorheen was daar net een poging in 2012 - bitboodskap, wat misluk het weens lang boodskapafleweringstye, SVE-lading en gebrek aan mobiele toepassings.

En skeptisisme is te wyte aan die feit dat boodskappers op die blokketting hul tyd vooruit is - mense is nie gereed om verantwoordelikheid vir hul rekening te neem nie, die besit van persoonlike inligting is nog nie 'n neiging nie, en tegnologie laat nie hoë snelhede op die blokketting toe nie. Meer tegnologiese analoë van ons projek sal volgende verskyn. Jy sal sien.

Bron: will.com

Voeg 'n opmerking