5 · Seguridad
En XChain la seguridad es por activo, no por cadena. Cada activo lleva una clase de seguridad mínima, y un activo de alto valor sencillamente no puede existir en el Dominio de datos. Esto vuelve estructuralmente imposibles los ataques de «degradación» y apoya la seguridad del valor en la criptografía y el capital, en lugar de en confiar en un conjunto pequeño de validadores.
Tres capas para el alto valor
Para el alto valor (T0–T1) se combinan tres capas:
- Prueba de validez ZK: ni un comité completamente comprometido puede falsificar un estado inválido; pierde la vivacidad, no la seguridad.
- Restaking global: el fraude en cualquier cadena recorta capital global.
- Watcher / prueba de fraude: detección y desafío.
Los datos de bajo valor (T3–T4) se protegen solo con prueba de publicación. Tres clases de seguridad de cadena cubren todo el rango, y las pessimistic proofs añaden aislamiento de fallos por encima: una cadena defectuosa solo puede perder su propia parte.
| Clase de seguridad | Se aplica a | Qué la respalda | ¿Puede llevar alto valor? |
|---|---|---|---|
| SOVEREIGN | T3–T4 · Dominio de datos | Sus propios validadores + prueba de publicación | No: prohibido estructuralmente por UAC |
| SHARED | T1–T2 · Execution | Partial Set Security — un conjunto de validadores prestado | Sí, hasta el límite de su clase |
| ZK_SECURED | T0–T1 · Settlement / Value | Prueba de validez obligatoria + restaking global + watchers | Sí: la clase más alta |
Figura 5 — Seguridad gastada según el valor: tres capas combinadas para el Dominio de valor, prueba de publicación a secas en el borde.
Lo que cuesta realmente verificar
«Verifica, no vuelvas a ejecutar» no pasa de ser un argumento hasta que alguien lo mide, así que aquí están las cifras. Proceden de la ruta real de verificación Groth16/BN254, la que está fusionada en master y demostrada de extremo a extremo en nodos devnet. ⚠️ No describen la testnet pública, que sigue ejecutando el binario previo a la actualización con un prover MOCK; esa distinción se registra en Estado y Red en Vivo y aquí no se disimula.
| Medido | Valor | Por qué importa |
|---|---|---|
| Verificar un certificado de transición de estado | ~1,19 ms (un emparejamiento BN254, Go puro, dentro de DeliverTx) | Con una cadencia de bloque de 3.000 ms, podrían verificarse ~2.500 certificados por bloque antes de que la verificación sea el cuello de botella |
Calcular la entrada pública MiMC(prev,tx,new) | ~14 µs | La cadena la deriva ella misma, así que una prueba queda atada a una transición y no puede reutilizarse para otra |
Coste de groth16.Verify frente al tamaño del circuito | Constante: independiente del número de entradas públicas y del número de restricciones | Por tanto, la cifra de 1,19 ms también representa la clave de verificación real de SP1, no solo el circuito sustituto actual |
| Generar una prueba (SP1 wrap → Groth16) | ~15,97 M de restricciones, ~21,5 GB de RAM | Fuera de la cadena por construcción: nunca se ejecuta en un validador. Probar exige una red de provers o una máquina de ≥64 GB |
Esa asimetría es justamente el sentido de la arquitectura. Producir una prueba pesa lo bastante como para requerir infraestructura dedicada; comprobar una es lo bastante barato como para ser irrelevante para la cadencia de bloque. Eso es lo que permite que el coste de la Root se mantenga casi constante mientras crece el volumen del borde, y también es la razón por la que la oferta de provers figura abiertamente como problema económico sin resolver en Problemas abiertos en lugar de darse por supuesta.
Cómo se ve el endurecimiento en la práctica
Tres propiedades son estructurales, y cada una se comprobó en lugar de afirmarse:
Determinismo. El verificador no usa coma flotante ni aleatoriedad. No es un detalle estético: si un validador calculara un resultado distinto, el app hash divergiría y la cadena se detendría. Se verifica repitiendo la misma verificación muchas veces con resultados idénticos, más una ejecución de extremo a extremo donde dos validadores llegan al mismo app hash tras verificar una prueba real dentro de un bloque.
Rechazo elegante de la basura. Todo lo que llega de una transacción es entrada hostil, y dentro de DeliverTx un pánico o un bloqueo equivalen a detener la cadena. El fuzzing encontró uno real: el decodificador de pruebas leía un campo nbCommitments no fiable y reservaba memoria a partir de él, de modo que un atacante podía fijarlo en unos cuatro mil millones y provocar una reserva de ~256 GB: una denegación de servicio por transacción que habría parado la cadena. La solución es una guarda de forma determinista aplicada antes de que la prueba llegue a la biblioteca criptográfica (longitud exactamente la esperada, recuento de compromisos cero); los timeouts se descartaron porque romperían el determinismo. Tras el parche: 4,26 millones de ejecuciones limpias de fuzzing, la antigua entrada que bloqueaba conservada como test de regresión que ahora termina en menos de un segundo, y un nodo en vivo que rechaza la entrada maliciosa mientras sigue produciendo bloques.
Pagar por el trabajo que uno provoca. Un hallazgo más sutil: la diferencia de gas entre una prueba real y una MOCK (~48.191 frente a ~40.638) venía casi por completo de almacenar una prueba más grande, no de los ~1,19 ms de CPU que cuesta de verdad la verificación, porque el gas se mide para operaciones de almacenamiento y no para el cálculo puro dentro de un manejador. Un atacante podía así comprar CPU real barata inundando con pruebas bien formadas pero inválidas. La solución es cobrar la verificación de forma explícita, antes de realizarla, para que la comisión refleje el coste impuesto.
Ninguno de estos hallazgos salió de razonar sobre el diseño; salieron de ejecutarlo. Ese es, en un párrafo, el argumento a favor de una testnet pública.
Conclusión: atar una clase de seguridad a cada activo es la clave de bóveda: convierte «no pongas valor donde no toca» de recomendación en garantía estructural. Todas las garantías nombradas hasta ahora —la frontera de Dominios, la separación READ/WRITE, las clases por activo— deben imponerse en algún lugar lo bastante pequeño como para auditarlo y confiar en él. Ese lugar es la cintura estrecha: siete primitivos, especificados a continuación.