Blockchain
Cosa è e come funziona ? Cosa significa "minare" ? Come si verificano le transazioni in un sistema anonimo e distribuito ?
Cerco di riportare qui le risposte che ho cercato di darmi su questi argomenti. Provo a suddividere la trattazione in più parti per non risultare eccessivamente lungo.
Il livello di approfondimento è "didattico" cioè cerco di dare dettagli sia architetturali che implementativi ma fermandomi ad un livello adeguato alla comprensione approfondita del meccanismo e non alla implementazione di un sistema reale.
Definizioni
Blockchain è una tecnologia che consente di certificare temporalmente e sequenzialmente una asserzione. In altre parole si ha un registro che certifica il suo contenuto informativo senza un garante e senza fiducia fra le parti. Questa potrebbe essere una definizione quanto più generica possibile della tecnologia, aperta, che sta dietro alle criptovalute ma è utilizzabile anche in altri ambiti.
DLT sta per "Distributed Ledger Tecnology" e sono quelle tecnologie atte a tenere un "Ledger", Libro Mastro in italiano, in maniera distribuita. Il libro mastro tiene la contabilità, cioè i movimenti di denaro, di magazzino, o di scambio di altri beni o servizi. Questa versione "distribuita" fa in modo che i nodi dove è presente una copia di questo libro mastro facciano da garanti del suo contenuto.
DLT sta per "Distributed Ledger Tecnology" e sono quelle tecnologie atte a tenere un "Ledger", Libro Mastro in italiano, in maniera distribuita. Il libro mastro tiene la contabilità, cioè i movimenti di denaro, di magazzino, o di scambio di altri beni o servizi. Questa versione "distribuita" fa in modo che i nodi dove è presente una copia di questo libro mastro facciano da garanti del suo contenuto.
SHA256 è un algoritmo di hashing (converte, in maniera non reversibile, qualunque testo in ingresso in una sequenza univoca di caratteri) con l'output caratterizzato dal fatto che, indipendentemente da ciò che si mette dentro, l'hash è sempre di 256 bit, 32 byte che in esadecimale diventano 64 caratteri è (dovrebbe essere) unico in funzione dell'input (dovrebbe perché c'è una seppur remota probabilità di conflitto definita da una dimostrazione teorica).
A parità di input l'output è sempre uguale.
Non reversibile, se non provando tutte le combinazioni possibili
Cambiando minimamente l'ingresso cambia sostanzialmente l'uscita e quindi è impossibile ricondurre due hash di uscita da sha256 a due contenuti simili.
Proof of Work per gestire, mediante una blockchain, una criptovaluta si rende necessario aggiungere complessità computazionale all'operazione di mining. Questo per rendere economicamente (in termini di energia elettrica necessaria) svantaggioso provare a ricalcolare un certo numero di blocchi a forza bruta.
In sostanza si tratta di imporre all'hash ottenuto dall'algoritmo di hashing scelto (nel nostro caso SHA-256) di rispettare alcuni vincoli come ad esempio "iniziale con 00", questa regola di validazione viene detta "Difficulty". Questo implicherà una ricerca a forza bruta per generare una hash così fatto. Cioè si cambierà il contenuto del campo "Nonce" e si riproverà a codificare con SHA-256 fin quando il risultato ottenuto non comincia con "00". Anche nell'uso di blockchain per altri scopi è utile inserire questo meccanismo nella validazione di un blocco per impedire attacchi volti alla ridefinizione di un numero di nodi tali (superiori al 50%) per modificare lo storico.
E' evidente che aumentando la Difficulty si impone una maggiore potenza di calcolo per validare il blocco. In molte criptovalute la Difficulty è dinamica e si adatta alla potenza di calcolo totale stimata messa a disposizione dai miner.
Questo è uno dei metodi usati per imporre un carico computazionale all'operazione di mining.
Nota: nella criptovaluta Bitcoin la "Difficulty" è dinamica e viene adeguata ogni 2016 blocchi minati (al momento in cui scrivo questo avviene circa ogni due settimane).
ICO sta per "Initial Coin Offering", in ambito criptovalute, coincide con il "conio" ed è la creazione del "primo nodo" che contiene la prima transazione.
Cosa è
Blockchain è una tecnologia che consente di avere un "registro" con "scritture" certificate sia a livello di tempo (momento in cui sono state fatte) sia a livello di non modificabilità e quindi di affidabilità. Ogni scrittura che si vuole aggiungere viene inserita in un blocco che viene cifrato ed inserito in un nodo di una catena condivisa in una rete P2P (Pear To Pear). Ogni variazione che si vuole fare al registro può andare solo in coda all'ultima inserita e tutto lo storico viene conservato.
Ogni blocco, ed il suo contenuto, è visibile in chiaro. Ma non è modificabile se non con una scrittura che va aggiunta in coda.
Per definire il contesto si deve fare riferimento alle criptovalute, ma solo perché questa è l'applicazione più pubblicizzata di questa tecnologia la quale è agnostica rispetto al contenuto informativo dei dati che gestisce. Esempi di criptovalute sono i "BitCoin", "Ethereum" e "Dash" solo per citarne qualcuna.
Ogni utente registrato nella rete della criptovaluta ha:
- un Wallet (borsellino letteralmente), che è un software per gestire le sue criptomonete
- una coppia di chiavi pubblica/privata (coppia di chiavi per codifica asimmetriche) dove quella pubblica rappresenta l'indirizzo al quale ricevere moneta virtuale e dal quale inviare moneta virtuale.
Come funziona
I blocchi
Il contenuto informativo sta nei blocchi. Ogni blocco può contenere, nel campo "Dati" una stringa di testo lunga a piacere e che può rappresentare qualunque cosa sia di interesse per chi implementa e mantiene la blockchain:
Ogni blocco è caratterizzato da:
- Nonce : un identificatore univoco del record
- Indice : che lo identifica univocamente in funzione della sua posizione nella catena
- Timestamp : che lo colloca nel tempo
- Data : il vero contenuto informativo costituito da un testo qualsiasi
- Hash : il contenuto del blocco ottenuto dall'algoritmo di hashing usato della parte relativa a Nonce+Indice+Data.
- Precedente : l'hash del blocco che precede il presente
import java.security.NoSuchAlgorithmException;
import utils.Cypher;
public class Block {
String id = "";
String nonce = "";
String dati = "";
String timestamp = "";
String precedente = "";
String hash = "";
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getNonce() {
return nonce;
}
public void setNonce(String nonce) {
this.nonce = nonce;
}
public String getDati() {
return dati;
}
public void setDati(String dati) {
this.dati = dati;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getPrecedente() {
return precedente;
}
public void setPrecedente(String precedente) {
this.precedente = precedente;
}
public String getHash() throws NoSuchAlgorithmException {
return Cypher.hash2Base64(this.toString());
}
public void setHash(String hash) {
this.hash = hash;
}
@Override
public String toString(){
return this.nonce+this.id+this.dati+this.precedente;
}
}
Validazione di un nodo
Una volta che si è generato un blocco nuovo e gli si è inserito il contenuto informativo, cioè il campo "Data", va validato. La validazione di un blocco è ciò che viene definito "mining" cioè "minare" il blocco. Questo processo richiede un certo sforzo computazionale. Tale sforzo è detto "Proof of Work" (vedi definizione nel paragrafo "Definizioni"). Questo sforzo computazionale è demandato ai nodi in cambio di criptovaluta.
Per validare un blocco i vari algoritmi di blockchain prevedono qualcosa di simile a:
0) Genera un codice a caso e lo inserisce in Nonce
1) Generare l'hash mediante SHA256 del blocco. Nello specifico viene sottoposto ad hash la stringa concatenata:
Nonce+Indice+Data+Timestamp+Precedente
Nota che nelle specifiche di Bitcoin è previsto il "doppio SHA-256" (vedi paragrafo "SHA-256 Doppio").
2) Verificare se l'hash così ottenuto rispetta la "Difficulty" impostata (inizia per "00" ad esempio).
3) Se non rispetta la difficulty ripeti dal punto 0)
4) Se la rispetta valida il nodo inserendo nel campo "hash" di questo l'hash ottenuto con SHA-256 che rispetta la difficulty.
Il blocco è validato, è inserito nella copia della catena che ha il mio nodo ed è ora da propagare sugli altri nodi.
Qui vediamo la classe che si occupa del crypting:
Qui vediamo la classe che si occupa del crypting:
package utils;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Cypher {
public static byte[] hash256(String pas) throws NoSuchAlgorithmException {
java.security.MessageDigest d = null;
d = java.security.MessageDigest.getInstance("SHA-256");
d.reset();
d.update(pas.getBytes());
return d.digest();
}
public static String hash2Base64(String pas) throws NoSuchAlgorithmException {
return Base64.getEncoder().encodeToString(hash256(pas));
}
public static byte[] hash2Base64Byte(String pas) throws NoSuchAlgorithmException {
return Base64.getEncoder().encode(hash256(pas));
}
public static void main(String[] args) throws NoSuchAlgorithmException {
System.out.println(hash2Base64("CiaoATutti28"));
}
}
Transazione
Una "transazione" è il passaggio di criptovaluta, o parte di essa, da un detentore ad un altro detentore. Questo, in un contesto di blockchain per criptovalute, costituisce il "contenuto informativo" (citato prima). In una blockchain non rivolta a criptovalute può essere una "registrazione" di uno scambio fra utenti o una registrazione di un fatto assoluto.
package mine;
import java.security.NoSuchAlgorithmException;
import java.sql.Timestamp;
import java.util.Random;
import model.Block;
import utils.Cypher;
public class ValidateBlock {
public static String seal = "00";
public static String givenRandomString() {
int leftLimit = 97; // letter 'a'
int rightLimit = 122; // letter 'z'
int targetStringLength = 5;
Random random = new Random();
StringBuilder buffer = new StringBuilder(targetStringLength);
for (int i = 0; i < targetStringLength; i++) {
int randomLimitedInt = leftLimit + (int) (random.nextFloat() * (rightLimit - leftLimit + 1));
buffer.append((char) randomLimitedInt);
}
String generatedString = buffer.toString();
return generatedString;
}
public static String getSeal() {
return seal;
}
public void setSeal(String seal) {
this.seal = seal;
}
/**
* Dato un blocco cerca una codifica SHA256 in BASE64 che cominci con il numero
* di "Difficulty" pari alla lunghezza dei caratteri definiti in "Seal". Appena
* la trova valorizza il timestamp del nodo
*
* @param b
* @return
* @throws NoSuchAlgorithmException
*/
public static boolean validateBlock(Block b) throws NoSuchAlgorithmException {
boolean ret = false;
String validHash = "11";
System.out.println("Inizio mining"+ new Timestamp(System.currentTimeMillis()));
String tempNonce = null;
while (!validHash.substring(0, getSeal().length()).equals(getSeal())) {
tempNonce = givenRandomString();
b.setNonce(tempNonce);
validHash = Cypher.hash2Base64(b.toString());
System.out.println(validHash);
}
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
b.setTimestamp(String.valueOf(timestamp.getTime()));
ret = true;
System.out.println("Fine mining"+ new Timestamp(System.currentTimeMillis()));
b.setHash(validHash);
b.setNonce(tempNonce);
return ret;
}
public static void main(String[] args) throws NoSuchAlgorithmException {
Block b = new Block();
b.setDati("Ciao a tutti quanti");
b.setId("1");
b.setNonce("0000");
if (validateBlock(b)) {
System.out.println("Id = " + b.getId());
System.out.println("Nonce = " + b.getNonce());
System.out.println("Dati = " + b.getDati());
System.out.println("Timestamp = " + b.getTimestamp());
System.out.println("Blocco precedente = " + b.getPrecedente());
System.out.println("Hash = " + b.getHash());
}
}
}
Validazione della transazione
La validazione di un transazione consiste nel recuperare i dati delle parti coinvolte nella transazione (o registrazione, se ce ne sono). Quindi se un utente A deve trasferire qualcosa all'utente B deve, semplicemente (usando il suo wallet) dichiarare che A cede a B il valore X. Dopo firma la transazione con la sua chiave privata. Prende il tutto e lo invia alla rete P2P per la validazione.
Uno o N nodo/i "miner" prenderà in carico la richiesta di transazione. Recupererà dai nodi della catena il "credito" dell'utente A, per verificare se ha credito sufficiente a compiere la transazione richiesta. Se sì raccoglierà questa richiesta in un nuovo nodo nel quale inserirà altre richieste di validazione di transazioni che è riuscito a validare e proverà a validare il nodo (vedi paragrafo "Validazione di un nodo"). Il primo miner che riesce a compiere la validazione illustrata risulta il vincente su gli altri che può quindi proporre il nodo all'inserimento nella blockchain e riceverà un premio in bitcoin per il lavoro svolto.
Il nodo verrà inserito alla fine della catena come nodo nuovo e verrà distribuito nelle varie copie, in giro per la rete, del database delle transazioni (cioè la catena dei nodi).
SHA-256 Doppio
Facciamo un esempio di SHA-256 singolo del contenuto "ciao" con il comando:
echo -n ciao |openssl dgst -sha256
b133a0c0e9bee3be20163d2ad31d6248db292aa6dcb1ee087a2aa50e0fc75ae2
Sha256 "doppio maccheronico" del contenuto "ciao" ottenuto facendo ripassare in Sha256 il risultato del primo passaggio:
echo -n b133a0c0e9bee3be20163d2ad31d6248db292aa6dcb1ee087a2aa50e0fc75ae2 |openssl dgst -sha256
Risultato:
c98b1c10cf6d3fd3a32ee8a92e9a17e80a1172a363d479982aa3877503d6c8b2
Sha256 doppio del contenuto "ciao":
echo -n ciao |openssl dgst -sha256 |openssl dgst -sha256
5eb8d9727ec6fa7144d55e03a8271df991f31f01a6330ce994a05bd2441db49f
Differiscono perché ogni rappresentazione su schermo della sequenza di byte generata dallo sha256 viene codificata in esadecimale per renderla come "caratteri stampabili" e quindi si ottiene una stringa di 64 byte e quindi 64 caratteri
To be continued...
Abbiamo il nostro blocco con il nostro SHA-256 doppio che inizia con 00. Nei prossimi post della serie passeremo alla rete pear to pear dei nodi.
Riferimenti
Quest'opera è distribuita con Licenza Creative Commons Attribuzione - Condividi allo stesso modo 4.0 Internazionale
Commenti
Posta un commento