Procedimientos de firma

SLH-DSA explicado matemáticamente

Cómo firma SLH-DSA-SHA2-256f (FIPS 205) sin ningún otro problema difícil que las funciones hash — desde las cadenas de hash y los árboles de Merkle hasta el bosque de árboles FORS.

Actualizado: 2026-11-09

1. De qué trata esto

En McGesund, los clientes de las tarifas Reseñas Premium y Señales Premium pueden elegir el nivel de firma PQ-Dual-Diversified. Entonces cada código QR lleva, además de la firma clásica Ed25519, dos firmas resistentes a la computación cuántica: ML-DSA-87 y SLH-DSA-SHA2-256f.

Este artículo explica la segunda. Está construida de forma distinta a todo lo demás que utilizamos.

SLH-DSA no es un cifrado. El contenido sigue siendo legible públicamente. SLH-DSA demuestra origen e integridad — como cualquier firma digital.

SLH-DSA significa Stateless Hash-Based Digital Signature Algorithm. Se desarrolló a partir de SPHINCS+ y se estandarizó en 2024 como FIPS 205. El nombre ya delata lo que tiene de especial: el procedimiento utiliza únicamente funciones hash. Ni retículos, ni curvas elípticas, ni grandes números primos.


2. ¿Qué se firma exactamente?

En McGesund, SLH-DSA firma el mismo conjunto de datos que cubre la firma Ed25519 del código QR: el payload del código QR. Contiene, entre otras cosas, a qué empresa pertenece el código (fid), de qué tipo es (typ), cuándo se emitió (iat) y hasta cuándo es válido (exp) — como una secuencia de bytes codificada de forma compacta (CBOR).

Esta secuencia de bytes es nuestro mensaje MM. Si alguien modifica después un solo bit, ninguna de las firmas encaja ya.

La firma SLH-DSA no va dentro del propio código QR. Con unos 49 KB es demasiado grande para eso. Se guarda como «sello» independiente junto al registro QR en el backend de McGesund y se carga en el navegador al hacer clic en «Comprobar autenticidad».


3. ¿Por qué un procedimiento basado solo en funciones hash?

Todo procedimiento de firma se basa en una tarea que, sin la clave secreta, es prácticamente irresoluble:

ProcedimientoLa seguridad se basa en
Ed25519el logaritmo discreto en una curva elíptica
FALCONvectores cortos en retículos NTRU
ML-DSAModule-LWE y Module-SIS (retículos)
SLH-DSAsolo en propiedades de la función hash

Un ordenador cuántico grande rompería Ed25519. FALCON y ML-DSA se consideran resistentes a la computación cuántica — pero ambos se apoyan en problemas de retículos. Si algún día se descubriera un ataque fundamental contra los retículos, ambos se verían afectados a la vez.

SLH-DSA, en cambio, solo necesita que la función hash haga aquello para lo que fue construida:

A partir de H(x) no se puede recalcular x, y nadie encuentra un segundo x′ con H(x′)=H(x).\text{A partir de } H(x) \text{ no se puede recalcular } x \text{, y nadie encuentra un segundo } x' \text{ con } H(x') = H(x) \text{.}

Es la suposición estudiada durante más tiempo y con mayor profundidad de toda la criptografía. Incluso un ordenador cuántico ayuda aquí solo de forma limitada: el algoritmo de Grover reduce a la mitad los bits de seguridad. Por eso la variante 256 usa valores hash de n=32n = 32 bytes =256= 256 bits — después de Grover siguen quedando 128 bits.

Precisamente por eso el nivel se llama Diversified: ML-DSA (retículos) y SLH-DSA (hash) proceden de familias matemáticas distintas. Si una cae, la otra sigue sosteniendo.


4. Pieza 1: firmar con cadenas de hash (WOTS+)

La idea básica es sorprendentemente sencilla. Empezamos con una sola cifra.

Toma un valor aleatorio secreto ss y aplícale el hash una y otra vez:

s  →  H(s)  →  H2(s)  →  …  →  H15(s)=ps \;\to\; H(s) \;\to\; H^2(s) \;\to\; \dots \;\to\; H^{15}(s) = p

El final de la cadena, pp, se publica. Es la clave pública para esta única cifra.

Para firmar una cifra dd entre 0 y 15, se revela el valor de la cadena en la posición dd:

σ=Hd(s)\sigma = H^{d}(s)

