Hvordan fungerer en decentral messenger på blockchain?

I begyndelsen af ​​2017 begyndte vi at oprette en messenger på blockchain [navn og link er i profilen] ved at diskutere fordelene i forhold til klassiske P2P messengers.

Væk 2.5 år, og vi var i stand til at bekræfte vores koncept: Messenger-applikationer er nu tilgængelige til iOS, Web PWA, Windows, GNU/Linux, Mac OS og Android.

I dag vil vi fortælle dig, hvordan blockchain-messengeren fungerer, og hvordan klientapplikationer kan arbejde med dens API.
Hvordan fungerer en decentral messenger på blockchain?

Vi ønskede, at blockchain skulle løse sikkerheds- og privatlivsproblemerne for klassiske P2P-budbringere:

  • Et klik for at oprette en konto - ingen telefoner eller e-mails, ingen adgang til adressebøger eller geolokationer.
  • Samtalepartnerne etablerer aldrig direkte forbindelser; al kommunikation foregår gennem et distribueret system af noder. Brugernes IP-adresser er ikke tilgængelige for hinanden.
  • Alle beskeder er krypteret End-to-End curve25519xsalsa20poly1305. Det ser ud til, at dette ikke vil overraske nogen, men vores kildekode er åben.
  • MITM-angreb er udelukket - hver meddelelse er en transaktion og er underskrevet af Ed25519 EdDSA.
  • Beskeden ender i sin egen blok. Konsistens og timestamp Du kan ikke rette op på blokkene, og derfor rækkefølgen af ​​beskederne.
  • "Jeg sagde det ikke" vil ikke fungere med beskeder på blockchain.
  • Der er ingen central struktur, der kontrollerer "ægtheden" af en besked. Dette gøres af et distribueret system af noder baseret på konsensus, og det ejes af brugerne.
  • Umulighed for censur - konti kan ikke blokeres og beskeder kan ikke slettes.
  • Blockchain 2FA er et alternativ til den helvedes 2FA via SMS, ødelagde en masse helbred.
  • Muligheden for at få alle dine samtaler fra enhver enhed når som helst betyder, at du slet ikke behøver at gemme samtaler lokalt.
  • Bekræftelse af levering af besked. Ikke til brugerens enhed, men til netværket. I bund og grund er dette en bekræftelse af modtagerens evne til at læse din besked. Dette er en nyttig funktion til at sende kritiske meddelelser.

Blockchain-fordele inkluderer også tæt integration med kryptovalutaerne Ethereum, Dogecoin, Lisk, Dash, Bitcoin (denne er stadig i gang) og muligheden for at sende tokens i chats. Vi lavede endda en indbygget kryptoudveksler.

Og så - hvordan det hele fungerer.

En besked er en transaktion

Alle er allerede vant til, at transaktioner i blockchain overfører tokens (mønter) fra en bruger til en anden. Ligesom Bitcoin. Vi oprettede en særlig type transaktion til transmission af meddelelser.

For at sende en besked i en messenger på blockchain, skal du gennemgå flere trin:

  1. Krypter beskedtekst
  2. Indsæt chiffertekst i en transaktion
  3. Underskriv transaktionen
  4. Send en transaktion til enhver netværksknude
  5. Et distribueret system af noder bestemmer "ægtheden" af en meddelelse
  6. Hvis alt er OK, er transaktionen med beskeden inkluderet i næste blok
  7. Modtageren henter beskedtransaktionen og dekrypterer

Trin 1-3 og 7 udføres lokalt på klienten, og trin 5-6 udføres på værterne.

Beskedkryptering

Beskeden er krypteret med afsenderens private nøgle og modtagerens offentlige nøgle. Vi tager den offentlige nøgle fra netværket, men for dette skal modtagerens konto initialiseres, det vil sige have mindst én transaktion. Du kan bruge en REST-anmodning GET /api/accounts/getPublicKey?address={ADAMANT address}, og når chats indlæses, vil samtalepartnernes offentlige nøgler allerede være tilgængelige.

Hvordan fungerer en decentral messenger på blockchain?

Messengeren krypterer meddelelser ved hjælp af curve25519xsalsa20poly1305 algoritmen (NaCl boks). Da kontoen indeholder Ed25519 nøgler, for at danne en boks, skal nøglerne først konverteres til Curve25519 Diffie-Hellman.

Her er et eksempel i 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)
  }
}

Dannelse af en transaktion med en besked

Transaktionen har følgende generelle 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": {}
}

For en beskedtransaktion er det vigtigste asset - du skal placere en besked i objektet chat med struktur:

  • message - gem den krypterede besked
  • own_message - intet
  • type — beskedtype

Beskeder er også opdelt i typer. I det væsentlige parameteren type fortæller dig, hvordan du forstår message. Du kan bare sende en tekst, eller du kan sende et objekt med interessante ting indeni - for eksempel er det sådan, messengeren laver kryptovaluta-overførsler i chats.

Som et resultat opretter vi en transaktion:

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

