Capítulo 03 de 10 · 12 min de lectura
Claves, firmas y direcciones
En una blockchain no hay usuarios, ni contraseñas, ni nadie que te dé de alta. Hay un número secreto que eliges tú, y unas matemáticas que permiten demostrar que lo tienes sin enseñarlo.
Ni usuarios ni contraseñas
En el capítulo anterior vimos que un hash identifica un dato, pero no dice de quién es. Un banco resuelve el “de quién” con una lista de clientes y una contraseña para cada uno. Una blockchain no puede: no hay nadie que lleve esa lista, y una contraseña solo sirve si se la enseñas a alguien que la compruebe… alguien en quien tendrías que confiar.
Lo que se necesita es poder demostrar ante todo el mundo que eres el dueño de una moneda sin revelar el secreto que te hace dueño. Parece imposible, y es exactamente lo que hace la criptografía de clave pública.
Un par de claves
Todo empieza con un número:
- La clave privada es un número de 256 bits elegido completamente al azar. Nada más. Nadie te lo asigna, no se registra en ningún sitio, y generarlo no requiere ni conexión a internet. Hay tantas posibles (unas 1077, otra vez el número de átomos del universo) que es imposible que dos personas elijan la misma por casualidad.
- La clave pública se calcula a partir de la privada, con una operación que es fácil en un sentido e impracticable en el otro. La puede ver todo el mundo.
Esa operación ocurre sobre una curva elíptica, que en Bitcoin y en xavicoin se llama secp256k1. Sin entrar en las matemáticas: la curva tiene un punto de partida conocido por todos, G, y una forma de “sumar” puntos. La clave pública es el resultado de sumar G consigo mismo tantas veces como diga la clave privada:
clave pública = clave privada × G
Hay un atajo para calcular esa multiplicación en un instante aunque el número sea astronómico. Para la operación inversa —dado el resultado, averiguar cuántas veces se sumó— no se conoce ninguno. Es la misma asimetría que en los hashes: un camino cuesta microsegundos y el otro, más que la edad del universo.
Genera tus propias claves. Son reales, y se crean en tu navegador: nada sale de tu ordenador.
1 Tu llavero
- Clave privada secreta · 32 bytes al azar
- Activa JavaScript para usar la demo.
- Clave pública 33 bytes · se puede enseñar a todo el mundo
- Hash de la clave pública 20 bytes
- Dirección lo que le das a quien te va a pagar
↓ multiplicar por un punto de la curva elíptica · sin vuelta atrás
↓ SHA-256 y después RIPEMD-160 · sin vuelta atrás
↓ versión + código de control + Base58 · solo cambia el formato
2 Firmar
Firma
Aún no has firmado nada.
3 Verificar · lo que hace cualquier nodo, sin conocer tu clave privada
—Firma el mensaje y después intenta hacer trampa: cambia una letra del mensaje, o deja que firme un impostor.
Qué garantiza una firma
Juega con el paso 3 de la demo hasta que veas fallar la verificación de las dos formas posibles. Una firma digital es un número que se calcula a partir de dos cosas: el mensaje y la clave privada. Y tiene tres propiedades que juntas la hacen mucho mejor que una firma de bolígrafo:
- Autenticidad. Solo quien tiene la clave privada puede producir una firma que verifique con su clave pública. El impostor firma perfectamente… pero con su clave, y eso no cuela.
- Integridad. La firma vale para ese mensaje exacto. Cambia
12.5por92.5y deja de valer. No se puede recortar la firma de un pago y pegarla en otro. - Verificable por cualquiera, sin secretos. Para comprobarla bastan el mensaje, la firma y la clave pública. Quien verifica no aprende nada sobre la privada, ni aunque vea millones de firmas.
Dos detalles que parecen menores y no lo son
La firma es determinista. El algoritmo de firma (ECDSA) necesita internamente un número aleatorio de un solo uso. Si alguna vez se repite, o es predecible, se puede calcular la clave privada a partir de dos firmas. No es teoría: así se rompió la seguridad de la PlayStation 3 en 2010, y así se robaron bitcoins de wallets de Android en 2013 por culpa de un generador de números aleatorios defectuoso. La solución moderna es no usar azar: ese número se deriva del mensaje y de la clave (estándar RFC 6979). Por eso en la demo, si firmas dos veces el mismo mensaje, sale exactamente la misma firma.
Solo vale una de las dos formas de la firma. Por cómo funciona la curva, si una firma (r, s) es válida, (r, −s) también lo es. Permitir las dos dejaría que un tercero alterase una firma ajena sin invalidarla. Bitcoin acabó exigiendo siempre la s “baja”, y xavicoin hace lo mismo.
De la clave pública a la dirección
A quien te va a pagar no le das tu clave pública, sino tu dirección, que se obtiene en dos pasos (los dos últimos de la demo):
- Se hashea la clave pública con SHA-256 y después RIPEMD-160: el
Hash160del capítulo anterior. Quedan 20 bytes. Así la dirección es más corta, y la clave pública no se revela hasta el momento de gastar. - Se le da un formato a prueba de errores humanos, llamado Base58Check:
- delante se añade un byte de versión, que identifica la red (en la devnet de xavicoin es
0x4b, y por eso las direcciones empiezan porX; en Bitcoin es0x00y empiezan por1); - detrás se añaden 4 bytes de código de control: los primeros del doble SHA-256 de todo lo anterior;
- y el conjunto se escribe en Base58, un alfabeto de letras y números del que se han quitado los cuatro caracteres que más se confunden al copiar a mano:
0,O,Iyl.
- delante se añade un byte de versión, que identifica la red (en la devnet de xavicoin es
Una transferencia en una blockchain no se puede deshacer, y no hay un teléfono de atención al cliente. Si te equivocas en una letra y esa dirección no es de nadie, el dinero se pierde para siempre. El código de control existe para que eso no pase: prueba a estropear esta dirección.
Activa JavaScript para usar el validador.
Con 4 bytes de control, una errata al azar pasa inadvertida una vez de cada 4.300 millones.
Una wallet es un llavero
Ahora se entiende algo que suele sorprender: una wallet no contiene monedas. Contiene claves. Las monedas están en la cadena, a la vista de todos, cada una asociada a un hash de clave pública. Tu “saldo” es la suma de las monedas que tus claves pueden firmar.
De ahí salen las dos reglas de oro, que no tienen excepción:
- Si pierdes la clave privada, pierdes las monedas. No hay “he olvidado mi contraseña”: nadie más la tuvo nunca. Se estima que varios millones de bitcoins son irrecuperables por esto.
- Si alguien copia tu clave privada, las monedas son suyas. No hace falta que te la quite; le basta con verla. Y no hay forma de demostrar que el ladrón no eres tú: para la red, quien firma es el dueño.
En xavicoin la wallet vive en el programa cliente (cli), no en el nodo: el nodo valida firmas, pero jamás ve una clave privada. La wallet es un fichero con las claves en hexadecimal:
{
"network": "devnet",
"keys": ["3c1f…a9e2"]
}
Cómo se usa para proteger una moneda
Aquí encajan las piezas de los tres capítulos. Cuando alguien te paga, la moneda nueva lleva escrito el hash de tu clave pública: es un candado que solo tu clave abre. Para gastarla, tu transacción tiene que aportar dos cosas: tu clave pública y una firma de la transacción. Cada nodo de la red comprueba entonces, por su cuenta, exactamente esto:
// internal/chain/validate.go
if crypto.PubKeyHash(crypto.Hash160(in.PubKey)) != utxo.Out.PubKeyHash {
return 0, ruleErrorf("la clave pública de la entrada %d no es la del dueño de la salida", i)
}
if !crypto.Verify(in.PubKey, tx.SigHash(i, utxo.Out), in.Signature) {
return 0, ruleErrorf("firma inválida en la entrada %d", i)
}
Dos líneas, dos preguntas: ¿esta clave pública es la del candado? y ¿la firma demuestra que quien gasta tiene la privada correspondiente, y autoriza esta transacción concreta? Si ambas son que sí, el pago es legítimo. En ningún momento ha hecho falta saber quién es nadie.
El código de xavicoin
xavicoin no implementa la curva elíptica a mano, y eso es una lección en sí misma: la criptografía casera es la forma más rápida de perder dinero. Usa la misma librería que btcd, una de las implementaciones de Bitcoin en Go, y se limita a envolverla. Firmar es una línea:
// internal/crypto/keys.go
// Sign firma un hash y devuelve la firma en DER. La firma es determinista
// (RFC 6979) y con S "baja", de modo que cada mensaje tiene una única firma
// canónica por clave.
func (k *PrivateKey) Sign(hash Hash) []byte {
return ecdsa.Sign(k.key, hash[:]).Serialize()
}
Verificar es donde están las precauciones: se rechaza todo lo que no tenga la forma exacta esperada antes de hacer ninguna cuenta.
func Verify(pubKey []byte, hash Hash, sig []byte) bool {
if len(pubKey) != PubKeySize || len(sig) > MaxSignatureSize {
return false
}
pub, err := secp256k1.ParsePubKey(pubKey)
if err != nil {
return false
}
parsed, err := ecdsa.ParseDERSignature(sig)
if err != nil {
return false
}
// Si (r, s) es válida también lo es (r, -s). Exigir la S baja elimina
// esa segunda forma, como hace Bitcoin desde BIP 146.
if s := parsed.S(); s.IsOverHalfOrder() {
return false
}
return parsed.Verify(hash[:], pub)
}
Y el formato de las direcciones es tan corto como su descripción:
// internal/crypto/base58.go
func Base58CheckEncode(version byte, payload []byte) string {
data := make([]byte, 0, 1+len(payload)+4)
data = append(data, version)
data = append(data, payload...)
sum := Hash256(data)
data = append(data, sum[:4]...)
return Base58Encode(data)
}
Lo que viene
Ya sabemos identificar datos (hashes) y demostrar quién autoriza qué (firmas). Falta juntarlo en lo que de verdad se mueve por la red: la transacción. Y ahí hay una sorpresa, porque Bitcoin no guarda saldos: guarda monedas sueltas, que se gastan enteras, como billetes.