本文へスキップ
ecdsa.com
C · C++

BoringSSL

Google の BoringSSL は、Chrome と Android で使われている OpenSSL のフォークです。ECDSA は DER 形式で NIST 曲線のみに対応し、ほかに Ed25519 と、専用の API による ML-KEM、ML-DSA、SLH-DSA を備えます。リリースはなく、安定性の保証もありません。
ライセンス
Apache-2.0
確認したバージョン
2026-10-19-b50cad27ee80 ·
ソースコード
boringssl.googlesource.com/boringssl
ドキュメント
commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html

互換性の概要

ECDSAEdDSAポスト量子暗号

ECDSA の曲線
P-224P-256P-384P-521
EdDSA
Ed25519

BoringSSL は Google による OpenSSL のフォークで、Chrome と Android で使われています。aws-lc-rs の基盤となるライブラリ AWS-LC はさらにそのフォークであり、ring はそのアセンブリを再利用しています。リリースはなく、API の安定性も約束されていないため、利用者はコミットを固定します。ここに挙げる事実は、コミット b50cad27ee80(2026年10月19日)をソースからビルドして確認したものです。

ECDSA は OpenSSL の慣例を踏襲しており、署名は DER、nonce はランダム、low-S 正規化はなく、検証は high-S も受け入れます。ECDSA_sign は自分で計算したダイジェストに署名します。OpenSSL と異なり、不正な入力は単なる検証失敗として扱われます。EVP_DigestVerify は生の r‖s 署名にも 3 バイトのデータにも 0 を返したため、形式の問題が現れるのはエラーキューだけです。エンコーディングは DER ⇄ 生形式の変換ツールで確認してください。

曲線は意図的に P-224、P-256、P-384、P-521 に限定されており(EC_GROUP_new_by_curve_name(NID_secp256k1) は NULL を返しました)、EdDSA で動作するのは Ed25519 だけです。EVP_PKEY_ED448 は互換性のために定義されていますが、EVP 経由での Ed448 鍵の生成は失敗しました。OpenSSL から BoringSSL に移行するコードは secp256k1、Brainpool、Ed448 を失いますが、コンパイルエラーにはならないため、そのアルゴリズムを要求するまで気付けません。

ポスト量子暗号への対応は充実しており、EVP ではなく個別の型付き API として提供されます。MLKEM768_* と MLKEM1024_*、MLDSA65_* と関連するサイズのもの、SLHDSA_SHA2_128S_* があり、チェックではいずれも一通り動作しました。ssl.h では X25519MLKEM768 ハイブリッド TLS グループ(0x11EC)も定義されています。サンプルでは ML-KEM-768 と ML-DSA-65 を直接使っています。お使いのブラウザーが何をネゴシエートするかは、ブラウザーのポスト量子チェックで確認できます。

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

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

  • ECDSA 署名のエンコーディング

    der

    EVP_DigestSign は ASN.1 DER を生成します。

    チェックによる記録
    fact ecdsa-signature-encoding = der
  • ECDSA の nonce

    random

    nonce はランダムです。同じメッセージの 2 つの署名は異なります。

    チェックによる記録
    fact ecdsa-nonce = random
  • 署名時の low-S

    either

    s は正規化されません。64 個の署名の中に high-S の値が現れました。

    チェックによる記録
    fact ecdsa-low-s-sign = either
  • 検証時の high-S

    accepts-high-s

    s を n − s に置き換えた DER 署名も検証を通りました。

    チェックによる記録
    fact ecdsa-low-s-verify = accepts-high-s
  • 署名呼び出しがハッシュする対象

    hashes-message-or-digest

    EVP_DigestSign はハッシュを計算します。ECDSA_sign はダイジェストに署名し、その署名はメッセージに対して検証できました。

    チェックによる記録
    fact ecdsa-prehash = hashes-message-or-digest
  • 不正な形式の ECDSA 署名

    returns-false

    EVP_DigestVerify は生の r‖s 署名と 3 バイトのデータに対して 0 を返しました。

    チェックによる記録
    fact ecdsa-malformed-signature = returns-false
    evidence ecdsa-malformed-signature: EVP_DigestVerify returned 0 for raw r||s and 0 for 3 bytes (1 = valid, 0 = invalid)
  • ECDSA の曲線

    P-224P-256P-384P-521

    P-224、P-256、P-384、P-521 です。secp256k1 のグループはありません。

    チェックによる記録
    fact ecdsa-curves = P-224, P-256, P-384, P-521
    evidence ecdsa-curves: EC_GROUP_new_by_curve_name(NID_secp256k1): NULL
  • EdDSA

    Ed25519

    ED25519_sign と ED25519_verify による Ed25519 です。EVP_PKEY_ED448 は定義されていますが、Ed448 鍵の生成は失敗しました。

    チェックによる記録
    fact eddsa = Ed25519
    evidence eddsa: EVP_PKEY_ED448 is defined; generating an Ed448 key through EVP: fails
  • ポスト量子アルゴリズム

    ML-KEMML-DSASLH-DSA

    専用のヘッダーを通じて、ML-KEM-768 でカプセル化とデカプセル化を、ML-DSA-65 と SLH-DSA-SHA2-128s で署名と検証を行えました。

    チェックによる記録
    fact pqc = ML-KEM, ML-DSA, SLH-DSA
    evidence pqc: ssl.h defines SSL_GROUP_X25519_MLKEM768 = 0x11ec
    evidence pqc: ML-DSA-65 signature 3309 bytes

