Kuinka hajautettu sanansaattaja toimii lohkoketjussa?

Vuoden 2017 alussa aloitimme luomaan messengerin lohkoketjuun [nimi ja linkki ovat profiilissa] keskustelemalla eduista klassisiin P2P-viestintään verrattuna.

Mennyt 2.5 vuonna, ja pystyimme vahvistamaan konseptimme: Messenger-sovellukset ovat nyt saatavilla iOS:lle, Web PWA:lle, Windowsille, GNU/Linuxille, Mac OS:lle ja Androidille.

Tänään kerromme sinulle, kuinka blockchain-messenger toimii ja kuinka asiakassovellukset voivat toimia sen API:n kanssa.
Kuinka hajautettu sanansaattaja toimii lohkoketjussa?

Halusimme lohkoketjun ratkaisevan klassisten P2P-lähettimien turvallisuus- ja yksityisyysongelmat:

  • Luo tili yhdellä napsautuksella - ei puhelimia tai sähköposteja, ei pääsyä osoitekirjoihin tai maantieteellisiin sijaintiin.
  • Keskustelukumppanit eivät koskaan muodosta suoria yhteyksiä, vaan kaikki viestintä tapahtuu hajautetun solmujärjestelmän kautta. Käyttäjien IP-osoitteet eivät ole toistensa käytettävissä.
  • Kaikki viestit ovat salattuja End-to-End curve25519xsalsa20poly1305. Näyttää siltä, ​​​​että tämä ei yllätä ketään, mutta lähdekoodimme on avoin.
  • MITM-hyökkäys on poissuljettu - jokainen viesti on tapahtuma ja sen on allekirjoittanut Ed25519 EdDSA.
  • Viesti päätyy omaan lohkoonsa. Johdonmukaisuus ja timestamp Et voi korjata lohkoja ja siten viestien järjestystä.
  • "En sanonut sitä" ei toimi lohkoketjun viestien kanssa.
  • Ei ole olemassa keskusrakennetta, joka tarkistaisi viestin "aitouden". Tämän tekee hajautettu solmujärjestelmä, joka perustuu konsensukseen, ja se on käyttäjien omistama.
  • Sensuurin mahdottomuus - tilejä ei voi estää eikä viestejä poistaa.
  • Blockchain 2FA on vaihtoehto helvetin 2FA:lle tekstiviestillä, pilannut paljon terveyttä.
  • Mahdollisuus saada kaikki keskustelusi miltä tahansa laitteelta milloin tahansa tarkoittaa, että sinun ei tarvitse tallentaa keskusteluja ollenkaan paikallisesti.
  • Viestin toimituksen vahvistus. Ei käyttäjän laitteeseen, vaan verkkoon. Pohjimmiltaan tämä on vahvistus vastaanottajan kyvystä lukea viestisi. Tämä on hyödyllinen ominaisuus kriittisten ilmoitusten lähettämiseen.

Lohkoketjun etuja ovat myös tiivis integraatio kryptovaluuttojen Ethereum, Dogecoin, Lisk, Dash ja Bitcoin kanssa (tämä on vielä kesken) ja mahdollisuus lähettää tokeneita chateissa. Teimme jopa sisäänrakennetun kryptonvaihtimen.

Ja sitten - miten se kaikki toimii.

Viesti on kauppa

Kaikki ovat jo tottuneet siihen, että lohkoketjun tapahtumat siirtävät rahakkeita (kolikoita) käyttäjältä toiselle. Kuten Bitcoin. Olemme luoneet erityisen tapahtumatyypin viestien välittämiseen.

Jos haluat lähettää viestin lohkoketjun messengerissä, sinun on suoritettava useita vaiheita:

  1. Salaa viestin teksti
  2. Lisää salateksti tapahtumaan
  3. Allekirjoita kauppa
  4. Lähetä tapahtuma mihin tahansa verkon solmuun
  5. Hajautettu solmujärjestelmä määrittää viestin "aitouden".
  6. Jos kaikki on kunnossa, tapahtuma viestillä sisällytetään seuraavaan lohkoon
  7. Vastaanottaja hakee viestitapahtuman ja purkaa salauksen

