چگونه یک پیام رسان غیرمتمرکز روی بلاک چین کار می کند؟

در ابتدای سال 2017، با بحث در مورد مزایای پیام رسان های کلاسیک P2P، شروع به ایجاد یک پیام رسان در بلاک چین کردیم [نام و پیوند در نمایه موجود است].

رفته 2.5 سال، و ما توانستیم مفهوم خود را تأیید کنیم: برنامه های پیام رسان اکنون برای iOS، Web PWA، Windows، GNU/Linux، Mac OS و Android در دسترس هستند.

امروز به شما خواهیم گفت که پیام رسان بلاک چین چگونه کار می کند و چگونه برنامه های مشتری می توانند با API آن کار کنند.
چگونه یک پیام رسان غیرمتمرکز روی بلاک چین کار می کند؟

ما می‌خواستیم بلاک چین مسائل امنیتی و حریم خصوصی پیام‌رسان‌های کلاسیک P2P را حل کند:

  • یک کلیک برای ایجاد یک حساب - بدون تلفن یا ایمیل، بدون دسترسی به دفترچه آدرس یا موقعیت جغرافیایی.
  • طرفین هرگز ارتباط مستقیم برقرار نمی کنند، تمام ارتباطات از طریق یک سیستم توزیع شده از گره ها صورت می گیرد. آدرس های IP کاربران برای یکدیگر قابل دسترسی نیستند.
  • همه پیام‌ها رمزگذاری شده‌اند End-to-End curve25519xsalsa20poly1305. به نظر می رسد که این هیچ کس را شگفت زده نخواهد کرد، اما کد منبع ما باز است.
  • حمله MITM مستثنی است - هر پیام یک تراکنش است و توسط Ed25519 EdDSA امضا شده است.
  • پیام در بلوک خود به پایان می رسد. سازگاری و timestamp شما نمی توانید بلوک ها و در نتیجه ترتیب پیام ها را اصلاح کنید.
  • "من این را نگفتم" با پیام های موجود در بلاک چین کار نمی کند.
  • هیچ ساختار مرکزی وجود ندارد که "اصالت" یک پیام را بررسی کند. این کار توسط یک سیستم توزیع شده از گره ها بر اساس اجماع انجام می شود و متعلق به کاربران است.
  • عدم امکان سانسور - حساب ها را نمی توان مسدود کرد و پیام ها را نمی توان حذف کرد.
  • Blockchain 2FA جایگزینی برای جهنمی 2FA از طریق پیامک است. سلامتی زیادی را خراب کرد
  • توانایی دریافت تمام مکالمات خود از هر دستگاهی در هر زمان به این معنی است که به هیچ وجه نیازی به ذخیره مکالمات به صورت محلی ندارید.
  • تایید تحویل پیام نه به دستگاه کاربر، بلکه به شبکه. در اصل، این تاییدی است بر توانایی گیرنده برای خواندن پیام شما. این یک ویژگی مفید برای ارسال اعلان های مهم است.

مزایای بلاک چین همچنین شامل ادغام نزدیک با ارزهای دیجیتال اتریوم، دوج کوین، لیسک، دش، بیت کوین (این مورد هنوز در حال انجام است) و امکان ارسال توکن در چت است. ما حتی یک مبدل رمزنگاری داخلی ساختیم.

و سپس - چگونه همه کار می کند.

پیام یک معامله است

همه قبلاً به این واقعیت عادت کرده اند که تراکنش ها در بلاک چین توکن ها (کوین ها) را از یک کاربر به کاربر دیگر منتقل می کنند. مثل بیت کوین. ما نوع خاصی از تراکنش را برای انتقال پیام ایجاد کردیم.

برای ارسال پیام در یک پیام رسان در بلاک چین، باید چندین مرحله را طی کنید:

  1. متن پیام را رمزگذاری کنید
  2. متن رمز را در یک تراکنش قرار دهید
  3. معامله را امضا کنید
  4. یک تراکنش را به هر گره شبکه ارسال کنید
  5. یک سیستم توزیع شده از گره ها "اصالت" یک پیام را تعیین می کند
  6. اگر همه چیز درست باشد، تراکنش با پیام در بلوک بعدی گنجانده می شود
  7. گیرنده تراکنش پیام را بازیابی و رمزگشایی می کند

مراحل 1-3 و 7 به صورت محلی بر روی مشتری و مراحل 5-6 بر روی هاست انجام می شود.

رمزگذاری پیام

پیام با کلید خصوصی فرستنده و کلید عمومی گیرنده رمزگذاری می شود. ما کلید عمومی را از شبکه می گیریم، اما برای این کار، حساب گیرنده باید مقداردهی اولیه شود، یعنی حداقل یک تراکنش داشته باشد. می توانید از درخواست REST استفاده کنید GET /api/accounts/getPublicKey?address={ADAMANT address}، و هنگام بارگیری چت ها، کلیدهای عمومی مخاطبین از قبل در دسترس خواهند بود.

چگونه یک پیام رسان غیرمتمرکز روی بلاک چین کار می کند؟

پیام رسان پیام ها را با استفاده از الگوریتم curve25519xsalsa20poly1305 رمزگذاری می کند (جعبه NaCl). از آنجایی که حساب شامل کلیدهای Ed25519 است، برای تشکیل یک جعبه، ابتدا باید کلیدها به Curve25519 Diffie-Hellman تبدیل شوند.

