// kit 01

PQC Toolkit

Cripto post-cuántica lista para producción. Elige stack, elige primitiva, copia el código.

$ app/api/sign/route.ts
L3
TS
1import { NextResponse } from 'next/server';
2import { ml_dsa65 } from '@noble/post-quantum/ml-dsa';
3import { ed25519 } from '@noble/curves/ed25519';
4 
5const PQ_PRIV = Buffer.from(process.env.PQ_DSA_PRIV!, 'base64');
6const PQ_PUB = Buffer.from(process.env.PQ_DSA_PUB!, 'base64');
7const ED_PRIV = Buffer.from(process.env.ED_PRIV!, 'hex');
8const ED_PUB = ed25519.getPublicKey(ED_PRIV);
9 
10function b64u(b: Uint8Array | Buffer) {
11 return Buffer.from(b).toString('base64url');
12}
13 
14export async function POST(req: Request) {
15 const claims = await req.json();
16 const header = { alg: 'EdDSA+ML-DSA-65', typ: 'JWT-HYBRID' };
17 const payload = { ...claims, iat: Math.floor(Date.now() / 1000) };
18 
19 const hb = b64u(Buffer.from(JSON.stringify(header)));
20 const pb = b64u(Buffer.from(JSON.stringify(payload)));
21 const msg = Buffer.from(`${hb}.${pb}`);
22 
23 const sigEd = ed25519.sign(msg, ED_PRIV);
24 const sigPq = ml_dsa65.sign(msg, PQ_PRIV);
25 
26 return NextResponse.json({
27 token: `${hb}.${pb}.${b64u(sigEd)}.${b64u(sigPq)}`,
28 pub: { ed: b64u(ED_PUB), pq: b64u(PQ_PUB) },
29 });
30}
TAMAÑO CLAVE
1952 B pub
FIRMA / CT
3293 B sig
NIVEL NIST
L3
NOTAS

JWT híbrido con EdDSA + ML-DSA-65. Los tokens son gordos (~6 KB codificados). Para clientes navegador, guarda el token server-side y entrega una cookie de referencia.

  • Más grande que el default de cabecera de fastify o express — sube el max header size del proxy.
  • Verifica ambas firmas; rechaza si cualquiera falla.
  • Rota claves trimestralmente. La clave PQ también vive en un KMS.