1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
/**
* example.ts — Usage example for mod.ts
* Run with: deno run example.ts
*/
/*** UTILITY ------------------------------------------ ***/
import {
decode,
generateHybridKeyPair,
generateKeyPair,
hybridSign,
hybridVerify,
JwtError,
KEY_SIZES,
sign,
verify
} from "./mod.ts";
/*** 1. ML-DSA only ----------------------------------- ***/
console.log("\n/*** ML-DSA only -------------------------------------- ***/\n");
const { publicKey, secretKey } = await generateKeyPair("ML-DSA-65");
console.log("Public key length (chars):", publicKey.length, "\n");
const token = await sign(
{
role: "member",
sub: "user_01jrwx8k9e4fv3z2"
},
secretKey,
{
algorithm: "ML-DSA-65",
expiresIn: 3600,
issuer: "kern.neue"
}
);
console.log("Token length (chars):", token.length, "\n");
const { header, payload } = decode(token);
console.log("Header:", header, "\n");
console.log("Payload:", payload, "\n");
try {
const claims = await verify(token, publicKey, {
algorithm: "ML-DSA-65",
issuer: "kern.neue"
});
console.log("✓ ML-DSA verification passed. sub:", claims.sub);
} catch (err) {
if (err instanceof JwtError)
console.error("✗", err.message, err.code);
}
/*** 2. Hybrid ML-DSA-65 + Ed25519 -------------------- ***/
console.log("\n/*** Hybrid ML-DSA-65 + Ed25519 ----------------------- ***/\n");
const hybridKeys = await generateHybridKeyPair("ML-DSA-65");
console.log("ML-DSA public key length (chars):", hybridKeys.mlDsa.publicKey.length, "\n");
console.log("Ed25519 public key length (chars):", hybridKeys.ed25519.publicKey.length, "\n");
const hybridToken = await hybridSign(
{
role: "admin",
sub: "user_01jrwx8k9e4fv3z2"
},
hybridKeys,
{
expiresIn: 3600,
issuer: "kern.neue"
}
);
console.log("Hybrid token length (chars):", hybridToken.length, "\n");
console.log("Hybrid header:", decode(hybridToken).header, "\n");
try {
const claims = await hybridVerify(
hybridToken,
{
ed25519PublicKey: hybridKeys.ed25519.publicKey,
mlDsaPublicKey: hybridKeys.mlDsa.publicKey
},
{
issuer: "kern.neue",
variant: "ML-DSA-65"
}
);
console.log("✓ Hybrid verification passed. sub:", claims.sub);
} catch (err) {
if (err instanceof JwtError)
console.error("✗", err.message, err.code);
}
/*** 3. Tamper detection ------------------------------ ***/
console.log("\n/*** Tamper detection --------------------------------- ***/\n");
const tampered = hybridToken.slice(0, -10) + "AAAAAAAAAA";
try {
await hybridVerify(tampered, {
ed25519PublicKey: hybridKeys.ed25519.publicKey,
mlDsaPublicKey: hybridKeys.mlDsa.publicKey
}, { variant: "ML-DSA-65" });
} catch (err) {
if (err instanceof JwtError)
console.log("✓ Tampered token rejected:", err.message, `[${err.code}]`);
}
/*** 4. Wrong public key ------------------------------ ***/
console.log("\n/*** Wrong public key --------------------------------- ***/\n");
const otherKeys = await generateHybridKeyPair("ML-DSA-65");
try {
await hybridVerify(
hybridToken,
{
ed25519PublicKey: otherKeys.ed25519.publicKey,
mlDsaPublicKey: otherKeys.mlDsa.publicKey
},
{
variant: "ML-DSA-65"
}
);
} catch (err) {
if (err instanceof JwtError)
console.log("✓ Wrong key rejected:", err.message, `[${err.code}]`);
}
/*** 5. Key sizes (raw bytes) ------------------------- ***/
console.log("\n/*** Key sizes (raw bytes) ---------------------------- ***/\n");
for (const [variant, sizes] of Object.entries(KEY_SIZES)) {
console.log(`${variant}`);
console.log(" ML-DSA public key: ", sizes.mlDsaPublicKey, "bytes");
console.log(" ML-DSA secret key: ", sizes.mlDsaSecretKey, "bytes");
console.log(" Ed25519 public key:", sizes.ed25519PublicKey, "bytes");
console.log(" Ed25519 secret key:", sizes.ed25519SecretKey, "bytes");
}
|