در اینجا یک مثال در جاوا اسکریپت آمده است:

/**
 * 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": "тут будет подпись"
  }
}

امضای معامله

برای اطمینان از اینکه همه از صحت فرستنده و گیرنده، زمان ارسال و محتوای پیام اطمینان دارند، معامله امضا می شود. امضای دیجیتال به شما امکان می دهد صحت تراکنش را با استفاده از کلید عمومی تأیید کنید - برای این کار به کلید خصوصی نیاز نیست.

اما خود امضا با استفاده از کلید خصوصی انجام می شود:

چگونه یک پیام رسان غیرمتمرکز روی بلاک چین کار می کند؟

نمودار نشان می دهد که ابتدا تراکنش را با SHA-256 هش می کنیم و سپس آن را امضا می کنیم Ed25519 EdDSA و امضا بگیر signatureو شناسه تراکنش بخشی از هش SHA-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 - SHA-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 باز هستند این کار را انجام می دهند. ایجاد یک درخواست POST به نقطه پایانی api/transactions:

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

در پاسخ، یک شناسه تراکنش از نوع دریافت خواهیم کرد

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

اعتبار سنجی تراکنش

یک سیستم توزیع شده از گره ها، بر اساس اجماع، "اصالت" پیام تراکنش را تعیین می کند. از چه کسی و به چه کسی، چه زمانی، آیا پیام با پیام دیگری جایگزین شده است و آیا زمان ارسال به درستی مشخص شده است. این یک مزیت بسیار مهم بلاک چین است - هیچ ساختار مرکزی که مسئول تأیید است وجود ندارد و توالی پیام ها و محتوای آنها را نمی توان جعل کرد.

ابتدا، یک گره دقت را بررسی می کند، و سپس آن را برای دیگران ارسال می کند - اگر اکثریت بگویند که همه چیز مرتب است، تراکنش در بلوک بعدی زنجیره گنجانده می شود - این اتفاق نظر است.

چگونه یک پیام رسان غیرمتمرکز روی بلاک چین کار می کند؟

بخشی از کد گره که مسئول بررسی است را می توان در GitHub مشاهده کرد - validator.js и verify.js. بله، گره در Node.js اجرا می شود.

از جمله تراکنش با پیام در بلوک

در صورت اجماع، تراکنش با پیام ما به همراه سایر تراکنش های معتبر در بلوک بعدی قرار می گیرد.

بلوک ها دارای یک توالی دقیق هستند و هر بلوک بعدی بر اساس هش های بلوک های قبلی تشکیل می شود.

چگونه یک پیام رسان غیرمتمرکز روی بلاک چین کار می کند؟

نکته این است که پیام ما نیز در این دنباله گنجانده شده است و نمی توان آن را "بازآرایی" کرد. اگر چندین پیام در یک بلوک قرار گیرند، ترتیب آنها توسط 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 ثانیه تحویل داده می‌شوند - این زمانی است که یک بلوک شبکه جدید ظاهر می‌شود - ما با اتصال سوکت مشتری به گره و گره به گره رسیدیم. هنگامی که یک گره تراکنش جدیدی را دریافت می کند، اعتبار آن را بررسی می کند و آن را به گره های دیگر ارسال می کند. این تراکنش برای مشتریان پیام رسان حتی قبل از اتفاق نظر و گنجاندن در بلوک در دسترس است. به این ترتیب، مانند پیام‌رسان‌های فوری معمولی، بلافاصله پیام‌ها را تحویل خواهیم داد.

برای ذخیره کتاب آدرس، KVS - Key-Value Storage - این نوع دیگری از تراکنش است که در آن asset این جعبه NaCl نیست که رمزگذاری شده است، اما جعبه مخفی NaCl. به این ترتیب پیام رسان داده های دیگر را ذخیره می کند.

انتقال فایل/تصویر و چت گروهی هنوز به کار زیادی نیاز دارد. البته، در قالب اشتباه و اشتباه، این می تواند به سرعت "خطا" شود، اما ما می خواهیم همان سطح حریم خصوصی را حفظ کنیم.

بله، هنوز کار برای انجام دادن وجود دارد - در حالت ایده آل، حریم خصوصی واقعی فرض می کند که کاربران به گره های شبکه عمومی متصل نخواهند شد، بلکه گره های خود را بالا می برند. فکر می کنید چند درصد از کاربران این کار را انجام می دهند؟ درست است، 0. ما توانستیم تا حدی این مشکل را با نسخه Tor پیام رسان حل کنیم.

ما ثابت کرده ایم که یک پیام رسان در بلاک چین می تواند وجود داشته باشد. پیش از این، تنها یک تلاش در سال 2012 وجود داشت - بیت پیام، که به دلیل زمان طولانی تحویل پیام، بارگیری CPU و کمبود برنامه های تلفن همراه ناموفق بود.

و شک و تردید به این دلیل است که پیام رسان های موجود در بلاک چین از زمان خود جلوتر هستند - مردم آماده نیستند مسئولیت حساب خود را بپذیرند، داشتن اطلاعات شخصی هنوز یک روند نیست و فناوری اجازه نمی دهد سرعت بالایی در بلاک چین وجود داشته باشد. آنالوگ های تکنولوژیکی بیشتری از پروژه ما در ادامه ظاهر خواهند شد. خواهی دید.

منبع: www.habr.com

اضافه کردن نظر