使い方

BoringSSL 専用のポスト量子 API で、ML-KEM-768 のカプセル化と ML-DSA-65 の署名を実行します。
#include <openssl/mldsa.h>
#include <openssl/mlkem.h>
#include <openssl/bytestring.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    /* ML-KEM-768: the receiver publishes the encoded public key. */
    uint8_t pub[MLKEM768_PUBLIC_KEY_BYTES], ct[MLKEM768_CIPHERTEXT_BYTES];
    uint8_t ss_sender[MLKEM_SHARED_SECRET_BYTES], ss_receiver[MLKEM_SHARED_SECRET_BYTES];
    struct MLKEM768_private_key priv;
    struct MLKEM768_public_key pk;
    MLKEM768_generate_key(pub, NULL, &priv);
    CBS cbs;
    CBS_init(&cbs, pub, sizeof pub);
    if (!MLKEM768_parse_public_key(&pk, &cbs)) return 1;
    MLKEM768_encap(ct, ss_sender, &pk);
    MLKEM768_decap(ss_receiver, ct, sizeof ct, &priv);
    printf("ML-KEM-768 secrets match: %d\n", memcmp(ss_sender, ss_receiver, sizeof ss_sender) == 0);

    /* ML-DSA-65 with an empty context string. */
    static const uint8_t msg[] = "release manifest";
    uint8_t dpub[MLDSA65_PUBLIC_KEY_BYTES], seed[MLDSA_SEED_BYTES];
    struct MLDSA65_private_key *dpriv = malloc(sizeof *dpriv);
    struct MLDSA65_public_key *dpk = malloc(sizeof *dpk);
    uint8_t *sig = malloc(MLDSA65_SIGNATURE_BYTES);
    MLDSA65_generate_key(dpub, seed, dpriv);
    MLDSA65_public_from_private(dpk, dpriv);
    MLDSA65_sign(sig, dpriv, msg, sizeof msg - 1, NULL, 0);
    printf("ML-DSA-65 verified: %d\n", MLDSA65_verify(dpk, sig, MLDSA65_SIGNATURE_BYTES, msg, sizeof msg - 1, NULL, 0));
    free(dpriv); free(dpk); free(sig);
    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 perl golang >/dev/null 2>&1 && git clone -q --filter=blob:none https://boringssl.googlesource.com/boringssl /bssl && git -C /bssl checkout -q b50cad27ee8013f241648ef6a7adf7f6f6b3d25b && cmake -S /bssl -B /bssl/build -G Ninja -DCMAKE_BUILD_TYPE=Release >/dev/null 2>&1 && ninja -C /bssl/build crypto >/dev/null
コマンド
cc -I/bssl/include -o usage usage.c /bssl/build/libcrypto.a -lstdc++ -lpthread && ./usage
一致すべき出力(正規表現)
ML-KEM-768 secrets match: 1\nML-DSA-65 verified: 1

ライブラリ