Hvordan fungerer en decentraliseret messenger pÄ blockchain

I begyndelsen af 2017 begyndte vi at udvikle en messaging-app pÄ blockchainen [navn og link er i profilen], der diskuterede fordelene i forhold til klassiske P2P-messaging-apps.

Der er gÄet 2.5 Är, og vi har formÄet at bekrÊfte vores koncept: nu er messaging-apps tilgÊngelige for iOS, Web PWA, Windows, GNU/Linux, Mac OS og Android.

I dag vil vi fortÊlle, hvordan messaging-appen pÄ blockchainen fungerer, og hvordan klientapplikationerne interagerer med dens API.
Hvordan fungerer en decentraliseret messenger pÄ blockchain

Vi Þnskede, at blockchainen skulle lÞse spÞrgsmÄlene om sikkerhed og privatliv i klassiske P2P-messaging-apps:

  • Et klik for at oprette en konto — ingen telefoner eller e-mails, ingen adgang til adresselister og geolokationer.
  • Samtalepartnere etablerer aldrig direkte forbindelser, al kommunikation foregĂ„r gennem et distribueret system af noder. IP-adresserne for brugerne er ikke tilgĂŠngelige for hinanden.
  • Alle beskeder er krypteret End-to-End curve25519xsalsa20poly1305. Det er mĂ„ske ikke overraskende for mange, men vores kildekode er Ă„ben.
  • MITM-angreb er udelukket — hver besked er en transaktion og underskrives med Ed25519 EdDSA.
  • Beskeden havner i sin blok. Sekvensen af timestamp blokke kan ikke ĂŠndres, og fĂžlgelig kan rĂŠkkefĂžlgen af beskederne heller ikke ĂŠndres.
  • "Det sagde jeg ikke" vil ikke fungere med beskeder pĂ„ blockchainen.
  • Der er ingen central struktur, der verificerer "validiteten" af beskeden. Dette udfĂžres af et distribueret system af noder baseret pĂ„ konsensus, og den tilhĂžrer brugerne.
  • Muligheden for censur er umulig — konti kan ikke blokeres, og beskeder kan ikke slettes.
  • Blockchain 2FA — et alternativ til det problematiske 2FA via SMS, som har Ăždelagt en del helbred.
  • Muligheden for at fĂ„ alle dine dialoger fra enhver enhed pĂ„ ethvert tidspunkt — det betyder, at dialoger ikke behĂžver at opbevares lokalt overhovedet.
  • BekrĂŠftelse af leveringen af beskeder. Ikke til brugerens enhed, men til netvĂŠrket. I bund og grund er dette en bekrĂŠftelse af, at modtageren kan lĂŠse din besked. Det er en nyttig funktion til at sende kritiske meddelelser.

Af fordelene ved blockchainen er der ogsÄ tÊt integration med kryptovalutaer som Ethereum, Dogecoin, Lisk, Dash, Bitcoin (denne er stadig under udvikling) og muligheden for at sende tokens i chats. Vi har endda lavet en indbygget crypto-exchanger.

Og nu — hvordan fungerer det hele.

Beskeden er en transaktion

Alle er blevet vant til, at transaktioner pÄ blockchainen overfÞrer tokens (mÞnter) fra en bruger til en anden. Ligesom med Bitcoin. Vi har dog skabt en sÊrlig type transaktion til overfÞrsel af beskeder.

For at sende en besked i messaging-appen pÄ blockchainen skal du gennemgÄ flere trin:

  1. Kryptere tekstbeskeden
  2. IndsĂŠt den krypterede tekst i transaktionen
  3. Underskriv transaktionen
  4. Send transaktionen til enhver node i netvĂŠrket
  5. Det distribuerede system af noder bestemmer 'autenticiteten' af meddelelsen
  6. Hvis alt er i orden – tilfþjes transaktionen med meddelelsen til den néste blok
  7. Modtageren udtrĂŠkker transaktionen med meddelelsen og dekrypterer den

Trin 1–3 og 7 udfĂžres lokalt pĂ„ klienten, mens 5–6 udfĂžres pĂ„ netvĂŠrksnodene.

Kryptering af meddelelsen

Meddelelsen krypteres med afsenderens private nÞgle og modtagerens offentlige nÞgle. Den offentlige nÞgle hentes fra netvÊrket, men for dette skal modtagerens konto vÊre initialiseret, dvs. have mindst én transaktion. REST-anmodning kan bruges GET /api/accounts/getPublicKey?address={ADAMANT address}, og nÄr chattie indlÊses, vil modpartens offentlige nÞgler allerede vÊre tilgÊngelige.

Hvordan fungerer en decentraliseret messenger pÄ blockchain

Messaging-programmet krypterer meddelelser med algoritmen curve25519xsalsa20poly1305 (NaCl Box). Da kontoen indeholder Ed25519 nĂžgler, skal nĂžglerne konverteres til Curve25519 Diffie-Hellman for at dannes en box.

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 transaktionen med meddelelsen

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 meddelelses-transaktion er den vigtigste vérdi asset – den skal indeholde meddelelsen i et objekt chat med strukturen:

  • message – gem den krypterede meddelelse
  • own_message – nonce
  • type – meddelelsestype

Meddelelser er ogsĂ„ opdelt i typer. I grund og bund informerer parameteren type hvordan man skal forstĂ„ message. Man kan sende blot tekst, eller man kan sende et objekt med interessante indhold – for eksempel sender messaging-programmet kryptovaluta-overfĂžrsler i chats.

