I begyndelsen af 2017 begyndte vi at udvikle en messaging-app pÄ blockchainen [navn og link er i profilen], der diskuterede fordelene i forhold til klassiske P2P-messaging-apps.
Der er gÄet 2.5 Är, og vi har formÄet at bekrÊfte vores koncept: nu er messaging-apps tilgÊngelige for iOS, Web PWA, Windows, GNU/Linux, Mac OS og Android.
I dag vil vi fortÊlle, hvordan messaging-appen pÄ blockchainen fungerer, og hvordan klientapplikationerne interagerer med dens API.

Vi Þnskede, at blockchainen skulle lÞse spÞrgsmÄlene om sikkerhed og privatliv i klassiske P2P-messaging-apps:
- Et klik for at oprette en konto â ingen telefoner eller e-mails, ingen adgang til adresselister og geolokationer.
- Samtalepartnere etablerer aldrig direkte forbindelser, al kommunikation foregÄr gennem et distribueret system af noder. IP-adresserne for brugerne er ikke tilgÊngelige for hinanden.
- Alle beskeder er krypteret End-to-End curve25519xsalsa20poly1305. Det er mÄske ikke overraskende for mange, men vores kildekode er Äben.
- MITM-angreb er udelukket â hver besked er en transaktion og underskrives med Ed25519 EdDSA.
- Beskeden havner i sin blok. Sekvensen af
timestampblokke kan ikke Êndres, og fÞlgelig kan rÊkkefÞlgen af beskederne heller ikke Êndres. - "Det sagde jeg ikke" vil ikke fungere med beskeder pÄ blockchainen.
- Der er ingen central struktur, der verificerer "validiteten" af beskeden. Dette udfÞres af et distribueret system af noder baseret pÄ konsensus, og den tilhÞrer brugerne.
- Muligheden for censur er umulig â konti kan ikke blokeres, og beskeder kan ikke slettes.
- Blockchain 2FA â et alternativ til det problematiske 2FA via SMS,
- Muligheden for at fĂ„ alle dine dialoger fra enhver enhed pĂ„ ethvert tidspunkt â det betyder, at dialoger ikke behĂžver at opbevares lokalt overhovedet.
- BekrĂŠftelse af leveringen af beskeder. Ikke til brugerens enhed, men til netvĂŠrket. I bund og grund er dette en bekrĂŠftelse af, at modtageren kan lĂŠse din besked. Det er en nyttig funktion til at sende kritiske meddelelser.
Af fordelene ved blockchainen er der ogsÄ tÊt integration med kryptovalutaer som Ethereum, Dogecoin, Lisk, Dash, Bitcoin (denne er stadig under udvikling) og muligheden for at sende tokens i chats. Vi har endda lavet en indbygget crypto-exchanger.
Og nu â hvordan fungerer det hele.
Beskeden er en transaktion
Alle er blevet vant til, at transaktioner pÄ blockchainen overfÞrer tokens (mÞnter) fra en bruger til en anden. Ligesom med Bitcoin. Vi har dog skabt en sÊrlig type transaktion til overfÞrsel af beskeder.
For at sende en besked i messaging-appen pÄ blockchainen skal du gennemgÄ flere trin:
- Kryptere tekstbeskeden
- IndsĂŠt den krypterede tekst i transaktionen
- Underskriv transaktionen
- Send transaktionen til enhver node i netvĂŠrket
- Det distribuerede system af noder bestemmer 'autenticiteten' af meddelelsen
- Hvis alt er i orden â tilfĂžjes transaktionen med meddelelsen til den nĂŠste blok
- Modtageren udtrĂŠkker transaktionen med meddelelsen og dekrypterer den
Trin 1â3 og 7 udfĂžres lokalt pĂ„ klienten, mens 5â6 udfĂžres pĂ„ netvĂŠrksnodene.
Kryptering af meddelelsen
Meddelelsen krypteres med afsenderens private nÞgle og modtagerens offentlige nÞgle. Den offentlige nÞgle hentes fra netvÊrket, men for dette skal modtagerens konto vÊre initialiseret, dvs. have mindst én transaktion. REST-anmodning kan bruges GET /api/accounts/getPublicKey?address={ADAMANT address}, og nÄr chattie indlÊses, vil modpartens offentlige nÞgler allerede vÊre tilgÊngelige.

