本文へスキップ
ecdsa.com
C

libsodium

Frank Denis による libsodium は、NaCl の移植性の高いフォークです。厳格に検証される Ed25519 署名、X25519、認証付き暗号、ML-KEM-768 とハイブリッド KEM の X-Wing を備えますが、ECDSA にはまったく対応していません。
ライセンス
ISC
確認したバージョン
1.0.22 ·
ソースコード
github.com/jedisct1/libsodium
ドキュメント
doc.libsodium.org/

互換性の概要

EdDSAポスト量子暗号

EdDSA
Ed25519Ed25519ph
秘密鍵の形式
seed-32expanded-64

libsodium は、明確な設計方針に基づいて厳選した少数のプリミティブを、誤用しにくい関数で提供しています。PHP に同梱され、多くの言語バインディングで使われ、メッセージングアプリにも組み込まれています。署名は Ed25519 のみです。1.0.22 のヘッダー(Alpine 3.24.2 のパッケージで確認)は ECDSA の関数を 1 つも宣言していないため、ES256 や secp256k1 を扱うものには別のライブラリが必要です。

Ed25519 の署名は、RFC 8032 の規定どおり決定的です(同じメッセージの 2 つの署名は同一でした)。crypto_sign_*_ph 関数は Ed25519ph を実装していますが、その署名は通常の Ed25519 の署名と互換性がなく、チェックでは通常の検証関数が Ed25519ph の署名を拒否しました。秘密鍵は 64 バイトで、32 バイトのシードの後に公開鍵が続きます。一方、ほかのほとんどのライブラリはシードだけを保存します。サンプルのように、crypto_sign_ed25519_sk_to_seed と crypto_sign_seed_keypair で両者を相互に変換できます。

ほかの実装で挙動が分かれる点について、libsodium の検証は厳格です。S を S + L に置き換えた署名(群の位数を法として同じ値であり、RFC 8032 で禁止されています)は拒否され、小さい位数の単位元(identity point)を公開鍵として検証した署名も拒否されました。これらの入力を受け入れるライブラリは、境界的なケースで libsodium と判定が食い違います。これは、有効性について合意しなければならないコンセンサスシステムでは重要です。crypto_sign_verify_detached は署名の長さを受け取らず、ちょうど 64 バイトを読み込むため、呼び出す前に長さを確認してください。

