Kuidas toimib plokiahelal pÔhinev detsentraliseeritud sÔnumivahetus?

2017. aasta alguses alustasime plokiahelal pÔhineva sÔnumivahetuse [nimi ja link on profiilis] loomist, keskendudes eelistele klassikaliste P2P sÔnumivahetajate ees.

On möödunud 2.5 aastat ja me oleme suutnud oma kontseptsiooni kinnitada: praegu on sÔnumivahetuse rakendused saadaval iOS, Web PWA, Windows, GNU/Linux, Mac OS ja Android jaoks.

TÀna rÀÀgime sellest, kuidas plokiahelal pÔhinev sÔnumivahetus töötab ja kuidas kliendirakendused selle API-ga töötavad.
Kuidas toimib plokiahelal pÔhinev detsentraliseeritud sÔnumivahetus?

Soovisime, et plokiahel lahendaks klassikaliste P2P sÔnumivahetajate turvalisuse ja privaatsuse probleemid:

  • Üks klikk konto loomiseks — ei mingeid telefone ja e-posti aadresse, pole juurdepÀÀsu aadressiraamatutele ja geolokatsioonidele.
  • Vestluspartnerid ei loo kunagi otseseid ĂŒhendusi, kogu suhtlemine toimub jaotatud sĂ”lmede sĂŒsteemi kaudu. Kasutajate IP-aadresse ei ole ĂŒksteisele nĂ€htavad.
  • KĂ”ik sĂ”numid krĂŒpteeritakse End-to-End curve25519xsalsa20poly1305. Tundub, et see ei ĂŒllata kedagi, kuid meie lĂ€htetekst on avatud.
  • MITM-rĂŒnnakud on vĂ€listatud — iga sĂ”num on tehing ja allkirjastatakse Ed25519 EdDSA-ga.
  • SĂ”num liigub oma blokki. Blokkide jĂ€rjestuse ja timestamp jĂ€rjekorraga ei saa midagi muuta, mis tĂ€hendab ka sĂ”numite jĂ€rjekorda.
  • "Ma ei öelnud seda" ei toimi plokiahela sĂ”numite puhul.
  • Keskset struktuuri, mis kontrollib sĂ”numi "usaldusvÀÀrsust", ei ole. Selle teeb jaotatud sĂ”lmede sĂŒsteem konsensuse pĂ”hjal, ja see kuulub kasutajatele.
  • Tsensuuri puudumine — kontode blokeerimine ja sĂ”numite kustutamine ei ole vĂ”imalik.
  • Plokiahela 2FA — alternatiiv hĂ€davajalikule SMS-pĂ”hisele 2FA-le, mis on rikkunud palju tervist.
  • VĂ”imalus saada kĂ”ik oma vestlused igalt seadmel igal hetkel — see tĂ€hendab, et ei ole vajadust vestlusi kohapeal salvestada.
  • SĂ”numite kohaletoimetamise kinnitamine. Mitte kasutaja seadmele, vaid vĂ”rku. PĂ”himĂ”tteliselt on see kinnitamine, et saaja vĂ”ib teie sĂ”numit lugeda. See on kasulik funktsioon kriitiliste teadetega saatmiseks.

Plokiahela eeliste hulka kuulub ka tihe integreerimine krĂŒptorahadega nagu Ethereum, Dogecoin, Lisk, Dash, Bitcoin (see on protsessis) ja vĂ”imalus saata tokeneid vestlustes. Oleme isegi loonud sisseehitatud krĂŒpto vahetusautomaat.

Edasi liikudes — kuidas see kĂ”ik töötab.

SÔnum on tehing

KĂ”ik on juba harjunud, et plokiahelas edastatakse tehingud ĂŒle kasutajate vahel (mĂŒndid). Nagu bitcoinil. Oleme loonud erilise tĂŒĂŒbi tehingute jaoks sĂ”numite edastamiseks.

Et saata sÔnum plokiahela messengeri, tuleb lÀbida mitu etappi:

  1. Ơifreerige sÔnumi tekst
  2. Asetage ĆĄifreeritud tekst tehingusse
  3. Allkirjastage tehing
  4. Saada tehing mis tahes vÔrgu sÔlmele
  5. Jaotatud sĂ”lmede sĂŒsteem mÀÀrab sĂ”numi "usaldusvÀÀrsuse"
  6. Kui kÔik on korras, lisatakse sÔnumitehing jÀrgmisse plokki
  7. Saaja ekstraktib sÔnumitehingu ja deƥifreerib selle

