本文へスキップ
ecdsa.com
C

liboqs (Open Quantum Safe)

liboqs は、Open Quantum Safe プロジェクトによるポスト量子 KEM と署名の C ライブラリです。ML-KEM、ML-DSA、SLH-DSA と多数の候補アルゴリズムを 1 つの API で提供していますが、作者たちの言葉によれば、研究とプロトタイピングを目的としたものです。
ライセンス
MIT
確認したバージョン
0.16.0 ·
ソースコード
github.com/open-quantum-safe/liboqs
ドキュメント
openquantumsafe.org/liboqs/

互換性の概要

ポスト量子暗号

EdDSA
none
ポスト量子アルゴリズム
ML-KEMML-DSASLH-DSAFalconHQCClassic-McElieceFrodoKEMBIKENTRUsntrup761KyberMAYOCROSSUOVSNOVAMQOM

liboqs は、ポスト量子の鍵カプセル化メカニズム(OQS_KEM)と署名方式(OQS_SIG)の実装を 1 つの C API にまとめたライブラリで、OpenSSL 3 向け Open Quantum Safe プロバイダーのエンジンでもあります。ここに挙げる事実は、リリース 0.16.0(コミット 5a1a854b0dc9)を CMake のデフォルトオプションでビルドして確認したものです。このオプションでは、共通鍵暗号のプリミティブに OpenSSL が使われます。README には、すべて大文字の英文で次の警告が書かれています。「現時点では、本番環境で、あるいはいかなる機密データの保護のためにも、このライブラリに依存することは推奨しません。」本番環境で使う ML-KEM と ML-DSA について、各ライブラリの主要な API が何を提供しているかは、OpenSSL、BoringSSL、AWS-LC、Bouncy Castle の各ページに記載されています。

デフォルトのビルドでは 41 個の KEM と 221 個の署名パラメーターセットが有効になっており、各ファミリーの 1 つのパラメーターセットで、鍵生成から検証またはデカプセル化までの一連の処理が完了しました。対象は、NIST 標準の ML-KEM、ML-DSA、SLH-DSA(SLH-DSA は通常版と事前ハッシュ版を合わせて 156 種類)、Falcon、KEM の候補である HQC、Classic McEliece、FrodoKEM、BIKE、NTRU、sntrup761、標準化前の Kyber、そして追加署名方式の候補である MAYO、CROSS、UOV、SNOVA、MQOM です。新しいコードでは Kyber768 ではなく ML-KEM-768 と指定してください。デフォルトのビルドでは、XMSS と LMS のパラメーターセットは 1 つも有効になっていません。

ML-DSA の署名はヘッジ付きです。同じ鍵で同じメッセージに 2 回署名すると異なる署名になったため、テストではバイト列を比較するのではなく、署名を検証しなければなりません。FIPS 204 のコンテキスト文字列は OQS_SIG_sign_with_ctx_str で利用できます。コンテキスト invoice-v1 で作成した署名は、invoice-v2 でも、空のコンテキストを使う通常の OQS_SIG_verify でも検証に失敗したため、署名側と検証側でコンテキストを一致させる必要があります。切り詰めた署名、3 バイトのデータ、別のデータに対する有効な署名は、いずれも同じ OQS_ERROR を返しました。

ML-KEM のデカプセル化は、破損した暗号文を報告しません。1 ビットを反転させると、OQS_KEM_decaps は OQS_SUCCESS と異なる共有秘密を返しました。これは FIPS 203 の暗黙的拒否が求める動作です。不一致が表面化するのは、導出した鍵を使ったとき、たとえば AEAD の復号に失敗したときだけです。また、この関数は暗号文の長さを受け取らず、ちょうど length_ciphertext バイト(ML-KEM-768 では 1088 バイト)を読み込みます。ML-KEM ツールとポスト量子署名ツールで両方の方式を試してください。

事実とその根拠となるチェック

以下の内容はドキュメントからの転記ではありません。2026年10月20日に、チェック content/libraries/verify/liboqs/run.sh がコンテナイメージ debian:trixie-20261005-slim 内で liboqs (Open Quantum Safe) 0.16.0 を実行しました。このページの内容はその出力と一致していなければならず、各事実には該当する出力行を示しています。

  • ECDSA の曲線

    none

    ECDSA はありません。有効なアルゴリズム識別子はすべてポスト量子のファミリーに属します。

    チェックによる記録
    fact ecdsa-curves = none
  • EdDSA

    none

    EdDSA はありません。liboqs が実装しているのはポスト量子方式だけです。

    チェックによる記録
    fact eddsa = none
  • ポスト量子アルゴリズム

    ML-KEMML-DSASLH-DSAFalconHQCClassic-McElieceFrodoKEMBIKENTRUsntrup761KyberMAYOCROSSUOVSNOVAMQOM

    デフォルトのビルドでは、列挙した各ファミリーの 1 つのパラメーターセットで、鍵生成、カプセル化または署名、デカプセル化または検証が完了しました。

    チェックによる記録
    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
  • ステートフルハッシュベース署名

    not-built

    デフォルトのビルドでは、XMSS と LMS のパラメーターセットは 1 つも有効になっていません。

    チェックによる記録
    fact stateful-signatures = not-built
    evidence stateful-signatures: no XMSS or LMS parameter set is enabled in this build
  • ML-DSA の署名モード

    hedged

    同じ鍵で同じメッセージに作成した 2 つの ML-DSA-65 署名は異なりました(ヘッジ付き署名)。

    チェックによる記録
    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
  • ML-DSA のコンテキスト文字列

    supported

    コンテキスト invoice-v1 で作成した署名は、同じコンテキストでは検証を通り、invoice-v2 と空のコンテキストでは検証に失敗しました。

    チェックによる記録
    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
  • 不正な形式の ML-DSA 署名

    returns-false

    切り詰めた署名、3 バイトのデータ、誤ったメッセージは、いずれも OQS_ERROR(-1)を返しました。

    チェックによる記録
    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)
  • 改変された ML-KEM 暗号文

    implicit-rejection

    暗号文の 1 ビットを反転させると、OQS_KEM_decaps は OQS_SUCCESS と異なる共有秘密を返しました。

    チェックによる記録
    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)

使い方

ML-KEM-768 で鍵交換を行い、コンテキスト文字列を指定して ML-DSA-65 で署名と検証を行います。
#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;
}

スニペットのテストハーネスは、すべてのサンプルをコンテナイメージ debian:trixie-20261005-slim 内でそのまま実行し、出力が一致しなければ実行は失敗します。

セットアップ
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
コマンド
cc -o usage usage.c -loqs -lcrypto && ./usage
一致すべき出力(正規表現)
ML-KEM-768 secrets match: 1\nML-DSA-65 verified: 1 \(3309-byte signature\)

ライブラリ