Kā blokķēdē darbojas decentralizēts kurjers?

2017. gada sākumā mēs sākām izveidot kurjeru blokķēdē [vārds un saite ir profilā], apspriežot priekÅ”rocÄ«bas salÄ«dzinājumā ar klasiskajiem P2P kurjeriem.

Nokārtots 2.5 gadā, un mēs varējām apstiprināt savu koncepciju: Messenger lietojumprogrammas tagad ir pieejamas operētājsistēmām iOS, Web PWA, Windows, GNU/Linux, Mac OS un Android.

Šodien mēs jums pastāstīsim, kā darbojas blokķēdes kurjers un kā klienta lietojumprogrammas var strādāt ar tā API.
Kā blokķēdē darbojas decentralizēts kurjers?

Mēs vēlējāmies, lai blokķēde atrisinātu klasisko P2P kurjeru droŔības un privātuma problēmas:

  • Viens klikŔķis, lai izveidotu kontu ā€“ nav tālruņu vai e-pasta, nav piekļuves adreÅ”u grāmatām vai Ä£eogrāfiskajām atraÅ”anās vietām.
  • Sarunu biedri nekad nenodibina tieÅ”us savienojumus, visa saziņa notiek caur sadalÄ«tu mezglu sistēmu. Lietotāju IP adreses nav pieejamas viena otrai.
  • Visi ziņojumi ir Å”ifrēti no end-to-end curve25519xsalsa20poly1305. Å Ä·iet, ka tas nevienu nepārsteigs, taču mÅ«su pirmkods ir atvērts.
  • MITM uzbrukums ir izslēgts - katrs ziņojums ir transakcija, un to paraksta Ed25519 EdDSA.
  • Ziņojums nonāk savā blokā. Konsekvence un timestamp JÅ«s nevarat labot blokus un lÄ«dz ar to arÄ« ziņojumu secÄ«bu.
  • ā€œEs to neteicuā€ nedarbosies ar ziņojumiem blokķēdē.
  • Nav centrālās struktÅ«ras, kas pārbaudÄ«tu ziņojuma ā€œautentitātiā€. To veic sadalÄ«ta mezglu sistēma, kuras pamatā ir vienprātÄ«ba, un tā pieder lietotājiem.
  • CenzÅ«ras neiespējamÄ«ba - kontus nevar bloķēt un ziņas nevar dzēst.
  • Blockchain 2FA ir alternatÄ«va elles 2FA, izmantojot SMS, sabojāja daudz veselÄ«bas.
  • Iespēja jebkurā laikā iegÅ«t visas savas sarunas no jebkuras ierÄ«ces nozÄ«mē, ka jums vispār nav jāuzglabā lokāli sarunas.
  • Ziņojuma piegādes apstiprinājums. Nevis lietotāja ierÄ«cei, bet tÄ«klam. BÅ«tÄ«bā tas ir apstiprinājums par adresāta spēju lasÄ«t jÅ«su ziņojumu. Å Ä« ir noderÄ«ga funkcija kritisku paziņojumu sÅ«tÄ«Å”anai.

Blockchain priekÅ”rocÄ«bas ietver arÄ« cieÅ”u integrāciju ar kriptovalÅ«tām Ethereum, Dogecoin, Lisk, Dash, Bitcoin (Ŕī joprojām tiek veikta) un iespēja nosÅ«tÄ«t marÄ·ierus tērzÄ“Å”anā. Mēs pat izveidojām iebÅ«vētu kriptonauda apmainÄ«tāju.

Un tad - kā tas viss darbojas.

Ziņojums ir darījums

Ikviens jau ir pieradis, ka darÄ«jumi blokķēdē pārsÅ«ta žetonus (monētas) no viena lietotāja pie cita. Tāpat kā Bitcoin. Mēs izveidojām Ä«paÅ”u darÄ«jumu veidu ziņojumu pārsÅ«tÄ«Å”anai.

Lai nosūtītu ziņojumu blokķēdes Messenger, jums jāveic vairākas darbības:

  1. Šifrēt ziņojuma tekstu
  2. Ievietojiet Å”ifrētu tekstu darÄ«jumā
  3. Parakstiet darījumu
  4. Nosūtiet darījumu uz jebkuru tīkla mezglu
  5. SadalÄ«ta mezglu sistēma nosaka ziņojuma ā€œautentitātiā€.
  6. Ja viss ir kārtībā, darījums ar ziņojumu tiek iekļauts nākamajā blokā
  7. Adresāts izgÅ«st ziņojuma transakciju un atÅ”ifrē

1.ā€“3. un 7. darbÄ«ba tiek veikta lokāli klientam, bet 5.ā€“6. darbÄ«ba tiek veikta saimniekiem.

