Trình nhắn tin phi tập trung hoạt động như thế nào trên blockchain?

Vào đầu năm 2017, chúng tôi bắt đầu tạo một trình nhắn tin trên blockchain [tên và liên kết có trong hồ sơ] bằng cách thảo luận về những ưu điểm so với các trình nhắn tin P2P cổ điển.

Không còn 2.5 năm, và chúng tôi đã có thể xác nhận ý tưởng của mình: các ứng dụng nhắn tin hiện đã có sẵn cho iOS, Web PWA, Windows, GNU/Linux, Mac OS và Android.

Hôm nay chúng tôi sẽ cho bạn biết cách hoạt động của trình nhắn tin blockchain và cách các ứng dụng khách có thể hoạt động với API của nó.
Trình nhắn tin phi tập trung hoạt động như thế nào trên blockchain?

Chúng tôi muốn blockchain giải quyết các vấn đề bảo mật và quyền riêng tư của các trình nhắn tin P2P cổ điển:

  • Một cú nhấp chuột để tạo tài khoản - không cần điện thoại hoặc email, không có quyền truy cập vào sổ địa chỉ hoặc vị trí địa lý.
  • Những người đối thoại không bao giờ thiết lập các kết nối trực tiếp; mọi giao tiếp diễn ra thông qua một hệ thống các nút phân tán. Địa chỉ IP của người dùng không thể truy cập được với nhau.
  • Tất cả các tin nhắn đều được mã hóa theo đường cong End-to-End25519xsalsa20poly1305. Có vẻ như điều này sẽ không làm ai ngạc nhiên, nhưng mã nguồn của chúng tôi là mở.
  • Cuộc tấn công MITM bị loại trừ - mỗi tin nhắn là một giao dịch và được ký bởi Ed25519 EdDSA.
  • Tin nhắn kết thúc trong khối riêng của nó. Tính nhất quán và timestamp Bạn không thể sửa các khối và do đó không thể sửa thứ tự của các tin nhắn.
  • “Tôi không nói điều đó” sẽ không hoạt động với các tin nhắn trên blockchain.
  • Không có cấu trúc trung tâm nào kiểm tra “tính xác thực” của tin nhắn. Điều này được thực hiện bởi một hệ thống nút phân tán dựa trên sự đồng thuận và nó thuộc sở hữu của người dùng.
  • Không thể kiểm duyệt - không thể chặn tài khoản và không thể xóa tin nhắn.
  • Blockchain 2FA là một giải pháp thay thế cho 2FA thông qua SMS, hủy hoại sức khỏe rất nhiều.
  • Khả năng nhận tất cả các cuộc hội thoại của bạn từ bất kỳ thiết bị nào vào bất kỳ lúc nào có nghĩa là bạn hoàn toàn không phải lưu trữ các cuộc hội thoại cục bộ.
  • Xác nhận gửi tin nhắn. Không phải với thiết bị của người dùng mà với mạng. Về cơ bản, đây là sự xác nhận về khả năng người nhận đọc tin nhắn của bạn. Đây là một tính năng hữu ích để gửi thông báo quan trọng.

Lợi ích của chuỗi khối cũng bao gồm tích hợp chặt chẽ với các loại tiền điện tử Ethereum, Dogecoin, Lisk, Dash, Bitcoin (điều này vẫn đang được tiến hành) và khả năng gửi mã thông báo trong các cuộc trò chuyện. Chúng tôi thậm chí còn tạo ra một bộ trao đổi tiền điện tử tích hợp.

Và sau đó - mọi chuyện diễn ra như thế nào.

Tin nhắn là một giao dịch

Mọi người đều đã quen với việc các giao dịch trong chuỗi khối chuyển mã thông báo (tiền xu) từ người dùng này sang người dùng khác. Giống như Bitcoin. Chúng tôi đã tạo một loại giao dịch đặc biệt để truyền tin nhắn.

Để gửi tin nhắn trong trình nhắn tin trên blockchain, bạn cần thực hiện một số bước:

  1. Mã hóa văn bản tin nhắn
  2. Đặt bản mã vào một giao dịch
  3. Ký giao dịch
  4. Gửi giao dịch đến bất kỳ nút mạng nào
  5. Một hệ thống nút phân tán xác định “tính xác thực” của tin nhắn
  6. Nếu mọi thứ đều ổn, giao dịch có thông báo sẽ được đưa vào khối tiếp theo
  7. Người nhận truy xuất giao dịch tin nhắn và giải mã

