Како децентрализовани месинџер функционише на блокчејну?

Почетком 2017. почели смо да креирамо месинџер на блокчејну [име и линк су у профилу] тако што смо разговарали о предностима у односу на класичне П2П гласнике.

Отишла 2.5 године, и успели смо да потврдимо наш концепт: апликације за мессенгер су сада доступне за иОС, Веб ПВА, Виндовс, ГНУ/Линук, Мац ОС и Андроид.

Данас ћемо вам рећи како функционише блоцкцхаин мессенгер и како клијентске апликације могу да раде са његовим АПИ-јем.
Како децентрализовани месинџер функционише на блокчејну?

Желели смо да блоцкцхаин реши проблеме безбедности и приватности класичних П2П гласника:

  • Један клик за креирање налога - без телефона или е-поште, без приступа адресарима или геолокацијама.
  • Саговорници никада не успостављају директне везе, сва комуникација се одвија кроз дистрибуирани систем чворова. ИП адресе корисника нису доступне једни другима.
  • Све поруке су шифроване Енд-то-Енд цурве25519ксалса20поли1305. Чини се да ово никога неће изненадити, али наш изворни код је отворен.
  • МИТМ напад је искључен – свака порука је трансакција и потписана је од Ед25519 ЕдДСА.
  • Порука завршава у свом блоку. Доследност и timestamp Не можете поправити блокове, а самим тим и редослед порука.
  • „Нисам то рекао“ неће радити са порукама на блокчејну.
  • Не постоји централна структура која проверава „аутентичност“ поруке. То ради дистрибуирани систем чворова заснован на консензусу, а у власништву је корисника.
  • Немогућност цензуре - налози се не могу блокирати и поруке се не могу брисати.
  • Блоцкцхаин 2ФА је алтернатива пакленој 2ФА путем СМС-а, упропастио много здравља.
  • Могућност да добијете све своје разговоре са било ког уређаја у било ком тренутку значи да уопште не морате да чувате разговоре локално.
  • Потврда испоруке поруке. Не на уређај корисника, већ на мрежу. У суштини, ово је потврда способности примаоца да прочита вашу поруку. Ово је корисна функција за слање критичних обавештења.

Предности блокчејна такође укључују блиску интеграцију са криптовалутама Етхереум, Догецоин, Лиск, Дасх, Битцоин (ова је још увек у току) и могућност слања токена у четовима. Чак смо направили и уграђени крипто измењивач.

А онда – како то све функционише.

Порука је трансакција

Сви су већ навикли на чињеницу да трансакције у блокчејну преносе токене (кованице) са једног корисника на другог. Као Битцоин. Направили смо посебну врсту трансакције за преношење порука.

Да бисте послали поруку у месинџеру на блокчејну, потребно је да прођете кроз неколико корака:

  1. Шифрујте текст поруке
  2. Ставите шифровани текст у трансакцију
  3. Потпишите трансакцију
  4. Пошаљите трансакцију на било који мрежни чвор
  5. Дистрибуирани систем чворова одређује „аутентичност“ поруке
  6. Ако је све у реду, трансакција са поруком је укључена у следећи блок
  7. Прималац преузима трансакцију поруке и дешифрује

Кораци 1–3 и 7 се изводе локално на клијенту, а кораци 5–6 се изводе на хостовима.

Шифровање поруке

Порука је шифрована приватним кључем пошиљаоца и јавним кључем примаоца. Узећемо јавни кључ са мреже, али за то налог примаоца мора бити иницијализован, односно имати најмање једну трансакцију. Можете користити РЕСТ захтев GET /api/accounts/getPublicKey?address={ADAMANT address}, а при учитавању ћаскања већ ће бити доступни јавни кључеви саговорника.

Како децентрализовани месинџер функционише на блокчејну?

Месинџер шифрује поруке користећи цурве25519ксалса20поли1305 алгоритам (НаЦл Бок). Пошто налог садржи кључеве Ед25519, да би се формирала кутија, кључеви прво морају бити конвертовани у Цурве25519 Диффие-Хеллман.

Ево примера у ЈаваСцрипт-у:

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

Формирање трансакције са поруком

Трансакција има следећу општу структуру:

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

За трансакцију поруке најважније је asset - потребно је да поставите поруку у објекат chat са структуром:

  • message - сачувајте шифровану поруку
  • own_message - једнократно
  • type — тип поруке

Поруке су такође подељене на типове. У суштини, параметар type говори вам како да разумете message. Можете послати само текст, или можете послати објекат са занимљивим стварима унутра - на пример, овако месинџер врши трансфере криптовалута у четовима.