Ziņojumu Å”ifrÄ“Å”ana

Ziņojums tiek Å”ifrēts ar sÅ«tÄ«tāja privāto atslēgu un adresāta publisko atslēgu. Mēs ņemsim publisko atslēgu no tÄ«kla, taču Å”im nolÅ«kam ir jābÅ«t inicializētam saņēmēja kontam, tas ir, jābÅ«t vismaz vienam darÄ«jumam. Varat izmantot REST pieprasÄ«jumu GET /api/accounts/getPublicKey?address={ADAMANT address}, un, ielādējot čatus, sarunu biedru publiskās atslēgas jau bÅ«s pieejamas.

Kā blokķēdē darbojas decentralizēts kurjers?

Kurjers Å”ifrē ziņojumus, izmantojot algoritmu curve25519xsalsa20poly1305 (NaCl kaste). Tā kā kontā ir Ed25519 atslēgas, lai izveidotu lodziņu, atslēgas vispirms ir jākonvertē uz Curve25519 Diffie-Hellman.

Šeit ir piemērs 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)
  }
}

DarÄ«juma noformÄ“Å”ana ar ziņojumu

DarÄ«jumam ir Ŕāda vispārējā struktÅ«ra:

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

Ziņojuma darījumam vissvarīgākais ir asset - objektā jāievieto ziņojums chat ar struktūru:

  • message - saglabājiet Å”ifrēto ziņojumu
  • own_message - vienreiz
  • type ā€” ziņojuma veids

ArÄ« ziņojumi ir sadalÄ«ti pa veidiem. BÅ«tÄ«bā parametrs type stāsta, kā saprast message. JÅ«s varat nosÅ«tÄ«t tikai Ä«sziņu vai arÄ« varat nosÅ«tÄ«t objektu, kurā ir interesantas lietas - piemēram, Ŕādi messenger veic kriptovalÅ«tas pārskaitÄ«jumus čatos.

Rezultātā mēs izveidojam darījumu:

{
  "transaction": {
    "type": 8,
    "amount": 0,
    "senderId": "U12499126640447739963",
    "senderPublicKey": "e9cafb1e7b403c4cf247c94f73ee4cada367fcc130cb3888219a0ba0633230b6",
    "asset": {
      "chat": {
        "message": "cb682accceef92d7cddaaddb787d1184ab5428",
        "own_message": "e7d8f90ddf7d70efe359c3e4ecfb5ed3802297b248eacbd6",
        "type": 1
      }
    },
    "recipientId": "U15677078342684640219",
    "timestamp": 63228087,
    "signature": "тут Š±ŃƒŠ“ŠµŃ‚ ŠæŠ¾Š“ŠæŠøсь"
  }
}

Darījuma paraksts

Lai visi bÅ«tu pārliecināti par sÅ«tÄ«tāja un saņēmēja autentiskumu, nosÅ«tÄ«Å”anas laiku un ziņojuma saturu, darÄ«jums tiek parakstÄ«ts. Ciparparaksts ļauj pārbaudÄ«t darÄ«juma autentiskumu, izmantojot publisko atslēgu ā€“ privātā atslēga tam nav nepiecieÅ”ama.

Bet pats paraksts tiek veikts, izmantojot privāto atslēgu:

Kā blokķēdē darbojas decentralizēts kurjers?

Diagrammā parādÄ«ts, ka vispirms darÄ«jums tiek sajaukts ar SHA-256 un pēc tam to jāparaksta Ed25519 EdDSA un saņemt parakstu signature, un darÄ«juma ID ir daļa no SHA-256 jaucējkoda.

IevieÅ”anas piemērs:

1 ā€” Izveidojiet datu bloku, ieskaitot ziņojumu