Các bước 1–3 và 7 được thực hiện cục bộ trên máy khách và các bước 5–6 được thực hiện trên máy chủ.

Mã hóa tin nhắn

Tin nhắn được mã hóa bằng khóa riêng của người gửi và khóa chung của người nhận. Chúng tôi sẽ lấy khóa chung từ mạng, nhưng để làm được điều này, tài khoản của người nhận phải được khởi tạo, tức là có ít nhất một giao dịch. Bạn có thể sử dụng yêu cầu REST GET /api/accounts/getPublicKey?address={ADAMANT address}và khi tải cuộc trò chuyện, khóa chung của người đối thoại sẽ có sẵn.

Trình nhắn tin phi tập trung hoạt động như thế nào trên blockchain?

Trình nhắn tin mã hóa tin nhắn bằng thuật toán Curve25519xsalsa20poly1305 (Hộp NaCl). Vì tài khoản chứa khóa Ed25519 nên để tạo thành hộp, trước tiên các khóa phải được chuyển đổi thành Curve25519 Diffie-Hellman.

Đây là một ví dụ trong 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)
  }
}

Hình thành giao dịch bằng tin nhắn

Giao dịch có cấu trúc chung như sau:

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

Đối với một giao dịch tin nhắn, điều quan trọng nhất là asset - bạn cần đặt một tin nhắn trong đối tượng chat với cấu trúc:

  • message - lưu tin nhắn được mã hóa
  • own_message -không một lần
  • type - loại tin nhắn

Tin nhắn cũng được chia thành các loại. Về cơ bản, tham số type cho bạn biết làm thế nào để hiểu message. Bạn có thể chỉ gửi một văn bản hoặc bạn có thể gửi một đối tượng có những điều thú vị bên trong - ví dụ: đây là cách trình nhắn tin thực hiện chuyển tiền điện tử trong các cuộc trò chuyện.

Kết quả là chúng ta tạo ra một giao dịch:

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

Chữ ký giao dịch

Để đảm bảo mọi người tin tưởng vào tính xác thực của người gửi và người nhận, thời gian gửi và nội dung tin nhắn, giao dịch được ký kết. Chữ ký số cho phép bạn xác minh tính xác thực của giao dịch bằng khóa chung - không cần khóa riêng cho việc này.

Nhưng bản thân chữ ký được thực hiện bằng khóa riêng:

Trình nhắn tin phi tập trung hoạt động như thế nào trên blockchain?

Sơ đồ cho thấy trước tiên chúng tôi băm giao dịch bằng SHA-256 và sau đó ký vào giao dịch đó Ed25519 EdDSA và lấy chữ ký signaturevà ID giao dịch là một phần của hàm băm SHA-256.

Ví dụ thực hiện:

1 - Tạo khối dữ liệu, bao gồm tin nhắn

