Wie funktioniert ein dezentraler Messenger auf der Blockchain?

Anfang 2017 haben wir damit begonnen, einen Messenger auf der Blockchain zu erstellen [Name und Link finden Sie im Profil], indem wir die Vorteile gegenüber klassischen P2P-Messengern diskutiert haben.

Bestanden 2.5 Jahr, und wir konnten unser Konzept bestätigen: Messenger-Anwendungen sind jetzt für iOS, Web PWA, Windows, GNU/Linux, Mac OS und Android verfügbar.

Heute erklären wir Ihnen, wie der Blockchain-Messenger funktioniert und wie Client-Anwendungen mit seiner API arbeiten können.
Wie funktioniert ein dezentraler Messenger auf der Blockchain?

Wir wollten, dass die Blockchain die Sicherheits- und Datenschutzprobleme klassischer P2P-Messenger löst:

  • Ein Klick genügt, um ein Konto zu erstellen – keine Telefone oder E-Mails, kein Zugriff auf Adressbücher oder Geostandorte.
  • Die Gesprächspartner stellen niemals direkte Verbindungen her, die gesamte Kommunikation erfolgt über ein verteiltes Knotensystem. Die IP-Adressen der Benutzer sind füreinander nicht zugänglich.
  • Alle Nachrichten werden End-to-End-curve25519xsalsa20poly1305 verschlüsselt. Es scheint, dass dies niemanden überraschen wird, aber unser Quellcode ist offen.
  • MITM-Angriff ist ausgeschlossen – jede Nachricht ist eine Transaktion und wird von Ed25519 EdDSA signiert.
  • Die Nachricht landet in einem eigenen Block. Konsistenz und timestamp Sie können die Blöcke und damit die Reihenfolge der Nachrichten nicht ändern.
  • „Das habe ich nicht gesagt“ funktioniert nicht mit Nachrichten auf der Blockchain.
  • Es gibt keine zentrale Struktur, die die „Authentizität“ einer Nachricht prüft. Dies erfolgt durch ein verteiltes System von Knoten, die auf Konsens basieren und im Besitz der Benutzer sind.
  • Unmöglichkeit der Zensur – Konten können nicht gesperrt und Nachrichten nicht gelöscht werden.
  • Blockchain 2FA ist eine Alternative zum höllischen 2FA per SMS. hat viel Gesundheit ruiniert.
  • Die Möglichkeit, alle Ihre Gespräche jederzeit von jedem Gerät abzurufen, bedeutet, dass Sie Gespräche überhaupt nicht lokal speichern müssen.
  • Bestätigung der Nachrichtenzustellung. Nicht zum Gerät des Benutzers, sondern zum Netzwerk. Im Wesentlichen ist dies eine Bestätigung dafür, dass der Empfänger Ihre Nachricht lesen kann. Dies ist eine nützliche Funktion zum Versenden kritischer Benachrichtigungen.

Zu den Vorteilen der Blockchain gehören auch die enge Integration mit den Kryptowährungen Ethereum, Dogecoin, Lisk, Dash, Bitcoin (diese befindet sich noch in der Entwicklung) und die Möglichkeit, Token in Chats zu versenden. Wir haben sogar einen integrierten Krypto-Austauscher entwickelt.

Und dann – wie das alles funktioniert.

Eine Nachricht ist eine Transaktion

Jeder ist bereits daran gewöhnt, dass Transaktionen in der Blockchain Token (Coins) von einem Benutzer zum anderen übertragen. Wie Bitcoin. Wir haben eine spezielle Art von Transaktion zur Übermittlung von Nachrichten erstellt.

Um eine Nachricht in einem Messenger auf der Blockchain zu senden, müssen Sie mehrere Schritte durchlaufen:

  1. Nachrichtentext verschlüsseln
  2. Fügen Sie Chiffretext in eine Transaktion ein
  3. Unterschreiben Sie die Transaktion
  4. Senden Sie eine Transaktion an einen beliebigen Netzwerkknoten
  5. Ein verteiltes Knotensystem bestimmt die „Authentizität“ einer Nachricht
  6. Wenn alles in Ordnung ist, wird die Transaktion mit der Nachricht in den nächsten Block aufgenommen
  7. Der Empfänger ruft die Nachrichtentransaktion ab und entschlüsselt sie