Vaiheet 1–3 ja 7 suoritetaan paikallisesti asiakkaalle ja vaiheet 5–6 suoritetaan isännillä.

Viestien salaus

Viesti salataan lähettäjän yksityisellä avaimella ja vastaanottajan julkisella avaimella. Otamme julkisen avaimen verkosta, mutta tätä varten vastaanottajan tili on alustettava, eli sillä on oltava vähintään yksi tapahtuma. Voit käyttää REST-pyyntöä GET /api/accounts/getPublicKey?address={ADAMANT address}, ja chatteja ladattaessa keskustelukumppanien julkiset avaimet ovat jo saatavilla.

Kuinka hajautettu sanansaattaja toimii lohkoketjussa?

Messenger salaa viestit curve25519xsalsa20poly1305-algoritmilla (NaCl-laatikko). Koska tili sisältää Ed25519-avaimia, avaimet on ensin muunnettava muotoon Curve25519 Diffie-Hellman laatikon muodostamiseksi.

Tässä on esimerkki JavaScriptistä:

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

Kaupan muodostaminen viestillä

Kaupalla on seuraava yleinen rakenne:

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

Viestitapahtuman kannalta tärkeintä on asset - sinun on asetettava viesti objektiin chat rakenteella:

  • message - tallenna salattu viesti
  • own_message - ei kertaakaan
  • type - viestin tyyppi

Viestit on myös jaettu tyyppeihin. Pohjimmiltaan parametri type kertoo kuinka ymmärtää message. Voit lähettää pelkän tekstin tai voit lähettää objektin, jonka sisällä on mielenkiintoisia asioita - esimerkiksi näin messenger tekee kryptovaluuttasiirtoja chateissa.

Tämän seurauksena luomme tapahtuman:

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

Tapahtuman allekirjoitus

Kauppa allekirjoitetaan, jotta varmistetaan, että kaikki ovat varmoja lähettäjän ja vastaanottajan aitoudesta, lähetysajankohdasta ja viestin sisällöstä. Digitaalisella allekirjoituksella voit varmistaa tapahtuman aitouden julkisella avaimella – yksityistä avainta ei tarvita tähän.

Mutta itse allekirjoitus suoritetaan yksityisellä avaimella:

Kuinka hajautettu sanansaattaja toimii lohkoketjussa?

Kaavio osoittaa, että tiivisämme tapahtuman ensin SHA-256:lla ja allekirjoitamme sen sitten Ed25519 EdDSA ja hanki allekirjoitus signature, ja tapahtumatunnus on osa SHA-256-tiivistettä.

Esimerkki toteutuksesta:

1 — Muodosta tietolohko, joka sisältää viestin

