Planteamiento y alcance
Implemente un wrapper de verificación de firmas ML-DSA cuyo llamador proporcione el algoritmo, la clave pública, el mensaje, la firma y el contexto. ¿Cómo valida las entradas, previene la reproducción entre protocolos (cross-protocol replay) y diseña los errores y las pruebas?
Qué evalúa el entrevistador
- Reutilizar una implementación validada de FIPS 204 en lugar de reescribir primitivas criptográficas basadas en retículos (lattice cryptography).
- Mantener el identificador de algoritmo, la clave pública, el mensaje, la firma y el contexto como entradas inequívocas.
- Distinguir entre firmas inválidas, entradas mal formadas, algoritmos no soportados y fallas internas sin filtrar detalles confidenciales.
- Utilizar la vinculación de contexto (context binding), una interfaz estrecha y pruebas con vectores para prevenir la reproducción entre protocolos y la desviación de la implementación (implementation drift).
Preguntas de aclaración
- ¿Qué conjunto de parámetros de ML-DSA se utiliza y ha superado la biblioteca la validación de vectores FIPS 204?
- ¿Qué protocolo define el contexto, puede estar vacío y qué codificación y límites de longitud aplican?
- ¿El fallo de verificación es un resultado de negocio ordinario o un evento de alerta y auditoría?
- ¿El mensaje se transmite por secuencias (streamed), se necesita una interfaz de pre-hash y cómo se rotan las claves?
Estructura de respuesta en 30 segundos
Mantendría el wrapper sobre la API de una biblioteca ML-DSA validada. Seleccionaría el conjunto de parámetros a partir de un identificador de algoritmo explícito, validaría las entradas de bytes y el contexto, y pasaría el contexto del protocolo con el mensaje a la verificación. Devolvería únicamente válido, inválido, no soportado o mal formado; nunca devolvería un seguimiento de excepción (exception trace). Probaría vectores oficiales, manipulación (tampering), conjuntos de parámetros erróneos, reproducción entre contextos, longitudes límite, concurrencia y rotación. Las claves privadas y los mensajes completos nunca entran en los logs.
Análisis detallado paso a paso
1. Establecer el límite del wrapper
FIPS 204 define la firma y verificación de ML-DSA; RFC 9882 señala que CMS utiliza el mismo algoritmo de verificación para firmas hedged y deterministas. El código de la aplicación no debe implementar NTT, muestreo (sampling) ni muestreo por rechazo (rejection sampling). Fije la dependencia, el conjunto de parámetros y la interfaz probada de la biblioteca.
2. Validar entradas y contexto
Compruebe que el identificador del algoritmo esté permitido, que los bytes de la clave pública y de la firma coincidan con el conjunto de parámetros seleccionado y que el mensaje cumpla con la política. Codifique el contexto de acuerdo con el protocolo. El contexto no es una etiqueta de log; proporciona separación de dominio para la firma y debe ser el mismo valor acordado por el firmante. Un contexto faltante o erróneo devuelve mal formado o inválido; nunca suponga un contexto vacío.
3. Diseñar una semántica de errores segura
Devuelva un resultado estructurado como valid, invalid, unsupported o malformed en lugar de repetir excepciones de la biblioteca, material de claves o detalles del analizador (parser). Las métricas y auditorías registran únicamente el algoritmo, la versión, la clase de resultado y el id de solicitud. Las fallas internas pasan por un canal de errores controlado y generación de alertas; una caída de la biblioteca no debe disfrazarse como una firma inválida.
4. Asegurar el comportamiento con vectores y pruebas de protocolo
Ejecute primero vectores compatibles con NIST ACVP o FIPS 204, luego pruebe alteraciones de bits (bit flips), truncamiento, diferentes contextos, identificadores de algoritmo incorrectos y claves antiguas. En casos entre protocolos, asegúrese de que el mismo mensaje no sea aceptado bajo un contexto diferente. Use entradas inmutables para llamadas concurrentes, acepte una ventana explícita de claves antiguas durante la rotación y rechace tras la expiración.
Ejemplo de respuesta de alta calidad
Haría de esto un wrapper delgado alrededor de una biblioteca validada, no una reimplementación de ML-DSA. El llamador debe proporcionar un identificador de algoritmo explícito, conjunto de parámetros, clave pública, mensaje, firma y contexto de protocolo. El wrapper valida formatos y tamaños, pasa el mismo contexto a la API de verificación y nunca reintenta con otro conjunto de parámetros ni con un contexto vacío tras un fallo. Devuelve únicamente válido, inválido, no soportado o mal formado; las fallas internas alertan por separado y los logs excluyen claves y mensajes. Los vectores FIPS/ACVP, pruebas de manipulación, truncamiento, reproducción entre contextos, rotación de claves y concurrencia aseguran el comportamiento mientras la versión de la biblioteca y los parámetros se mantienen fijados.
Errores comunes
- Reimplementar NTT, muestreo o muestreo por rechazo de ML-DSA.
- Ignorar el identificador de algoritmo e intentar usar una clave pública a través de distintos conjuntos de parámetros.
- Reintentar con un contexto vacío o alternativo después de que falle la verificación.
- Agrupar fallas de la biblioteca, firmas inválidas y entradas mal formadas en un resultado no justificado.
- Escribir mensajes completos, claves o seguimientos de excepciones en los logs.
- Probar solo el camino feliz (happy path) sin casos con vectores, manipulación, reproducción y rotación.
Preguntas y respuestas de seguimiento
¿Las firmas hedged y deterministas necesitan un código de verificación diferente?
No. RFC 9882 establece que ambas usan el mismo algoritmo de verificación, por lo que el wrapper no debe bifurcarse en dos rutas de verificación según el modo de firma.
¿Por qué el contexto previene la reproducción entre protocolos?
Porque vincula una firma a un dominio de protocolo. El mismo mensaje y clave tienen un significado de verificación diferente bajo contextos distintos; un verificador no debe suponer ni recurrir a valores por defecto cuando falta el contexto.
¿Cómo maneja la actualización de una biblioteca?
Fije el conjunto de parámetros y la versión de la biblioteca, ejecute vectores oficiales y muestras de compatibilidad histórica, y luego realice un despliegue canary del cambio. Registre la versión y la clase de resultado, conservando el verificador anterior hasta que se complete la migración si el comportamiento difiere.