Die Schritte 1–3 und 7 werden lokal auf dem Client ausgeführt und die Schritte 5–6 werden auf den Hosts ausgeführt.

Nachrichtenverschlüsselung

Die Nachricht wird mit dem privaten Schlüssel des Absenders und dem öffentlichen Schlüssel des Empfängers verschlüsselt. Wir werden den öffentlichen Schlüssel aus dem Netzwerk entnehmen, aber dafür muss das Konto des Empfängers initialisiert sein, also mindestens eine Transaktion haben. Sie können eine REST-Anfrage verwenden GET /api/accounts/getPublicKey?address={ADAMANT address}, und beim Laden von Chats sind die öffentlichen Schlüssel der Gesprächspartner bereits verfügbar.

Wie funktioniert ein dezentraler Messenger auf der Blockchain?

Der Messenger verschlüsselt Nachrichten mit dem Curve25519xsalsa20poly1305-Algorithmus (NaCl-Box). Da das Konto Ed25519-Schlüssel enthält, müssen die Schlüssel zunächst in Curve25519 Diffie-Hellman konvertiert werden, um eine Box zu bilden.

Hier ist ein Beispiel 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)
  }
}

Eine Transaktion mit einer Nachricht bilden

Die Transaktion hat die folgende allgemeine Struktur:

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

Für eine Nachrichtentransaktion ist das Wichtigste asset - Sie müssen eine Nachricht in das Objekt einfügen chat mit Struktur:

  • message - Speichern Sie die verschlüsselte Nachricht
  • own_message -nonce
  • type - Nachrichtentyp

Nachrichten werden ebenfalls in Typen unterteilt. Im Wesentlichen der Parameter type sagt dir, wie du es verstehen kannst message. Sie können nur eine SMS senden oder ein Objekt mit interessanten Dingen darin senden – so führt der Messenger beispielsweise Kryptowährungsübertragungen in Chats durch.

Als Ergebnis erstellen wir eine Transaktion:

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

Transaktionssignatur

Um sicherzustellen, dass jeder von der Authentizität des Absenders und Empfängers, dem Zeitpunkt des Versands und dem Inhalt der Nachricht überzeugt ist, wird die Transaktion signiert. Mit einer digitalen Signatur können Sie die Authentizität einer Transaktion mithilfe eines öffentlichen Schlüssels überprüfen – ein privater Schlüssel ist hierfür nicht erforderlich.

Die Signatur selbst erfolgt jedoch mit dem privaten Schlüssel:

Wie funktioniert ein dezentraler Messenger auf der Blockchain?

Das Diagramm zeigt, dass wir die Transaktion zunächst mit SHA-256 hashen und dann signieren Ed25519 EdDSA und eine Unterschrift erhalten signature, und die Transaktions-ID ist Teil des SHA-256-Hashs.

Beispielimplementierung:

1 – Bilden Sie einen Datenblock, einschließlich einer Nachricht