/**
 * 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 - Laske SHA-256 tietolohkosta

/**
 * 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 — Allekirjoita kauppa

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

Tapahtuman lähettäminen viestillä verkkosolmuun

Koska verkko on hajautettu, mikä tahansa solmu, jolla on avoin API, käy. POST-pyynnön tekeminen päätepisteeseen api/transactions:

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

Vastauksena saamme tyyppisen tapahtumatunnuksen

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

Tapahtuman vahvistaminen

Hajautettu solmujärjestelmä, joka perustuu konsensukseen, määrittää tapahtumasanoman "aitouden". Keneltä ja kenelle, milloin, korvattiinko viesti toisella ja onko lähetysaika ilmoitettu oikein. Tämä on lohkoketjun erittäin tärkeä etu - varmentamisesta vastaavaa keskusrakennetta ei ole, eikä viestien järjestystä ja niiden sisältöä voi väärentää.

Ensin yksi solmu tarkistaa tarkkuuden ja lähettää sen sitten muille - jos enemmistö sanoo, että kaikki on kunnossa, tapahtuma sisällytetään ketjun seuraavaan lohkoon - tämä on konsensus.

Kuinka hajautettu sanansaattaja toimii lohkoketjussa?

Tarkistuksista vastaava solmukoodin osa on nähtävissä GitHubissa - validator.js и verify.js. Kyllä, solmu toimii Node.js:ssä.

Viestiä sisältävän tapahtuman sisällyttäminen lohkoon

Jos yhteisymmärrykseen päästään, viestimme sisältävä tapahtuma sisällytetään seuraavaan lohkoon muiden kelvollisten tapahtumien kanssa.

Lohkoilla on tiukka järjestys, ja jokainen seuraava lohko muodostetaan edellisten lohkojen hajautusten perusteella.

Kuinka hajautettu sanansaattaja toimii lohkoketjussa?

Asia on siinä, että viestimme sisältyy myös tähän sarjaan, eikä sitä voida "järjestää uudelleen". Jos useita viestejä putoaa lohkoon, niiden järjestyksen määrää timestamp viestejä.

Viestien lukeminen

Messenger-sovellus hakee lohkoketjusta tapahtumat, jotka lähetetään vastaanottajalle. Tätä varten teimme päätepisteen api/chatrooms.

Kaikki tapahtumat ovat kaikkien saatavilla - voit vastaanottaa salattuja viestejä. Mutta vain vastaanottaja voi purkaa salauksen yksityisellä avaimellaan ja lähettäjän julkisella avaimella:

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

Ja mitä muuta?

Koska viestit toimitetaan tällä tavalla noin 5 sekunnissa - tämä on aika, jolloin uusi verkkolohko ilmestyy - päädyimme asiakas-solmu- ja solmu-solmuliitäntään. Kun solmu vastaanottaa uuden tapahtuman, se tarkistaa sen voimassaolon ja välittää sen muille solmuille. Tapahtuma on messenger-asiakkaiden käytettävissä jo ennen kuin konsensus tapahtuu ja sisällytetään lohkoon. Tällä tavalla toimitamme viestit välittömästi, aivan kuten tavalliset pikaviestit.

Osoitekirjan tallentamiseksi teimme KVS:n - Key-Value Storage - tämän toisen tyyppisen tapahtuman, jossa asset se ei ole NaCl-box, joka on salattu, mutta NaCl-salaisuuslaatikko. Näin messenger tallentaa muita tietoja.

Tiedostojen/kuvien siirrot ja ryhmäkeskustelut vaativat edelleen paljon työtä. Tietysti kömmähdys-ja-köyhä-muodossa tämä voidaan "vääntää" nopeasti, mutta haluamme säilyttää saman tason yksityisyyden.

Kyllä, työtä on vielä tehtävänä - ihannetapauksessa todellinen yksityisyys edellyttää, että käyttäjät eivät muodosta yhteyttä julkisen verkon solmuihin, vaan nostavat omiaan. Minkä prosenttiosuuden käyttäjistä luulet tekevän näin? Aivan oikein, 0. Pystyimme ratkaisemaan tämän ongelman osittain Messengerin Tor-versiolla.

Olemme osoittaneet, että sanansaattaja lohkoketjussa voi olla olemassa. Aiemmin yritys oli vain yksi vuonna 2012 - bittiviesti, joka epäonnistui pitkien viestien toimitusaikojen, suorittimen kuormituksen ja mobiilisovellusten puutteen vuoksi.

Ja skeptisyys johtuu siitä, että lohkoketjun sanansaattajat ovat aikaansa edellä - ihmiset eivät ole valmiita ottamaan vastuuta tilistään, henkilötietojen omistaminen ei ole vielä trendi, eikä tekniikka salli suuria nopeuksia lohkoketjussa. Lisää teknisiä analogeja projektistamme ilmestyy seuraavaksi. Tulet näkemään.

Lähde: will.com

Lisää kommentti