Pular para o conteúdo
ecdsa.com
C

liboqs (Open Quantum Safe)

A liboqs, a biblioteca C de KEMs e assinaturas pós-quânticas do projeto Open Quantum Safe: ML-KEM, ML-DSA e SLH-DSA ao lado de uma longa lista de algoritmos candidatos sob uma única API — destinada, nas palavras dos autores, a pesquisa e prototipagem.
Licença
MIT
Versão verificada
0.16.0 ·
Código-fonte
github.com/open-quantum-safe/liboqs
Documentação
openquantumsafe.org/liboqs/

Visão geral da compatibilidade

Pós-quântica

EdDSA
none
Algoritmos pós-quânticos
ML-KEMML-DSASLH-DSAFalconHQCClassic-McElieceFrodoKEMBIKENTRUsntrup761KyberMAYOCROSSUOVSNOVAMQOM

A liboqs reúne implementações de mecanismos de encapsulamento de chave pós-quânticos (OQS_KEM) e de esquemas de assinatura (OQS_SIG) sob uma única API em C, e é o motor do provedor Open Quantum Safe para o OpenSSL 3. Os fatos desta página foram verificados na versão 0.16.0 (commit 5a1a854b0dc9), compilada com as opções padrão do CMake, que usam o OpenSSL para as primitivas simétricas. O README diz, em maiúsculas: “NO MOMENTO, NÃO RECOMENDAMOS CONFIAR NESTA BIBLIOTECA EM UM AMBIENTE DE PRODUÇÃO NEM PARA PROTEGER QUAISQUER DADOS SENSÍVEIS.” Para ML-KEM e ML-DSA em produção, as páginas do OpenSSL, do BoringSSL, do AWS-LC e do Bouncy Castle listam o que as APIs principais de cada um oferecem.

O build padrão ativou 41 KEMs e 221 conjuntos de parâmetros de assinatura, e um conjunto de parâmetros de cada família completou o ciclo de ida e volta: os padrões do NIST ML-KEM, ML-DSA e SLH-DSA (156 variantes de SLH-DSA, puras e pré-hash), o Falcon, os candidatos a KEM HQC, Classic McEliece, FrodoKEM, BIKE, NTRU e sntrup761, o Kyber anterior à padronização e os candidatos adicionais de assinatura MAYO, CROSS, UOV, SNOVA e MQOM. Em código novo, use o nome ML-KEM-768, não Kyber768. Nenhum conjunto de parâmetros XMSS ou LMS vem ativado no build padrão.

A assinatura ML-DSA é hedged (usa aleatoriedade adicional): duas assinaturas da mesma mensagem com a mesma chave foram diferentes; por isso, os testes devem verificar as assinaturas em vez de comparar bytes. As strings de contexto do FIPS 204 são aceitas por meio de OQS_SIG_sign_with_ctx_str; uma assinatura feita com o contexto invoice-v1 falhou com invoice-v2 e com o OQS_SIG_verify simples, que usa o contexto vazio, então os dois lados precisam usar o mesmo contexto. Uma assinatura truncada, um blob de 3 bytes e uma assinatura válida sobre outros dados retornaram, todos, o mesmo OQS_ERROR.

O desencapsulamento ML-KEM não acusa um texto cifrado danificado: com um bit invertido, OQS_KEM_decaps retornou OQS_SUCCESS e um segredo compartilhado diferente, como exige a rejeição implícita do FIPS 203. A divergência só aparece quando as chaves derivadas são usadas, por exemplo como uma falha de descriptografia AEAD. A função também não recebe o tamanho do texto cifrado e lê exatamente length_ciphertext bytes, 1088 no ML-KEM-768. Experimente os dois esquemas na ferramenta de ML-KEM e na ferramenta de assinaturas pós-quânticas.

Os fatos e as verificações por trás deles

Nada abaixo foi copiado da documentação. A verificação content/libraries/verify/liboqs/run.sh executou liboqs (Open Quantum Safe) 0.16.0 na imagem de contêiner debian:trixie-20261005-slim em 20 de outubro de 2026; a página precisa corresponder ao que a verificação imprimiu, e cada fato lista essas linhas.

  • Curvas ECDSA

    none

    Sem ECDSA: todos os identificadores de algoritmo ativados pertencem a uma família pós-quântica.

    Registrado pela verificação
    fact ecdsa-curves = none
  • EdDSA

    none

    Sem EdDSA: a liboqs implementa apenas esquemas pós-quânticos.

    Registrado pela verificação
    fact eddsa = none
  • Algoritmos pós-quânticos

    ML-KEMML-DSASLH-DSAFalconHQCClassic-McElieceFrodoKEMBIKENTRUsntrup761KyberMAYOCROSSUOVSNOVAMQOM

    No build padrão, um conjunto de parâmetros de cada família listada completou a geração de chaves, o encapsulamento ou a assinatura e o desencapsulamento ou a verificação.

    Registrado pela verificação
    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
  • Assinaturas baseadas em hash com estado

    not-built

    Nenhum conjunto de parâmetros XMSS ou LMS vem ativado no build padrão.

    Registrado pela verificação
    fact stateful-signatures = not-built
    evidence stateful-signatures: no XMSS or LMS parameter set is enabled in this build
  • Modo de assinatura do ML-DSA

    hedged

    Duas assinaturas ML-DSA-65 de uma mesma mensagem com a mesma chave foram diferentes (assinatura hedged).

    Registrado pela verificação
    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
  • String de contexto do ML-DSA

    supported

    Uma assinatura feita com o contexto invoice-v1 foi verificada com ele e falhou com invoice-v2 e com o contexto vazio.

    Registrado pela verificação
    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
  • Assinatura ML-DSA malformada

    returns-false

    Uma assinatura truncada, 3 bytes e uma mensagem errada retornaram, todos, OQS_ERROR (-1).

    Registrado pela verificação
    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 ML-KEM modificado

    implicit-rejection

    Com um bit do texto cifrado invertido, OQS_KEM_decaps retornou OQS_SUCCESS e um segredo compartilhado diferente.

    Registrado pela verificação
    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

Execute uma troca de chaves ML-KEM-768 e assine e verifique com ML-DSA-65 usando uma string 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;
}

O executor de trechos de código roda cada exemplo literalmente na imagem de contêiner debian:trixie-20261005-slim, e a execução falha se a saída não corresponder.

Configuração
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
A saída deve corresponder a (expressão regular)
ML-KEM-768 secrets match: 1\nML-DSA-65 verified: 1 \(3309-byte signature\)

Bibliotecas