Quien quiera verificar aplica el hash a σ\sigma otras 15−d15 - d veces. Si sale exactamente pp, la firma es auténtica:

H15−d(σ)=?pH^{15-d}(\sigma) \stackrel{?}{=} p

Un ejemplo mínimo

Firmamos la cifra d=6d = 6:

  • El firmante publica σ=H6(s)\sigma = H^6(s).
  • El verificador calcula H9(σ)=H15(s)H^{9}(\sigma) = H^{15}(s) y lo compara con pp. Encaja.

Un falsificador que haya visto σ\sigma puede calcular sin esfuerzo H7(s)H^7(s), H8(s)H^8(s), etc. — es decir, firmar cifras mayores. Cifras menores no puede, porque para ello tendría que aplicar el hash hacia atrás.

La suma de control contra el «contar hacia arriba»

Para que nadie pueda simplemente aumentar cifras, se firma además una suma de control:

C=∑i(15−di)C = \sum_{i} (15 - d_i)

Si un falsificador aumenta una cifra del mensaje, CC se vuelve menor — y para ello tendría que calcular hacia atrás en la cadena de la suma de control. Así quedan bloqueadas ambas direcciones.

Extrapolado a un valor hash

Un valor hash de 32 bytes tiene 64 cifras en base 16. A ellas se suman 3 cifras de suma de control:

len=64+3=67 cadenas\text{len} = 64 + 3 = 67 \text{ cadenas}

Una firma así se llama WOTS+ (Winternitz One-Time Signature). Su gran inconveniente está en el nombre: One-Time, de un solo uso. Quien firma dos mensajes distintos con la misma clave revela tantos valores de cadena que las falsificaciones se vuelven posibles.


5. Pieza 2: muchas claves de un solo uso bajo un mismo techo (árbol de Merkle)

Si cada clave solo puede usarse una vez, se necesitan muchísimas — pero se quiere publicar solo una clave pública.

