Aller au contenu
ecdsa.com
C

liboqs (Open Quantum Safe)

liboqs, la bibliothèque C du projet Open Quantum Safe consacrée aux KEM et aux signatures post-quantiques : ML-KEM, ML-DSA et SLH-DSA aux côtés d’une longue liste d’algorithmes candidats, derrière une seule API ; selon ses auteurs, elle est destinée à la recherche et au prototypage.
Licence
MIT
Version vérifiée
0.16.0 ·
Code source
github.com/open-quantum-safe/liboqs
Documentation
openquantumsafe.org/liboqs/

Compatibilité en un coup d’œil

Post-quantique

EdDSA
none
Algorithmes post-quantiques
ML-KEMML-DSASLH-DSAFalconHQCClassic-McElieceFrodoKEMBIKENTRUsntrup761KyberMAYOCROSSUOVSNOVAMQOM

liboqs rassemble des implémentations de mécanismes d’encapsulation de clé (OQS_KEM) et de schémas de signature (OQS_SIG) post-quantiques derrière une seule API C, et c’est le moteur du fournisseur Open Quantum Safe pour OpenSSL 3. Les faits présentés ici ont été vérifiés sur la version 0.16.0 (commit 5a1a854b0dc9), compilée avec les options CMake par défaut, qui utilisent OpenSSL pour les primitives symétriques. Le README avertit, en majuscules : « NOUS NE RECOMMANDONS PAS ACTUELLEMENT DE S’APPUYER SUR CETTE BIBLIOTHÈQUE DANS UN ENVIRONNEMENT DE PRODUCTION NI POUR PROTÉGER LA MOINDRE DONNÉE SENSIBLE. » Pour ML-KEM et ML-DSA en production, les pages OpenSSL, BoringSSL, AWS-LC et Bouncy Castle indiquent ce que proposent leurs API principales.

Le build par défaut a activé 41 KEM et 221 jeux de paramètres de signature, et un jeu de paramètres de chaque famille a effectué un aller-retour complet : les normes NIST ML-KEM, ML-DSA et SLH-DSA (156 variantes SLH-DSA, pures et avec pré-hachage), Falcon, les candidats KEM HQC, Classic McEliece, FrodoKEM, BIKE, NTRU et sntrup761, Kyber dans sa version antérieure à la normalisation, ainsi que les candidats de signature supplémentaires MAYO, CROSS, UOV, SNOVA et MQOM. Dans du nouveau code, nommez ML-KEM-768, et non Kyber768. Aucun jeu de paramètres XMSS ou LMS n’est activé dans le build par défaut.

La signature ML-DSA est en mode hedged (avec aléa) : deux signatures du même message avec la même clé différaient, si bien que les tests doivent vérifier les signatures plutôt que comparer des octets. Les chaînes de contexte de FIPS 204 sont prises en charge via OQS_SIG_sign_with_ctx_str ; une signature produite sous le contexte invoice-v1 a échoué sous invoice-v2 et avec le simple OQS_SIG_verify, qui utilise le contexte vide, ce qui oblige les deux parties à s’accorder sur ce contexte. Une signature tronquée, un bloc de 3 octets et une signature valide portant sur d’autres données ont tous renvoyé le même OQS_ERROR.

La décapsulation ML-KEM ne signale pas un texte chiffré endommagé : avec un bit inversé, OQS_KEM_decaps a renvoyé OQS_SUCCESS et un secret partagé différent, comme l’exige le rejet implicite de FIPS 203. La divergence n’apparaît qu’à l’utilisation des clés dérivées, par exemple sous la forme d’un échec de déchiffrement AEAD. La fonction ne prend pas non plus de longueur de texte chiffré et lit exactement length_ciphertext octets, soit 1088 pour ML-KEM-768. Essayez les deux schémas dans l’outil ML-KEM et l’outil de signatures post-quantiques.

Les faits et les vérifications qui les fondent

Rien de ce qui suit n’est copié d’une documentation. La vérification content/libraries/verify/liboqs/run.sh a exécuté liboqs (Open Quantum Safe) 0.16.0 dans l’image de conteneur debian:trixie-20261005-slim le 20 octobre 2026 ; la page doit correspondre à ce que la vérification a affiché, et chaque fait cite les lignes en question.

  • Courbes ECDSA

    none

    Pas d’ECDSA : chaque identifiant d’algorithme activé appartient à une famille post-quantique.

    Relevé par la vérification
    fact ecdsa-curves = none
  • EdDSA

    none

    Pas d’EdDSA : liboqs n’implémente que des schémas post-quantiques.

    Relevé par la vérification
    fact eddsa = none
  • Algorithmes post-quantiques

    ML-KEMML-DSASLH-DSAFalconHQCClassic-McElieceFrodoKEMBIKENTRUsntrup761KyberMAYOCROSSUOVSNOVAMQOM

    Dans le build par défaut, un jeu de paramètres de chaque famille listée a mené à bien la génération de clés, l’encapsulation ou la signature, puis la décapsulation ou la vérification.

    Relevé par la vérification
    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
  • Signatures avec état à base de hachage

    not-built

    Aucun jeu de paramètres XMSS ou LMS n’est activé dans le build par défaut.

    Relevé par la vérification
    fact stateful-signatures = not-built
    evidence stateful-signatures: no XMSS or LMS parameter set is enabled in this build
  • Mode de signature ML-DSA

    hedged

    Deux signatures ML-DSA-65 d’un même message avec une même clé étaient différentes (signature hedged, avec aléa).

    Relevé par la vérification
    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
  • Chaîne de contexte ML-DSA

    supported

    Une signature produite sous le contexte invoice-v1 a été vérifiée avec ce contexte et a échoué avec invoice-v2 ainsi qu’avec le contexte vide.

    Relevé par la vérification
    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
  • Signature ML-DSA mal formée

    returns-false

    Une signature tronquée, 3 octets et un mauvais message ont tous renvoyé OQS_ERROR (-1).

    Relevé par la vérification
    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)
  • Texte chiffré ML-KEM modifié

    implicit-rejection

    Avec un bit du texte chiffré inversé, OQS_KEM_decaps a renvoyé OQS_SUCCESS et un secret partagé différent.

    Relevé par la vérification
    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)

Utilisation

Effectuer un échange de clés ML-KEM-768, puis signer et vérifier avec ML-DSA-65 sous une chaîne de contexte.
#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;
}

Le banc de test des extraits de code exécute chaque exemple tel quel dans l’image de conteneur debian:trixie-20261005-slim, et l’exécution échoue si la sortie ne correspond pas.

Mise en place
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
Commande
cc -o usage usage.c -loqs -lcrypto && ./usage
La sortie doit correspondre à cette expression régulière
ML-KEM-768 secrets match: 1\nML-DSA-65 verified: 1 \(3309-byte signature\)

Bibliothèques