Hoe werkt een gedecentraliseerde messenger op de blockchain?

Begin 2017 zijn we begonnen met het maken van een messenger op de blockchain [naam en link staan ​​in het profiel] door de voordelen ten opzichte van klassieke P2P-messengers te bespreken.

Weg 2.5 jaar, en we konden ons concept bevestigen: messenger-applicaties zijn nu beschikbaar voor iOS, Web PWA, Windows, GNU/Linux, Mac OS en Android.

Vandaag vertellen we u hoe de blockchain-messenger werkt en hoe clientapplicaties kunnen werken met de API.
Hoe werkt een gedecentraliseerde messenger op de blockchain?

We wilden dat de blockchain de beveiligings- en privacyproblemen van klassieke P2P-boodschappers zou oplossen:

  • Eén klik om een ​​account aan te maken - geen telefoons of e-mails, geen toegang tot adresboeken of geolocaties.
  • De gesprekspartners brengen nooit directe verbindingen tot stand; alle communicatie vindt plaats via een gedistribueerd systeem van knooppunten. De IP-adressen van gebruikers zijn niet voor elkaar toegankelijk.
  • Alle berichten zijn gecodeerd End-to-End curve25519xsalsa20poly1305. Het lijkt erop dat dit niemand zal verbazen, maar onze broncode is open.
  • MITM-aanval is uitgesloten: elk bericht is een transactie en is ondertekend door Ed25519 EdDSA.
  • Het bericht komt in een eigen blok terecht. Consistentie en timestamp Je kunt de blokken, en dus ook de volgorde van de berichten, niet repareren.
  • “Dat heb ik niet gezegd” zal niet werken met berichten op de blockchain.
  • Er is geen centrale structuur die de “authenticiteit” van een bericht controleert. Dit wordt gedaan door een gedistribueerd systeem van knooppunten, gebaseerd op consensus, en is eigendom van de gebruikers.
  • Onmogelijkheid van censuur - accounts kunnen niet worden geblokkeerd en berichten kunnen niet worden verwijderd.
  • Blockchain 2FA is een alternatief voor het helse 2FA via sms, heeft veel gezondheid verwoest.
  • De mogelijkheid om al uw gesprekken op elk gewenst moment vanaf elk apparaat te ontvangen, betekent dat u gesprekken helemaal niet lokaal hoeft op te slaan.
  • Bevestiging van bezorging van het bericht. Niet op het apparaat van de gebruiker, maar op het netwerk. In wezen is dit een bevestiging van het vermogen van de ontvanger om uw bericht te lezen. Dit is een handige functie voor het verzenden van kritische meldingen.

Voordelen van Blockchain omvatten ook nauwe integratie met de cryptocurrencies Ethereum, Dogecoin, Lisk, Dash, Bitcoin (deze is nog in ontwikkeling) en de mogelijkheid om tokens in chats te verzenden. We hebben zelfs een ingebouwde crypto-wisselaar gemaakt.

En dan - hoe het allemaal werkt.

Een bericht is een transactie

Iedereen is er al aan gewend dat transacties in de blockchain tokens (munten) van de ene gebruiker naar de andere overbrengen. Zoals Bitcoin. We hebben een speciaal type transactie gecreëerd voor het verzenden van berichten.

Om een ​​bericht in een messenger op de blockchain te versturen, moet je een aantal stappen doorlopen:

  1. Versleutel berichttekst
  2. Zet cijfertekst in een transactie
  3. Onderteken de transactie
  4. Stuur een transactie naar een willekeurig netwerkknooppunt
  5. Een gedistribueerd systeem van knooppunten bepaalt de ‘authenticiteit’ van een bericht
  6. Als alles in orde is, wordt de transactie met het bericht opgenomen in het volgende blok
  7. De ontvanger haalt de berichttransactie op en decodeert

Stappen 1–3 en 7 worden lokaal op de client uitgevoerd, en stappen 5–6 worden op de hosts uitgevoerd.

Versleuteling van berichten

Het bericht wordt gecodeerd met de privésleutel van de afzender en de publieke sleutel van de ontvanger. We nemen de openbare sleutel van het netwerk, maar hiervoor moet het account van de ontvanger worden geïnitialiseerd, dat wil zeggen dat er minimaal één transactie is. U kunt een REST-verzoek gebruiken GET /api/accounts/getPublicKey?address={ADAMANT address}, en bij het laden van chats zijn de openbare sleutels van de gesprekspartners al beschikbaar.

Hoe werkt een gedecentraliseerde messenger op de blockchain?

De messenger codeert berichten met behulp van het curve25519xsalsa20poly1305-algoritme (NaCl-doos). Omdat het account Ed25519-sleutels bevat, moeten de sleutels eerst worden geconverteerd naar Curve25519 Diffie-Hellman om een ​​box te vormen.

Hier is een 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)
  }
}

Een transactie vormen met een bericht

De transactie heeft de volgende algemene structuur:

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

Voor een berichttransactie is het allerbelangrijkste asset - je moet een bericht in het object plaatsen chat met structuur:

  • message - sla het gecodeerde bericht op
  • own_message - geen moment
  • type — berichttype

Berichten zijn ook onderverdeeld in typen. Kortom, de parameter type vertelt je hoe je het moet begrijpen message. Je kunt alleen een sms sturen, of je kunt een object sturen met interessante dingen erin. Dit is bijvoorbeeld hoe de messenger cryptocurrency-overdrachten uitvoert in chats.