La solución es un árbol de Merkle: las claves públicas de 2h′2^{h'} pares WOTS+ forman las hojas. Cada dos vecinas se pasan juntas por el hash, los resultados de nuevo por parejas, hasta que arriba queda una única raíz.

nodo=H(izquierda ∥ derecha)\text{nodo} = H(\text{izquierda} \,\|\, \text{derecha})

En SLH-DSA-SHA2-256f, cada árbol tiene la altura h′=4h' = 4, es decir, 24=162^4 = 16 hojas.

Para demostrar que una hoja concreta pertenece al árbol, se entrega la ruta de autenticación: los 4 nodos hermanos en el camino hacia arriba. Con ellos, el verificador va calculando hashes desde la hoja hasta la raíz. Si sale la raíz conocida, la hoja pertenece al árbol.


6. Pieza 3: árboles sobre árboles (hiperárbol)

Dieciséis claves de un solo uso, por supuesto, no bastan. Por eso SLH-DSA apila árboles unos encima de otros: la raíz de un árbol se firma con una clave WOTS+ del árbol de encima. Esta torre se llama hiperárbol.

En SLH-DSA-SHA2-256f hay d=17d = 17 capas, cada una de altura 4:

h=d⋅h′=17⋅4=68h = d \cdot h' = 17 \cdot 4 = 68

Así, en la base quedan disponibles

268≈2,95⋅10202^{68} \approx 2{,}95 \cdot 10^{20}

hojas. La raíz del árbol superior se llama PK.root\text{PK.root} — es la clave pública propiamente dicha.

Importante: nadie calcula estos árboles de antemano. Todos los valores secretos se derivan cuando hacen falta a partir de una semilla secreta SK.seed\text{SK.seed}. Solo se almacenan cuatro valores de 32 bytes cada uno:

ParteContenidoTamaño
SK.seedsemilla para todos los valores secretos de las cadenas32 B
SK.prfsemilla para el componente aleatorio RR32 B
PK.seedsemilla pública, separa unos pares de claves de otros32 B
PK.rootraíz del árbol superior32 B

La clave privada consta de los cuatro (128 bytes); la pública, solo de PK.seed y PK.root (64 bytes).


7. Pieza 4: un bosque contra los aciertos casuales (FORS)

Ahora el verdadero problema: ¿cómo sabe el firmante cuál de las 2682^{68} hojas sigue sin usar?

Los procedimientos basados en hash más antiguos (XMSS, LMS) llevan para ello un contador. Este no debe restablecerse nunca — ni por una copia de seguridad, ni por un segundo servidor. Si aun así ocurre, una clave de un solo uso se utiliza dos veces y el procedimiento queda roto. A estos procedimientos se les llama con estado.

SLH-DSA es sin estado: la hoja se elige de forma pseudoaleatoria a partir del propio mensaje. Entonces puede ocurrir que dos mensajes caigan en la misma hoja. Por eso, en la base no cuelga una firma de un solo uso, sino una firma de pocos usos: FORS (Forest of Random Subsets).

FORS consta de k=35k = 35 pequeños árboles de Merkle con 2a=29=5122^a = 2^9 = 512 hojas cada uno. Las hojas son valores aleatorios secretos.

Para firmar, el hash del mensaje se descompone en 35 números de 9 bits cada uno. Cada número elige exactamente una hoja en «su» árbol. La firma contiene, para cada árbol:

  • el valor secreto de esa hoja
  • su ruta de autenticación (9 nodos)

Para otro mensaje, un falsificador tendría que acertar en los 35 árboles hojas cuyos secretos ya se hubieran revelado. Aunque la misma instancia FORS se haya usado unas cuantas veces, eso no tiene ninguna posibilidad.


8. El proceso completo de firma

  1. Componente aleatorio. A partir de SK.prf\text{SK.prf}, un número aleatorio nuevo y el mensaje se obtiene un valor RR de 32 bytes.
  2. Hash del mensaje.
    digest=Hmsg(R, PK.seed, PK.root, M)\text{digest} = H_{\text{msg}}(R,\ \text{PK.seed},\ \text{PK.root},\ M)
    Los 49 bytes del digest se reparten: 40 bytes eligen las 35 hojas FORS; el resto determina qué árbol (idx_tree) y qué hoja (idx_leaf) de la base del hiperárbol se utilizan.
  3. Firma FORS sobre el mensaje. De ella resulta una clave pública FORS.
  4. Firma del hiperárbol sobre esta clave FORS: 17 firmas WOTS+, cada una con una ruta de autenticación, capa a capa hasta PK.root\text{PK.root}.

La firma terminada es simplemente la concatenación:

σ=R ∥ σFORS ∥ σHT\sigma = R \,\|\, \sigma_{\text{FORS}} \,\|\, \sigma_{\text{HT}}

9. Por qué la firma ocupa 49.856 bytes

Con los parámetros de SLH-DSA-SHA2-256f, el tamaño se puede recalcular exactamente (n=32n = 32 bytes por valor hash):

ParteCálculoBytes
RRnn32
FORSk⋅(1+a)⋅n=35⋅10⋅32k \cdot (1 + a) \cdot n = 35 \cdot 10 \cdot 3211.200
Hiperárbol(h+d⋅len)⋅n=(68+17⋅67)⋅32(h + d \cdot \text{len}) \cdot n = (68 + 17 \cdot 67) \cdot 3238.624
Total49.856

A modo de comparación: una firma Ed25519 ocupa 64 bytes y ML-DSA-87, 4.627 bytes. El tamaño es el precio de que SLH-DSA se las arregle con nada más que funciones hash.


10. Cómo verifica el navegador

En SLH-DSA, verificar significa: volver a calcular hashes.

  1. Recalcular el digest a partir de RR, la clave pública y el mensaje.
  2. A partir de las 35 hojas FORS reveladas y sus rutas, calcular las 35 raíces de los árboles y, con ellas, la clave pública FORS.
  3. Con cada una de las 17 firmas WOTS+, completar el hash de las cadenas hasta el final, formar la clave pública WOTS+ y subir por la ruta calculando hashes hasta la raíz del árbol.
  4. Al final debe salir exactamente PK.root\text{PK.root}.

Son unos pocos miles de llamadas al hash — una nimiedad para un ordenador. En el navegador, la verificación nos lleva entre 6 y 12 milisegundos aproximadamente.


11. ¿Qué ocurre si alguien modifica el conjunto de datos?

Si cambia aunque sea un solo bit del mensaje MM, el digest cambia por completo. Con ello, los 35 números apuntan a otras hojas FORS y el procedimiento, a otro lugar del hiperárbol.

Los secretos revelados ya no encajan: las raíces recalculadas difieren y al final no sale PK.root\text{PK.root}. La verificación falla.

Para construir aun así una firma válida, un atacante tendría que conocer secretos que nunca se han publicado — es decir, calcular una función hash hacia atrás.


12. ¿Por qué precisamente 256f?

FIPS 205 define doce conjuntos de parámetros: dos familias de hash (SHA-2 y SHAKE), tres niveles de seguridad (128, 192, 256) y, para cada uno, una variante rápida («f») y una pequeña («s»).

VarianteFirmaFirmar (en nuestro sistema)Verificar
SHA2-256s29.792 Baprox. 2,6 saprox. 3 ms
SHA2-256f49.856 Baprox. 0,26 saprox. 6 ms

256 significa la categoría de seguridad 5 de NIST — el mismo nivel que FALCON-1024 y ML-DSA-87.

Hemos elegido «f» porque las empresas pueden emitir hasta 500 códigos QR de una sola vez. Con «s», la firma tardaría más de 20 minutos; con «f», menos de un minuto. A cambio, la firma es más grande — como no va dentro del código QR, es asumible.

SHA-2 en lugar de SHAKE, porque SHA-256 y SHA-512 están acelerados por hardware en prácticamente cualquier equipo.


13. El azar al firmar

FIPS 205 permite dos formas de generar RR:

  • determinista: mismo mensaje, misma firma
  • aleatorizada («hedged»): interviene además un número aleatorio nuevo

Utilizamos la variante aleatorizada. Por eso, dos firmas sobre el mismo mensaje tienen un aspecto distinto — y ambas son válidas. Esto dificulta los ataques que combinan mediciones en el dispositivo (consumo eléctrico, tiempo) con firmas repetidas.


14. Qué hace McGesund concretamente con esto

El nivel. PQ-Dual-Diversified está disponible en Reseñas Premium y Señales Premium. Un código QR lleva entonces tres firmas:

FirmaFamiliaUbicación
Ed25519curva elípticaen el código QR
ML-DSA-87retículossello en el backend
SLH-DSA-SHA2-256ffunciones hashsello en el backend

El proceso de firma. Una firma SLH-DSA cuesta aproximadamente un cuarto de segundo de cálculo. Para que mientras tanto el servidor siga disponible para todos los demás, el cálculo lo hacen hilos en segundo plano dedicados.

La verificación. El navegador del lector carga ambos sellos y los verifica con el mismo módulo WASM que todas las demás firmas PQ. Nosotros entregamos los datos; el cálculo se hace en el dispositivo del visitante.

La comprobación con NIST. Nuestro módulo supera los vectores de prueba oficiales de NIST para SLH-DSA-SHA2-256f: a partir de las semillas de NIST se obtienen, byte a byte, las mismas claves, y todas las firmas manipuladas a propósito se rechazan. Puede comprobarlo usted mismo en el navegador en la página de pruebas de NIST.

El ancla temporal. Como con todas las claves, la huella de la clave SLH-DSA se ancla mediante OpenTimestamps en un bloque de Bitcoin.


15. SLH-DSA, ML-DSA y FALCON, uno al lado del otro

PropiedadFALCON (FN-DSA)ML-DSA-87SLH-DSA-SHA2-256f
Baseretículos NTRUretículos de módulossolo funciones hash
EstándarFIPS 206 (en elaboración)FIPS 204, definitivoFIPS 205, definitivo
Clave pública1.793 B2.592 B64 B
Firma1.280 B4.627 B49.856 B
Firmarmilisegundosmilisegundosaprox. 0,26 s
Verificarmilisegundosmilisegundosmilisegundos
Suposiciónproblema de retículosproblema de retículosfunción hash

En pocas palabras: SLH-DSA es el más lento y el más grande de los tres procedimientos — y el más conservador. No se apoya en nada que cualquier otra firma no presuponga ya de todos modos: una función hash segura.


16. Una frase para llevarse

SLH-DSA firma con cadenas de hash, las agrupa en aˊrboles de Merkley elige la hoja a partir del propio mensaje — segura mientrasla funcioˊn hash sea segura.\boxed{ \begin{array}{c} \text{SLH-DSA firma con cadenas de hash, las agrupa en árboles de Merkle}\\ \text{y elige la hoja a partir del propio mensaje — segura mientras}\\ \text{la función hash sea segura.} \end{array}}

Quien posee la semilla secreta firma en un cuarto de segundo. Quien no la posee tendría que calcular SHA-256 o SHA-512 hacia atrás — incluso con un ordenador cuántico.

Para el lector de una valoración, eso significa: aunque algún día cayeran todos los procedimientos basados en retículos, esta firma seguiría siendo verificable. No tiene que creernos. Puede recalcularlo.