Crittografia e algoritmo ECDSALa crittografia viene utilizzata per rendere possibili uno dei due seguenti scenari:
1. A vuole mandare un messaggio segreto a B, in modo che solo B possa leggerne il contenuto (A deve codificare un messaggio mediante una chiave pubblicata da B e quindi nota a tutti, inviarlo a B che lo decodifica mediante la chiave privata che "inverte" l'azione di quella determinata chiave pubblica; in tutto questo processo il messaggio rimane segreto al resto del mondo)
2. A vuole inviare un messaggio pubblico a B; poichè il messaggio è pubblico A deve tutelare se stesso (e B) dal fatto che qualcun altro si interponga tra A e B e possa modificare il nome del mittente del messaggio o qualunque altra parte del messaggio stesso (A firma il messaggio con la sua chiave privata, lo invia a B che verifica a sua volta con la chiave pubblica relativa che il messaggio sia stato effettivamente firmato da chi possiede la chiave privata relativa e non sia stato modificato, in tutto questo processo il messaggio è sempre visibile al resto del mondo)
Nel sistema Bitcoin i messaggi si chiamano transazioni (perchè spostano del valore - rappresentato dalla moneta Bitcoin - da un utente a un altro). Quindi d'ora in poi considereremo i termini "messaggi" e "transazioni" come sinonimi. Poichè tutte queste transazioni devono essere pubbliche, la crittografia nel sistema Bitcoin viene utilizzata per rispondere alle esigenze evidenziate nello scenario 2, cioè viene utilizzata per certificare di fronte a tutto il mondo che una transazione sia stata effettivamente effettuata dall'autore dichiarato nel messaggio e che la transazione non sia stata manomessa in alcuna sua parte.
Il metodo crittografico scelto per certificare le transazioni nel mondo dei Bitcoin si basa su un algoritmo di firma digitale che lavora con curve ellittiche detto ECDSA (Elliptic Curve Digital Signature Algorithm).
Le curve ellittiche entrano in scena nelle seguenti tre situazioni:
• GENERAZIONE DI UNA CHIAVE PUBBLICA A PARTIRE DA UNA CHIAVE PRIVATA: quando si genera un indirizzo di un portafoglio; l'algebra delle curve ellittiche è alla base del meccanismo che permette di ricavare da una chiave privata una chiave pubblica; la chiave pubblica viene poi trasformata con un ulteriore passaggio (vedi
http://gobittest.appspot.com/Address) in un indirizzo Bitcoin
• FIRMA DIGITALE DI UNA TRANSAZIONE/MESSAGGIO CON LA CHIAVE PRIVATA: quando A deve effettuare un pagamento; A deve firmare mediante la propria chiave privata la transazione/messaggio di pagamento, per certificare in modo visibile a tutti la validità di questo atto di pagamento; la firma di A è necessaria per muovere dei fondi da un certo indirizzo, questa firma è ottenuta applicando in modo appropriato la chiave privata alla transazione (o meglio: al doppio hash della transazione) da eseguire
• VERIFICA DELLA FIRMA DIGITALE MEDIANTE LA CHIAVE PUBBLICA: quando un nodo della rete, addetto alla convalida delle transazioni, alla trasmissione di quest'ultime alla rete e alla loro registrazione in un registro pubblico detto "block chain", deve verificare mediante la chiave pubblica che la transazione sia stata firmata effettivamente dalla chiave privata corrispondente (pur senza conoscerla) e che la transazione non sia stata modificata in alcuna sua parte
Generazione di una chiave pubblica a partire da una chiave privataSi fissa un punto G della curva (che nel caso della secp256k1 è stato fissato dalla SEC), si sceglie un numero casuale d tra 1 e n - 1 (dove n è l'ordine di G), e si ottiene così la chiave pubblica P = d*G.
Facciamo un esempio nel caso semplificato di
E(F_11 )={(2,2),(2,-2),(3,1),(3,-1),(4,4),(4,-4),(5,0),(6,5),(6,-5),(7,3),(7,-3)} ∪ {O}
Scegliamo un punto base. Proviamo con A = (2,2)
Osserviamo che o(A) = 4 (l'ordine di A) infatti
A+A=2*A=D (vedi calcolo effettuato in precedenza, D(5,0) )
A+A+A=3*A=2*A+A=D+A=A'
A+A+A+A= 4*A = 3*A+A = A'+A = O
Poichè A ha ordine un numero non primo, non è un buon candidato per essere scelto come punto base. (NB: in questo caso o(A) = 4, quindi il cofattore o(E) : o(A) sarebbe uguale a 3 )
Proviamo con B = (3,1). Si può verificare che esso ha periodo 12, cioè B genera tutto E(F_11) (<B> = E(F_11)) (NB: in questo caso il cofattore è 1, così come succede per la curva secp256k1, da ciò si deduce che E(F_11) è un gruppo ciclico, anche se non ha un numero primo di elementi).
Quindi:
E = E(F_11) G (il punto base della curva) = Bd (la chiave privata) = 4 (numero scelto a caso tra 1 e 11)
P (la chiave pubblica corrispondente a d=4) = 4*B = 2*(2*B) = (3,-1) .
Firma digitale di un messaggio mediante una chiave privataChe cos'è una firma?
E' una coppia di numeri r , s (entrambi di lunghezza max 256 bit, minori di n) che si ottengono a partire da:
il messaggio
m** , la chiave privata
d, un numero casuale
k**ciò che si firma realmente non è il messaggio originale, ma una sua "impronta digitale" (detta "message digest", una stringa di 256 bit), impronta che è il risultato di un doppio hash del messaggio originale; nel caso particolare in cui si firma non un messaggio qualunque ma una transazione è da sottolineare come si effettua il doppio sha256 della transazione quando essa è ancora in una forma incompleta e non definitiva (è chiaro che nel momento in cui si firma una transazione la firma stessa non può essere già presente nella transazione stessa! Quindi a rigore in quel caso non si firma neanche tutto il messaggio, messaggio che però deve alla fine contenere anche la firma come sua parte essenziale --> a sottolineare la natura "spuria" della firma rispetto al resto della transazione è recentemente intervenuto il soft fork "segregated witness" (firma separata), dove di fatto la firma viene considerata una parte a se stante della transazione ed è trattata in modo particolare.
Algoritmo di generazione della firma
1. Scegliere un numero intero casuale k nell'intervallo [1,n-1] (dove n è l'ordine della curva)
2. Calcolare il punto della curva X1 = k*G = (x1,y1), convertire x1 in uno scalare e porre r = x1 mod n
(ritornare al passo 1 se r = 0; qui G è il generatore della curva, lo stesso utilizzato per passare dalle chiavi private alle chiavi pubbliche; la conversione di x1 in intero implica passare dal campo Fp delle coordinate all'insieme degli scalari)
3. Calcolare e = hash(m) (nel caso della secp256k1, si utilizza la funzione crittografica sha256 applicata 2 volte, in questo modo si traduce un messaggio in uno scalare di 256 bit confrontabile con gli altri scalari; applicare 2 volte l'hash rende l'operazione più resistente al cosiddetto "length extension attack" --> https://en.wikipedia.org/wiki/Length_extension_attack)
4. Calcolare s = k^-1 * (r*d + e) mod n
(ritorna al passo 1 se s = 0)
5. La firma è la coppia (r, s)
Osservazioni:
tutte le operazioni (a parte il passaggio 2) si fanno sugli scalari, quindi si lavora sempre modulo n (non p!)
r è la coordinata x di un punto del tutto casuale della curva che si ottiene moltiplicando G per uno scalare k generato al momento (scalare che si può vedere come un'altra chiave privata "usa e getta" generata al volo per l'occasione); r è la prima parte della firma
s è ottenuto a partire dalla coordinata r che viene moltiplicata per la chiave privata d; a questo prodotto viene poi aggiunta l'informazione e che dipende dal messaggio m (e = sha256(sha256(m))); il tutto è moltiplicato per l'inverso di k modulo n;
s è ottenuto quindi a partire da r, per mezzo del messaggio m e della chiave privata d
la verifica consiste nel procedimento inverso: si parte da s e si ricostruisce r usando il messaggio m e la chiave pubblica P corrispondente alla chiave privata d (nella verifica non si utilizza mai nè la chiave privata d nè il numero casuale k, che devono rimanere sconosciuti!)
Nota bene: firmare due transazioni con lo stesso numero k casuale (che produce quindi lo stesso valore di r) rende immediatamente ricavabile dalla chiave pubblica la chiave privata:
http://www.nilsschneider.net/2013/01/28/recovering-bitcoin-private-keys.htmlproblemi legati a cattive firme:
https://bitcointalk.org/index.php?topic=271486.msg2907468#msg2907468
Verifica della firma digitale mediante la chiave pubblicaVERIFICA DELLA FIRMA DIGITALE MEDIANTE LA CHIAVE PUBBLICA
Algoritmo di verifica della firma
Date la coppia di firme (r, s) del messaggio m and la chiave pubblica P:
1. Controllare che r e s appartengano entrambi all'intervallo [1,n-1]
2. Calcolare e = hash(m)
3. Calcolare w = s^-1 mod n
(qui si utilizza la seconda parte della firma)
4. Calcolare u1 = e*w mod n, u2 = r*w mod n
(qui si utilizza il messaggio m e la seconda parte della firma per u1, entrambe le parti della firma per u2)
5. Calcolare il punto X = (x0,y0) = u1*G + u2*P
(se X è il punto all'infinito rifiuta; questo è il punto dove si utilizza la chiave pubblica P )
6. Convertire x0 in un intero e porre v = x0 mod n.
7. Confronta v e r, se v = r allora la firma è corretta.
------------------------------------------------------------------------------------------------------------
Dimostriamo perchè questa verifica è corretta:
Notiamo innanzitutto che k = u1+u2*d, infatti:
k = s^-1 * (e + r*d) (vedi punto 4 dell'algoritmo di firma)
= s^-1*e + s^-1 * r*d = u1 + u2*d mod n (ricordiamo che u1=s^-1*e , u2=s^-1*r )
Quindi X = u1*G + u2*P = u1*G + u2*d*G = (u1+u2*d)*G = k*G = X1 (ricordiamo che P = d*G , X1 = k*G), ovvero
X = X1-------------------------------------------------------------------------------------------------------------
Nota bene: chi verifica non calcola mai esplicitamente nè k nè d, queste due informazioni rimangono sempre ignote;
chi verifica spezza il percorso che lo porta a X in due parti, cioè decompone k che non conosce in due parti: k = u1 + u2*d (il verificatore calcola solo u1 e u2, non conosce d e quindi nemmeno k!)
u1 = s^-1*e (termine che usa il contributo del messaggio e serve per muoversi dal generatore G verso X)
u2 = s^-1 * r (questa parte serve per muoversi da P invece che da G sempre per raggiungere X; in questo modo il risultato corretto è ottenuto pur non conoscendo la chiave privata d)
Il verificatore grazie a s, che condensa diverse informazioni, riesce a determinare i seguenti due punti,
A = u1*G e B = u2*P
la somma di questi due punti deve dare finalmente X
Alla fine si ottiene quindi che il verificatore ha ricostruito con le informazioni in suo possesso l'identità del punto X che coincide con il punto X1 da cui è partito colui che ha fatto la firma, quindi
x0 = x1 (
v = r mod n )
Riassumendo:
chi fa la firma determina un punto X casuale e fornisce pubblicamente la posizione di X (prima parte della firma), il messaggio, la chiave pubblica e un valore s (seconda parte della firma) che dipende dalla posizione di X, dal messaggio e dalla chiave privata d
chi verifica l'autenticità del messaggio, verifica se, partendo dalla seconda parte della firma s, riesce a invertire il processo per riottenere la prima parte della firma r (che corrisponde alla posizione di X, già nota); per invertire questo processo deve utilizzare due informazioni base: il messaggio m e la chiave pubblica P.
Note finali:1) quando si firma un messaggio vero e proprio (non una transazione) con un client bitcoin tipo Bitcoin Core viene richiesto esplicitamente di inserire l'indirizzo di chi sta firmando. Bitcoin Core infatti provvede a recuperare la chiave privata associata all'indirizzo in automatico (NB: è possibile firmare solo con un indirizzo di cui si possiede la chiave privata!).
Anche nel caso della verifica, però, viene richiesto solo l'indirizzo, non la chiave pubblica. Ma come è possibile recuperare la chiave pubblica dall'indirizzo? In generale non è possibile. Però nel caso in cui si abbiano a disposizione, oltre all'indirizzo, la firma e il messaggio stesso allora si può ricostruire la chiave pubblica, infatti:
X = u1*G + u2*P --> X = s^-1*e*G + s^-1*r*P
in quest'ultima equazione il destinatario del messaggio che deve effettuare la verifica ha a disposizione tutti i valori tranne uno, P, che costituisce quindi l'incognita dell'equazione e che si ricava quindi in funzione degli altri dati:
s*X = e*G + r*P
r*P = s*X - e*G
P = r^-1 (s*X - e*G)A questo punto chi verifica si limita a trasformare la chiave pubblica P nell'indirizzo corrispondente e a controllare infine se quest'ultimo coincide con l'indirizzo che gli è stato trasmesso.
Quindi
nel caso di un messaggio normale firmato con una chiave bitcoin la verifica non consiste più nel ricavare r a partire da s e da P (oltre che da m), ma invece
consiste nel ricavare la chiave pubblica P dalla firma r,s (e dal messaggio m) e nel confrontare quindi l'indirizzo che P genera con quello inviato in chiaro dal firmatario.
2) se (r,s) è una firma valida per il messaggio m, lo è anche (r,-s) (sostanzialmente il verificatore che parte da -s trova -X1, ma due punti opposti X1 e -X1 hanno sempre la stessa ascissa, quindi anche da -s si riottene sempre r).
Questo fatto consentiva, fino a qualche tempo fa, di prendere una transazione che arrivava nella mempool (quindi una transazione non ancora confermata) e modificare il segno di s. Questa modifica non cambiava di una virgola address di partenza, importo e address di arrivo della transazione, ma provocava un cambio del TXID (cioè del codice identificativo della transazione), che è un hash della transazione intera, firma compresa. In questo caso si parla di "
Transaction Malleability".
Bitcoin Core dalla versione 0.11.1 non consente più questa flessibilità che poteva portare problemi:
Inherent ECDSA signature malleability We require that the S value inside ECDSA signatures is at most the curve order divided by 2 (essentially restricting this value to its lower half range). See reference: Low S values in signatures
quindi all'algoritmo della firma, per precisione, va aggiunto adesso un ulteriore passaggio:
se s è maggiore di (n+1)/2 allora sostituisci s con (n - s)
le versioni più recenti di Bitcoin Core non propagano più quindi transazioni nelle quali le firme presentano una s maggiore di (n+1)/2.
Esempio pratico di firma e verifica utilizzando l'algoritmo ECDSA applicato alla curva secp256k1