Saltar al contenido principal

Firma poscuántica

qorechain-pqc es la biblioteca de criptografía poscuántica de código abierto y basada exclusivamente en estándares que hay detrás de QoreChain. Ofrece a wallets, integradores y herramientas exactamente las mismas primitivas que usa la cadena — en seis lenguajes, con una API consistente, con compatibilidad byte a byte demostrada frente a una suite compartida de vectores de prueba entre lenguajes.

La biblioteca envuelve implementaciones auditadas de los estándares finales del NIST. No inventa un esquema propio: una variante no estándar es precisamente lo que rompe la interoperabilidad (una firma producida en un lugar no se verificaría en otro). Cada binding se valida contra los mismos vectores, de modo que una firma ML-DSA producida en un lenguaje se verifica en todos los demás, los secretos compartidos de ML-KEM coinciden en los seis y los digests de SHAKE-256 son idénticos.

Primitivas

PrimitivaEstándarRolNiveles (predeterminado en negrita)
ML-DSAFIPS-204firmas digitales44 · 65 · 87
ML-KEMFIPS-203encapsulación de claves512 · 768 · 1024
SHAKE-256FIPS-202hash de salida extensible

Son las mismas primitivas que QoreChain ejecuta a nivel de protocolo: firmas ML-DSA-87 (Dilithium-5), encapsulación de claves ML-KEM-1024 y SHAKE-256 como hash de aplicación predeterminado. Consulta Seguridad poscuántica para ver cómo la cadena las utiliza.

Tamaños (bytes)

Elige el nivel de seguridad según tu presupuesto de tamaño/seguridad.

EsquemaSeguridadClave públicaFirma / Texto cifrado
ML-DSA-44L213122420
ML-DSA-65L319523309
ML-DSA-87L525924627
ML-KEM-512L1800768
ML-KEM-768L311841088
ML-KEM-1024L515681568

No puedes hacer más pequeño un estándar del NIST y seguir siendo estándar. ML-DSA-87 tiene tamaños de clave/firma fijos y bytes fijos — "optimizarlo" produce una variante no estándar que ninguna otra implementación puede verificar. Para reducir la huella on-chain, usa las palancas que se describen más abajo en lugar de alterar el esquema.

Lenguajes y paquetes

Cada lenguaje expone la misma API, cada uno respaldado por una implementación auditada distinta. Esto es lo que garantiza la compatibilidad byte a byte — backends independientes que coinciden en el estándar.

LenguajePaqueteInstalaciónRespaldado por
JavaScript / TypeScript@qorechain/pqc (npm)npm i @qorechain/pqc@noble/post-quantum
Rustqorechain-pqc (crates.io)cargo add qorechain-pqcfips204 · fips203 · sha3
Pythonqorechain-pqc (PyPI)pip install qorechain-pqc (se importa como qorpqc)liboqs-python
Gogithub.com/qorechain/qorechain-pqc/gogo get github.com/qorechain/qorechain-pqc/goCloudflare CIRCL
Cc/ (biblioteca estática + cabecera)compílala desde el repositorioliboqs + OpenSSL
Javaio.github.qorechain:qorechain-pqc (Maven Central)io.github.qorechain:qorechain-pqc:0.1.1Bouncy Castle
Disponibilidad

Los bindings de JavaScript, Rust, Python, Go y Java están todos publicados en la versión 0.1.1 — instálalos directamente desde npm, crates.io, PyPI, el proxy de módulos de Go y Maven Central con los comandos anteriores. La distribución de Python se instala como qorechain-pqc pero se importa como qorpqc. El paquete de Java está en Maven Central como io.github.qorechain:qorechain-pqc:0.1.1 (backend Bouncy Castle). El binding de C es una biblioteca estática + cabecera que compilas desde github.com/qorechain/qorechain-pqc.

Firma determinista (crítica para el consenso)

A partir de la versión 0.1.1, sign() produce la variante determinista de ML-DSA (FIPS-204 §3.4, donde la aleatoriedad de firma son 32 bytes a cero) en los seis bindings — y esta es la única variante que la cadena acepta. El verificador de transacciones de QoreChain rechaza las firmas ML-DSA hedged (aleatorizadas), de modo que una firma hedged falla on-chain aunque se verifique criptográficamente.