Messaging-programmet krypterer meddelelser med algoritmen curve25519xsalsa20poly1305 (). Da kontoen indeholder Ed25519 nĂžgler, skal nĂžglerne konverteres til Curve25519 Diffie-Hellman for at dannes en box.
Her er et eksempel i 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)
}
}Dannelse af transaktionen med meddelelsen
Transaktionen har fĂžlgende generelle struktur:
{
"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": {}
} For en meddelelses-transaktion er den vigtigste vĂŠrdi asset â den skal indeholde meddelelsen i et objekt chat med strukturen:
messageâ gem den krypterede meddelelseown_messageâ noncetypeâ meddelelsestype
Meddelelser er ogsĂ„ opdelt i typer. I grund og bund informerer parameteren type hvordan man skal forstĂ„ message. Man kan sende blot tekst, eller man kan sende et objekt med interessante indhold â for eksempel sender messaging-programmet kryptovaluta-overfĂžrsler i chats.
Resultatet er, at vi danner transaktionen:
{
"transaction": {
"type": 8,
"amount": 0,
"senderId": "U12499126640447739963",
"senderPublicKey": "e9cafb1e7b403c4cf247c94f73ee4cada367fcc130cb3888219a0ba0633230b6",
"asset": {
"chat": {
"message": "cb682accceef92d7cddaaddb787d1184ab5428",
"own_message": "e7d8f90ddf7d70efe359c3e4ecfb5ed3802297b248eacbd6",
"type": 1
}
},
"recipientId": "U15677078342684640219",
"timestamp": 63228087,
"signature": "her vil vĂŠre en signatur"
}
}Transaktionens signatur
For everyone to be assured of the authenticity of the sender and recipient, the time of sending, and the content of the message, the transaction is signed. A digital signature allows verifying the transaction's authenticity using the public key â the private key is not needed for this.
The signature itself is generated using the private key:

The scheme shows that we first hash the transaction using SHA-256 and then sign it. and we obtain the signature signatur, and the transaction ID is part of the SHA-256 hash.
Example implementation:
1 â Form a data block, including the message
/**
* 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 â Compute the SHA-256 of the data block
/**
* 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 â Sign the transaction
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'))
}Sending the transaction with a message to a network node
Since the network is decentralized, any node with an open API will do. We make a POST request to the endpoint api/transactions:
curl 'api/transactions' -X POST
-d 'TX_DATA'In response we will receive the transaction ID of type
{
"success": true,
"nodeTimestamp": 63228852,
"transactionId": "6146865104403680934"
}Verification of transaction authenticity
The distributed system of nodes based on consensus determines the "authenticity" of the transaction-message. From whom and to whom, when, whether the message has been replaced with another, and whether the correct sending time is specified. This is a very important advantage of blockchain â there is no central structure responsible for checks, and the sequence of messages and their contents cannot be forged.
First, one node checks the authenticity, and then it sends it to others â if the majority say everything is fine, the transaction will be included in the next block of the chain â this is the consensus.

Part of the node's code that is responsible for checks can be seen on GitHub â og . Ah, the node runs on Node.js.
Including the transaction with a message in the block
If consensus is reached, the transaction with our message will get into the next block alongside other authentic transactions.
Blocks have a strict sequence, and each subsequent block is formed based on the hashes of the previous blocks.

Essensen er, at vores besked ogsÄ er inkluderet i denne sekvens og ikke kan "omarrangeres". Hvis flere beskeder kommer ind i blokken, vil deres rÊkkefÞlge blive bestemt ud fra timestamp beskeder.
LĂŠsning af beskeder
Messenger-appen henter transaktioner fra blockchainen, som er sendt til modtageren. For dette har vi lavet en endpoint api/chatrooms.
Alle transaktioner er tilgĂŠngelige for enhver â man kan fĂ„ de krypterede beskeder. Men kun modtageren kan dekryptere dem med sin private nĂžgle og senderens offentlige nĂžgle:
**
* 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) : ''
}Hvad mere?
Da beskeder leveres pĂ„ denne mĂ„de omkring 5 sekunder â den tid det tager for en ny blok at fremkomme i netvĂŠrket â har vi opfundet socket-forbindelse mellem klient-node og node-node. NĂ„r en node modtager en ny transaktion, tjekker den dens gyldighed og videresender den til andre noder. Transaktionen er tilgĂŠngelig for messenger-klienter, inden konsensus opnĂ„s og den inkluderes i blokken. SĂ„dan vil vi levere beskeder Ăžjeblikkeligt, ligesom de gĂŠngse messengere.
For at gemme adressebogen har vi lavet KVS â Key-Value Storage â det er en anden type transaktioner, hvor asset der ikke krypteres en NaCl-box, men . PĂ„ den mĂ„de gemmer messengeren ogsĂ„ andre data.
Fil/-billedoverfĂžrsel og gruppechats krĂŠver stadig meget arbejde. SelvfĂžlgelig kan man hurtigt "fikse" det i et klodset format, men vi Ăžnsker at bevare det samme niveau af privatliv.
Ja, der er stadig meget at arbejde pÄ - i det ideelle tilfÊlde forudsÊtter virkelig privatliv, at brugerne ikke opretter forbindelse til offentlige knude i netvÊrket, men i stedet opsÊtter deres egne. Hvad tÊnker du, hvor mange procent af brugerne gÞr det? Korrekt, 0. Delvist har vi lÞst dette spÞrgsmÄl med en Tor-version af messengeren.
Vi har bevist, at messengeren pĂ„ blockchainen kan eksistere. Der har tidligere kun vĂŠret et forsĂžg i 2012 â , som mislykkedes pĂ„ grund af den lange leveringstid for beskeder, CPU-belastning og mangel pĂ„ mobile applikationer.
Og skepsis skyldes, at messengere pĂ„ blockchainen er forud for deres tid â folk er ikke klar til at tage ansvar for deres konto, ejerskab af personlig information er stadig ikke en trend, og teknologierne tillader ikke hĂžje hastigheder pĂ„ blockchainen. Snart vil der komme mere teknologiske alternativer til vores projekt. Bare vent og se.
Kilde: habr.com
