Jak funguje decentralizovaný messenger na blockchainu?

Na začátku roku 2017 jsme začali vytvářet messenger na blockchainu [jméno a odkaz jsou v profilu] diskusí o výhodách oproti klasickým P2P messengerům.

Pryč 2.5 rok a mohli jsme potvrdit náš koncept: aplikace messenger jsou nyní dostupné pro iOS, Web PWA, Windows, GNU/Linux, Mac OS a Android.

Dnes vám prozradíme, jak funguje blockchain messenger a jak mohou klientské aplikace pracovat s jeho API.
Jak funguje decentralizovaný messenger na blockchainu?

Chtěli jsme, aby blockchain vyřešil problémy se zabezpečením a soukromím klasických P2P messengerů:

  • Jedním kliknutím vytvoříte účet – žádné telefony nebo e-maily, žádný přístup k adresářům nebo geolokacím.
  • Účastníci rozhovoru nikdy nenavazují přímé spojení, veškerá komunikace probíhá prostřednictvím distribuovaného systému uzlů. IP adresy uživatelů nejsou vzájemně přístupné.
  • Všechny zprávy jsou šifrovány End-to-End curve25519xsalsa20poly1305. Zdá se, že to nikoho nepřekvapí, ale náš zdrojový kód je otevřený.
  • MITM útok je vyloučen – každá zpráva je transakce a je podepsána Ed25519 EdDSA.
  • Zpráva skončí ve vlastním bloku. Důslednost a timestamp Nemůžete opravit bloky, a tedy pořadí zpráv.
  • „To jsem neřekl“ nebude fungovat se zprávami na blockchainu.
  • Neexistuje žádná centrální struktura, která by kontrolovala „pravost“ zprávy. To se provádí distribuovaným systémem uzlů založeným na konsensu a je ve vlastnictví uživatelů.
  • Nemožnost cenzury - účty nelze zablokovat a zprávy mazat.
  • Blockchain 2FA je alternativou k pekelnému 2FA prostřednictvím SMS, zničil hodně zdraví.
  • Možnost získat všechny své konverzace z libovolného zařízení a kdykoli znamená, že konverzace nemusíte vůbec ukládat lokálně.
  • Potvrzení o doručení zprávy. Ne do zařízení uživatele, ale do sítě. V podstatě se jedná o potvrzení schopnosti příjemce číst vaši zprávu. Toto je užitečná funkce pro zasílání kritických upozornění.

Mezi výhody blockchainu patří také úzká integrace s kryptoměnami Ethereum, Dogecoin, Lisk, Dash, Bitcoin (ten stále probíhá) a možnost posílat tokeny v chatech. Dokonce jsme vyrobili vestavěný kryptoměnič.

A pak – jak to všechno funguje.

Zpráva je transakce

Všichni jsou již zvyklí na to, že transakce v blockchainu přenášejí tokeny (coiny) od jednoho uživatele k druhému. Jako Bitcoin. Vytvořili jsme speciální typ transakce pro přenos zpráv.

Chcete-li odeslat zprávu v messengeru na blockchainu, musíte projít několika kroky:

  1. Šifrovat text zprávy
  2. Vložte šifrovaný text do transakce
  3. Podepište transakci
  4. Odešlete transakci do libovolného síťového uzlu
  5. Distribuovaný systém uzlů určuje „pravost“ zprávy
  6. Pokud je vše v pořádku, transakce se zprávou je zařazena do dalšího bloku
  7. Příjemce načte transakci zprávy a dešifruje ji

Kroky 1–3 a 7 se provádějí lokálně na klientovi a kroky 5–6 se provádějí na hostitelích.

Šifrování zpráv

Zpráva je zašifrována soukromým klíčem odesílatele a veřejným klíčem příjemce. Vezmeme veřejný klíč ze sítě, ale k tomu musí být účet příjemce inicializován, to znamená mít alespoň jednu transakci. Můžete použít požadavek REST GET /api/accounts/getPublicKey?address={ADAMANT address}a při načítání chatů již budou veřejné klíče účastníků rozhovoru k dispozici.

Jak funguje decentralizovaný messenger na blockchainu?

Messenger šifruje zprávy pomocí algoritmu curve25519xsalsa20poly1305 (NaCl box). Vzhledem k tomu, že účet obsahuje klíče Ed25519, pro vytvoření krabice musí být klíče nejprve převedeny na Curve25519 Diffie-Hellman.

Zde je příklad v JavaScriptu:

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

Vytvoření transakce se zprávou

Transakce má následující obecnou strukturu:

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

Pro transakci zpráv je nejdůležitější asset - do objektu musíte umístit zprávu chat se strukturou:

  • message - uložit zašifrovanou zprávu
  • own_message -nikdo
  • type — typ zprávy

Zprávy jsou také rozděleny do typů. V podstatě parametr type říká, jak rozumět message. Můžete poslat jen text, nebo můžete poslat objekt se zajímavými věcmi uvnitř - například takto messenger provádí převody kryptoměn v chatech.