Etapid 1–3 ja 7 teostatakse kohapeal kliendis, etapid 5–6 vĂ”rgu sĂ”lmedes.

SÔnumi ƥifreerimine

SĂ”numid ĆĄifreeritakse saatja privaatvĂ”tmega ja saaja avaliku vĂ”tmega. Avaliku vĂ”tme saame vĂ”rgust, kuid selleks peab saaja konto olema initsialiseeritud, st tal peab olema vĂ€hemalt ĂŒks tehing. VĂ”ib kasutada REST-pĂ€ringut GET /api/accounts/getPublicKey?address={ADAMANT address}, ja vestluste laadimisel on kĂ”igi vestlejate avalikud vĂ”tmed juba olemas.

Kuidas toimib plokiahelal pÔhinev detsentraliseeritud sÔnumivahetus?

Messenger ƥifreerib sÔnumid algoritmiga curve25519xsalsa20poly1305 (NaCl Box). Kuna konto sisaldab Ed25519 vÔtmeid, tuleb box'i loomise eel need vÔtmed kÔigepealt muuta Curve25519 Diffie-Hellman'iks.

Siin on nÀide JavaScriptis:

/**
 * 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)
  }
}

SÔnumitehingu loomine

Tehingul on jĂ€rgmine ĂŒldine struktuur:

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

SĂ”numitehingu puhul on kĂ”ige olulisem vÀÀrtus asset — siia tuleb sĂ”num paigutada objektis chat sellise struktuuriga:

  • message — salvestame ĆĄifreeritud sĂ”numi
  • own_message — nonce
  • type — sĂ”numi tĂŒĂŒp

SĂ”numid jagunevad samuti tĂŒĂŒpideks. Sisuliselt nĂ€itab parameeter type kuidas mĂ”ista message. Saame saata lihtsalt teksti vĂ”i objekti huvitavate elementidega — nĂ€iteks tehingud krĂŒptovaluutas vestlustes.

KokkuvÔttes koostame tehingu:

{
  "transaction": {
    "type": 8,
    "amount": 0,
    "senderId": "U12499126640447739963",
    "senderPublicKey": "e9cafb1e7b403c4cf247c94f73ee4cada367fcc130cb3888219a0ba0633230b6",
    "asset": {
      "chat": {
        "message": "cb682accceef92d7cddaaddb787d1184ab5428",
        "own_message": "e7d8f90ddf7d70efe359c3e4ecfb5ed3802297b248eacbd6",
        "type": 1
      }
    },
    "recipientId": "U15677078342684640219",
    "timestamp": 63228087,
    "signature": "siin on allkiri"
  }
}

Tehingu allkiri

Kuna kĂ”ik peavad olema veendunud saatja ja saaja, saatmise aja ning sĂ”numi sisu usaldusvÀÀrsuses, allkirjastatakse tehing. Digitaalne allkiri vĂ”imaldab kontrollida tehingu autentsust avaliku vĂ”tme abil — selle jaoks ei ole vajalik privaatne vĂ”ti.

Ja siin on allkiri, mis luuakse privaatse vÔtme abil:

Kuidas toimib plokiahelal pÔhinev detsentraliseeritud sÔnumivahetus?

Skeemist nĂ€htub, et tehingu peame esmalt SHA-256 jĂ€rgi rĂŒhmitama ja seejĂ€rel allkirjastama. Ed25519 EdDSA ja saame allkirja allkiri, ja tehingu identifikaator on osa SHA-256 rĂ€sist.

NĂ€ite rakendamine:

1 — Loomine andmeplokist, sealhulgas sĂ”num

/**
 * 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 — SHA-256 arvutamine andmeplokist

/**
 * 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 — Tehingu allkirjastamine

adamant.transactionSign = function (trs, keypair) {
  var hash = this.getHash(trs)
  return this.sign(hash, keypair).toString('hex')
}

/**
 * Loob allkirja pÔhjal rÀsist ja vÔtme paarist.
 * @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'))
}

Tehingu saatmine sÔnumiga vÔrku sÔlme

Kuna vÔrk on detsentraliseeritud, sobib iga sÔlm, millel on avatud API. Teeme POST-pÀringu lÔpp-punktile api/transactions:

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

Vastuseks saame tehingu ID tĂŒĂŒpi

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

Tehingu usaldusvÀÀrsuse kontrollimine

Detsentraliseeritud sĂ”lmede sĂŒsteem konsensuse alusel mÀÀrab tehingu-sĂ”numi "usaldusvÀÀrsuse". Kes ja kellele, millal, kas sĂ”num ei ole asendatud teisega ning kas saatmise aeg on Ă”igesti mĂ€rgitud. See on vĂ€ga oluline plokiahela eelis — puudub kesksĂŒsteem, mis vastutaks kontrollimise eest, ja sĂ”numite jĂ€rjestus ning nende sisu ei ole vale.

Esmalt kontrollib ĂŒks sĂ”lm usaldusvÀÀrsust ja seejĂ€rel jagab teistega — kui enamus ĂŒtleb, et kĂ”ik on korras, siis tehakse tehing jĂ€rgmisse plokki — see ongi konsensus.

Kuidas toimib plokiahelal pÔhinev detsentraliseeritud sÔnumivahetus?

Osaliselt koodi sĂ”lmest, mis vastutab kontrollimise eest, saab vaadata GitHubis — validator.js ja verify.js. Aha, sĂ”lm töötab Node.js-il.

Lisame tehingu sÔnumiga plokki

Kui konsensus on saavutatud, siis meie sÔnum koos teiste usaldusvÀÀrsete tehingutega lÀheb jÀrgmisse plokki.

Plokid on rangelt jÀrjestatud ning iga jÀrgnev plokk genereeritakse eelneva ploki hash'i baasil.

Kuidas toimib plokiahelal pÔhinev detsentraliseeritud sÔnumivahetus?

Oluline on see, et meie sĂ”num on samuti selles jĂ€rjestuses ja seda ei saa „liigutada“. Kui plokki satub mitu sĂ”numit, siis nende jĂ€rjekord mÀÀratakse selon timestamp sĂ”numite.

SÔnumite lugemine

Messengingirakendus tÔmbab plokiahelast tehingud, mis on adresseeritud saajale. Selleks oleme loonud lÔpp-punkti api/chatrooms.

KĂ”ik tehingud on kĂ”igile kĂ€ttesaadavad — on vĂ”imalik saada krĂŒpteeritud sĂ”numeid. Ent nende dekrĂŒpteerida suudab vaid saaja oma privaatse vĂ”tmega ja saatja avaliku vĂ”tmega:

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

Ja mis veel?

Kuna sĂ”numid toimetatakse sellisel viisil umbes 5 sekundi jooksul — see on aeg, mil uus plokk vĂ”rku ilmub — oleme vĂ€lja töötanud socket-ĂŒhenduse klient-node ja node-node. Kui node saab uue tehingu, kontrollib ta selle kehtivust ning edastab teistele node'idele. Tehing on klientmessengeridele kĂ€tte saadav juba enne konsensuse saavutamist ja plokki lisamist. Nii toimetame sĂ”numid koheselt, nagu tavaliselt messengereides.

Aadressiraamatu hoidmiseks oleme teinud KVS — vĂ”tme-vÀÀrtuse salvestuse — see on veel ĂŒks tehingute tĂŒĂŒp, kus asset krĂŒpteeritakse mitte NaCl-box, vaid NaCl-secretbox. Nii salvestab messenger ka teisi andmeid.

Failide/piltide edastamine ja grupivestlused vajavad veel palju tööd. Muidugi, formaadis „kiirelt ja lihtsalt“ saab selle kiiresti „kokku kloppida“, aga me tahame sĂ€ilitada sama tasemega privaatsust.

Jah, on veel palju, millega tegeleda — ideaalis eeldab reaalne privaatsus, et kasutajad ei ĂŒhenduks avalike node'idega, vaid kĂ€ivitaksid oma. Kuidas teil tundub, kui palju protsente kasutajatest seda teeb? Õige, 0. Osaliselt oleme selle probleemi lahendanud Tor- versiooniga messengeri.

Me oleme tĂ”estanud, et messenger plokiahelal vĂ”ib eksisteerida. Varasemalt oli ainult ĂŒks katse 2012. aastal — bitmessage, mis kukkus lĂ€bi suurte sĂ”numite edastamise aegade, protsessori koormuse ja mobiilirakenduste puudumise tĂ”ttu.

Skeptitsism on seotud sellega, et plokiahelal pĂ”hinevad sĂ”numitoojad on ajast ees — inimesed ei ole valmis vĂ”tma vastutust oma konto eest, isikliku teabe omamine ei ole veel trendiks, ja tehnoloogia ei vĂ”imalda plokiahelal kĂ”rgeid kiireid. JĂ€rgmised tulevad vĂ€lja meie projekti tehniliselt arenenumad analoogid. Te nĂ€ete.

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster