À u principiu di 2017, avemu cuminciatu à creà un messageru nantu à u blockchain [nome è ligame sò in u prufilu] discutendu i vantaghji nantu à i messageri P2P classici.
Andatu 2.5 anni, è simu stati capaci di dimustrà u nostru cuncettu: l'applicazioni di messageria per iOS, Web PWA, sò avà dispunibili, Windows, GNU/Linux, Mac OS è Android.
Oghje vi diceremu cumu funziona u messenger blockchain è cumu l'applicazioni di u cliente ponu travaglià cù a so API.

Vulemu chì u blockchain risolve i prublemi di sicurità è privacy di i messageri P2P classici:
- Un clic per creà un contu - senza telefoni o e-mail, nè accessu à libri d'indirizzu o geolocazioni.
- L'interlocutori ùn stabiliscenu mai cunnessione diretta; tutta a cumunicazione si faci per un sistema distribuitu di nodi. L'indirizzi IP di l'utilizatori ùn sò micca accessibili per l'altri.
- Tutti i missaghji sò criptati End-to-End curve25519xsalsa20poly1305. Sembra chì questu ùn sorprenderà à nimu, ma u nostru codice fonte hè apertu.
- L'attaccu MITM hè esclusu - ogni missaghju hè una transazzione è hè firmatu da Ed25519 EdDSA.
- U missaghju finisci in u so propiu bloccu. Cuerenza è
timestampÙn pudete micca riparà i blocchi, è dunque l'ordine di i missaghji. - "Ùn aghju micca dettu chì" ùn hà micca travagliatu cù missaghji nantu à u blockchain.
- Ùn ci hè micca una struttura cintrali chì faci cuntrolli nantu à l'"autenticità" di un missaghju. Questu hè fattu da un sistema distribuitu di nodi basatu annantu à u cunsensu, è hè propiu di l'utilizatori.
- Impussibilità di censura - i cunti ùn ponu micca esse bluccati è i missaghji ùn ponu micca esse eliminati.
- Blockchain 2FA hè una alternativa à l'infernale 2FA via SMS,
- A capacità di uttene tutte e vostre conversazioni da qualsiasi dispositivu in ogni mumentu significa chì ùn avete micca bisognu di guardà conversazioni in u locu.
- Cunfirmazione di u messagiu. Micca à u dispusitivu di l'utilizatori, ma à a reta. Essenzialmente, questu hè a cunferma di a capacità di u destinatariu di leghje u vostru messagiu. Questa hè una funzione utile per mandà notificazioni critiche.
I benefici di Blockchain includenu ancu una integrazione stretta cù e cripthe di monete Ethereum, Dogecoin, Lisk, Dash, Bitcoin (questu hè sempre in prugressu) è a capacità di mandà tokens in chats. Avemu ancu fattu un scambiatore di criptu integratu.
E poi - cumu tuttu funziona.
Un missaghju hè una transazzione
Tutti sò digià abituati à u fattu chì e transazzioni in u blockchain trasferisce tokens (muniti) da un utilizatore à l'altru. Cum'è Bitcoin. Avemu creatu un tipu speziale di transazzione per trasmette missaghji.
Per mandà un missaghju in un messenger nantu à u blockchain, avete bisognu di passà per parechji passi:
- Cripte u testu di u messagiu
- Mettite u testu cifratu in una transazzione
- Firmà a transazzione
- Mandate una transazzione à qualsiasi node di a reta
- Un sistema distribuitu di nodi determina l'"autenticità" di un messagiu
- Se tuttu hè bè, a transazzione cù u messagiu hè inclusa in u prossimu bloccu
- U destinatariu recupera a transazzione di missaghju è decripta
I passi 1-3 è 7 sò realizati in u locu nantu à u cliente, è i passi 5-6 sò realizati nantu à l'ospiti.
Criptazione di i missaghji
U messagiu hè criptatu cù a chjave privata di u mittente è a chjave publica di u destinatariu. Pigliemu a chjave publica da a reta, ma per questu, u cuntu di u destinatariu deve esse inizializatu, vale à dì, avè almenu una transazzione. Pudete aduprà una dumanda REST GET /api/accounts/getPublicKey?address={ADAMANT address}, è quandu caricate chats, i chjavi publichi di l'interlocutori seranu digià dispunibili.

U messenger cripta i missaghji cù l'algoritmu curve25519xsalsa20poly1305 (). Siccomu u contu cuntene chjavi Ed25519, per furmà una scatula, i chjavi devenu esse prima cunvertiti in Curve25519 Diffie-Hellman.
Eccu un esempiu in 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)
}
}Formà una transazzione cù un missaghju
A transazzione hà a seguente struttura generale:
{
"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": {}
} Per una transazzione di missaghju, u più impurtante hè asset - avete bisognu di mette un missaghju in l'ughjettu chat cù struttura:
message- salvà u messagiu criptatuown_message- nullatype- tipu di missaghju
I missaghji sò ancu divisi in tipi. Essenzialmente, u paràmetru type vi dice cumu capisce message. Pudete mandà solu un testu, o pudete mandà un ughjettu cù cose interessanti in l'internu - per esempiu, questu hè cumu u messenger face trasferimenti di criptocurrency in chats.
In u risultatu, creamu una transazzione:
{
"transaction": {
"type": 8,
"amount": 0,
"senderId": "U12499126640447739963",
"senderPublicKey": "e9cafb1e7b403c4cf247c94f73ee4cada367fcc130cb3888219a0ba0633230b6",
"asset": {
"chat": {
"message": "cb682accceef92d7cddaaddb787d1184ab5428",
"own_message": "e7d8f90ddf7d70efe359c3e4ecfb5ed3802297b248eacbd6",
"type": 1
}
},
"recipientId": "U15677078342684640219",
"timestamp": 63228087,
"signature": "тут будет подпись"
}
}Firma di transazzione
Per assicurà chì tutti sò cunfidenti in l'autenticità di u mittente è u destinatariu, u tempu di mandà è u cuntenutu di u missaghju, a transazzione hè firmata. Una firma digitale permette di verificà l'autenticità di una transazzione cù una chjave publica - una chjave privata ùn hè micca necessariu per questu.
Ma a firma stessa hè realizata cù a chjave privata:

U diagramma mostra chì avemu prima a transazzione cù SHA-256 è dopu firmà è ottene una firma signature, è l'ID di transazzione hè parti di l'hash SHA-256.
Esempiu di implementazione:
1 - Formà un bloccu di dati, cumpresu un missaghju
/**
* 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 - Cunta SHA-256 da u bloccu di dati
/**
* 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 - Firmà a transazzione
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'))
}Mandate una transazzione cù un messagiu à un node di rete
Siccomu a reta hè decentralizata, qualsiasi di i nodi cù una API aperta farà. Fà una dumanda POST à l'endpoint api/transactions:
curl 'api/transactions' -X POST
-d 'TX_DATA'In risposta, riceveremu un ID di transazzione di u tipu
{
"success": true,
"nodeTimestamp": 63228852,
"transactionId": "6146865104403680934"
}Validazione di a transazzione
Un sistema distribuitu di nodi, basatu annantu à u cunsensu, determina l'"autenticità" di u missaghju di transazzione. Da quale è à quale, quandu, se u messagiu hè statu rimpiazzatu cù un altru, è se l'ora di l'invio hè stata indicata currettamente. Questu hè un vantaghju assai impurtante di u blockchain - ùn ci hè micca una struttura cintrali chì hè rispunsevule per a verificazione, è a sequenza di i missaghji è u so cuntenutu ùn ponu esse falsificati.
Prima, un node verifica l'accuratezza, è poi u manda à l'altri - se a maiuranza dice chì tuttu hè in ordine, a transazzione serà inclusa in u prossimu blocu di a catena - questu hè cunsensu.

A parte di u codice di u nodu chì hè rispunsevule per i cuntrolli pò esse vistu in GitHub - и . Iè, u node corre nantu à Node.js.
Includite una transazzione cù un messagiu in un bloccu
Se u cunsensu hè righjuntu, a transazzione cù u nostru missaghju serà inclusa in u prossimu bloccu cù altre transazzione validu.
I blocchi anu una sequenza stretta, è ogni bloccu sussegwenti hè furmatu basatu annantu à l'hash di blocchi precedenti.

U puntu hè chì u nostru missaghju hè ancu inclusu in questa sequenza è ùn pò micca esse "rearranged". Sè parechji missaghji falà in un bloccu, u so ordine sarà determinata da timestamp missaghji.
Lettura di missaghji
L'applicazione di messenger recupera transacciones da u blockchain chì sò mandati à u destinatariu. Per questu avemu fattu un puntu finale api/chatrooms.
Tutte e transazzione sò dispunibuli per tutti - pudete riceve missaghji criptati. Ma solu u destinatariu pò decifrare cù a so chjave privata è a chjave publica di u mittente:
**
* 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) : ''
}È chì altru ?
Siccomu i missaghji sò mandati in questu modu in circa 5 seconde - questu hè u tempu chì appare un novu bloccu di rete - avemu ghjuntu cun una cunnessione di socket client-à-node è node-à-node. Quandu un node riceve una nova transazzione, verifica a so validità è u trasmette à altri nodi. A transazzione hè dispunibule per i clienti di messageria ancu prima chì u cunsensu si faci è l'inclusione in u bloccu. In questu modu, daremu i missaghji istantaneamente, cum'è i messageri istantanei regulari.
Per almacenà u libru di indirizzu, avemu fattu KVS - Key-Value Storage - questu hè un altru tipu di transazzione in quale asset ùn hè micca NaCl-box chì hè criptatu, ma . Questu hè cumu u messenger guarda altre dati.
I trasferimenti di file / imaghjini è i chats di gruppu necessitanu sempre assai travagliu. Di sicuru, in u formatu blunder-and-blunder questu pò esse "screwed up" rapidamente, ma vulemu mantene u listessu livellu di privacy.
Iè, ci hè ancu un travagliu per esse fattu - idealmente, a vera privacy assume chì l'utilizatori ùn anu micca cunnette à i nodi di a rete publica, ma suscitarà u so propiu. Chì percentuale di l'utilizatori pensate chì faci questu? Hè propiu, 0. Pudemu risolve parzialmente stu prublema cù a versione Tor di u messenger.
Avemu pruvucatu chì un messageru nantu à a blockchain pò esse. Prima, ci era solu un tentativu in 2012 - , chì hà fiascatu per via di lunghi tempi di consegna di messagi, carica di CPU, è mancanza di applicazioni mobili.
È u scetticismu hè duvuta à u fattu chì i messageri nantu à u blockchain sò davanti à u so tempu - a ghjente ùn hè micca pronta per piglià a rispunsabilità di u so contu, pussede l'infurmazioni persunali ùn hè ancu una tendenza, è a tecnulugia ùn permette micca alta velocità in u blockchain. Più analoghi tecnologichi di u nostru prughjettu appariscenu dopu. Viderete.
Source: www.habr.com