V důsledku toho vytvoříme transakci:

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

Podpis transakce

Aby bylo zajištěno, že si každý může být jistý pravostí odesílatele a příjemce, časem odeslání a obsahem zprávy, je transakce podepsána. Digitální podpis umožňuje ověřit pravost transakce pomocí veřejného klíče – soukromý klíč k tomu není potřeba.

Samotný podpis se však provádí pomocí soukromého klíče:

Jak funguje decentralizovaný messenger na blockchainu?

Diagram ukazuje, že transakci nejprve hashujeme pomocí SHA-256 a poté ji podepisujeme Ed25519 EdDSA a získat podpis signaturea ID transakce je součástí hash SHA-256.

Příklad implementace:

1 — Vytvořte datový blok včetně zprávy

/**
 * 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 - Spočítejte SHA-256 z datového bloku

/**
 * 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 — Podepište transakci

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

Odeslání transakce se zprávou do síťového uzlu

Vzhledem k tomu, že síť je decentralizovaná, bude stačit kterýkoli z uzlů s otevřeným API. Vytvoření požadavku POST na koncový bod api/transactions:

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

Jako odpověď obdržíme ID transakce typu

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

Ověření transakce

Distribuovaný systém uzlů, založený na konsensu, určuje „pravost“ transakční zprávy. Od koho a komu, kdy, zda byla zpráva nahrazena jinou a zda byl správně uveden čas odeslání. To je velmi důležitá výhoda blockchainu – neexistuje žádná centrální struktura, která by byla zodpovědná za ověřování, a sled zpráv a jejich obsah nelze zfalšovat.

Nejprve jeden uzel zkontroluje přesnost a pak to pošle ostatním - pokud většina řekne, že je vše v pořádku, transakce bude zařazena do dalšího bloku řetězce - to je konsensus.

Jak funguje decentralizovaný messenger na blockchainu?

Část kódu uzlu, která je zodpovědná za kontroly, lze zobrazit na GitHubu - validator.js и ověřit.js. Ano, uzel běží na Node.js.

Včetně transakce se zprávou v bloku

Pokud bude dosaženo konsensu, transakce s naší zprávou bude zahrnuta do dalšího bloku spolu s ostatními platnými transakcemi.

Bloky mají přísnou sekvenci a každý následující blok je tvořen na základě hashů předchozích bloků.

Jak funguje decentralizovaný messenger na blockchainu?

Jde o to, že naše zpráva je také zahrnuta v této sekvenci a nelze ji „přeuspořádat“. Pokud do bloku spadá několik zpráv, jejich pořadí bude určeno podle timestamp zprávy.

Čtení zpráv

Aplikace messenger načítá transakce z blockchainu, které jsou odesílány příjemci. Za tímto účelem jsme udělali konečný bod api/chatrooms.

Všechny transakce jsou dostupné všem – můžete přijímat šifrované zprávy. Ale pouze příjemce může dešifrovat pomocí svého soukromého klíče a veřejného klíče odesílatele:

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

A co ještě?

Vzhledem k tomu, že zprávy jsou tímto způsobem doručeny přibližně za 5 sekund – to je doba, kdy se objeví nový síťový blok – přišli jsme se spojením soketu klient-uzel a uzel-uzel. Když uzel přijme novou transakci, zkontroluje její platnost a předá ji dalším uzlům. Transakce je k dispozici klientům messengeru ještě předtím, než dojde ke konsensu a zařazení do bloku. Tímto způsobem budeme doručovat zprávy okamžitě, stejně jako běžní instant messenger.

Pro uložení adresáře jsme vytvořili KVS - Key-Value Storage - to je další typ transakce, ve které asset není to NaCl-box, který je šifrovaný, ale NaCl-tajná schránka. Takto messenger ukládá další data.

Přenos souborů/obrázků a skupinové chaty stále vyžadují hodně práce. Samozřejmě, že ve formátu typu chyba a omyl to lze rychle „podělat“, ale chceme zachovat stejnou úroveň soukromí.

Ano, stále je na čem pracovat – v ideálním případě skutečné soukromí předpokládá, že se uživatelé nebudou připojovat k veřejným síťovým uzlům, ale budou si zvyšovat své vlastní. Jaké procento uživatelů to podle vás dělá? Správně, 0. Tento problém jsme dokázali částečně vyřešit pomocí Tor verze messengeru.

Dokázali jsme, že messenger na blockchainu může existovat. Dříve to byl pouze jeden pokus v roce 2012 - bitová zpráva, který selhal kvůli dlouhým dobám doručení zpráv, zatížení procesoru a nedostatku mobilních aplikací.

A skepticismus je dán tím, že poslové na blockchainu předběhli dobu – lidé nejsou připraveni převzít zodpovědnost za svůj účet, vlastnit osobní údaje zatím není trendem a technologie neumožňují vysoké rychlosti na blockchainu. Další technologické obdoby našeho projektu se objeví příště. Uvidíte.

Zdroj: www.habr.com

Přidat komentář