Saltar al contenido
ecdsa.com
C

liboqs (Open Quantum Safe)

liboqs, la biblioteca en C de criptografía poscuántica (KEM y firmas) del proyecto Open Quantum Safe: ML-KEM, ML-DSA y SLH-DSA junto a una larga lista de candidatos tras una sola API, pensada, según sus autores, para investigación y prototipos.
Licencia
MIT
Versión comprobada
0.16.0 ·
Código fuente
github.com/open-quantum-safe/liboqs
Documentación
openquantumsafe.org/liboqs/

Compatibilidad de un vistazo

Criptografía poscuántica

EdDSA
none
Algoritmos poscuánticos
ML-KEMML-DSASLH-DSAFalconHQCClassic-McElieceFrodoKEMBIKENTRUsntrup761KyberMAYOCROSSUOVSNOVAMQOM

liboqs reúne implementaciones poscuánticas de mecanismos de encapsulación de claves (OQS_KEM) y esquemas de firma (OQS_SIG) tras una única API en C, y es el motor del proveedor Open Quantum Safe para OpenSSL 3. Los datos de esta página se comprobaron en la versión 0.16.0 (commit 5a1a854b0dc9), compilada con las opciones predeterminadas de CMake, que usan OpenSSL para las primitivas simétricas. El README dice, en mayúsculas: «ACTUALMENTE NO RECOMENDAMOS CONFIAR EN ESTA BIBLIOTECA EN UN ENTORNO DE PRODUCCIÓN NI PARA PROTEGER NINGÚN DATO SENSIBLE». Para ML-KEM y ML-DSA en producción, las páginas de OpenSSL, BoringSSL, AWS-LC y Bouncy Castle indican qué ofrecen sus API principales.

La compilación predeterminada activó 41 KEM y 221 conjuntos de parámetros de firma, y un conjunto de parámetros de cada familia superó una prueba de ida y vuelta completa: los estándares del NIST ML-KEM, ML-DSA y SLH-DSA (156 variantes de SLH-DSA, puras y pre-hash), Falcon, los candidatos a KEM HQC, Classic McEliece, FrodoKEM, BIKE, NTRU y sntrup761, el Kyber previo al estándar y los candidatos adicionales de firma MAYO, CROSS, UOV, SNOVA y MQOM. En código nuevo, usa el nombre ML-KEM-768, no Kyber768. La compilación predeterminada no activa ningún conjunto de parámetros XMSS ni LMS.

La firma ML-DSA es hedged (reforzada con aleatoriedad): dos firmas del mismo mensaje con la misma clave fueron distintas, así que las pruebas deben verificar las firmas en lugar de comparar bytes. Las cadenas de contexto de FIPS 204 se admiten mediante OQS_SIG_sign_with_ctx_str; una firma hecha con el contexto invoice-v1 falló con invoice-v2 y con OQS_SIG_verify a secas, que usa el contexto vacío, así que ambas partes deben acordarlo. Una firma truncada, un blob de 3 bytes y una firma válida sobre otros datos devolvieron todos el mismo OQS_ERROR.

La desencapsulación ML-KEM no avisa de un texto cifrado dañado: con un bit invertido, OQS_KEM_decaps devolvió OQS_SUCCESS y un secreto compartido distinto, como exige el rechazo implícito de FIPS 203. La discrepancia solo aparece al usar las claves derivadas, por ejemplo como un fallo de descifrado AEAD. Además, la función no recibe la longitud del texto cifrado y lee exactamente length_ciphertext bytes, 1088 en ML-KEM-768. Prueba ambos esquemas en la herramienta de ML-KEM y en la herramienta de firmas poscuánticas.

Datos y las comprobaciones que los respaldan