Као резултат, креирамо трансакцију:

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

Потпис трансакције

Да би сви били сигурни у аутентичност пошиљаоца и примаоца, време слања и садржај поруке, трансакција се потписује. Дигитални потпис вам омогућава да проверите аутентичност трансакције помоћу јавног кључа - приватни кључ није потребан за ово.

Али сам потпис се врши помоћу приватног кључа:

Како децентрализовани месинџер функционише на блокчејну?

Дијаграм показује да прво хеширамо трансакцију са СХА-256, а затим је потписујемо Ед25519 ЕдДСА и добити потпис signature, а ИД трансакције је део СХА-256 хеша.

Пример имплементације:

1 — Формирајте блок података, укључујући поруку

/**
 * 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 - Бројите СХА-256 из блока података

/**
 * 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 — Потпишите трансакцију

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

Слање трансакције са поруком мрежном чвору

Пошто је мрежа децентрализована, било који од чворова са отвореним АПИ-јем ће одговарати. Прављење ПОСТ захтева до крајње тачке api/transactions:

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

Као одговор добићемо ИД трансакције тог типа

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

Валидација трансакције

Дистрибуирани систем чворова, заснован на консензусу, одређује „аутентичност“ поруке о трансакцији. Од кога и коме, када, да ли је порука замењена другом и да ли је тачно назначено време слања. Ово је веома важна предност блокчејна – не постоји централна структура која је одговорна за верификацију, а редослед порука и њихов садржај се не могу лажирати.

Прво, један чвор проверава тачност, а затим га шаље другима - ако већина каже да је све у реду, трансакција ће бити укључена у следећи блок ланца - ово је консензус.

Како децентрализовани месинџер функционише на блокчејну?

Део кода чвора који је одговоран за провере може се видети на ГитХуб-у - валидатор.јс и верифи.јс. Да, чвор ради на Ноде.јс.

Укључујући трансакцију са поруком у блоку

Ако се постигне консензус, трансакција са нашом поруком биће укључена у следећи блок заједно са осталим важећим трансакцијама.

Блокови имају строги редослед, а сваки следећи блок се формира на основу хешева претходних блокова.

Како децентрализовани месинџер функционише на блокчејну?

Поента је да је и наша порука укључена у овај низ и да се не може „преуредити“. Ако неколико порука падне у блок, њихов редослед ће бити одређен по timestamp поруке.

Читање порука

Апликација мессенгер преузима трансакције из блокчејна које се шаљу примаоцу. За ово смо направили крајњу тачку api/chatrooms.

Све трансакције су доступне свима - можете примати шифроване поруке. Али само прималац може да дешифрује користећи свој приватни кључ и јавни кључ пошиљаоца:

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

И шта још?

Пошто се поруке испоручују на овај начин за око 5 секунди – ово је време када се појављује нови мрежни блок – дошли смо до везе клијент-чвор и чвор-чвор сокета. Када чвор прими нову трансакцију, проверава њену валидност и прослеђује је другим чворовима. Трансакција је доступна клијентима месинџера чак и пре него што дође до консензуса и укључивања у блок. На овај начин ћемо испоручити поруке тренутно, баш као и обични инстант мессенгери.

За складиштење адресара направили смо КВС - Кеи-Валуе Стораге - ово је још једна врста трансакције у којој asset није НаЦл-кутија та која је шифрована, већ НаЦл-тајна кутија. Овако месинџер чува остале податке.

Пренос датотека/слика и групна ћаскања и даље захтевају много посла. Наравно, у формату грешака и грешака ово се може брзо „зезнути“, али желимо да задржимо исти ниво приватности.

Да, има још посла – у идеалном случају, права приватност претпоставља да се корисници неће повезивати на јавне мрежне чворове, већ ће подићи своје. Шта мислите, колики проценат корисника то ради? Тако је, 0. Успели смо делимично да решимо овај проблем са Тор верзијом месинџера.

Доказали смо да гласник на блокчејну може постојати. Раније је био само један покушај 2012. битмессаге, који није успео због дугог времена испоруке порука, оптерећења ЦПУ-а и недостатка мобилних апликација.

А скептицизам је због чињенице да су гласници на блокчејну испред свог времена – људи нису спремни да преузму одговорност за свој налог, поседовање личних података још није тренд, а технологија не дозвољава велике брзине на блокчејну. Следеће ће се појавити више технолошких аналога нашег пројекта. Видећете.

Извор: ввв.хабр.цом

Додај коментар