Als gevolg hiervan creëren we een transactie:

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

Handtekening van de transactie

Om ervoor te zorgen dat iedereen vertrouwen heeft in de authenticiteit van de afzender en ontvanger, het tijdstip van verzending en de inhoud van het bericht, wordt de transactie ondertekend. Met een digitale handtekening kunt u de authenticiteit van een transactie verifiëren met behulp van een publieke sleutel; hiervoor is geen private sleutel nodig.

Maar de handtekening zelf wordt uitgevoerd met behulp van de privésleutel:

Hoe werkt een gedecentraliseerde messenger op de blockchain?

Het diagram laat zien dat we de transactie eerst met SHA-256 hashen en vervolgens ondertekenen Ed25519 EdDSA en een handtekening krijgen signatureen de transactie-ID maakt deel uit van de SHA-256-hash.

Voorbeeld implementatie:

1 — Vorm een ​​datablok, inclusief een bericht

/**
 * 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 uit het 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 — Onderteken de transactie

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

Het verzenden van een transactie met een bericht naar een netwerkknooppunt

Omdat het netwerk gedecentraliseerd is, zijn alle knooppunten met een open API geschikt. Een POST-verzoek indienen bij het eindpunt api/transactions:

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

Als reactie ontvangen wij een transactie-ID van het type

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

Transactievalidatie

Een gedistribueerd systeem van knooppunten, gebaseerd op consensus, bepaalt de ‘authenticiteit’ van het transactiebericht. Van wie en naar wie, wanneer, of het bericht is vervangen door een ander en of het tijdstip van verzending correct is aangegeven. Dit is een heel belangrijk voordeel van de blockchain: er is geen centrale structuur die verantwoordelijk is voor de verificatie, en de volgorde van berichten en hun inhoud kan niet worden vervalst.

Eerst controleert één knooppunt de nauwkeurigheid en stuurt het vervolgens naar anderen - als de meerderheid zegt dat alles in orde is, wordt de transactie opgenomen in het volgende blok van de keten - dit is consensus.

Hoe werkt een gedecentraliseerde messenger op de blockchain?

Het deel van de knooppuntcode dat verantwoordelijk is voor controles kan worden bekeken op GitHub - validator.js и verifieer.js. Ja, het knooppunt draait op Node.js.

Inclusief een transactie met een bericht in een blok

Als er consensus wordt bereikt, wordt de transactie met ons bericht samen met andere geldige transacties in het volgende blok opgenomen.

Blokken hebben een strikte volgorde en elk volgend blok wordt gevormd op basis van de hashes van voorgaande blokken.

Hoe werkt een gedecentraliseerde messenger op de blockchain?

Het punt is dat onze boodschap ook in deze reeks is opgenomen en niet kan worden ‘herschikt’. Als meerdere berichten in een blok vallen, wordt hun volgorde bepaald door timestamp berichten.

Berichten lezen

De messenger-applicatie haalt transacties op uit de blockchain die naar de ontvanger worden verzonden. Hiervoor hebben we een eindpunt gemaakt api/chatrooms.

Alle transacties zijn voor iedereen beschikbaar - u kunt gecodeerde berichten ontvangen. Maar alleen de ontvanger kan ontsleutelen met zijn privésleutel en de publieke sleutel van de afzender:

**
 * 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 meer?

Omdat berichten op deze manier in ongeveer 5 seconden worden afgeleverd - dit is het moment waarop een nieuw netwerkblok verschijnt - hebben we een client-naar-knooppunt- en knooppunt-naar-knooppunt-socketverbinding bedacht. Wanneer een knooppunt een nieuwe transactie ontvangt, controleert het de geldigheid ervan en stuurt deze door naar andere knooppunten. De transactie is beschikbaar voor messenger-clients, zelfs voordat er consensus ontstaat en in het blok wordt opgenomen. Op deze manier bezorgen we berichten direct, net als gewone instant messengers.

Om het adresboek op te slaan, hebben we KVS gemaakt - Key-Value Storage - dit is een ander type transactie waarin asset het is niet de NaCl-box die versleuteld is, maar NaCl-geheime box. Dit is hoe de messenger andere gegevens opslaat.

Bestands-/afbeeldingsoverdrachten en groepschats vergen nog steeds veel werk. Natuurlijk kan dit in het blunder-en-blunder-formaat snel ‘verpest’ worden, maar we willen hetzelfde niveau van privacy behouden.

Ja, er is nog werk aan de winkel - idealiter gaat echte privacy ervan uit dat gebruikers geen verbinding zullen maken met openbare netwerkknooppunten, maar hun eigen knooppunten zullen opzetten. Welk percentage van de gebruikers denkt u dat dit doet? Dat klopt, 0. We hebben dit probleem gedeeltelijk kunnen oplossen met de Tor-versie van de messenger.

We hebben bewezen dat er een messenger op de blockchain kan bestaan. Voorheen was er slechts één poging in 2012: bitbericht, wat mislukte vanwege lange bezorgtijden van berichten, CPU-belasting en gebrek aan mobiele applicaties.

En de scepsis is te wijten aan het feit dat boodschappers op de blockchain hun tijd vooruit zijn: mensen zijn niet bereid om de verantwoordelijkheid voor hun account te nemen, het bezit van persoonlijke informatie is nog geen trend en de technologie staat geen hoge snelheden op de blockchain toe. Meer technologische analogen van ons project zullen hierna verschijnen. Je zult het zien.

Bron: www.habr.com

Voeg een reactie