Перейти к содержимому
ecdsa.com
C

libsodium

libsodium от Frank Denis — переносимый форк NaCl: подписи Ed25519 со строгой проверкой, X25519, аутентифицированное шифрование, ML-KEM-768 и гибридный KEM X-Wing, но ECDSA нет совсем.
Лицензия
ISC
Проверенная версия
1.0.22 ·
Исходный код
github.com/jedisct1/libsodium
Документация
doc.libsodium.org/

Совместимость вкратце

EdDSAПостквантовая криптография

EdDSA
Ed25519Ed25519ph

libsodium предлагает небольшой, намеренно ограниченный набор примитивов за функциями, которые трудно использовать неправильно; библиотека входит в состав PHP, на ней построены привязки для многих языков, и её встраивают в мессенджеры. Подписи только Ed25519: в заголовочных файлах версии 1.0.22 (проверено на пакете Alpine 3.24.2) не объявлено ни одной функции ECDSA, поэтому для всего, что работает с ES256 или secp256k1, нужна другая библиотека.

Подписание Ed25519 детерминированное, как и требует RFC 8032 (две подписи одного сообщения совпали), а функции crypto_sign_*_ph реализуют Ed25519ph, подписи которого нельзя использовать вместо обычных подписей Ed25519: при тестировании обычная функция проверки отклонила такую подпись. Секретный ключ занимает 64 байта: 32-байтовый seed, за которым следует открытый ключ, тогда как большинство других библиотек хранят только seed; crypto_sign_ed25519_sk_to_seed и crypto_sign_seed_keypair переводят одну форму в другую, как показано в примере.

Проверка строгая именно там, где реализации ведут себя по-разному. Подпись, в которой S заменили на S + L (значение, равное S по модулю порядка группы; RFC 8032 такие подписи запрещает), была отклонена, как и подпись, которую проверяли по нейтральному элементу группы (точке малого порядка) в качестве открытого ключа. Библиотеки, которые принимают такие входные данные, расходятся с libsodium в граничных случаях, а это важно для систем консенсуса, где все участники должны одинаково решать, действительна ли подпись. crypto_sign_verify_detached не принимает длину подписи и читает ровно 64 байта, поэтому проверяйте длину перед вызовом.

Постквантовые алгоритмы в 1.0.22 ограничены инкапсуляцией ключа: crypto_kem_mlkem768_* (1184-байтовые открытые ключи, 1088-байтовые шифртексты) и гибридный X-Wing (crypto_kem_xwing_*, 1216 и 1120 байт), который также используют по умолчанию универсальные функции crypto_kem_*. ML-DSA и других постквантовых подписей нет. Ключи везде представлены сырыми байтами (32-байтовые открытые ключи и seed), PEM, DER и JWK не поддерживаются. Сравните размеры KEM в песочнице постквантовых KEM.

Факты и проверки, на которых они основаны

Ничего из приведённого ниже не скопировано из документации. 20 октября 2026 г. проверка content/libraries/verify/libsodium/run.sh запустила libsodium 1.0.22 в образе контейнера alpine:3.24.2; содержимое страницы должно совпадать с выводом проверки, а у каждого факта приведены соответствующие строки вывода.

  • Кривые 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

    Ed25519 через crypto_sign_*, Ed25519ph через crypto_sign_init, _update и _final_*; обычная функция проверки отклоняет подписи Ed25519ph.

    Что записала проверка
    fact eddsa = Ed25519, Ed25519ph
    evidence eddsa: crypto_sign_final_verify (Ed25519ph) accepts its signature: yes; the plain verifier rejects it: yes
  • Детерминированные подписи Ed25519

    yes

    Две подписи одного сообщения одним и тем же ключом совпали.

    Что записала проверка
    fact ed25519-deterministic = yes
  • Структура закрытого ключа Ed25519

    expanded-64

    crypto_sign_SECRETKEYBYTES равно 64: seed, за которым следует открытый ключ.

    Что записала проверка
    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)
  • Подпись Ed25519 с неканоническим S

    rejected

    Подпись, в которой S заменили на S + L, отклонена.

    Что записала проверка
    fact ed25519-non-canonical-s = rejected
  • Открытый ключ Ed25519 малого порядка

    rejected

    Подпись не прошла проверку, когда открытым ключом служил нейтральный элемент группы.

    Что записала проверка
    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 байта в формате raw; PEM, DER и JWK не поддерживаются.

    Что записала проверка
    fact public-key-formats = raw-32
  • Форматы закрытых ключей

    seed-32expanded-64

    Ключи выводятся из 32-байтового seed (crypto_sign_seed_keypair) и хранятся в виде 64 байт; crypto_sign_ed25519_sk_to_seed извлекает 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-байтовый seed, который ожидают другие библиотеки, создайте отделённую подпись и проверьте её.
#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

Библиотеки