Nada de lo que sigue está copiado de la documentación. La comprobación content/libraries/verify/liboqs/run.sh ejecutó liboqs (Open Quantum Safe) 0.16.0 en la imagen de contenedor debian:trixie-20261005-slim el 20 de octubre de 2026; la página debe coincidir con lo que imprimió, y cada dato cita esas líneas.

  • Curvas ECDSA

    none

    Sin ECDSA: todos los identificadores de algoritmo activados pertenecen a una familia poscuántica.

    Registrado por la comprobación
    fact ecdsa-curves = none
  • EdDSA

    none

    Sin EdDSA: liboqs solo implementa esquemas poscuánticos.

    Registrado por la comprobación
    fact eddsa = none
  • Algoritmos poscuánticos

    ML-KEMML-DSASLH-DSAFalconHQCClassic-McElieceFrodoKEMBIKENTRUsntrup761KyberMAYOCROSSUOVSNOVAMQOM

    En la compilación predeterminada, un conjunto de parámetros de cada familia de la lista completó la generación de claves, la encapsulación o la firma, y la desencapsulación o la verificación.

    Registrado por la comprobación
    fact pqc = ML-KEM, ML-DSA, SLH-DSA, Falcon, HQC, Classic-McEliece, FrodoKEM, BIKE, NTRU, sntrup761, Kyber, MAYO, CROSS, UOV, SNOVA, MQOM
    evidence pqc: enabled: 41 KEMs, 221 signature schemes, 0 stateful signature schemes
    evidence pqc: enabled parameter sets by identifier prefix: ML-KEM- 3, ML-DSA- 3, SLH_DSA 156, Falcon- 4, HQC- 3, Classic-McEliece- 10, FrodoKEM- 6, eFrodoKEM- 6, BIKE- 3, NTRU- 6, sntrup 1, Kyber 3, MAYO- 4, cross- 18, OV- 12, SNOVA 12, mqom2 12
    evidence pqc: first parameter set of each family run end to end; failures: none
  • Firmas basadas en hash con estado

    not-built

    La compilación predeterminada no activa ningún conjunto de parámetros XMSS ni LMS.

    Registrado por la comprobación
    fact stateful-signatures = not-built
    evidence stateful-signatures: no XMSS or LMS parameter set is enabled in this build
  • Modo de firma de ML-DSA

    hedged

    Dos firmas ML-DSA-65 de un mismo mensaje con la misma clave fueron distintas (firma hedged).

    Registrado por la comprobación
    fact ml-dsa-signing = hedged
    evidence ml-dsa-signing: ML-DSA-65: public key 1952 bytes, signature 3309 bytes; two signatures of one message are different
  • Cadena de contexto de ML-DSA

    supported

    Una firma con el contexto invoice-v1 se verificó con él y falló con invoice-v2 y con el contexto vacío.

    Registrado por la comprobación
    fact ml-dsa-context-string = supported
    evidence ml-dsa-context-string: signed with context "invoice-v1": verifies with it yes, with "invoice-v2" no, with OQS_SIG_verify no
    evidence ml-dsa-context-string: an OQS_SIG_sign signature verifies with a zero-length context: yes
  • Firma ML-DSA mal formada

    returns-false

    Una firma truncada, 3 bytes y un mensaje incorrecto devolvieron todos OQS_ERROR (-1).

    Registrado por la comprobación
    fact ml-dsa-malformed-signature = returns-false
    evidence ml-dsa-malformed-signature: OQS_SIG_verify: truncated signature -1, 3 bytes -1, wrong message -1 (OQS_SUCCESS = 0, OQS_ERROR = -1)
  • Texto cifrado de ML-KEM modificado

    implicit-rejection

    Con un bit del texto cifrado invertido, OQS_KEM_decaps devolvió OQS_SUCCESS y un secreto compartido distinto.

    Registrado por la comprobación
    fact ml-kem-modified-ciphertext = implicit-rejection
    evidence ml-kem-modified-ciphertext: ML-KEM-768 (public key 1184, ciphertext 1088 bytes): one flipped bit, OQS_KEM_decaps returned 0 and the secrets differ
    evidence ml-kem-modified-ciphertext: kem.h: OQS_API OQS_STATUS OQS_KEM_decaps(const OQS_KEM *kem, uint8_t *shared_secret, const uint8_t *ciphertext, const uint8_t *secret_key)

Uso

Ejecuta un intercambio de claves ML-KEM-768 y firma y verifica con ML-DSA-65 usando una cadena de contexto.
#include <oqs/oqs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    OQS_init();
    /* ML-KEM-768: the receiver publishes pk, the sender encapsulates a fresh secret to it. */
    OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_ml_kem_768);
    uint8_t *pk = malloc(kem->length_public_key), *sk = malloc(kem->length_secret_key);
    uint8_t *ct = malloc(kem->length_ciphertext), sent[32], received[32];
    OQS_KEM_keypair(kem, pk, sk);
    OQS_KEM_encaps(kem, ct, sent, pk);
    /* Decapsulation never reports a damaged ciphertext: it yields a different secret instead. */
    OQS_KEM_decaps(kem, received, ct, sk);
    printf("ML-KEM-768 secrets match: %d\n", memcmp(sent, received, 32) == 0);

    /* ML-DSA-65 with a FIPS 204 context string that ties the signature to one purpose. */
    OQS_SIG *sig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_65);
    uint8_t *vk = malloc(sig->length_public_key), *dk = malloc(sig->length_secret_key);
    uint8_t *s = malloc(sig->length_signature);
    const uint8_t msg[] = "order #1042 approved", ctx[] = "invoice-v1";
    size_t len = 0;
    OQS_SIG_keypair(sig, vk, dk);
    OQS_SIG_sign_with_ctx_str(sig, s, &len, msg, sizeof msg - 1, ctx, sizeof ctx - 1, dk);
    OQS_STATUS rc = OQS_SIG_verify_with_ctx_str(sig, msg, sizeof msg - 1, s, len, ctx, sizeof ctx - 1, vk);
    printf("ML-DSA-65 verified: %d (%zu-byte signature)\n", rc == OQS_SUCCESS, len);

    OQS_MEM_secure_free(sk, kem->length_secret_key);
    OQS_MEM_secure_free(dk, sig->length_secret_key);
    free(pk), free(ct), free(vk), free(s);
    OQS_KEM_free(kem), OQS_SIG_free(sig);
    OQS_destroy();
    return 0;
}

El arnés de pruebas de fragmentos de código ejecuta cada ejemplo tal cual en la imagen de contenedor debian:trixie-20261005-slim, y la ejecución falla si la salida no coincide.

Configuración
apt-get -qq update >/dev/null && apt-get -qq install -y --no-install-recommends build-essential cmake ninja-build git ca-certificates libssl-dev >/dev/null 2>&1 && git clone -q --depth 1 --branch 0.16.0 https://github.com/open-quantum-safe/liboqs /oqs 2>/dev/null && test "$(git -C /oqs rev-parse HEAD)" = 5a1a854b0dc9f2141bdc771c555ee60c37950183 && cmake -S /oqs -B /oqs/build -G Ninja -DOQS_BUILD_ONLY_LIB=ON >/dev/null 2>&1 && ninja -C /oqs/build install >/dev/null
Comando
cc -o usage usage.c -loqs -lcrypto && ./usage
La salida debe coincidir (expresión regular)
ML-KEM-768 secrets match: 1\nML-DSA-65 verified: 1 \(3309-byte signature\)

Bibliotecas