1.0.22 のポスト量子暗号への対応は、鍵カプセル化だけです。crypto_kem_mlkem768_*(公開鍵 1184 バイト、暗号文 1088 バイト)と、ハイブリッドの X-Wing(crypto_kem_xwing_*、1216 バイトと 1120 バイト)があり、汎用の crypto_kem_* 関数もデフォルトで X-Wing を使います。ML-DSA などのポスト量子署名はありません。鍵は一貫して生のバイト列(32 バイトの公開鍵とシード)で、PEM、DER、JWK には対応していません。KEM のサイズはポスト量子 KEM ラボで比較してください。

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

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

  • ECDSA の曲線

    none

    ECDSA はありません。crypto_sign_PRIMITIVE は ed25519 で、ECDSA の関数を宣言しているヘッダーはありません。

    チェックによる記録
    fact ecdsa-curves = none
    evidence ecdsa-curves: crypto_sign_PRIMITIVE is "ed25519"; the header set declares no ECDSA functions
  • EdDSA

    Ed25519Ed25519ph

    crypto_sign_* による Ed25519 と、crypto_sign_init、_update、_final_* による Ed25519ph です。通常の検証関数は Ed25519ph の署名を拒否します。

    チェックによる記録
    fact eddsa = Ed25519, Ed25519ph
    evidence eddsa: crypto_sign_final_verify (Ed25519ph) accepts its signature: yes; the plain verifier rejects it: yes
  • 決定的な Ed25519 署名

    yes

    同じ鍵による同じメッセージへの 2 つの署名は同一でした。

    チェックによる記録
    fact ed25519-deterministic = yes
  • Ed25519 秘密鍵の構造

    expanded-64

    crypto_sign_SECRETKEYBYTES は 64 で、シードの後に公開鍵が続きます。

    チェックによる記録
    fact ed25519-private-key = expanded-64
    evidence ed25519-private-key: crypto_sign_SECRETKEYBYTES = 64: the 32-byte seed followed by the 32-byte public key (seed matches: yes)
  • 非正規の S を含む Ed25519 署名

    rejected

    S を S + L に置き換えた署名は拒否されました。

    チェックによる記録
    fact ed25519-non-canonical-s = rejected
  • 位数の小さい Ed25519 公開鍵

    rejected

    単位元(identity point)を公開鍵とした検証は拒否されました。

    チェックによる記録
    fact ed25519-small-order-key = rejected
    evidence ed25519-small-order-key: the identity point as public key with R = identity, S = 0
  • 不正な形式の Ed25519 署名

    rejected

    64 バイトの無意味なデータに対して、crypto_sign_verify_detached は -1 を返しました。

    チェックによる記録
    fact ed25519-malformed-signature = rejected
    evidence ed25519-malformed-signature: 64 bytes of 0xab: crypto_sign_verify_detached returned -1; the function takes no length and reads exactly crypto_sign_BYTES = 64 bytes
  • 署名モード

    detachedcombined

    分離署名(64 バイト)と結合形式の署名付きメッセージ(署名をメッセージの先頭に付加)の両方を利用できます。

    チェックによる記録
    fact signature-modes = detached, combined
    evidence signature-modes: crypto_sign prepends the 64-byte signature to the message: 82 bytes for a 18-byte message
  • ポスト量子アルゴリズム

    ML-KEMX-Wing

    ML-KEM-768(crypto_kem_mlkem768_*)と X-Wing(crypto_kem_xwing_*、汎用の crypto_kem_* のデフォルト)でカプセル化とデカプセル化ができました。ポスト量子署名はありません。

    チェックによる記録
    fact pqc = ML-KEM, X-Wing
    evidence pqc: crypto_kem_mlkem768: public key 1184 bytes, ciphertext 1088 bytes
    evidence pqc: crypto_kem_xwing: public key 1216 bytes, ciphertext 1120 bytes; generic crypto_kem_primitive() is "xwing"
  • 公開鍵の形式

    raw-32

    公開鍵は 32 バイトの生データです。PEM、DER、JWK には対応していません。

    チェックによる記録
    fact public-key-formats = raw-32
  • 秘密鍵の形式

    seed-32expanded-64

    鍵は 32 バイトのシードから導出され(crypto_sign_seed_keypair)、64 バイトとして保存されます。crypto_sign_ed25519_sk_to_seed でシードを取り出せます。

    チェックによる記録
    fact private-key-formats = seed-32, expanded-64
    evidence private-key-formats: crypto_sign_seed_keypair reproduces the key from the seed: yes; crypto_sign_ed25519_sk_to_seed recovers it: yes

使い方

Ed25519 の鍵を生成し、ほかのライブラリが想定する 32 バイトのシードを取り出して、分離署名で署名と検証を行います。
#include <sodium.h>
#include <stdio.h>
#include <string.h>

int main(void) {
    if (sodium_init() < 0) return 1;
    const unsigned char msg[] = "order #1042 approved";
    unsigned char pk[crypto_sign_PUBLICKEYBYTES], sk[crypto_sign_SECRETKEYBYTES];
    unsigned char sig[crypto_sign_BYTES], seed[32];

    crypto_sign_keypair(pk, sk);
    /* Other libraries store the 32-byte seed; libsodium's secret key is seed || public key. */
    crypto_sign_ed25519_sk_to_seed(seed, sk);

    /* Detached signature: 64 bytes, deterministic per RFC 8032. */
    crypto_sign_detached(sig, NULL, msg, sizeof msg - 1, sk);
    int ok = crypto_sign_verify_detached(sig, msg, sizeof msg - 1, pk) == 0;

    printf("secret key %d bytes, seed %zu bytes, signature %d bytes, verified: %d\n",
           crypto_sign_SECRETKEYBYTES, sizeof seed, crypto_sign_BYTES, ok);
    return 0;
}

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

セットアップ
apk add --no-cache -q build-base libsodium-dev=1.0.22-r0 >/dev/null
コマンド
cc -o usage usage.c -lsodium && ./usage
一致すべき出力(正規表現)
secret key 64 bytes, seed 32 bytes, signature 64 bytes, verified: 1

ライブラリ