Resultatet er, at vi danner transaktionen:

{
  "transaction": {
    "type": 8,
    "amount": 0,
    "senderId": "U12499126640447739963",
    "senderPublicKey": "e9cafb1e7b403c4cf247c94f73ee4cada367fcc130cb3888219a0ba0633230b6",
    "asset": {
      "chat": {
        "message": "cb682accceef92d7cddaaddb787d1184ab5428",
        "own_message": "e7d8f90ddf7d70efe359c3e4ecfb5ed3802297b248eacbd6",
        "type": 1
      }
    },
    "recipientId": "U15677078342684640219",
    "timestamp": 63228087,
    "signature": "her vil vĂŠre en signatur"
  }
}

Transaktionens signatur

For everyone to be assured of the authenticity of the sender and recipient, the time of sending, and the content of the message, the transaction is signed. A digital signature allows verifying the transaction's authenticity using the public key — the private key is not needed for this.

The signature itself is generated using the private key:

Hvordan fungerer en decentraliseret messenger pÄ blockchain

The scheme shows that we first hash the transaction using SHA-256 and then sign it. Ed25519 EdDSA and we obtain the signature signatur, and the transaction ID is part of the SHA-256 hash.

Example implementation:

1 — Form a data block, including the message

/**
 * 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 — Compute the SHA-256 of the data block

/**
 * 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 — Sign the transaction

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

Sending the transaction with a message to a network node

Since the network is decentralized, any node with an open API will do. We make a POST request to the endpoint api/transactions:

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

In response we will receive the transaction ID of type

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

Verification of transaction authenticity

The distributed system of nodes based on consensus determines the "authenticity" of the transaction-message. From whom and to whom, when, whether the message has been replaced with another, and whether the correct sending time is specified. This is a very important advantage of blockchain — there is no central structure responsible for checks, and the sequence of messages and their contents cannot be forged.

First, one node checks the authenticity, and then it sends it to others — if the majority say everything is fine, the transaction will be included in the next block of the chain — this is the consensus.

Hvordan fungerer en decentraliseret messenger pÄ blockchain

Part of the node's code that is responsible for checks can be seen on GitHub — validator.js og verify.js. Ah, the node runs on Node.js.

Including the transaction with a message in the block

If consensus is reached, the transaction with our message will get into the next block alongside other authentic transactions.

Blocks have a strict sequence, and each subsequent block is formed based on the hashes of the previous blocks.

Hvordan fungerer en decentraliseret messenger pÄ blockchain

Essensen er, at vores besked ogsÄ er inkluderet i denne sekvens og ikke kan "omarrangeres". Hvis flere beskeder kommer ind i blokken, vil deres rÊkkefÞlge blive bestemt ud fra timestamp beskeder.

LĂŠsning af beskeder

Messenger-appen henter transaktioner fra blockchainen, som er sendt til modtageren. For dette har vi lavet en endpoint api/chatrooms.

Alle transaktioner er tilgĂŠngelige for enhver — man kan fĂ„ de krypterede beskeder. Men kun modtageren kan dekryptere dem med sin private nĂžgle og senderens 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) : ''
}

Hvad mere?

Da beskeder leveres pĂ„ denne mĂ„de omkring 5 sekunder — den tid det tager for en ny blok at fremkomme i netvĂŠrket — har vi opfundet socket-forbindelse mellem klient-node og node-node. NĂ„r en node modtager en ny transaktion, tjekker den dens gyldighed og videresender den til andre noder. Transaktionen er tilgĂŠngelig for messenger-klienter, inden konsensus opnĂ„s og den inkluderes i blokken. SĂ„dan vil vi levere beskeder Ăžjeblikkeligt, ligesom de gĂŠngse messengere.

For at gemme adressebogen har vi lavet KVS — Key-Value Storage — det er en anden type transaktioner, hvor asset der ikke krypteres en NaCl-box, men NaCl-secretbox. PĂ„ den mĂ„de gemmer messengeren ogsĂ„ andre data.

Fil/-billedoverfĂžrsel og gruppechats krĂŠver stadig meget arbejde. SelvfĂžlgelig kan man hurtigt "fikse" det i et klodset format, men vi Ăžnsker at bevare det samme niveau af privatliv.

Ja, der er stadig meget at arbejde pÄ - i det ideelle tilfÊlde forudsÊtter virkelig privatliv, at brugerne ikke opretter forbindelse til offentlige knude i netvÊrket, men i stedet opsÊtter deres egne. Hvad tÊnker du, hvor mange procent af brugerne gÞr det? Korrekt, 0. Delvist har vi lÞst dette spÞrgsmÄl med en Tor-version af messengeren.

Vi har bevist, at messengeren pĂ„ blockchainen kan eksistere. Der har tidligere kun vĂŠret et forsĂžg i 2012 — bitmessage, som mislykkedes pĂ„ grund af den lange leveringstid for beskeder, CPU-belastning og mangel pĂ„ mobile applikationer.

Og skepsis skyldes, at messengere pĂ„ blockchainen er forud for deres tid — folk er ikke klar til at tage ansvar for deres konto, ejerskab af personlig information er stadig ikke en trend, og teknologierne tillader ikke hĂžje hastigheder pĂ„ blockchainen. Snart vil der komme mere teknologiske alternativer til vores projekt. Bare vent og se.

Kilde: habr.com

KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere đŸ”„ KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster