Hoe wurket in desintralisearre messenger op 'e blockchain?

Oan it begjin fan 2017 binne wy ​​begûn mei it meitsjen fan in boadskipper op 'e blockchain [namme en keppeling binne yn it profyl] troch de foardielen te besprekken boppe klassike P2P-messengers.

Passearre 2.5 jier, en wy koenen ús konsept befêstigje: messenger-applikaasjes binne no beskikber foar iOS, Web PWA, Windows, GNU/Linux, Mac OS en Android.

Hjoed sille wy jo fertelle hoe't de blockchain-messenger wurket en hoe't kliïntapplikaasjes kinne wurkje mei syn API.
Hoe wurket in desintralisearre messenger op 'e blockchain?

Wy woenen dat de blockchain de feiligens- en privacyproblemen fan klassike P2P-messengers oplosse:

  • Ien klik om in akkount te meitsjen - gjin tillefoans of e-post, gjin tagong ta adresboeken of geolokaasjes.
  • De petearpartners meitsje nea direkte ferbiningen; alle kommunikaasje fynt plak fia in ferspraat systeem fan knopen. De IP-adressen fan brûkers binne net foar elkoar tagonklik.
  • Alle berjochten binne fersifere End-to-End curve25519xsalsa20poly1305. It liket derop dat dit gjinien sil ferrasse, mar ús boarnekoade is iepen.
  • MITM oanfal is útsletten - elk berjocht is in transaksje en wurdt tekene troch Ed25519 EdDSA.
  • It berjocht einiget yn in eigen blok. Konsistinsje en timestamp Jo kinne de blokken net reparearje, en dus de folchoarder fan 'e berjochten.
  • "Ik sei dat net" sil net wurkje mei berjochten op 'e blockchain.
  • D'r is gjin sintrale struktuer dy't kontrolearret op 'e "autentisiteit" fan in berjocht. Dit wurdt dien troch in ferspraat systeem fan knopen basearre op konsensus, en it is eigendom fan de brûkers.
  • Unmooglikheid fan sensuer - akkounts kinne net blokkearre wurde en berjochten kinne net wiske wurde.
  • Blockchain 2FA is in alternatyf foar de helske 2FA fia SMS, in protte sûnens ferneatige.
  • De mooglikheid om op elk momint al jo petearen fan elk apparaat te krijen betsjut dat jo hielendal gjin konversaasjes lokaal hoege op te slaan.
  • Befêstiging fan berjochtlevering. Net nei it apparaat fan de brûker, mar nei it netwurk. Yn essinsje is dit befêstiging fan it fermogen fan de ûntfanger om jo berjocht te lêzen. Dit is in nuttige funksje foar it ferstjoeren fan krityske notifikaasjes.

Blockchain-foardielen omfetsje ek nauwe yntegraasje mei de cryptocurrencies Ethereum, Dogecoin, Lisk, Dash, Bitcoin (dizze is noch oan 'e gong) en de mooglikheid om tokens te stjoeren yn petearen. Wy hawwe sels in ynboude krypto-útwikseler makke.

En dan - hoe't it allegear wurket.

In berjocht is in transaksje

Elkenien is al wend oan it feit dat transaksjes yn 'e blockchain tokens (munten) oerdrage fan de iene brûker nei de oare. Lykas Bitcoin. Wy hawwe in spesjaal soarte transaksje makke foar it ferstjoeren fan berjochten.

Om in berjocht te stjoeren yn in boadskipper op 'e blockchain, moatte jo ferskate stappen trochgean:

  1. Fersiferje berjochttekst
  2. Set sifertekst yn in transaksje
  3. Undertekenje de transaksje
  4. Stjoer in transaksje nei elke netwurkknooppunt
  5. In ferspraat systeem fan knopen bepaalt de "autentisiteit" fan in berjocht
  6. As alles goed is, is de transaksje mei it berjocht opnommen yn it folgjende blok
  7. De ûntfanger hellet de berjochttransaksje op en ûntsiferet

Stappen 1-3 en 7 wurde lokaal útfierd op 'e kliïnt, en stappen 5-6 wurde útfierd op' e hosts.

Berjocht fersifering

It berjocht is fersifere mei de privee kaai fan de stjoerder en de iepenbiere kaai fan de ûntfanger. Wy sille de iepenbiere kaai fan it netwurk nimme, mar hjirfoar moat it akkount fan de ûntfanger inisjalisearre wurde, dat is, op syn minst ien transaksje hawwe. Jo kinne in REST-fersyk brûke GET /api/accounts/getPublicKey?address={ADAMANT address}, en by it laden fan petearen sille de iepenbiere kaaien fan 'e petearen al beskikber wêze.

Hoe wurket in desintralisearre messenger op 'e blockchain?

De messenger fersiferet berjochten mei it curve25519xsalsa20poly1305 algoritme (NaCl Box). Sûnt it akkount befettet Ed25519 kaaien, te foarmjen in doaze, de kaaien moatte earst wurde omboud ta Curve25519 Diffie-Hellman.

Hjir is in foarbyld yn 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)
  }
}

It foarmjen fan in transaksje mei in berjocht

De transaksje hat de folgjende algemiene struktuer:

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

Foar in berjocht transaksje is it wichtichste ding asset - jo moatte in berjocht pleatse yn it objekt chat mei struktuer:

  • message - bewarje it fersifere berjocht
  • own_message - net
  • type - berjocht type

Berjochten wurde ek ferdield yn soarten. Yn essinsje, de parameter type fertelt jo hoe te begripen message. Jo kinne gewoan in tekst ferstjoere, of jo kinne in objekt stjoere mei ynteressante dingen binnen - dit is bygelyks hoe't de boadskipper cryptocurrency-oerdrachten makket yn petearen.

As gefolch meitsje wy in transaksje:

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

Transaksje hântekening

Om derfoar te soargjen dat elkenien betrouwen is yn 'e echtheid fan' e stjoerder en ûntfanger, de tiid fan ferstjoeren en de ynhâld fan it berjocht, wurdt de transaksje tekene. In digitale hantekening lit jo de autentisiteit fan in transaksje ferifiearje mei in iepenbiere kaai - in privee kaai is net nedich foar dit.

Mar de hantekening sels wurdt útfierd mei de privee kaai:

Hoe wurket in desintralisearre messenger op 'e blockchain?

It diagram lit sjen dat wy de transaksje earst hashje mei SHA-256 en dan tekenje Ed25519 EdDSA en krije in hantekening signature, en de transaksje-ID is diel fan 'e SHA-256-hash.

Foarbyld ymplemintaasje:

1 - Formearje in gegevensblok, ynklusyf in berjocht

/**
 * 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 út it gegevensblok

/**
 * 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 - Undertekenje de transaksje

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

It ferstjoeren fan in transaksje mei in berjocht nei in netwurkknooppunt

Sûnt it netwurk is desintralisearre, sil ien fan 'e knopen mei in iepen API dwaan. It meitsjen fan in POST-fersyk nei it einpunt api/transactions:

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

As antwurd krije wy in transaksje-ID fan it type

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

Transaksje Validaasje

In ferdield systeem fan knopen, basearre op konsensus, bepaalt de "autentisiteit" fan it transaksjeberjocht. Fan wa en oan wa, wannear, oft it berjocht ferfongen is troch in oar, en oft de tiid fan ferstjoeren goed oanjûn is. Dit is in heul wichtich foardiel fan 'e blockchain - d'r is gjin sintrale struktuer dy't ferantwurdlik is foar ferifikaasje, en de folchoarder fan berjochten en har ynhâld kinne net fake wurde.

Earst kontrolearret ien knooppunt de krektens, en stjoert it dan nei oaren - as de mearderheid seit dat alles yn oarder is, sil de transaksje opnommen wurde yn it folgjende blok fan 'e keten - dit is konsensus.

Hoe wurket in desintralisearre messenger op 'e blockchain?

It diel fan 'e knooppuntkoade dat ferantwurdlik is foar kontrôles kin wurde besjoen op GitHub - validator.js и ferifiearje.js. Yep, it knooppunt rint op Node.js.

Ynklusyf in transaksje mei in berjocht yn in blok

As konsensus wurdt berikt, wurdt de transaksje mei ús berjocht opnommen yn it folgjende blok tegearre mei oare jildige transaksjes.

Blokken hawwe in strange folchoarder, en elk folgjende blok wurdt foarme basearre op de hashes fan eardere blokken.

Hoe wurket in desintralisearre messenger op 'e blockchain?

It punt is dat ús berjocht ek is opnommen yn dizze folchoarder en kin net wurde "werarrangearre". As ferskate berjochten falle yn in blok, harren folchoarder wurdt bepaald troch timestamp berjochten.

Berjochten lêze

De messenger-applikaasje hellet transaksjes op út 'e blockchain dy't nei de ûntfanger stjoerd wurde. Dêrfoar hawwe wy in einpunt makke api/chatrooms.

Alle transaksjes binne beskikber foar elkenien - jo kinne fersifere berjochten ûntfange. Mar allinich de ûntfanger kin ûntsiferje mei syn privee kaai en de iepenbiere kaai fan de stjoerder:

**
 * 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 noch mear?

Sûnt berjochten wurde levere op dizze wize yn likernôch 5 sekonden - dit is de tiid dat in nij netwurk blok ferskynt - wy kamen mei in client-to-node en node-to-node socket ferbining. As in knooppunt in nije transaksje ûntfangt, kontrolearret it de jildigens en stjoert it troch nei oare knooppunten. De transaksje is beskikber foar messenger-kliïnten sels foardat konsensus optreedt en ynklúzje yn it blok. Op dizze manier sille wy berjochten direkt leverje, krekt as gewoane instant messengers.

Om it adresboek op te slaan, hawwe wy KVS makke - Key-Value Storage - dit is in oar type transaksje wêryn asset it is net NaCl-box dat is fersifere, mar NaCl-secretbox. Dit is hoe't de messenger oare gegevens opslaan.

Bestâns-/ôfbyldingsferfier en groepchats fereaskje noch in soad wurk. Fansels, yn it blunder-en-blunder-formaat kin dit fluch "opskroeven" wurde, mar wy wolle itselde nivo fan privacy behâlde.

Ja, d'r is noch wurk te dwaan - ideaal, echte privacy giet derfan út dat brûkers gjin ferbining sille meitsje mei iepenbiere netwurkknooppunten, mar har eigen ophelje. Hokker persintaazje brûkers tinke jo dat dit docht? Dat is rjocht, 0. Wy koene dit probleem foar in part oplosse mei de Tor-ferzje fan 'e boadskipper.

Wy hawwe bewiisd dat in boadskipper op 'e blockchain kin bestean. Earder wie der mar ien poging yn 2012 - bitberjocht, dy't mislearre troch lange leveringstiden fan berjochten, CPU-lading en gebrek oan mobile applikaasjes.

En skepsis is te tankjen oan it feit dat boaden op 'e blockchain har tiid foarút binne - minsken binne net ree om ferantwurdlikens te nimmen foar har akkount, it besit fan persoanlike ynformaasje is noch gjin trend, en technology lit gjin hege snelheden op' e blockchain tastean. Mear technologyske analogen fan ús projekt sille folgjende ferskine. Jo sille sjen.

Boarne: www.habr.com

Add a comment