Transaktions signatur

For at sikre, at alle er sikre på ægtheden af ​​afsender og modtager, tidspunktet for afsendelse og indholdet af beskeden, underskrives transaktionen. En digital signatur giver dig mulighed for at verificere ægtheden af ​​en transaktion ved hjælp af en offentlig nøgle - en privat nøgle er ikke nødvendig for dette.

Men selve signaturen udføres ved hjælp af den private nøgle:

Hvordan fungerer en decentral messenger på blockchain?

Diagrammet viser, at vi først hash transaktionen med SHA-256 og derefter underskriver den Ed25519 EdDSA og få en underskrift signature, og transaktions-id'et er en del af SHA-256-hash.

Eksempel på implementering:

1 — Dann en datablok, inklusive en meddelelse

/**
 * 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 - Tæl SHA-256 fra datablokken

/**
 * 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 — Underskriv transaktionen

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

Sender en transaktion med en besked til en netværksknude

Da netværket er decentraliseret, vil enhver af noderne med en åben API klare sig. Lav en POST-anmodning til slutpunktet api/transactions:

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

Som svar vil vi modtage et transaktions-id af typen

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

Transaktionsvalidering

Et distribueret system af noder, baseret på konsensus, bestemmer "ægtheden" af transaktionsmeddelelsen. Fra hvem og til hvem, hvornår, om beskeden blev erstattet med en anden, og om tidspunktet for afsendelse var angivet korrekt. Dette er en meget vigtig fordel ved blockchain - der er ingen central struktur, der er ansvarlig for verifikation, og rækkefølgen af ​​beskeder og deres indhold kan ikke forfalskes.

Først tjekker en node nøjagtigheden og sender den derefter til andre - hvis flertallet siger, at alt er i orden, vil transaktionen blive inkluderet i den næste blok af kæden - dette er konsensus.

Hvordan fungerer en decentral messenger på blockchain?

Den del af nodekoden, der er ansvarlig for kontrol, kan ses på GitHub - validator.js и verify.js. Jep, noden kører på Node.js.

Herunder en transaktion med en besked i en blok

Hvis der opnås konsensus, vil transaktionen med vores besked blive inkluderet i den næste blok sammen med andre gyldige transaktioner.

Blokke har en streng rækkefølge, og hver efterfølgende blok dannes baseret på hasherne fra tidligere blokke.

Hvordan fungerer en decentral messenger på blockchain?

Pointen er, at vores budskab også er inkluderet i denne sekvens og ikke kan "omarrangeres". Hvis flere meddelelser falder i en blok, vil deres rækkefølge blive bestemt af timestamp Beskeder.

Læser beskeder

Messenger-applikationen henter transaktioner fra blockchainen, der sendes til modtageren. Til dette lavede vi et slutpunkt api/chatrooms.

Alle transaktioner er tilgængelige for alle - du kan modtage krypterede beskeder. Men kun modtageren kan dekryptere ved hjælp af sin private nøgle og afsenderens offentlige nøgle:

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

Og hvad ellers?

Da beskeder leveres på denne måde på cirka 5 sekunder - det er det tidspunkt, hvor en ny netværksblok dukker op - kom vi frem til en klient-til-node og node-til-node socket-forbindelse. Når en node modtager en ny transaktion, kontrollerer den dens gyldighed og videresender den til andre noder. Transaktionen er tilgængelig for messenger-klienter, selv før konsensus opstår og inklusion i blokken. På denne måde leverer vi beskeder med det samme, ligesom almindelige instant messengers.

For at gemme adressebogen lavede vi KVS - Key-Value Storage - dette er en anden type transaktion, hvor asset det er ikke NaCl-boks der er krypteret, men NaCl-hemmelighedsboks. Sådan gemmer messenger andre data.

Fil-/billedoverførsler og gruppechat kræver stadig meget arbejde. I blunder-and-blunder-formatet kan dette selvfølgelig hurtigt "skrues op", men vi ønsker at bevare det samme niveau af privatliv.

Ja, der er stadig arbejde at gøre - ideelt set forudsætter ægte privatliv, at brugerne ikke vil oprette forbindelse til offentlige netværksknuder, men vil rejse deres egne. Hvor mange procent af brugerne tror du gør dette? Det er rigtigt, 0. Vi var i stand til delvist at løse dette problem med Tor-versionen af ​​messenger.

Vi har bevist, at en messenger på blockchain kan eksistere. Tidligere var der kun et forsøg i 2012 - bitmeddelelse, som mislykkedes på grund af lange leveringstider for beskeder, CPU-belastning og mangel på mobilapplikationer.

Og skepsis skyldes, at budbringere på blockchain er forud for deres tid – folk er ikke klar til at tage ansvar for deres konto, at eje personlige oplysninger er endnu ikke en trend, og teknologien tillader ikke høje hastigheder på blockchain. Flere teknologiske analoger af vores projekt vil dukke op næste gang. Du vil se.

Kilde: www.habr.com

Tilføj en kommentar