/**
 * 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 ā€” skaitiet SHA-256 no datu bloka

/**
 * 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 ā€” Parakstiet darÄ«jumu

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

DarÄ«juma nosÅ«tÄ«Å”ana ar ziņojumu uz tÄ«kla mezglu

Tā kā tÄ«kls ir decentralizēts, derēs jebkurÅ” mezgls ar atvērtu API. POST pieprasÄ«juma veikÅ”ana galapunktam api/transactions:

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

Atbildot uz to, mēs saņemsim Ŕāda veida darÄ«juma ID

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

Darījuma apstiprināŔana

SadalÄ«ta mezglu sistēma, pamatojoties uz vienprātÄ«bu, nosaka transakcijas ziņojuma ā€œautentitātiā€. No kā un kam, kad, vai ziņa aizstāta ar citu un vai nosÅ«tÄ«Å”anas laiks norādÄ«ts pareizi. Tā ir ļoti svarÄ«ga blokķēdes priekÅ”rocÄ«ba ā€“ nav centrālās struktÅ«ras, kas bÅ«tu atbildÄ«ga par verifikāciju, un ziņojumu secÄ«bu un to saturu nevar viltot.

Pirmkārt, viens mezgls pārbauda precizitāti, un pēc tam nosūta citiem - ja vairākums saka, ka viss ir kārtībā, darījums tiks iekļauts nākamajā ķēdes blokā - tā ir vienprātība.

Kā blokķēdē darbojas decentralizēts kurjers?

Mezgla koda daļu, kas ir atbildÄ«ga par pārbaudēm, var apskatÄ«t vietnē GitHub - validator.js Šø verify.js. Jā, mezgls darbojas vietnē Node.js.

DarÄ«juma ar ziņojumu iekļauÅ”ana blokā

Ja tiek panākta vienprātība, darījums ar mūsu ziņojumu tiks iekļauts nākamajā blokā kopā ar citiem derīgajiem darījumiem.

Blokiem ir stingra secÄ«ba, un katrs nākamais bloks tiek veidots, pamatojoties uz iepriekŔējo bloku jaucējkodiem.

Kā blokķēdē darbojas decentralizēts kurjers?

Lieta tāda, ka arÄ« mÅ«su vēstÄ«jums ir iekļauts Å”ajā secÄ«bā un to nevar ā€œpārkārtotā€. Ja blokā ietilpst vairāki ziņojumi, to secÄ«bu noteiks timestamp ziņas.

Ziņu lasÄ«Å”ana

Messenger lietojumprogramma izgūst darījumus no blokķēdes, kas tiek nosūtīti adresātam. Šim nolūkam mēs izveidojām beigu punktu api/chatrooms.

Visi darÄ«jumi ir pieejami ikvienam ā€“ jÅ«s varat saņemt Å”ifrētus ziņojumus. Bet tikai adresāts var atÅ”ifrēt, izmantojot savu privāto atslēgu un sÅ«tÄ«tāja publisko atslēgu:

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

Un kas vēl?

Tā kā ziņojumi Ŕādā veidā tiek piegādāti apmēram 5 sekunžu laikā ā€” Å”ajā laikā parādās jauns tÄ«kla bloks, mēs nonācām pie klienta-mezgla un mezgla-mezgla ligzdas savienojuma. Kad mezgls saņem jaunu darÄ«jumu, tas pārbauda tā derÄ«gumu un pārsÅ«ta to citiem mezgliem. DarÄ«jums ir pieejams Messenger klientiem pat pirms vienprātÄ«bas un iekļauÅ”anas blokā. Tādā veidā mēs piegādāsim ziņas uzreiz, tāpat kā parastie tÅ«lÄ«tējie kurjeri.

Lai saglabātu adreÅ”u grāmatu, mēs izveidojām KVS - Key-Value Storage - tas ir vēl viens darÄ«juma veids, kurā asset tas nav NaCl-box, kas ir Å”ifrēts, bet NaCl slepenā kaste. Tādā veidā kurjers saglabā citus datus.

Failu/attēlu pārsÅ«tÄ«Å”ana un grupu tērzÄ“Å”ana joprojām prasa daudz darba. Protams, kļūdÄ«Å”anās formātā to var ātri ā€œieskrÅ«vētā€, taču mēs vēlamies saglabāt tādu paÅ”u privātuma lÄ«meni.

Jā, vēl ir jāstrādā ā€“ ideālā gadÄ«jumā Ä«sts privātums paredz, ka lietotāji nevis pieslēgsies publiskajiem tÄ«kla mezgliem, bet gan pacels savus. Kā jÅ«s domājat, cik procentu lietotāju tā rÄ«kojas? TieÅ”i tā, 0. Mēs varējām daļēji atrisināt Å”o problēmu ar Messenger Tor versiju.

Mēs esam pierādÄ«juÅ”i, ka sÅ«tnis blokķēdē var pastāvēt. IepriekÅ” bija tikai viens mēģinājums 2012. bitziņa, kas neizdevās garo ziņojumu piegādes laiku, CPU slodzes un mobilo lietojumprogrammu trÅ«kuma dēļ.

Un skepse ir saistÄ«ta ar to, ka sÅ«tņi blokķēdē ir priekŔā savam laikam ā€“ cilvēki nav gatavi uzņemties atbildÄ«bu par savu kontu, personÄ«gās informācijas iegÅ«Å”ana vēl nav tendence, un tehnoloÄ£ijas nepieļauj lielu ātrumu blokķēdē. Tālāk parādÄ«sies vairāk mÅ«su projekta tehnoloÄ£isko analogu. JÅ«s redzēsiet.

Avots: www.habr.com

Pievieno komentāru