Datos clave:

  • No cambies el valor predeterminado. La firma determinista es crítica para el consenso; cada binding la documenta como tal.
  • La salida determinista es idéntica byte a byte en los seis bindings para la misma clave y el mismo mensaje — garantizado por los vectores de prueba compartidos entre lenguajes.
  • La firma hedged sigue disponible como opción explícita en cada binding (p. ej. {hedged: true} en JavaScript, sign_hedged en Rust, mldsaSignHedged en Java, sign(..., hedged=True) en Python) para casos de uso fuera de la cadena — la cadena no acepta firmas hedged.
  • La versión 0.1.0 del binding de JavaScript firmaba en modo hedged por defecto — si construiste herramientas de transacciones contra 0.1.0, actualiza a 0.1.1; las transacciones firmadas con el valor predeterminado antiguo se rechazan on-chain.

Derivación determinista de claves y recuperación

La derivación estándar del ecosistema vincula la clave ML-DSA-87 a la cuenta, por lo que es recuperable solo con el mnemónico de la cuenta:

seed = SHAKE-256("qorechain:pqc:v1|" + cosmosAddress + "|" + mnemonic)
(publicKey, secretKey) = mldsa.keygen(seed)

Todas las herramientas publicadas (@qorechain/wallet-adapter, @qorechain/sdk, @qorechain/chain-bridge ≥0.1.1) derivan esta misma clave, de modo que un mnemónico produce una única clave sea cual sea la herramienta. Recupera una clave en la CLI (mnemónico por stdin):

qorechaind tx pqc recover-key mykey qor1youraddress...
# legacy tooling derivation (shake256(mnemonic) only, unbound to the address):
qorechaind tx pqc recover-key mykey qor1youraddress... --derivation bridge

Rotación de claves (mismo algoritmo)

A partir de la versión de cadena v3.1.85, MsgRotatePQCKey rota la clave ML-DSA-87 de una cuenta dentro del mismo algoritmo — anteriormente el registro era de un solo uso y MigratePQCKey solo cruzaba entre algoritmos. Úsalo para migrar una clave con derivación legacy a la derivación canónica vinculada a la dirección, o para retirar una clave comprometida.

La rotación lleva doble firma: tanto la clave antigua como la nueva firman el mensaje con separación de dominio "qorechain-pqc-rotate-v1|chainId|algorithm|account|oldPubHex|newPubHex". El replay es estructuralmente imposible — una vez rotada, la clave antigua ya no coincide con la clave registrada, por lo que el mismo mensaje no puede volver a aplicarse. La rotación es una operación exclusiva de la clave raíz (nunca delegable a un authenticator), y la propia transacción sigue firmándose en modo híbrido con la clave antigua, lo que demuestra la propiedad actual.

CLI de un solo paso (mnemónico por stdin; recupera la clave antigua, deriva o genera la nueva, aplica la doble firma y difunde):

# migrate a legacy-derived key to the canonical derivation:
qorechaind tx pqc rotate-key --old-derivation bridge --new-derivation adapter \
--from mykey --chain-id qorechain-vladi -o json -y

# rotate to a brand-new random key (compromise recovery):
qorechaind tx pqc rotate-key --old-derivation adapter --new-random \
--from mykey --chain-id qorechain-vladi -o json -y

En código, @qorechain/wallet-adapter (≥0.1.7) y @qorechain/sdk (≥0.7.0) exponen el mismo flujo:

import { rotatePqcKeyMsgFromMnemonic } from "@qorechain/wallet-adapter";

// Builds the dual-signed MsgRotatePQCKey migrating shake256(mnemonic) -> canonical:
const msg = await rotatePqcKeyMsgFromMnemonic({
mnemonic, address: "qor1youraddress...", chainId: "qorechain-vladi",
});
// Sign & broadcast with the account's normal hybrid signer (old key cosigns the envelope).

Tras una rotación correcta, la clave nueva firma (código 0) y la clave antigua se rechaza (pqc código 21).

API consistente

Todos los lenguajes ofrecen la misma superficie:

keygen() -> (publicKey, secretKey)
sign(secretKey, message) -> signature
verify(publicKey, message, signature) -> bool

kem.keygen() -> (publicKey, secretKey)
kem.encapsulate(publicKey) -> (cipherText, sharedSecret)
kem.decapsulate(secretKey, cipherText)-> sharedSecret

shake256(data, outLen=32) -> digest

Inicio rápido (JavaScript / TypeScript)

import { mldsa, mlkem, shake256, pubkeyHash } from '@qorechain/pqc';

// ML-DSA-87 signatures
const { publicKey, secretKey } = mldsa.keygen();
const sig = mldsa.sign(secretKey, message);
mldsa.verify(publicKey, message, sig); // true

// ML-KEM-1024 key encapsulation
const { publicKey: ek, secretKey: dk } = mlkem.keygen();
const { cipherText, sharedSecret } = mlkem.encapsulate(ek);
mlkem.decapsulate(dk, cipherText); // === sharedSecret

// SHAKE-256 + blockchain helpers
shake256(data, 32); // 32-byte digest
pubkeyHash(publicKey, 20); // pay-to-pubkey-hash

Hay exports específicos por nivel disponibles cuando el predeterminado no es lo que necesitas: mldsa44/65/87 y mlkem512/768/1024 (mldsa / mlkem son los predeterminados de nivel L5).

Los bindings de Rust, Go, C, Python y Java replican esto exactamente. Por ejemplo:

// Rust
use qorechain_pqc::mldsa::default as mldsa;
let (pk, sk) = mldsa::keygen()?;
let sig = mldsa::sign(&sk, msg)?;
assert!(mldsa::verify(&pk, msg, &sig));
// Go
pk, sk, _ := pqc.MLDSA.Keygen()
sig, _ := pqc.MLDSA.Sign(sk, msg)
pqc.MLDSA.Verify(pk, msg, sig) // true

Helpers de blockchain

Más allá de las primitivas en bruto, la biblioteca expone dos helpers que los integradores necesitan para interactuar con las cuentas y transacciones de QoreChain.

pubkeyHash(pk, len=20)

Un helper de registro pay-to-pubkey-hash. Produce un hash SHAKE-256 corto (20–32 bytes) de una clave pública. El patrón: almacenar solo el pubkeyHash en el estado de la cuenta y exigir la clave pública completa en la transacción. El estado de la cuenta se mantiene mínimo sin importar que la clave ocupe 1–2,5 KB.

hybridSignBytes(bodyWithoutPqcExt, authInfo)

El framing de sign-bytes con extensión híbrida compatible con wallets de QoreChain. Produce exactamente los bytes que deben firmarse con ML-DSA-87 (Dilithium-5) para formar la mitad PQC de una transacción híbrida.

Esta es la pieza que wallets e integradores usan para producir la firma híbrida obligatoria en la ruta de transacciones cosmos. En la versión actual de la cadena, las firmas híbridas son obligatorias por defecto (hybrid_signature_mode = required, allow_classical_fallback = false): toda transacción por la ruta cosmos debe llevar una firma Dilithium-5 junto a su firma clásica secp256k1. Consulta Seguridad poscuántica para el modelo de aplicación.

La firma clásica secp256k1 se calcula sobre los sign bytes estándar (que excluyen la extensión PQC), y la firma ML-DSA-87 se calcula y se adjunta como la extensión PQCHybridSignature. Como los sign bytes clásicos excluyen la extensión, la firma clásica sigue siendo válida entienda o no el verificador la parte PQC.

Hay tres maneras de producir esta firma híbrida:

  • La CLIqorechaind tx pqc cosign adjunta la cofirma Dilithium-5 a una transacción (después de qorechaind tx pqc gen-key). Consulta Comandos de transacción.
  • El SDK de QoreChainbuildHybridTx (con includePqcPublicKey) hace el equivalente en TypeScript/Python/Go/Rust. Consulta Cuentas del SDK y firma PQC.
  • qorechain-pqc directamente — usa hybridSignBytes para enmarcar los sign bytes y mldsa.sign para producir la firma Dilithium-5, cuando construyas herramientas fuera del SDK en uno de los seis lenguajes soportados.

Optimizar la huella on-chain

Las claves y firmas ML-DSA son grandes para los estándares clásicos. Como los bytes de un estándar son fijos, la forma de mantener pequeña la huella on-chain es usar estas tres palancas — ninguna de las cuales altera el estándar:

  1. Elige el nivel de seguridad de forma deliberada. Las firmas ML-DSA-65 (L3) son ~28% más pequeñas que las de ML-DSA-87 (L5) y siguen siendo muy fuertes; los textos cifrados de ML-KEM-768 son más pequeños que los de 1024. Elige según el caso de uso.
  2. Pay-to-pubkey-hash. Almacena solo pubkeyHash(pk) (20–32 bytes de SHAKE-256) en el estado de la cuenta y exige la clave pública completa en la transacción. El estado de la cuenta se mantiene mínimo sea cual sea el tamaño de la clave.
  3. Firmas de verificar y descartar. Una firma debe vivir en la transacción (datos del bloque) pero nunca debería escribirse en el árbol de estado persistente.

¿Por qué no Falcon? FN-DSA (Falcon) daría firmas más pequeñas, pero está excluido intencionadamente: FN-DSA es un borrador de FIPS-206 (no final), y una biblioteca basada exclusivamente en estándares solo publica estándares finalizados. Podrá reconsiderarse cuando FIPS-206 se finalice.

Relacionado