/**
 * 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 - Đếm SHA-256 từ khối dữ liệu

/**
 * 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 — Ký giao dịch

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

Gửi giao dịch kèm tin nhắn tới nút mạng

Vì mạng được phân cấp nên bất kỳ nút nào có API mở đều có thể thực hiện được. Thực hiện yêu cầu POST tới điểm cuối api/transactions:

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

Đáp lại, chúng tôi sẽ nhận được ID giao dịch thuộc loại

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

Xác thực giao dịch

Một hệ thống nút phân tán, dựa trên sự đồng thuận, xác định “tính xác thực” của thông báo giao dịch. Từ ai và đến ai, khi nào, liệu tin nhắn có được thay thế bằng tin nhắn khác hay không và liệu thời gian gửi có được chỉ định chính xác hay không. Đây là một lợi thế rất quan trọng của blockchain - không có cấu trúc trung tâm chịu trách nhiệm xác minh và chuỗi tin nhắn cũng như nội dung của chúng không thể bị giả mạo.

Đầu tiên, một nút kiểm tra tính chính xác và sau đó gửi nó cho những nút khác - nếu đa số nói rằng mọi thứ đều ổn, giao dịch sẽ được đưa vào khối tiếp theo của chuỗi - đây là sự đồng thuận.

Trình nhắn tin phi tập trung hoạt động như thế nào trên blockchain?

Bạn có thể xem phần mã nút chịu trách nhiệm kiểm tra trên GitHub - trình xác thực.js и xác minh.js. Đúng, nút chạy trên Node.js.

Bao gồm một giao dịch với một tin nhắn trong một khối

Nếu đạt được sự đồng thuận, giao dịch có thông báo của chúng tôi sẽ được đưa vào khối tiếp theo cùng với các giao dịch hợp lệ khác.

Các khối có trình tự nghiêm ngặt và mỗi khối tiếp theo được hình thành dựa trên giá trị băm của các khối trước đó.

Trình nhắn tin phi tập trung hoạt động như thế nào trên blockchain?

Vấn đề là thông điệp của chúng ta cũng nằm trong trình tự này và không thể “sắp xếp lại”. Nếu có nhiều tin nhắn rơi vào một khối thì thứ tự của chúng sẽ được xác định bởi timestamp bài viết.

đọc tin nhắn

Ứng dụng nhắn tin truy xuất các giao dịch từ blockchain được gửi đến người nhận. Đối với điều này, chúng tôi đã tạo ra một điểm cuối api/chatrooms.

Tất cả các giao dịch đều có sẵn cho mọi người - bạn có thể nhận được tin nhắn được mã hóa. Nhưng chỉ người nhận mới có thể giải mã bằng khóa riêng của mình và khóa chung của người gửi:

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

Và những gì khác?

Vì các tin nhắn được gửi theo cách này trong khoảng 5 giây - đây là thời điểm một khối mạng mới xuất hiện - chúng tôi đã đưa ra kết nối ổ cắm máy khách đến nút và nút này đến nút khác. Khi một nút nhận được một giao dịch mới, nó sẽ kiểm tra tính hợp lệ của nó và chuyển tiếp nó đến các nút khác. Giao dịch có sẵn cho các ứng dụng khách nhắn tin ngay cả trước khi xảy ra sự đồng thuận và đưa vào khối. Bằng cách này, chúng tôi sẽ gửi tin nhắn ngay lập tức, giống như các trình nhắn tin tức thời thông thường.

Để lưu trữ sổ địa chỉ, chúng tôi đã tạo KVS - Lưu trữ giá trị khóa - đây là một loại giao dịch khác trong đó asset không phải hộp NaCl được mã hóa mà là Hộp bí NaCl. Đây là cách trình nhắn tin lưu trữ dữ liệu khác.

Truyền tệp/hình ảnh và trò chuyện nhóm vẫn đòi hỏi nhiều công việc. Tất nhiên, ở định dạng sai lầm, điều này có thể được "làm hỏng" một cách nhanh chóng, nhưng chúng tôi muốn duy trì mức độ riêng tư tương tự.

Có, vẫn còn nhiều việc phải làm - lý tưởng nhất là quyền riêng tư thực sự giả định rằng người dùng sẽ không kết nối với các nút mạng công cộng mà sẽ tự tạo ra nút mạng của riêng họ. Bạn nghĩ bao nhiêu phần trăm người dùng thực hiện điều này? Đúng vậy, 0. Chúng tôi đã có thể giải quyết một phần vấn đề này bằng phiên bản Tor của trình nhắn tin.

Chúng tôi đã chứng minh rằng trình nhắn tin trên blockchain có thể tồn tại. Trước đây, chỉ có một lần thử vào năm 2012 - tin nhắn bit, không thành công do thời gian gửi tin nhắn dài, tải CPU và thiếu ứng dụng di động.

Và sự hoài nghi là do các trình nhắn tin trên blockchain đã đi trước thời đại - mọi người chưa sẵn sàng chịu trách nhiệm về tài khoản của mình, việc sở hữu thông tin cá nhân chưa phải là xu hướng và công nghệ không cho phép tốc độ cao trên blockchain. Nhiều tương tự công nghệ của dự án của chúng tôi sẽ xuất hiện tiếp theo. Bạn sẽ thấy.

Nguồn: www.habr.com

Thêm một lời nhận xét