/**
 * 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 – Zählen Sie SHA-256 aus dem Datenblock

/**
 * 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 – Unterzeichnen Sie die Transaktion

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

Senden einer Transaktion mit einer Nachricht an einen Netzwerkknoten

Da das Netzwerk dezentralisiert ist, reicht jeder Knoten mit einer offenen API aus. Senden einer POST-Anfrage an den Endpunkt api/transactions:

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

Als Antwort erhalten wir eine Transaktions-ID des Typs

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

Transaktionsvalidierung

Ein verteiltes, auf Konsens basierendes Knotensystem bestimmt die „Authentizität“ der Transaktionsnachricht. Von wem und an wen, wann, ob die Nachricht durch eine andere ersetzt wurde und ob der Zeitpunkt des Versands korrekt angegeben wurde. Dies ist ein sehr wichtiger Vorteil der Blockchain – es gibt keine zentrale Struktur, die für die Verifizierung verantwortlich ist, und die Reihenfolge der Nachrichten und deren Inhalt können nicht gefälscht werden.

Zuerst prüft ein Knoten die Richtigkeit und sendet sie dann an andere. Wenn die Mehrheit sagt, dass alles in Ordnung ist, wird die Transaktion in den nächsten Block der Kette aufgenommen – das ist Konsens.

Wie funktioniert ein dezentraler Messenger auf der Blockchain?

Der Teil des Node-Codes, der für die Prüfungen verantwortlich ist, kann auf GitHub eingesehen werden - validator.js и überprüfen.js. Ja, der Knoten läuft auf Node.js.

Einbinden einer Transaktion mit einer Nachricht in einen Block

Wenn ein Konsens erzielt wird, wird die Transaktion mit unserer Nachricht zusammen mit anderen gültigen Transaktionen in den nächsten Block aufgenommen.

Blöcke haben eine strenge Reihenfolge und jeder nachfolgende Block wird basierend auf den Hashes vorheriger Blöcke gebildet.

Wie funktioniert ein dezentraler Messenger auf der Blockchain?

Der Punkt ist, dass unsere Botschaft auch in dieser Reihenfolge enthalten ist und nicht „umgeordnet“ werden kann. Fallen mehrere Nachrichten in einen Block, wird deren Reihenfolge bestimmt timestamp Nachrichten.

Nachrichten lesen

Die Messenger-Anwendung ruft Transaktionen aus der Blockchain ab, die an den Empfänger gesendet werden. Dafür haben wir einen Endpunkt erstellt api/chatrooms.

Alle Transaktionen stehen jedem zur Verfügung – Sie können verschlüsselte Nachrichten empfangen. Aber nur der Empfänger kann mit seinem privaten Schlüssel und dem öffentlichen Schlüssel des Absenders entschlüsseln:

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

Und was noch?

Da Nachrichten auf diese Weise in etwa 5 Sekunden zugestellt werden – das ist die Zeit, in der ein neuer Netzwerkblock erscheint – haben wir uns eine Client-zu-Knoten- und Knoten-zu-Knoten-Socket-Verbindung ausgedacht. Wenn ein Knoten eine neue Transaktion empfängt, prüft er deren Gültigkeit und leitet sie an andere Knoten weiter. Die Transaktion ist für Messenger-Kunden verfügbar, noch bevor ein Konsens zustande kommt und in den Block aufgenommen wird. Auf diese Weise stellen wir Nachrichten sofort zu, genau wie bei normalen Instant Messengern.

Um das Adressbuch zu speichern, haben wir KVS (Key-Value Storage) erstellt. Dies ist eine andere Art von Transaktion, bei der asset Es ist nicht die NaCl-Box, die verschlüsselt ist, sondern NaCl-Geheimbox. Auf diese Weise speichert der Messenger weitere Daten.

Datei-/Bildübertragungen und Gruppenchats erfordern immer noch viel Arbeit. Natürlich kann das in einem Blunder-and-Blunder-Format schnell „vermasselt“ werden, aber wir wollen das gleiche Maß an Privatsphäre aufrechterhalten.

Ja, es gibt noch viel zu tun – im Idealfall geht echter Datenschutz davon aus, dass Benutzer keine Verbindung zu öffentlichen Netzwerkknoten herstellen, sondern ihre eigenen aufbauen. Was glauben Sie, wie viel Prozent der Nutzer tun dies? Genau, 0. Mit der Tor-Version des Messengers konnten wir dieses Problem teilweise lösen.

Wir haben bewiesen, dass es einen Messenger auf der Blockchain geben kann. Zuvor gab es 2012 nur einen Versuch - Bitnachricht, was aufgrund langer Nachrichtenübermittlungszeiten, CPU-Auslastung und fehlender mobiler Anwendungen fehlschlug.

Und die Skepsis ist auf die Tatsache zurückzuführen, dass Messenger auf der Blockchain ihrer Zeit voraus sind – die Menschen sind nicht bereit, die Verantwortung für ihr Konto zu übernehmen, der Besitz persönlicher Daten ist noch kein Trend und die Technologie erlaubt keine hohen Geschwindigkeiten auf der Blockchain. Als nächstes werden weitere technologische Analogien unseres Projekts erscheinen. Du wirst sehen.

Source: habr.com

Kommentar hinzufügen