Saltar al contenido
ecdsa.com
C

libsodium

libsodium de Frank Denis, el fork multiplataforma de NaCl: firmas Ed25519 con verificación estricta, X25519, cifrado autenticado, y ML-KEM-768 más el KEM híbrido X-Wing, pero nada de ECDSA.
Licencia
ISC
Versión comprobada
1.0.22 ·
Código fuente
github.com/jedisct1/libsodium
Documentación
doc.libsodium.org/

Compatibilidad de un vistazo

EdDSACriptografía poscuántica

EdDSA
Ed25519Ed25519ph
Formatos de clave privada
seed-32expanded-64

libsodium ofrece un conjunto pequeño de primitivas que la biblioteca elige por ti, tras funciones difíciles de usar mal; viene incluida en PHP, la usan bindings para muchos lenguajes y está integrada en aplicaciones de mensajería. Las firmas son solo Ed25519: los archivos de cabecera de la 1.0.22 (comprobados con el paquete de Alpine 3.24.2) no declaran ninguna función ECDSA, así que todo lo que use ES256 o secp256k1 necesita otra biblioteca.

La firma Ed25519 es determinista, como especifica el RFC 8032 —dos firmas del mismo mensaje fueron idénticas—, y las funciones crypto_sign_*_ph implementan Ed25519ph, cuyas firmas no son intercambiables con las de Ed25519 simple: en la comprobación, el verificador simple rechazó una. La clave secreta ocupa 64 bytes, la semilla de 32 bytes seguida de la clave pública, mientras que la mayoría de las demás bibliotecas guardan solo la semilla; crypto_sign_ed25519_sk_to_seed y crypto_sign_seed_keypair convierten entre ambas formas, como muestra el ejemplo.

La verificación es estricta justo donde otras implementaciones difieren. Se rechazó una firma con S sustituido por S + L —el mismo valor módulo el orden del grupo, prohibido por el RFC 8032—, y también una firma comprobada con el punto identidad, de orden pequeño, como clave pública. Las bibliotecas que aceptan esas entradas discrepan de libsodium en los casos límite, lo que importa en los sistemas de consenso, que deben ponerse de acuerdo sobre qué es válido. crypto_sign_verify_detached no recibe la longitud de la firma y lee exactamente 64 bytes, así que comprueba la longitud antes de llamarla.

En la 1.0.22, la compatibilidad poscuántica se limita a la encapsulación de claves: crypto_kem_mlkem768_* (claves públicas de 1184 bytes, textos cifrados de 1088 bytes) y el híbrido X-Wing (crypto_kem_xwing_*, 1216 y 1120 bytes), que es también lo que usan por defecto las funciones genéricas crypto_kem_*. No hay ML-DSA ni ninguna otra firma poscuántica. Las claves son siempre bytes en bruto —claves públicas y semillas de 32 bytes—, sin compatibilidad con PEM, DER ni JWK. Compara los tamaños de los KEM en el laboratorio de KEM poscuánticos.

Datos y las comprobaciones que los respaldan

Nada de lo que sigue está copiado de la documentación. La comprobación content/libraries/verify/libsodium/run.sh ejecutó libsodium 1.0.22 en la imagen de contenedor alpine:3.24.2 el 20 de octubre de 2026; la página debe coincidir con lo que imprimió, y cada dato cita esas líneas.

  • Curvas ECDSA

    none

    Sin ECDSA: crypto_sign_PRIMITIVE es ed25519 y ningún archivo de cabecera declara una función ECDSA.

    Registrado por la comprobación
    fact ecdsa-curves = none
    evidence ecdsa-curves: crypto_sign_PRIMITIVE is "ed25519"; the header set declares no ECDSA functions
  • EdDSA

    Ed25519Ed25519ph

    Ed25519 mediante crypto_sign_* y Ed25519ph mediante crypto_sign_init, _update y _final_*; el verificador simple rechaza las firmas Ed25519ph.

    Registrado por la comprobación
    fact eddsa = Ed25519, Ed25519ph
    evidence eddsa: crypto_sign_final_verify (Ed25519ph) accepts its signature: yes; the plain verifier rejects it: yes
  • Firmas Ed25519 deterministas

    yes

    Dos firmas del mismo mensaje con la misma clave fueron idénticas.

    Registrado por la comprobación
    fact ed25519-deterministic = yes
  • Estructura de la clave privada Ed25519

    expanded-64

    crypto_sign_SECRETKEYBYTES es 64: la semilla seguida de la clave pública.

    Registrado por la comprobación
    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)
  • Firma Ed25519 con S no canónico

    rejected

    Se rechazó una firma con S sustituido por S + L.

    Registrado por la comprobación
    fact ed25519-non-canonical-s = rejected
  • Clave pública Ed25519 de orden pequeño

    rejected

    Se rechazó la verificación con el punto identidad como clave pública.

    Registrado por la comprobación
    fact ed25519-small-order-key = rejected
    evidence ed25519-small-order-key: the identity point as public key with R = identity, S = 0
  • Firma Ed25519 mal formada

    rejected

    Con 64 bytes de basura, crypto_sign_verify_detached devolvió -1.

    Registrado por la comprobación
    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
  • Modos de firma

    detachedcombined

    Están disponibles tanto las firmas separadas (64 bytes) como los mensajes firmados combinados (la firma antepuesta al mensaje).

    Registrado por la comprobación
    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
  • Algoritmos poscuánticos

    ML-KEMX-Wing

    Con ML-KEM-768 (crypto_kem_mlkem768_*) y X-Wing (crypto_kem_xwing_*, el valor predeterminado de las funciones genéricas crypto_kem_*) se encapsuló y desencapsuló; no hay firmas poscuánticas.

    Registrado por la comprobación
    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"
  • Formatos de clave pública

    raw-32

    Las claves públicas son 32 bytes en bruto; no hay compatibilidad con PEM, DER ni JWK.

    Registrado por la comprobación
    fact public-key-formats = raw-32
  • Formatos de clave privada

    seed-32expanded-64

    Las claves se derivan de una semilla de 32 bytes (crypto_sign_seed_keypair) y se guardan en 64 bytes; crypto_sign_ed25519_sk_to_seed recupera la semilla.

    Registrado por la comprobación
    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

Uso

Genera una clave Ed25519, extrae la semilla de 32 bytes que esperan otras bibliotecas, y firma y verifica una firma separada.
#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;
}

El arnés de pruebas de fragmentos de código ejecuta cada ejemplo tal cual en la imagen de contenedor alpine:3.24.2, y la ejecución falla si la salida no coincide.

Configuración
apk add --no-cache -q build-base libsodium-dev=1.0.22-r0 >/dev/null
Comando
cc -o usage usage.c -lsodium && ./usage
La salida debe coincidir (expresión regular)
secret key 64 bytes, seed 32 bytes, signature 64 bytes, verified: 1

Bibliotecas