-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathALGORITHM.html
More file actions
1315 lines (1304 loc) · 117 KB
/
Copy pathALGORITHM.html
File metadata and controls
1315 lines (1304 loc) · 117 KB
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Algorithm Reference — Anon-leyline</title>
<link
href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400;0,500;1,400&family=Inter:wght@400;500&family=JetBrains+Mono:wght@400&display=swap"
rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<style>
:root {
--canvas: #faf9f5;
--card: #efe9de;
--card-soft: #f5f0e8;
--cream-strong: #e8e0d2;
--dark: #181715;
--dark-el: #252320;
--dark-soft: #1f1e1b;
--primary: #5cccb0;
--primary-active: #3ea98e;
--primary-disabled: #e6dfd8;
--ink: #141413;
--body-color: #3d3d3a;
--body-strong: #252523;
--muted: #6c6a64;
--muted-soft: #8e8b82;
--hairline: #e6dfd8;
--hairline-soft: #ebe6df;
--teal: #5db892;
--amber: #72e85a;
--dark-border: #2c2a27;
--badge-active-bg: #5db87220;
--badge-active-fg: #3a8f62;
--badge-active-border: #5db87240;
--badge-legacy-bg: #e8a55a20;
--badge-legacy-fg: #a0661a;
--badge-legacy-border: #e8a55a40;
--badge-upcoming-bg: #cc785c20;
--badge-upcoming-fg: #a9583e;
--badge-upcoming-border: #cc785c40;
--example-key: #cc785c;
--example-val: #5db8a6;
--on-dark: #faf9f5;
--on-dark-soft: #a09d96;
/* semantic */
--bg: var(--canvas);
--fg: var(--ink);
--fg-body: var(--body-color);
--fg-muted: var(--muted);
--border: var(--hairline);
--surface: var(--card);
--surface-soft: var(--card-soft);
--nav-bg: var(--canvas);
--code-bg: var(--dark-soft);
--badge-bg: var(--card);
--badge-fg: var(--ink);
--graph-filter: none;
}
[data-theme="dark"] {
--bg: var(--dark);
--fg: var(--on-dark);
--fg-body: var(--on-dark-soft);
--fg-muted: var(--muted);
--border: var(--dark-border);
--surface: var(--dark-el);
--surface-soft: var(--dark-soft);
--nav-bg: var(--dark);
--code-bg: var(--dark-soft);
--badge-bg: var(--dark-border);
--badge-fg: var(--on-dark-soft);
--badge-active-bg: #5db87215;
--badge-active-fg: #5db872;
--badge-active-border: #5db87230;
--badge-legacy-bg: #e8a55a15;
--badge-legacy-fg: #e8a55a;
--badge-legacy-border: #e8a55a30;
--badge-upcoming-bg: #cc785c15;
--badge-upcoming-fg: #5cc8cc;
--badge-upcoming-border: #cc785c30;
--graph-filter: invert(0.88) hue-rotate(180deg);
}
* {box-sizing: border-box;margin: 0;padding: 0}
html {scroll-behavior: smooth;font-size: 16px}
body {font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;background: var(--bg);color: var(--fg);line-height: 1.55;transition: background .2s, color .2s;}
/* ── NAV ── */
.topnav {position: sticky;top: 0;z-index: 100;background: var(--nav-bg);border-bottom: 1px solid var(--border);height: 64px;display: flex;align-items: center;justify-content: space-between;padding: 0 32px;gap: 16px;transition: background .2s, border-color .2s;}
.topnav-brand {display: flex;align-items: center;gap: 10px;text-decoration: none}
.spike {width: 20px;height: 20px;flex-shrink: 0}
.brand-name {font-family: 'EB Garamond', Georgia, serif;font-size: 20px;font-weight: 400;letter-spacing: -.3px;color: var(--fg);}
.brand-sub {font-size: 13px;color: var(--fg-muted);font-weight: 500;margin-left: 4px}
.theme-btn {background: var(--surface);border: 1px solid var(--border);color: var(--fg);cursor: pointer;border-radius: 8px;padding: 6px 14px;font-size: 13px;font-weight: 500;font-family: 'Inter', sans-serif;transition: background .15s;}
.theme-btn:hover {background: var(--cream-strong)}
[data-theme="dark"] .theme-btn:hover {background: var(--dark-el)}
/* ── LAYOUT ── */
.layout {display: flex;min-height: calc(100vh - 64px)}
.sidebar {width: 260px;flex-shrink: 0;position: sticky;top: 64px;height: calc(100vh - 64px);overflow-y: auto;border-right: 1px solid var(--border);padding: 24px 0;background: var(--bg);transition: background .2s, border-color .2s;}
.sidebar-label {font-size: 11px;font-weight: 500;letter-spacing: 1.5px;text-transform: uppercase;color: var(--fg-muted);padding: 0 20px 8px;}
.sidebar a {display: block;padding: 7px 20px;font-size: 13.5px;color: var(--fg-muted);text-decoration: none;border-left: 2px solid transparent;transition: color .12s, border-color .12s, background .12s;}
.sidebar a:hover {color: var(--fg);background: var(--surface-soft);border-left-color: var(--primary)}
.sidebar a.active {color: var(--primary);border-left-color: var(--primary);font-weight: 500}
.sidebar-num {display: inline-block;width: 20px;font-size: 11px;color: var(--fg-muted);opacity: .6;}
/* ── MAIN ── */
.main {flex: 1;padding: 64px 56px}
/* ── HERO ── */
.page-hero {margin-bottom: 64px}
.page-hero h1 {font-family: 'EB Garamond', Georgia, serif;font-size: 56px;font-weight: 400;letter-spacing: -1.2px;line-height: 1.08;color: var(--fg);margin-bottom: 16px;}
.page-hero p {font-size: 17px;color: var(--fg-body);max-width: 560px;line-height: 1.6}
.hero-stats {display: flex;gap: 24px;margin-top: 28px;flex-wrap: wrap}
.hstat {padding: 12px 20px;background: var(--surface);border-radius: 12px;border: 1px solid var(--border)}
.hstat-n {font-family: 'EB Garamond', serif;font-size: 28px;font-weight: 400;color: var(--primary)}
.hstat-l {font-size: 12px;font-weight: 500;color: var(--fg-muted);margin-top: 2px}
/* ── SECTION ── */
.algo-section {margin-bottom: 80px;scroll-margin-top: 88px}
.section-header {margin-bottom: 28px}
.section-num {font-size: 12px;font-weight: 500;letter-spacing: 1.5px;text-transform: uppercase;color: var(--primary);margin-bottom: 8px;}
.section-title {font-family: 'EB Garamond', Georgia, serif;font-size: 36px;font-weight: 400;letter-spacing: -.5px;color: var(--fg);margin-bottom: 8px;line-height: 1.15;}
.section-tagline {font-size: 15px;color: var(--fg-muted);font-style: italic;margin-bottom: 16px}
.section-desc {font-size: 15.5px;color: var(--fg-body);line-height: 1.65;max-width: 660px}
/* ── BADGES ── */
.badges {display: flex;gap: 8px;flex-wrap: wrap;margin: 16px 0}
.badge {padding: 3px 12px;border-radius: 9999px;font-size: 12px;font-weight: 500;letter-spacing: .3px;}
.badge-active {background: var(--badge-active-bg);color: var(--badge-active-fg);border: 1px solid var(--badge-active-border)}
.badge-legacy {background: var(--badge-legacy-bg);color: var(--badge-legacy-fg);border: 1px solid var(--badge-legacy-border)}
.badge-upcoming {background: var(--badge-upcoming-bg);color: var(--badge-upcoming-fg);border: 1px solid var(--badge-upcoming-border)}
[data-theme="dark"] .badge-active {background: var(--badge-active-bg);color: var(--badge-active-fg);border-color: var(--badge-active-border)}
[data-theme="dark"] .badge-legacy {background: var(--badge-legacy-bg);color: var(--badge-legacy-fg);border-color: var(--badge-legacy-border)}
[data-theme="dark"] .badge-upcoming {background: var(--badge-upcoming-bg);color: var(--badge-upcoming-fg);border-color: var(--badge-upcoming-border)}
/* ── GRAPH ── */
.graph-wrap {background: var(--surface);border: 1px solid var(--border);border-radius: 12px;padding: 28px 24px;margin: 24px 0;overflow-x: auto;}
.graph-wrap .mermaid {display: flex;justify-content: center;min-height: 80px}
.graph-label {font-size: 11px;font-weight: 500;letter-spacing: 1px;text-transform: uppercase;color: var(--fg-muted);margin-bottom: 12px}
/* ── ALGO LISTS ── */
.algo-lists {display: grid;grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));gap: 16px;margin-top: 20px}
.alist {background: var(--surface);border: 1px solid var(--border);border-radius: 10px;padding: 16px 18px}
.alist-title {font-size: 11px;font-weight: 500;letter-spacing: 1px;text-transform: uppercase;margin-bottom: 10px;padding-bottom: 8px;border-bottom: 1px solid var(--border)}
.alist-title.t-active {color: var(--badge-active-fg)}
.alist-title.t-legacy {color: var(--badge-legacy-fg)}
.alist-title.t-upcoming {color: var(--badge-upcoming-fg)}
[data-theme="dark"] .alist-title.t-active {color: var(--badge-active-fg)}
[data-theme="dark"] .alist-title.t-legacy {color: var(--badge-legacy-fg)}
[data-theme="dark"] .alist-title.t-upcoming {color: var(--badge-upcoming-fg)}
.alist ul {list-style: none;display: flex;flex-wrap: wrap;gap: 5px}
.alist ul li {font-family: 'JetBrains Mono', monospace;font-size: 11.5px;background: var(--bg);border: 1px solid var(--border);border-radius: 6px;padding: 2px 8px;color: var(--fg-body);}
/* ── EXAMPLE BLOCK ── */
.example-wrap {background: var(--code-bg);border-radius: 12px;padding: 20px 22px;margin: 24px 0;color: var(--cream-strong);font-family: 'JetBrains Mono', monospace;font-size: 12.5px;line-height: 1.7;overflow-x: auto;}
.example-label {font-family: 'Inter', sans-serif;font-size: 11px;font-weight: 500;letter-spacing: 1px;text-transform: uppercase;color: var(--muted-soft);margin-bottom: 12px;}
.example-wrap .ex-row {display: block;white-space: pre}
.example-wrap .ex-key {color: var(--example-key)}
.example-wrap .ex-val {color: var(--example-val)}
.example-wrap .ex-cmt {color: var(--muted);font-style: italic}
/* ── INTERNALS BLOCK ── */
.internals-wrap {background: var(--surface-soft);border: 1px solid var(--border);border-left: 3px solid var(--primary);border-radius: 8px;padding: 18px 22px;margin: 24px 0;}
.internals-label {font-size: 11px;font-weight: 500;letter-spacing: 1px;text-transform: uppercase;color: var(--primary);margin-bottom: 10px;}
.internals-wrap p {font-size: 14.5px;color: var(--fg-body);line-height: 1.65;margin-bottom: 8px}
.internals-wrap p:last-child {margin-bottom: 0}
.internals-wrap code {font-family: 'JetBrains Mono', monospace;font-size: 12.5px;background: var(--bg);border: 1px solid var(--border);padding: 1px 6px;border-radius: 4px;color: var(--fg);}
/* ── DIVIDER ── */
.section-divider {height: 1px;background: var(--border);margin: 0 0 80px}
/* ── FOOTER ── */
footer {background: var(--dark);color: var(--on-dark-soft);padding: 48px 56px;font-size: 13px;border-top: 1px solid var(--dark-border);}
footer a {color: var(--on-dark-soft);text-decoration: none}
footer a:hover {color: var(--on-dark)}
/* ── RESPONSIVE ── */
@media(max-width:900px) {.sidebar {display: none}.main {padding: 40px 24px}.page-hero h1 {font-size: 36px}.section-title {font-size: 28px}}
@media(max-width:600px) {.topnav {padding: 0 16px}.main {padding: 28px 16px}.algo-lists {grid-template-columns: 1fr}}
</style>
</head>
<body>
<nav class="topnav">
<a class="topnav-brand" href="#">
<svg class="spike" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 1v18M1 10h18M3.22 3.22l13.56 13.56M16.78 3.22L3.22 16.78" stroke="var(--primary)"
stroke-width="1.6" stroke-linecap="round" />
</svg>
<span class="brand-name">Anon-leyline</span>
<span class="brand-sub">NextSSL Algorithm Reference</span>
</a>
<button class="theme-btn" id="themeBtn" onclick="toggleTheme()">☾ Dark</button>
</nav>
<div class="layout">
<nav class="sidebar" id="sidebar"></nav>
<main class="main" id="main"></main>
</div>
<footer>
<div style="max-width:900px">
Anon-leyline · Algorithm Reference · 22 categories · <a href="algo.json">algo.json</a>
</div>
</footer>
<script>
// ══════════════════════════════════════════════
// DATA — all content lives here
// ══════════════════════════════════════════════
const ALGOS = [
{
id: 'encoding',
example: `<span class="ex-row"><span class="ex-cmt"># Input bytes</span></span>
<span class="ex-row">input = "hello" <span class="ex-cmt">// 5 bytes: 0x68 65 6c 6c 6f</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">base64</span> → <span class="ex-val">"aGVsbG8="</span> <span class="ex-cmt">// 64-char alphabet + padding</span></span>
<span class="ex-row"><span class="ex-key">base64url</span>→ <span class="ex-val">"aGVsbG8"</span> <span class="ex-cmt">// URL-safe, no padding</span></span>
<span class="ex-row"><span class="ex-key">base32</span> → <span class="ex-val">"NBSWY3DP"</span> <span class="ex-cmt">// case-insensitive</span></span>
<span class="ex-row"><span class="ex-key">base16/hex</span> → <span class="ex-val">"68656c6c6f"</span> <span class="ex-cmt">// 2 chars per byte</span></span>
<span class="ex-row"><span class="ex-key">base58</span> → <span class="ex-val">"Cn8eVZg"</span> <span class="ex-cmt">// Bitcoin alphabet, no 0OIl</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">crc32</span> → <span class="ex-val">0x3610a686</span> <span class="ex-cmt">// 4-byte corruption check</span></span>
<span class="ex-row"><span class="ex-key">adler32</span> → <span class="ex-val">0x062c0215</span> <span class="ex-cmt">// faster, weaker than crc32</span></span>`,
internals: `<p><b>Encoding</b> is a reversible alphabet remap — pure bit-shuffling, zero security. Variants differ by alphabet size and resulting blow-up: <code>hex</code> = 2× size, 16 chars; <code>base64</code> = 1.33×, 64 chars; <code>base85</code> = 1.25×, 85 chars. URL-safe variants swap <code>+/</code> for <code>-_</code>. <code>base58</code> drops visually ambiguous <code>0/O/I/l</code> for human transcription. <code>bech32</code> adds a BCH checksum to catch typos in Bitcoin addresses.</p>
<p><b>Checksum</b> is a one-way short fingerprint — also zero crypto security, an attacker can trivially forge. <code>CRC32</code> uses polynomial division (fast in hardware, good random-error detection). <code>Adler32</code> uses modular sums (faster but weaker collision profile). <code>xxHash</code>/<code>xxh3</code> are non-crypto but extremely fast for hash tables. Use <b>hash functions</b> (next section) when you need adversarial integrity.</p>`,
title: 'Encoding & Checksum',
tagline: 'Transform binary data into portable text and detect corruption',
desc: 'Encoding maps arbitrary bytes into a restricted alphabet safe for text protocols — Base64 in email attachments, Hex in debug output, Bech32 in Bitcoin addresses. Checksums like CRC32 and Adler32 add a short numeric fingerprint so receivers can detect accidental bit-flips during storage or transmission. Neither provides cryptographic security; a deliberate attacker can forge both.',
graph: `flowchart LR
A([Binary Data]) --> B[Encode]
B -->|Base64 / Hex| C([Text String])
B -->|Bech32 / PEM| D([Structured Text])
C --> G[Decode]
G --> H([Original Bytes])
A --> E[Checksum]
E -->|CRC32 / Adler32| F([Short Code])
F --> I{Compare on receive}
I -->|Matches| J([Data intact])
I -->|Differs| K([Corruption detected])`,
lists: {
active: ['base16', 'base32', 'base32hex', 'base58', 'base58check', 'base62', 'base64', 'base64url', 'base85', 'bech32', 'bech32m', 'pem', 'der', 'cer', 'pkcs7', 'pkcs8', 'pkcs12', 'spki', 'ff70', 'crc8', 'crc16', 'crc16-ccitt', 'crc32', 'crc32c', 'crc64', 'crc64-ecma', 'adler32', 'fletcher16', 'fletcher32', 'xxhash32', 'xxhash64', 'xxh3'],
legacy: ['base91', 'ber'],
upcoming: []
}
},
{
id: 'hash',
example: `<span class="ex-row"><span class="ex-key">sha256</span>(<span class="ex-val">"hello"</span>)</span>
<span class="ex-row">→ <span class="ex-val">2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824</span></span>
<span class="ex-row"> <span class="ex-cmt">(32 bytes, always — fixed-size digest)</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">sha256</span>(<span class="ex-val">"hellp"</span>) <span class="ex-cmt">// 1 letter changed</span></span>
<span class="ex-row">→ <span class="ex-val">b1ec05deafe88bc81e6dab7a7d4f7f6ed68ad34f3ac2c1a405b0d3e6a64b08f3</span></span>
<span class="ex-row"> <span class="ex-cmt">(~half the bits flipped — avalanche effect)</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">shake128</span>(<span class="ex-val">"hello"</span>, <span class="ex-val">outLen=8</span>) → <span class="ex-val">3a9159f071e4dd1c</span></span>
<span class="ex-row"><span class="ex-key">shake128</span>(<span class="ex-val">"hello"</span>, <span class="ex-val">outLen=64</span>) → <span class="ex-val">3a9159f071e4dd1c...</span> <span class="ex-cmt">// caller picks length</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">blake3</span>(<span class="ex-val">"hello"</span>) → <span class="ex-val">ea8f163db38682925e44...</span> <span class="ex-cmt">// 5-10× faster than sha256</span></span>`,
internals: `<p><b>Hash</b> vs <b>Digest</b> vs <b>XOF</b> — same family, different output behaviour. <b>Hash function</b> = the algorithm. <b>Digest</b> = its output (fixed-length byte string). They are not separate things; "digest" is just what the hash spits out. <code>SHA-256</code> always outputs 32 bytes, no more, no less.</p>
<p><b>XOF (Extendable Output Function)</b> = a hash that lets the caller request any output length. <code>SHAKE128(msg, 8)</code> gives 8 bytes; <code>SHAKE128(msg, 1024)</code> gives 1024 bytes — and the first 8 bytes of the long output equal the short output. Useful for KDFs, masking, mask-generation in RSA-PSS.</p>
<p>Construction families differ internally: <b>SHA-2</b> (sha256, sha512) uses <b>Merkle-Damgård</b> — fixed compression function chained block-by-block. <b>SHA-3 / Keccak</b> uses <b>sponge construction</b> — absorb input into a 1600-bit state, then squeeze output (this is how SHAKE gets arbitrary length naturally). <b>BLAKE3</b> uses a <b>Merkle tree</b> for parallel hashing on multi-core. <b>SHA-1</b>/<b>MD5</b> are legacy because collisions have been demonstrated.</p>`,
title: 'Hash / Digest / XOF',
tagline: 'One-way fingerprinting — any input maps to a fixed-size digest',
desc: 'A cryptographic hash function compresses any-size input into a fixed-size digest (e.g. 256 bits for SHA-256). Three properties matter: preimage resistance (you cannot reverse the digest to find the input), collision resistance (no two inputs produce the same digest), and the avalanche effect (flipping one bit changes ~half the output bits). XOFs (Extendable Output Functions) like SHAKE128 stretch to any desired output length.',
graph: `flowchart TD
A([Input — any size]) --> B[Hash Function]
B --> C([Fixed Digest])
D([Same input again]) --> E[Same Hash Fn]
E --> F([Identical digest])
G([Input + 1 bit changed]) --> H[Same Hash Fn]
H --> I([Completely different digest])
C --> J{Reverse?}
J -->|Computationally impossible| K([One-way property])`,
lists: {
active: ['sha224', 'sha256', 'sha384', 'sha512', 'sha512-224', 'sha512-256', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512', 'keccak256', 'keccak512', 'shake128', 'shake256', 'cshake128', 'cshake256', 'kmac128', 'kmac256', 'kmacxof128', 'kmacxof256', 'parallelhash128', 'parallelhash256', 'tuplehash128', 'tuplehash256', 'kangarootwelve', 'marsupilami14', 'blake2b', 'blake2s', 'blake2bp', 'blake2sp', 'blake3', 'skein256', 'skein512', 'skein1024', 'sm3', 'streebog256', 'streebog512'],
legacy: ['md2', 'md4', 'md5', 'sha0', 'sha1', 'gost-r-34.11-94', 'ripemd128', 'ripemd160', 'ripemd256', 'ripemd320', 'tiger', 'whirlpool', 'has160', 'nt-hash', 'lm-hash', 'md6', 'radio-gatun', 'groestl', 'jh', 'cubehash', 'echo', 'simd', 'fugue', 'hamsi', 'luffa', 'shabal', 'bmw', 'shavite3'],
upcoming: ['poseidon', 'pedersen-hash', 'mimc', 'rescue', 'griffin', 'reinforced-concrete', 'haraka', 'lsh', 'highwayhash', 'mgf1']
}
},
{
id: 'pwkdf',
example: `<span class="ex-row"><span class="ex-key">argon2id</span>(</span>
<span class="ex-row"> password = <span class="ex-val">"hunter2"</span>,</span>
<span class="ex-row"> salt = <span class="ex-val">random(16 bytes)</span>,</span>
<span class="ex-row"> m = <span class="ex-val">65536 KB</span>, <span class="ex-cmt">// 64 MB RAM per attempt</span></span>
<span class="ex-row"> t = <span class="ex-val">3</span>, <span class="ex-cmt">// 3 iterations</span></span>
<span class="ex-row"> p = <span class="ex-val">4</span> <span class="ex-cmt">// 4 parallel lanes</span></span>
<span class="ex-row">)</span>
<span class="ex-row">→ <span class="ex-val">$argon2id$v=19$m=65536,t=3,p=4$c2FsdHNhbHQ$kfL2...</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Attacker on GPU: ~10 attempts/sec/GPU vs ~10^9 for raw SHA-256</span></span>
<span class="ex-row"><span class="ex-cmt">// 8-char password takes centuries instead of minutes</span></span>`,
internals: `<p>All password KDFs share one purpose: be deliberately slow so brute-force costs more than the data is worth. They differ in <i>what</i> they make expensive.</p>
<p><b>PBKDF2</b> = HMAC iterated N times. CPU-bound only — GPUs and ASICs absolutely crush it because each attempt fits in tiny memory. Acceptable only when memory-hard is impossible (FIPS-locked, embedded).</p>
<p><b>bcrypt</b> = Blowfish-based, modest memory (~4 KB). Better than PBKDF2 against GPUs but still GPU-attackable today.</p>
<p><b>scrypt</b> = first memory-hard KDF. Forces the attacker to allocate large RAM per attempt — GPUs have lots of cores but limited per-core memory bandwidth.</p>
<p><b>Argon2</b> = current winner (Password Hashing Competition 2015). Three variants: <code>Argon2d</code> data-dependent (max GPU resistance, but timing side-channel risk), <code>Argon2i</code> data-independent (side-channel-safe, slightly weaker), <code>Argon2id</code> hybrid (does Argon2i for first pass, Argon2d after — recommended default).</p>`,
title: 'Password KDFs',
tagline: 'Slow-by-design functions that make brute-forcing passwords expensive',
desc: 'Passwords have low entropy — an attacker can try millions per second with a GPU. Password KDFs like Argon2 and scrypt are deliberately slow and memory-hard: they require a configurable amount of RAM and CPU time per attempt, making brute-force and dictionary attacks economically infeasible even with specialized hardware. A random salt ensures two users with the same password get different hashes.',
graph: `flowchart TD
A([Password]) --> D
B([Random Salt]) --> D
C([Cost params\ntime + memory]) --> D
D[Memory-hard KDF\nArgon2 / scrypt / bcrypt] --> E([Derived Key])
E --> F([Store as hash\nor use as encryption key])
G([Attacker GPU]) -.->|Needs huge RAM\nper attempt| D`,
lists: {
active: ['pbkdf2', 'pbkdf2-hmac-sha256', 'pbkdf2-hmac-sha512', 'bcrypt', 'scrypt', 'argon2d', 'argon2i', 'argon2id', 'yescrypt', 'lyra2', 'balloon'],
legacy: ['pbkdf2-hmac-sha1', 'catena', 'pomelo', 'makwa', 'bsdicrypt', 'md5crypt', 'sha256crypt', 'sha512crypt'],
upcoming: ['pbkdf1', 'pkcs12-kdf', 'evp-bytestokey', 'kdf2']
}
},
{
id: 'blockcipher',
example: `<span class="ex-row"><span class="ex-key">aes-128</span>.encrypt(</span>
<span class="ex-row"> key = <span class="ex-val">0x000102030405060708090a0b0c0d0e0f</span>,</span>
<span class="ex-row"> plaintext = <span class="ex-val">"hello world!!!!!"</span> <span class="ex-cmt">// exactly 16 bytes = 1 block</span></span>
<span class="ex-row">)</span>
<span class="ex-row">→ ciphertext = <span class="ex-val">0x69c4e0d86a7b0430d8cdb78070b4c55a</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">aes-128</span>.decrypt(key, ciphertext) → <span class="ex-val">"hello world!!!!!"</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Wrong key by 1 bit → completely different garbage:</span></span>
<span class="ex-row"><span class="ex-key">aes-128</span>.decrypt(<span class="ex-val">key^1</span>, ciphertext) → <span class="ex-val">0x8b...random bytes...</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Block cipher ALONE only handles ONE block. For longer messages →</span></span>
<span class="ex-row"><span class="ex-cmt">// use a mode (CTR/GCM/etc — see "Block Cipher Modes" section).</span></span>`,
internals: `<p>All block ciphers map a fixed-size plaintext block to a same-size ciphertext block under a secret key. They differ in <b>internal structure</b>, <b>block size</b>, <b>key size</b>, and <b>round count</b>.</p>
<p><b>SPN (Substitution-Permutation Network)</b> — used by <code>AES</code>, <code>ARIA</code>, <code>SM4</code>. Each round applies S-box (non-linear substitution) + linear mixing layer + round-key XOR. AES uses 10/12/14 rounds for 128/192/256-bit keys. Hardware-friendly: most modern CPUs have AES-NI instructions (~1 cycle/byte).</p>
<p><b>Feistel network</b> — used by <code>DES</code>, <code>3DES</code>, <code>Camellia</code>, <code>Blowfish</code>. Split block in half, apply round function to one half, XOR into the other, swap. Same circuit encrypts and decrypts (just reverse the key schedule). Why: 1970s hardware constraints.</p>
<p><b>ARX (Add-Rotate-XOR)</b> — used by <code>Threefish</code>, also by stream ciphers like ChaCha. Only +, rotate, XOR — no S-box tables, constant-time by default, fast in software.</p>
<p><b>Lightweight variants</b> (<code>PRESENT</code>, <code>SIMON</code>, <code>SPECK</code>, <code>GIFT</code>) shrink block size to 64 bits and use minimal gates for IoT. Trade margin for chip area.</p>`,
title: 'Symmetric Block Ciphers',
tagline: 'Encrypt fixed-size blocks using a shared secret key',
desc: 'A block cipher takes a fixed-size plaintext block (typically 128 bits) and a secret key, and produces a ciphertext block of the same size through multiple rounds of substitution and permutation. The same key decrypts. AES (Advanced Encryption Standard) is the universal standard today. "Symmetric" means both parties share the same key — key distribution is a separate problem solved by key exchange protocols.',
graph: `flowchart LR
A([Plaintext block\n128 bits]) --> C
B([Secret Key\n128 / 192 / 256 bits]) --> C
C[Block Cipher\nAES / Camellia / SM4] --> D([Ciphertext block\n128 bits])
D --> E[Decrypt]
B2([Same Key]) --> E
E --> F([Plaintext block])
G([Wrong Key]) -.->|Garbage output| E`,
lists: {
active: ['aes-128', 'aes-192', 'aes-256', 'aria-128', 'aria-192', 'aria-256', 'camellia-128', 'camellia-192', 'camellia-256', 'seed', 'sm4', 'kuznyechik', 'present', 'led', 'piccolo', 'clefia', 'threefish-256', 'threefish-512', 'threefish-1024'],
legacy: ['magma', '3des', 'des', 'blowfish', 'twofish', 'serpent', 'cast5', 'cast6', 'idea', 'rc2', 'rc5', 'rc6', 'misty1', 'kasumi', 'safer', 'skipjack', 'speck', 'simon', 'xtea', 'tea', 'gost28147', 'anubis', 'khazad', 'noekeon'],
upcoming: ['kalyna', 'belt', 'shacal', 'shacal-2', 'feal', 'safer+', 'prince', 'pride', 'twine', 'katan', 'ktantan', 'gift', 'skinny', 'lblock', 'rectangle', 'mmb']
}
},
{
id: 'stream',
example: `<span class="ex-row"><span class="ex-key">chacha20</span>.keystream(</span>
<span class="ex-row"> key = <span class="ex-val">0x00...00 (32 bytes, all zero)</span>,</span>
<span class="ex-row"> nonce = <span class="ex-val">0x00...00 (12 bytes, all zero)</span>,</span>
<span class="ex-row"> count = <span class="ex-val">0</span></span>
<span class="ex-row">)</span>
<span class="ex-row">→ first 64 bytes of keystream =</span>
<span class="ex-row"> <span class="ex-val">76b8e0ada0f13d90405d6ae55386bd28...</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Encrypt "hello" = XOR each byte with keystream:</span></span>
<span class="ex-row">plaintext = <span class="ex-val">"hello"</span> <span class="ex-cmt">// 68 65 6c 6c 6f</span></span>
<span class="ex-row">keystream = <span class="ex-val">"76 b8 e0 ad a0"</span> <span class="ex-cmt">// first 5 bytes</span></span>
<span class="ex-row">ciphertext = <span class="ex-val">"1e dd 8c c1 cf"</span> <span class="ex-cmt">// XOR</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// FATAL: reuse same (key, nonce) on different plaintexts → keystream cancels,</span></span>
<span class="ex-row"><span class="ex-cmt">// XOR of two ciphertexts reveals XOR of plaintexts. Always fresh nonce.</span></span>`,
internals: `<p>Stream ciphers all do the same thing: take a key + nonce, produce a long pseudorandom stream, XOR with plaintext. The difference is <b>how the stream is generated</b>.</p>
<p><b>ChaCha20 / Salsa20</b> — ARX design (add, rotate, XOR) on a 512-bit state, 20 rounds. No S-boxes → constant-time by construction → no cache-timing leaks. 256-bit key, 96-bit nonce (or 192-bit for XChaCha20 = randomly generatable). Modern default.</p>
<p><b>RC4</b> — byte-permutation stream (legacy). Statistical biases in early output bytes broke WEP, TLS-RC4. Banned in TLS 1.3.</p>
<p><b>HC-128/256, Rabbit, SOSEMANUK, Grain, Trivium</b> — eSTREAM portfolio (2008). Different design families: HC uses table-driven state, Grain uses two interconnected feedback shift registers (hardware-tiny), Trivium uses three coupled NLFSRs.</p>
<p><b>AES-CTR</b> is technically a stream cipher built from a block cipher (encrypt counter values, use as keystream). Listed under "Block Cipher Modes" because conceptually it's a mode wrapping AES.</p>
<p><b>Round-count variants</b> (<code>ChaCha8</code>, <code>ChaCha12</code>, <code>ChaCha20</code>) trade safety margin for speed. ChaCha20 is the conservative default.</p>`,
title: 'Stream Ciphers',
tagline: 'Generate a pseudorandom keystream and XOR it with plaintext',
desc: 'A stream cipher generates a pseudorandom keystream from a key and nonce, then XORs it byte-by-byte with the plaintext. This makes encryption trivially parallelizable and allows encrypting messages of arbitrary length without padding. ChaCha20 is the modern standard — it powers HTTPS traffic via ChaCha20-Poly1305. Never reuse a key+nonce pair: reuse completely breaks security.',
graph: `flowchart TD
A([Key + Nonce]) --> B[Keystream Generator\nChaCha20 / Salsa20]
B --> C([Pseudorandom stream])
D([Plaintext bytes]) --> E[XOR]
C --> E
E --> F([Ciphertext])
F --> G[XOR]
C2([Same keystream]) --> G
G --> H([Plaintext])
I([Reuse nonce!]) -.->|Catastrophic break| B`,
lists: {
active: ['chacha20', 'xchacha20', 'salsa20', 'xsalsa20', 'chacha8', 'chacha12', 'hc128', 'hc256', 'rabbit', 'sosemanuk', 'grain128', 'zuc', 'snow3g', 'aes-ctr-drbg'],
legacy: ['rc4', 'grainv1', 'mickeyv2', 'trivium', 'isaac', 'isaac+', 'panama', 'wake', 'seal', 'a5/1', 'a5/2', 'e0'],
upcoming: ['salsa20/8', 'salsa20/12', 'spritz', 'vmpc', 'cryptmt', 'dragon', 'edon80', 'f-fcsr', 'hermes8', 'lex', 'nls', 'pomaranch', 'a5/3']
}
},
{
id: 'modes',
example: `<span class="ex-row"><span class="ex-cmt">// Plaintext = "hello world, this is a long message!!" (38 bytes = 2.4 blocks)</span></span>
<span class="ex-row"><span class="ex-cmt">// Block cipher alone handles 16 bytes. Mode = how to handle more.</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">ECB</span> <span class="ex-cmt">// each block encrypted independently — BROKEN</span></span>
<span class="ex-row"> AES(K, P[0]) || AES(K, P[1]) || AES(K, P[2])</span>
<span class="ex-row"> <span class="ex-cmt">// identical plaintext blocks → identical ciphertext blocks (leaks patterns)</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">CBC</span> <span class="ex-cmt">// chained XOR — sequential, needs random IV</span></span>
<span class="ex-row"> C[i] = AES(K, P[i] XOR C[i-1]), C[-1] = IV</span>
<span class="ex-row"> <span class="ex-cmt">// cannot parallelize encryption; decryption parallel ok</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">CTR</span> <span class="ex-cmt">// counter mode — fully parallel</span></span>
<span class="ex-row"> keystream[i] = AES(K, nonce || counter+i)</span>
<span class="ex-row"> C[i] = P[i] XOR keystream[i]</span>
<span class="ex-row"> <span class="ex-cmt">// turns a block cipher into a stream cipher; preferred modern mode</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">XTS</span> <span class="ex-cmt">// disk encryption — tweak = sector#, no IV per sector needed</span></span>
<span class="ex-row"> C[i] = AES(K1, P[i] XOR T) XOR T, T = AES(K2, sector) · α^i</span>`,
internals: `<p>A mode of operation extends a block cipher to messages longer than one block. The differences are in <b>parallelism</b>, <b>error propagation</b>, and <b>whether they leak patterns</b>.</p>
<p><b>ECB</b> — pure block-by-block. The famous "ECB penguin" image (identical pixels stay visible) is exactly this leak. Never use except in toy/test code.</p>
<p><b>CBC</b> — XOR with previous ciphertext before encrypting. Hides patterns, but encryption is strictly sequential. Vulnerable to padding-oracle attacks (POODLE, Lucky13) when used naïvely. Decryption is parallel.</p>
<p><b>CFB / OFB</b> — feedback modes turning the block cipher into a self-synchronising or synchronous stream cipher. Mostly historical (used in old protocols).</p>
<p><b>CTR</b> — encrypt incrementing counter values, XOR result with plaintext. Fully parallel both ways, no padding needed, random-access decryption. Modern default for raw confidentiality. Add a MAC or use GCM for authentication.</p>
<p><b>XTS</b> — two keys, "tweak" derived from sector number. Designed specifically for full-disk encryption (BitLocker, FileVault, LUKS) where you cannot store per-sector IVs.</p>
<p><b>CBC-CS1/2/3</b> — ciphertext stealing variants that avoid padding (output same length as input).</p>`,
title: 'Block Cipher Modes',
tagline: 'Rules for applying a block cipher to messages longer than one block',
desc: 'A block cipher alone only encrypts one 128-bit block. Modes of operation define how to chain the cipher across multiple blocks. ECB (legacy) encrypts each block independently — identical plaintext blocks produce identical ciphertext, leaking patterns. CBC chains blocks via XOR but is sequential. CTR mode turns the block cipher into a stream cipher using a counter, enabling full parallelism. GCM/AEAD modes add authentication on top.',
graph: `flowchart TD
A([Long message]) --> B{Choose Mode}
B -->|ECB — broken| C([Blocks encrypted\nindependently\nleaks patterns])
B -->|CBC — legacy| D([XOR prev ciphertext\nthen encrypt\nsequential only])
B -->|CTR — active| E([Encrypt counter\nthen XOR\nfully parallel])
B -->|GCM — AEAD| F([CTR + auth tag\nencrypt AND verify])`,
lists: {
active: ['ctr', 'xts', 'cbc-cs1', 'cbc-cs2', 'cbc-cs3'],
legacy: ['ecb', 'cbc', 'cfb', 'cfb1', 'cfb8', 'ofb'],
upcoming: []
}
},
{
id: 'aead',
example: `<span class="ex-row"><span class="ex-key">chacha20-poly1305</span>.seal(</span>
<span class="ex-row"> key = <span class="ex-val">random(32 bytes)</span>,</span>
<span class="ex-row"> nonce = <span class="ex-val">random(12 bytes)</span>, <span class="ex-cmt">// must be unique per key</span></span>
<span class="ex-row"> plaintext = <span class="ex-val">"hello"</span>,</span>
<span class="ex-row"> aad = <span class="ex-val">"v1,user=alice"</span> <span class="ex-cmt">// authenticated, NOT encrypted</span></span>
<span class="ex-row">)</span>
<span class="ex-row">→ ciphertext = <span class="ex-val">"1edd8cc1cf"</span> <span class="ex-cmt">// same length as plaintext</span></span>
<span class="ex-row"> tag = <span class="ex-val">"7e8c...9a14"</span> <span class="ex-cmt">// 16-byte authentication tag</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">open</span>(key, nonce, ct, tag, aad) → <span class="ex-val">"hello"</span> <span class="ex-cmt">// tag valid</span></span>
<span class="ex-row"><span class="ex-key">open</span>(key, nonce, ct, tag, <span class="ex-val">"v1,user=eve"</span>) → <span class="ex-val">ERROR</span> <span class="ex-cmt">// aad changed → reject</span></span>
<span class="ex-row"><span class="ex-key">open</span>(key, nonce, <span class="ex-val">ct^1</span>, tag, aad) → <span class="ex-val">ERROR</span> <span class="ex-cmt">// 1 bit flipped → reject</span></span>`,
internals: `<p>AEAD = AEAD construction. They differ in <b>which primitive provides confidentiality</b>, <b>which provides authentication</b>, and <b>how they handle nonce reuse</b>.</p>
<p><b>AES-GCM</b> = AES-CTR encryption + GHASH (Galois-field MAC). Fastest with AES-NI + PCLMUL hardware. Nonce reuse is <b>catastrophic</b> — reveals authentication key. Standard for TLS 1.3, IPsec, SSH.</p>
<p><b>ChaCha20-Poly1305</b> = ChaCha20 stream + Poly1305 one-time MAC. Software-fast (no AES-NI required), constant-time. Default on mobile and ARM. Also breaks on nonce reuse.</p>
<p><b>AES-GCM-SIV</b> = nonce-misuse-resistant variant. Repeated nonces only leak whether messages were identical, nothing more. Pay ~30% throughput. Use when nonce uniqueness is hard to guarantee.</p>
<p><b>AES-CCM</b> = Counter + CBC-MAC. Older, used in 802.11i/WPA2 and Bluetooth. Two-pass (slower than GCM).</p>
<p><b>AES-OCB</b> = single-pass, parallelisable, faster than GCM — but patent issues kept it niche. Now patent-free.</p>
<p><b>AES-SIV</b> = synthetic IV. Deterministic AEAD: same plaintext + AAD → same ciphertext (useful for deduplication/key-wrap).</p>
<p><b>XChaCha20-Poly1305</b> = 192-bit nonce variant. Big enough to use random nonces safely (no counter needed).</p>
<p><b>AEGIS, Ascon-AEAD</b> = newer designs using AES-round-based or sponge constructions. ASCON won NIST Lightweight Crypto.</p>`,
title: 'AEAD Algorithms',
tagline: 'Encrypt and authenticate in one operation — confidentiality + integrity',
desc: 'AEAD (Authenticated Encryption with Associated Data) solves the classic mistake of encrypting without authenticating. It produces a ciphertext plus a short authentication tag. On decryption, if the tag fails to verify — whether from key mismatch, ciphertext tampering, or nonce reuse — the entire decryption is rejected. Additional Data (AAD) like packet headers is authenticated but not encrypted. AES-GCM and ChaCha20-Poly1305 are the two dominant standards.',
graph: `flowchart TD
A([Plaintext]) --> E
B([Key]) --> E
C([Nonce]) --> E
D([Additional Data\nAAD]) --> E
E[AEAD Cipher\nAES-GCM / ChaCha20-Poly1305] --> F([Ciphertext])
E --> G([Auth Tag\n128 bits])
F --> H{Decrypt + Verify}
G --> H
H -->|Tag valid| I([Plaintext])
H -->|Tag invalid| J([Rejected entirely])`,
lists: {
active: ['aes-gcm', 'aes-ccm', 'aes-gcm-siv', 'aes-siv', 'aes-ocb', 'aes-eax', 'aes-kw', 'aes-kwp', 'aes-gmac', 'aes-xpn', 'aes-fpe-ff1', 'aes-fpe-ff3-1', 'chacha20-poly1305', 'xchacha20-poly1305', 'aegis128l', 'aegis256', 'deoxys-ii', 'ocb3', 'kccm', 'ascon-aead128', 'ascon-aead128a', 'ascon-80pq'],
legacy: ['morus', 'kiasu', 'marble', 'elephant-dumbo', 'elephant-jumbo', 'gift-cofb', 'grain-128aead', 'isap-a-128a', 'isap-k-128a', 'photon-beetle', 'romulus', 'sparkle-schwaemm', 'tinyjambu', 'xoodyak', 'colm', 'silc'],
upcoming: ['aez', 'otr-aead', 'cloc', 'jambu', 'icepole', 'ketje', 'keyak', 'norx', 'acorn', 'aegis-128', 'rocca', 'rocca-s', 'tiaoxin', 'paeq', 'poet', 'drygascon', 'subterranean', 'sundae', 'spook', 'pyjamask', 'comet', 'estate', 'lotus', 'locus', 'spix', 'orbita', 'saeb', 'mixfeed', 'elmd', 'hs1-siv', 'iscream', 'scream', 'wage']
}
},
{
id: 'mac',
example: `<span class="ex-row"><span class="ex-key">hmac-sha256</span>(</span>
<span class="ex-row"> key = <span class="ex-val">"shared-secret-key"</span>,</span>
<span class="ex-row"> msg = <span class="ex-val">"transfer $100 to Bob"</span></span>
<span class="ex-row">)</span>
<span class="ex-row">→ tag = <span class="ex-val">f7bc83f430538424b13298e6aa6fb143... (32 bytes)</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Receiver recomputes:</span></span>
<span class="ex-row">expected = <span class="ex-key">hmac-sha256</span>(key, received_msg)</span>
<span class="ex-row"><span class="ex-key">constant_time_eq</span>(expected, received_tag) → <span class="ex-val">true</span> <span class="ex-cmt">// authentic</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Attacker modifies msg to "transfer $100 to Eve":</span></span>
<span class="ex-row">→ recomputed tag won't match — they don't have the key to forge a new tag</span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">poly1305</span>(one_time_key, msg) → <span class="ex-val">16-byte tag</span> <span class="ex-cmt">// key MUST be fresh each msg</span></span>`,
internals: `<p>A MAC proves authenticity using a shared secret. Differences are in <b>which primitive backs it</b> and <b>whether the key can be reused</b>.</p>
<p><b>HMAC</b> = hash-based MAC. <code>HMAC(K,m) = H((K⊕opad) || H((K⊕ipad) || m))</code>. The double-nesting and pads are designed so that HMAC stays secure even if the underlying hash has minor weaknesses (this is why HMAC-SHA1 is still safe despite SHA-1 collisions). Same key reusable across millions of messages.</p>
<p><b>Poly1305</b> = polynomial evaluation over GF(2^130 - 5). Blazing fast, but a <b>one-time MAC</b>: the key must change every message. Paired with ChaCha20 (which derives a fresh Poly1305 key from key+nonce per message).</p>
<p><b>CMAC / OMAC</b> = block-cipher-based MAC (AES-CMAC). Used when you already have AES hardware and want to avoid bringing in a hash.</p>
<p><b>GMAC</b> = the authentication-only mode of GCM (encrypt nothing, just authenticate AAD).</p>
<p><b>SipHash</b> = short, keyed pseudorandom function (64-bit output). Not a full cryptographic MAC — designed to stop hash-flooding DoS in language hash tables. <code>SipHash-2-4</code> = 2 compression + 4 finalisation rounds.</p>
<p><b>KMAC</b> = built natively from Keccak (SHA-3) sponge; cleaner than HMAC-SHA3.</p>`,
title: 'MAC Algorithms',
tagline: 'Prove a message came from the key-holder and was not tampered with',
desc: 'A Message Authentication Code (MAC) is a short tag computed from a message and a secret key. The receiver recomputes the tag with the same key — if tags match, the message is authentic and unmodified. Unlike hash functions, MACs require the key, so an attacker cannot forge tags without it. HMAC wraps any hash function; Poly1305 is an ultra-fast one-time MAC used inside ChaCha20-Poly1305.',
graph: `flowchart LR
A([Message]) --> C
B([Secret Key]) --> C
C[MAC Function\nHMAC-SHA256 / Poly1305] --> D([Tag])
D --> F{Verify}
A2([Same message]) --> E[Recompute tag]
B2([Same key]) --> E
E --> F
F -->|Tags match| G([Authentic])
F -->|Tags differ| H([Tampered or wrong key])`,
lists: {
active: ['hmac', 'hmac-sha256', 'hmac-sha512', 'hmac-sha3-256', 'hmac-blake2b', 'hmac-blake2s', 'aes-cmac', 'aes-pmac', 'vmac', 'umac', 'poly1305', 'siphash', 'siphash-2-4', 'siphash-4-8', 'kmac128-mac', 'kmac256-mac', 'blake2b-mac', 'blake2s-mac', 'blake3-mac', 'ascon-mac', 'ascon-prf', 'ghash'],
legacy: ['xcbc-mac', 'cbc-mac', 'des-mac', 'kdf1'],
upcoming: ['hmac-sha3-384', 'hmac-sha3-512', 'hmac-md5', 'hmac-sha1', 'aes-cmac-prf-128', 'lightmac', 'chaskey', 'emac', 'tmac', 'omac']
}
},
{
id: 'kdf',
example: `<span class="ex-row"><span class="ex-cmt">// HKDF = Extract-then-Expand</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-key">prk</span> = HKDF-Extract(</span>
<span class="ex-row"> salt = <span class="ex-val">"random-or-empty"</span>,</span>
<span class="ex-row"> ikm = <span class="ex-val">shared_DH_secret</span> <span class="ex-cmt">// 32 bytes of DH output</span></span>
<span class="ex-row">)</span>
<span class="ex-row">→ prk = <span class="ex-val">0xd0e7e8... (32 bytes pseudorandom key)</span></span>
<span class="ex-row"></span>
<span class="ex-row">enc_key = HKDF-Expand(prk, info=<span class="ex-val">"tls13 traffic c→s"</span>, L=32)</span>
<span class="ex-row">mac_key = HKDF-Expand(prk, info=<span class="ex-val">"tls13 traffic s→c"</span>, L=32)</span>
<span class="ex-row">iv = HKDF-Expand(prk, info=<span class="ex-val">"tls13 iv"</span>, L=12)</span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Each output is independent — leaking enc_key tells you nothing about mac_key.</span></span>`,
internals: `<p>KDFs split into two flavours: <b>password KDFs</b> (slow, memory-hard — covered earlier) and <b>cryptographic KDFs</b> (fast, take an already-strong secret and turn it into many keys). This section is the latter.</p>
<p><b>HKDF</b> (RFC 5869) is the modern default. Two-phase: <b>Extract</b> concentrates entropy from a possibly-non-uniform source (like raw DH output) into a uniform pseudorandom key; <b>Expand</b> stretches that PRK into any number of context-labelled output keys. Used in TLS 1.3, Signal, Noise, HPKE.</p>
<p><b>TLS-KDF / SSH-KDF / IKE-KDF</b> = protocol-specific KDFs that bake fixed labels and counter formats into the construction. Functionally similar to HKDF.</p>
<p><b>KBKDF (SP 800-108)</b> = NIST's "KDF in Counter Mode" — generic recipe using a PRF (HMAC or CMAC) plus a counter, label, and context.</p>
<p><b>X9.63-KDF / Concat-KDF / X9.42</b> = older single-pass KDFs (hash || counter || shared || info). Still mandated in some standards (ECIES, CMS).</p>
<p><b>BIP32 / SLIP10</b> = hierarchical deterministic key derivation for cryptocurrency wallets. Adds chain-codes and indexed derivation paths (<code>m/44'/0'/0'/0/0</code>).</p>`,
title: 'Key Derivation Functions',
tagline: 'Stretch one master secret into many purpose-specific keys',
desc: 'A single Diffie-Hellman shared secret or pre-shared key cannot safely be used directly for multiple purposes. KDFs like HKDF (Extract-then-Expand) take a high-entropy input and derive as many independent keys as needed — separate keys for encryption, authentication, IVs, and forward-secrecy ratchets. Each output key is computationally independent even though they share the same root.',
graph: `flowchart TD
A([Master Secret or\nShared DH output]) --> B[KDF Extract\nHKDF-Extract]
B --> C([Pseudorandom Key\nPRK])
C --> D[KDF Expand\nHKDF-Expand]
D --> E([Encryption Key])
D --> F([MAC Key])
D --> G([IV / Nonce])
D --> H([Next ratchet key])`,
lists: {
active: ['hkdf', 'hkdf-expand', 'hkdf-extract', 'hkdf-expand-label', 'kdf-tls12', 'kdf-tls13', 'kdf-ssh', 'kdf-ikev1', 'kdf-ikev2', 'kdf-srtp', 'kdf-sp800-108', 'kda-onestep', 'kda-twostep', 'concat-kdf', 'x942-kdf', 'x963-kdf', 'noise-kdf', 'bip32-kdf', 'slip10', 'sskdf', 'ecdh-kdf', 'cmkdf', 'me-kdf'],
legacy: [],
upcoming: ['evp-bytestokey', 'kdf2']
}
},
{
id: 'kem',
example: `<span class="ex-row"><span class="ex-cmt">// ─── X25519 (Elliptic Curve Diffie-Hellman) ─────────────────────────────</span></span>
<span class="ex-row"><span class="ex-cmt">// Both parties use the same curve base point G (a known public constant)</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Alice generates her key pair</span></span>
<span class="ex-row">alice_priv = <span class="ex-val">random(32 bytes)</span></span>
<span class="ex-row">alice_pub = X25519(alice_priv, <span class="ex-val">G</span>) <span class="ex-cmt">// G = Curve25519 base point (public constant)</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Bob generates his key pair</span></span>
<span class="ex-row">bob_priv = <span class="ex-val">random(32 bytes)</span></span>
<span class="ex-row">bob_pub = X25519(bob_priv, <span class="ex-val">G</span>) <span class="ex-cmt">// G = same base point for everyone</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Public keys (alice_pub, bob_pub) are exchanged over the network</span></span>
<span class="ex-row"><span class="ex-cmt">// Private keys (alice_priv, bob_priv) never leave the device</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Each party computes the shared secret independently:</span></span>
<span class="ex-row">alice_shared = X25519(alice_priv, bob_pub) ─┐</span>
<span class="ex-row"> ├─→ <span class="ex-val">identical 32-byte secret</span></span>
<span class="ex-row">bob_shared = X25519(bob_priv, alice_pub) ─┘</span>
<span class="ex-row"></span>
<span class="ex-row">assert alice_shared == bob_shared</span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// ─── ML-KEM-768 (Post-Quantum Key Encapsulation) ──────────────────────</span></span>
<span class="ex-row"><span class="ex-cmt">// One-shot model: no interactive back-and-forth needed</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Recipient (Bob) generates long-term keys once</span></span>
<span class="ex-row">(<span class="ex-key">pk</span>, <span class="ex-key">sk</span>) = ML-KEM.KeyGen() <span class="ex-cmt">// pk = public key, sk = secret key</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Sender (Alice) encapsulates to Bob's public key</span></span>
<span class="ex-row">(ct, ss_send) = ML-KEM.Encaps(<span class="ex-key">pk</span>) <span class="ex-cmt">// ct = ciphertext sent to Bob, ss = shared secret</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Recipient decrypts ciphertext with secret key</span></span>
<span class="ex-row">ss_recv = ML-KEM.Decaps(<span class="ex-key">sk</span>, ct) <span class="ex-cmt">// same shared secret recovered</span></span>
<span class="ex-row"></span>
<span class="ex-row">assert ss_send == ss_recv <span class="ex-cmt">// 32-byte shared secret established</span></span>`,
internals: `<p>Two different models for the same goal: produce a shared secret from public keys.</p>
<p><b>Diffie-Hellman / ECDH</b> is <b>interactive and symmetric</b>: each party has a (priv, pub) pair; they exchange pubs and each computes the same value with their priv + other's pub. Math: classic DH uses modular exponentiation in a prime-order group; ECDH uses scalar multiplication on an elliptic curve. <code>X25519</code> = ECDH on Curve25519 (Montgomery form, constant-time ladder, no malleable points). <code>X448</code> = same but Curve448 (higher security level, slower).</p>
<p><b>KEM</b> (Key Encapsulation Mechanism) is <b>one-shot and asymmetric</b>: only the recipient has a keypair. Sender runs <code>Encaps(pub) → (ciphertext, shared_secret)</code>; ships the ciphertext; recipient runs <code>Decaps(priv, ciphertext) → shared_secret</code>. Same end result, different shape — and crucially, KEMs work even when the underlying primitive is non-commutative (which is why all post-quantum schemes use KEM form, not DH form).</p>
<p><b>ML-KEM (Kyber)</b> = NIST PQ winner. Based on Module-LWE (lattice problem). Three security levels: 512/768/1024.</p>
<p><b>Classic McEliece</b> = code-based, huge public keys (~1 MB) but tiny ciphertexts and rock-solid 40-year-old security assumption.</p>
<p><b>HPKE</b> (RFC 9180) = hybrid public-key encryption — KEM + KDF + AEAD bundled into a clean API. Used by ECH, MLS, Oblivious HTTP.</p>
<p><b>RSA-OAEP</b> = encryption-flavoured KEM using RSA. Legacy in PQ era but still everywhere.</p>`,
title: 'Key Agreement / KEM',
tagline: 'Two parties derive the same shared secret without transmitting it',
desc: 'Key exchange lets two parties who have never met derive a shared secret over a public channel. In Diffie-Hellman / ECDH, each side generates a key pair; mathematical operations on each other\'s public keys produce the same value without it ever travelling on the wire. KEMs (Key Encapsulation Mechanisms) like ML-KEM (Kyber) are the post-quantum equivalent: the sender encapsulates a random key in a ciphertext that only the recipient\'s private key can open.',
graph: `flowchart LR
A([Alice private key]) --> C
B([Bob public key]) --> C
C[ECDH / ML-KEM] --> D([Shared Secret])
D --> E[KDF]
E --> F([Session keys])
G([Bob private key]) --> H
I([Alice public key]) --> H
H[Same ECDH] --> D
J([Network attacker]) -.->|Sees only\npublic keys| C`,
lists: {
active: ['dh', 'dhp', 'ecdh', 'x25519', 'x448', 'x3dh', 'hpke', 'ecies', 'rsa-oaep', 'csidh', 'frodokem', 'kyber', 'ml-kem-512', 'ml-kem-768', 'ml-kem-1024', 'ntru', 'ntruprime', 'sntrup761', 'classic-mceliece', 'mceliece-348864', 'mceliece-348864f', 'mceliece-460896', 'mceliece-460896f', 'mceliece-6688128', 'mceliece-6688128f', 'mceliece-6960119', 'mceliece-6960119f', 'mceliece-8192128', 'mceliece-8192128f', 'bike-1', 'bike-3', 'bike-5', 'hqc-128', 'hqc-192', 'hqc-256', 'ntruhps2048677', 'ntruhps4096821', 'ntruhrss701'],
legacy: ['ecmqv', 'rsa-pkcs1v15-enc', 'elgamal', 'sike'],
upcoming: ['saber', 'newhope', 'round5', 'lac', 'ledacrypt', 'nts-kem', 'rollo', 'rqc', 'ntru+']
}
},
{
id: 'sig',
example: `<span class="ex-row"><span class="ex-cmt">// Ed25519 — deterministic, fast, 64-byte signatures</span></span>
<span class="ex-row">(<span class="ex-key">priv</span>, <span class="ex-key">pub</span>) = ed25519.keygen() <span class="ex-cmt">// 32-byte keys each</span></span>
<span class="ex-row"></span>
<span class="ex-row">sig = ed25519.sign(priv, <span class="ex-val">"hello world"</span>)</span>
<span class="ex-row"> → <span class="ex-val">0x4eaf06... (64 bytes, R || s)</span></span>
<span class="ex-row"></span>
<span class="ex-row">ed25519.verify(pub, <span class="ex-val">"hello world"</span>, sig) → <span class="ex-val">true</span></span>
<span class="ex-row">ed25519.verify(pub, <span class="ex-val">"hello earth"</span>, sig) → <span class="ex-val">false</span> <span class="ex-cmt">// msg changed</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// RSA-PSS — same idea, 256-byte signatures (RSA-2048)</span></span>
<span class="ex-row">sig = RSA-PSS.sign(rsa_priv, sha256(<span class="ex-val">"hello"</span>))</span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// ECDSA — randomized — k MUST be unique and secret per signature</span></span>
<span class="ex-row">sig = ECDSA.sign(priv, sha256(msg), k=<span class="ex-val">random</span>)</span>
<span class="ex-row"><span class="ex-cmt">// PS3 hack 2010: Sony reused k → priv key recovered with arithmetic</span></span>`,
internals: `<p>All signature schemes do the same thing — sign with a private key, verify with the corresponding public key — but differ in <b>underlying math</b>, <b>signature size</b>, <b>determinism</b>, and <b>side-channel hazards</b>.</p>
<p><b>RSA-PSS</b> — RSA-based, probabilistic padding (PSS = Probabilistic Signature Scheme). Big keys (2048-4096 bits), big sigs (256-512 bytes), well-understood. <b>RSA-PKCS#1 v1.5</b> is the legacy padding still seen in old certificates — has known vulnerabilities when used naïvely (Bleichenbacher).</p>
<p><b>ECDSA</b> — elliptic-curve DSA. Smaller keys (~64 bytes pub on P-256) and signatures (~64-72 bytes DER). <b>Randomized</b>: each signature uses a fresh random nonce <code>k</code>. If <code>k</code> repeats across two signatures → private key extractable by simple algebra (Sony PS3, multiple Bitcoin wallet breaches).</p>
<p><b>Deterministic ECDSA</b> (RFC 6979) — derive <code>k</code> from <code>HMAC(priv, msg)</code>. Same security, no RNG dependence.</p>
<p><b>Ed25519 / EdDSA</b> — Schnorr-family signature on Curve25519. Deterministic by construction (k = hash(priv || msg)), constant-time, no padding needed, no malleability. Single best general-purpose choice today. <b>Ed448</b> = same on Curve448 for higher margin.</p>
<p><b>Schnorr</b> — linear signature. Signatures are <b>aggregable</b>: you can combine N signatures into one (MuSig, MuSig2). Bitcoin Taproot uses Schnorr for this reason.</p>
<p><b>BLS12-381</b> — pairing-friendly curve. Allows <b>signature aggregation</b> (single signature for thousands of signers) and <b>threshold signing</b>. Used by Ethereum consensus, Filecoin, Dfinity.</p>
<p><b>SM2 / GOST / SR25519</b> — national/protocol-specific variants (China, Russia, Polkadot).</p>`,
title: 'Digital Signatures',
tagline: 'Prove authorship and integrity using a private key anyone can verify',
desc: 'Digital signatures are the public-key equivalent of a MAC. The signer uses their private key to produce a signature over a message hash; anyone with the signer\'s public key can verify it. This gives non-repudiation — the signer cannot deny having signed, because nobody else has their private key. ECDSA and Ed25519 are the workhorses of TLS, code signing, and cryptocurrency transactions.',
graph: `flowchart TD
A([Message]) --> B[Hash]
B --> C([Digest])
C --> D[Sign with Private Key\nEd25519 / ECDSA]
D --> E([Signature])
E --> F{Verify}
C2([Digest]) --> F
G([Signer public key]) --> F
F -->|Valid| H([Authentic + Non-repudiable])
F -->|Invalid| I([Rejected])`,
lists: {
active: ['rsa-pss', 'ecdsa', 'det-ecdsa', 'ecdsa-recoverable', 'ed25519', 'ed448', 'sr25519', 'sm2-sign', 'gost-r-34.10-2012', 'schnorr', 'bbs', 'bls12-381-g1', 'bls12-381-g2'],
legacy: ['rsa-pkcs1v15-sign', 'dsa', 'gost-r-34.10-2001', 'rainbow', 'ge-mss'],
upcoming: ['ecdsa-secp256k1', 'rsa-fdh', 'kcdsa', 'ecgdsa', 'eckdsa', 'musig', 'musig2', 'bls-aggregate', 'rsa-blind-sig', 'bls-blind-sig', 'cryptonote-ring-sig', 'mlsag', 'clsag', 'group-sig']
}
},
{
id: 'pqsig',
example: `<span class="ex-row"><span class="ex-cmt">// ML-DSA-65 (Dilithium-3) — NIST PQ standard</span></span>
<span class="ex-row">(pk, sk) = ML-DSA-65.keygen()</span>
<span class="ex-row"> pk: <span class="ex-val">1952 bytes</span> sk: <span class="ex-val">4032 bytes</span></span>
<span class="ex-row"></span>
<span class="ex-row">sig = ML-DSA-65.sign(sk, <span class="ex-val">"hello"</span>)</span>
<span class="ex-row"> → <span class="ex-val">3309 bytes</span> <span class="ex-cmt">// ~50× larger than Ed25519's 64</span></span>
<span class="ex-row"></span>
<span class="ex-row">ML-DSA-65.verify(pk, <span class="ex-val">"hello"</span>, sig) → <span class="ex-val">true</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Falcon-512 — same security level, much smaller sigs</span></span>
<span class="ex-row">sig = Falcon-512.sign(sk, <span class="ex-val">"hello"</span>) → <span class="ex-val">~666 bytes</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// SLH-DSA-SHA2-128f (SPHINCS+) — pure hash, huge sigs</span></span>
<span class="ex-row">sig = SLH-DSA-128f.sign(sk, <span class="ex-val">"hello"</span>) → <span class="ex-val">17088 bytes</span></span>`,
internals: `<p>All three NIST-standardised PQ signature families do the same job (sign / verify) but rest on <b>different hard problems</b> and trade <b>sig size</b> vs <b>speed</b> vs <b>assumption strength</b>.</p>
<p><b>ML-DSA (Dilithium)</b> — Module-Learning-With-Errors lattice problem. Balanced: medium-size keys + sigs, fast on commodity CPUs, fully deterministic and side-channel-friendly. <b>Default PQ signature</b> for most use cases. Three levels: 44 / 65 / 87.</p>
<p><b>Falcon</b> — NTRU lattice + Fast Fourier sampling. Produces the <b>smallest</b> PQ signatures (~700-1300 bytes) — best for size-constrained protocols like TLS handshakes and certificate chains. Catch: signing requires floating-point arithmetic, which is hard to make constant-time → significant side-channel hazard. Keygen is slow.</p>
<p><b>SLH-DSA (SPHINCS+)</b> — pure hash-based, stateless. Security rests <b>only</b> on the hash function being collision/preimage-resistant — no fancy algebra, no lattice assumption. Considered the most conservative PQ choice. Cost: huge signatures (8-50 KB) and slow signing. Variants: <code>f</code> = fast (bigger sigs), <code>s</code> = small (slower).</p>
<p><b>Stateful hash signatures</b> (LMS, XMSS) get <i>way</i> smaller sigs than SLH-DSA — but at the cost of stateful signing (see next section).</p>
<p><b>Upcoming</b> (NIST Round 2 / additional onramp): <code>UOV</code>, <code>MAYO</code>, <code>SQIsign</code> (isogeny-based, tiny keys but slow), <code>HAWK</code> (lattice without FFT).</p>`,
title: 'PQ Digital Signatures',
tagline: 'Signatures that remain secure even against quantum computers',
desc: 'A sufficiently large quantum computer (running Shor\'s algorithm) can break ECDSA and RSA in polynomial time. Post-quantum signature schemes are built on mathematical problems believed to be quantum-hard: lattice problems (ML-DSA/Dilithium, Falcon) and hash-based constructions (SPHINCS+/SLH-DSA). NIST standardized ML-DSA, Falcon, and SLH-DSA in 2024. Migration is urgent for long-lived keys.',
graph: `flowchart TD
A([ECDSA / RSA]) -->|Broken by\nQuantum computer| B([Insecure in PQ era])
C([Lattice problem\nML-DSA / Dilithium / Falcon]) --> D[PQ Signature]
E([Hash-based\nSPHINCS+ / SLH-DSA]) --> D
D --> F([Sign])
D --> G{Verify}
G -->|Secure against\nquantum attacks| H([Future-proof])`,
lists: {
active: ['dilithium', 'ml-dsa-44', 'ml-dsa-65', 'ml-dsa-87', 'falcon-512', 'falcon-1024', 'falcon-padded-512', 'falcon-padded-1024', 'sphincs+', 'slh-dsa-sha2-128f', 'slh-dsa-sha2-128s', 'slh-dsa-sha2-192f', 'slh-dsa-sha2-192s', 'slh-dsa-sha2-256f', 'slh-dsa-sha2-256s', 'slh-dsa-shake-128f', 'slh-dsa-shake-128s', 'slh-dsa-shake-192f', 'slh-dsa-shake-192s', 'slh-dsa-shake-256f', 'slh-dsa-shake-256s', 'haetae', 'almar'],
legacy: [],
upcoming: ['picnic', 'uov', 'mayo', 'prov', 'sqisign', 'hawk', 'hufu', 'sdith', 'less', 'meds', 'cross', 'wave', 'gravity-sphincs', 'wots+', 'fors', 'hors']
}
},
{
id: 'stateful',
example: `<span class="ex-row"><span class="ex-cmt">// XMSS — Merkle tree of 2^h one-time signing keys (here h=10 → 1024 sigs)</span></span>
<span class="ex-row"></span>
<span class="ex-row">(pk, sk) = XMSS.keygen(h=10)</span>
<span class="ex-row"> pk = <span class="ex-val">root of Merkle tree (~64 bytes)</span></span>
<span class="ex-row"> sk = <span class="ex-val">seed + index counter (starts at 0)</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// First signature uses leaf 0, increments counter</span></span>
<span class="ex-row">sig_0 = XMSS.sign(sk, <span class="ex-val">"msg1"</span>)</span>
<span class="ex-row"> → idx=0 || WOTS+_sig || auth_path[10 hashes]</span>
<span class="ex-row"> → <span class="ex-val">~2500 bytes</span></span>
<span class="ex-row"></span>
<span class="ex-row">sig_1 = XMSS.sign(sk, <span class="ex-val">"msg2"</span>) <span class="ex-cmt">// idx=1, counter persisted to disk</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// CRITICAL: if process crashes and counter resets to 0 →</span></span>
<span class="ex-row"><span class="ex-cmt">// signing two msgs with idx=0 → WOTS+ key revealed → forge anything</span></span>`,
internals: `<p>All four are <b>Merkle-tree of one-time signatures</b>. Differences are tree depth, hash choice, and whether multiple trees are stacked.</p>
<p><b>WOTS+</b> = Winternitz one-time signature, the leaf primitive. Each leaf is a hash chain of length <code>w</code>. Signing reveals certain chain positions based on the message digest — once revealed, that leaf is burned forever.</p>
<p><b>LMS</b> (RFC 8554) = single Merkle tree of WOTS+ leaves. Simple, NIST-approved (SP 800-208). Tree depth fixed at keygen → fixed max number of signatures.</p>
<p><b>HSS</b> = "Hierarchical" LMS. Stack multiple LMS trees: root tree signs the public keys of subtrees. Enables astronomical signature counts (2^60+) without 2^60-leaf single tree.</p>
<p><b>XMSS</b> (RFC 8391) = XMSS uses bitmasked hash compression for tighter security proof under second-preimage instead of collision resistance. <b>XMSS-MT</b> = multi-tree variant analogous to HSS.</p>
<p><b>Why "stateful" matters</b>: the leaf index <i>must</i> persist across reboots, replicas, backups. Restoring a backup that resets the counter and then signing is <b>catastrophic</b> — forgery is trivial. This is why SLH-DSA (stateless SPHINCS+) exists despite its huge signatures.</p>
<p><b>Use case</b>: firmware-update signing keys that live in HSMs with strict counter persistence — tiny signature footprint (~2KB) and pure hash security.</p>`,
title: 'Stateful Hash Signatures',
tagline: 'Hash-based signatures using a Merkle tree of one-time keypairs',
desc: 'LMS, XMSS, and HSS build a Merkle tree from thousands of one-time signing keys (WOTS+). The root of the tree is the public key. Each signature reveals one leaf key plus an authentication path to the root. These are unconditionally quantum-secure — security rests only on the hash function. The critical constraint: each leaf can only be used once. Signing state must be persisted; losing it or reusing an index is catastrophic.',
graph: `flowchart TD
A([WOTS+ one-time keys\nLeaf 1 … Leaf N]) --> B[Merkle Tree\nHash each layer up]
B --> C([Root = Public Key])
D([Sign message 1]) --> E([Use leaf 1\n+ auth path to root])
F([Sign message 2]) --> G([Use leaf 2\n+ auth path to root])
H([Reuse leaf 1!]) -.->|State corruption\ncatastrophic break| D
E --> I([Verifier checks\npath to root])`,
lists: {
active: ['lms', 'hss', 'xmss', 'xmssmt'],
legacy: [],
upcoming: ['gmss', 'xmss-t', 'bpqs', 'wots']
}
},
{
id: 'mpc',
example: `<span class="ex-row"><span class="ex-cmt">// Shamir secret sharing — 2-of-3 split</span></span>
<span class="ex-row">secret = <span class="ex-val">42</span></span>
<span class="ex-row"><span class="ex-cmt">// Pick random polynomial of degree T-1 = 1: f(x) = 42 + 45·x (over prime field)</span></span>
<span class="ex-row">share_1 = (1, f(1)) = (<span class="ex-val">1, 87</span>) → Alice</span>
<span class="ex-row">share_2 = (2, f(2)) = (<span class="ex-val">2, 132</span>) → Bob</span>
<span class="ex-row">share_3 = (3, f(3)) = (<span class="ex-val">3, 177</span>) → Carol</span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Any 2 reconstruct via Lagrange interpolation:</span></span>
<span class="ex-row">Alice + Bob: solve f(x) through (1,87),(2,132) → f(0) = <span class="ex-val">42</span> ✓</span>
<span class="ex-row">Alice alone: ANY value 0…p is equally consistent — zero info leak</span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// FROST — threshold Schnorr signing (2-of-3)</span></span>
<span class="ex-row">round1: each signer broadcasts a nonce commitment</span>
<span class="ex-row">round2: 2 signers compute partial sigs → aggregate → 1 valid Schnorr sig</span>
<span class="ex-row"><span class="ex-cmt">// Full private key never assembled in any single place.</span></span>`,
internals: `<p>Three overlapping technologies — all about distributing trust.</p>
<p><b>Secret sharing</b> = split data so reconstruction needs a threshold. <code>Shamir</code> uses polynomial interpolation in a finite field — information-theoretically secure (unbounded attacker, fewer than T shares = zero information). <code>Feldman VSS</code> adds Pedersen-style commitments so shareholders can detect malicious dealers. <code>Pedersen VSS</code> goes further (hides the secret from the dealer too).</p>
<p><b>Threshold signatures</b> = T-of-N signing without ever combining the private key. <code>FROST</code> (threshold Schnorr) — clean two-round protocol, used in Bitcoin/Ethereum custody. <code>GG18 / GG20 / CMP / Lindell17</code> — threshold ECDSA, much harder than Schnorr (ECDSA's nonce-and-inverse structure is non-linear). <code>tBLS</code> — threshold BLS, trivial because BLS is naturally linear-aggregable.</p>
<p><b>General MPC</b> = jointly compute any function on private inputs. <code>SPDZ</code> uses Beaver triples + MACs for malicious security. <code>BMR / GMW</code> for Boolean circuits. <code>Yao garbled circuits</code> for two-party.</p>
<p><b>DKG</b> = distributed key generation — generate (priv shares, single pub) without anyone seeing the priv. Required to bootstrap threshold systems without a trusted dealer.</p>
<p><b>OT / VOLE / Beaver triples</b> = the cryptographic primitives MPC protocols are built from.</p>`,
title: 'Threshold / MPC',
tagline: 'Split secrets across multiple parties so no single party holds the key',
desc: 'Threshold cryptography distributes trust. Shamir\'s Secret Sharing splits a secret into N shares such that any T shares reconstruct it but T-1 shares reveal nothing. FROST enables distributed threshold signatures: T-of-N parties jointly sign without ever assembling the private key in one place. MPC (Multi-Party Computation) extends this to general computations — parties jointly compute a function on private inputs without learning each other\'s data.',
graph: `flowchart TD
A([Secret key]) --> B[Secret Sharing\nShamir / Feldman VSS]
B --> C([Share 1 → Alice])
B --> D([Share 2 → Bob])
B --> E([Share 3 → Carol])
C --> F{Reconstruct\nneeds T-of-N shares}
D --> F
F --> G([Secret reconstructed])
E -.->|Not needed if T=2| F
H([Single server compromised]) -.->|Not enough shares| F`,
lists: {
active: ['frost', 'tbls', 'gargos', 'tecla', 'the-clash', 'classic-schnorr-t', 'bam', 'ccgmp', 'haystack', 'mithril', 'quorus', 'redeta', 'splitkey', 'minimpc', 'maestro', 'amber', 'hermine', 'least', 'tanuki', 'vinaigrette', 'pantheria', 'zama-tfhe', 'zama-zhenith', 'piver', 'schmivitz', 'smallwood', 'shamir', 'feldman-vss', 'pedersen-vss', 'dkg', 'pvss', 'ot', 'vole', 'beaver', 'mpc-ecdsa', 'mpc-schnorr'],
legacy: ['roast'],
upcoming: ['gg18', 'gg20', 'gg21', 'cmp', 'lindell17', 'doerner-shelat', 'spdz', 'mascot', 'bmr', 'gmw', 'proactive-ss', 'async-dkg', 'robust-dkg', 'ring-sig-generic', 'linkable-ring-sig']
}
},
{
id: 'lightweight',
example: `<span class="ex-row"><span class="ex-cmt">// ASCON-AEAD128 — NIST Lightweight Crypto winner (2023)</span></span>
<span class="ex-row"><span class="ex-cmt">// 320-bit sponge state, runs on 8-bit microcontrollers</span></span>
<span class="ex-row"></span>
<span class="ex-row">ct, tag = ascon.encrypt(</span>
<span class="ex-row"> key = <span class="ex-val">16 bytes</span>,</span>
<span class="ex-row"> nonce = <span class="ex-val">16 bytes</span>,</span>
<span class="ex-row"> ad = <span class="ex-val">"sensor-id=42"</span>,</span>
<span class="ex-row"> pt = <span class="ex-val">"hello"</span></span>
<span class="ex-row">)</span>
<span class="ex-row">→ ct = <span class="ex-val">"1edd8cc1cf"</span> tag = <span class="ex-val">16 bytes</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Footprint comparison on 8-bit AVR:</span></span>
<span class="ex-row">AES-GCM: <span class="ex-val">~1900 bytes ROM, ~150 cycles/byte</span></span>
<span class="ex-row">ASCON: <span class="ex-val"> ~700 bytes ROM, ~100 cycles/byte</span></span>
<span class="ex-row">HIGHT: <span class="ex-val"> ~400 bytes ROM (block cipher only)</span></span>`,
internals: `<p>Lightweight ≠ less secure. These are full 128-bit-security designs that <b>compress better into limited hardware</b>: smaller state, fewer gates, lower power.</p>
<p><b>ASCON</b> — sponge construction (like SHA-3) with a 320-bit state and a single permutation reused for AEAD, hashing, and XOF. One implementation covers all three primitives → tiny ROM. NIST LWC winner; widely adopted on IoT now.</p>
<p><b>LEA</b> (Korea standard) — 32-bit ARX block cipher. Tuned for ARM Cortex-M and 32-bit MCUs; ~2× faster than AES in pure software on those targets.</p>
<p><b>HIGHT</b> — 64-bit block, 8-bit operations, designed for ultra-low-end 8-bit microcontrollers (RFID tags). Used in some Korean industrial standards.</p>
<p><b>PHOTON-Beetle / Sparkle / TinyJambu / Xoodyak / Romulus</b> — NIST LWC finalists. Different design families (sponge, AES-round-based, block-cipher-based). All retained for legacy reasons; ASCON is the standard.</p>
<p><b>Spongent / PRESENT / KLEIN</b> — even smaller hardware footprint (<2000 GE), used in RFID and disposable sensors. PRESENT-80 has known cryptanalytic margin issues now.</p>`,
title: 'Lightweight Crypto',
tagline: 'Secure algorithms designed for microcontrollers and IoT devices',
desc: 'Standard AES requires ~1400 bytes of ROM, hardware S-boxes, and multiple clock cycles per block — too heavy for an 8-bit microcontroller with 2 KB RAM. Lightweight ciphers and hashes achieve similar security goals with a fraction of the code size and power budget. ASCON (NIST LWC winner 2023) provides authenticated encryption with a 320-bit state. LEA and HIGHT are block ciphers optimised for 32-bit and 8-bit processors respectively.',
graph: `flowchart LR
A([IoT Sensor\n8-bit MCU\n2 KB RAM]) --> B
B{Algorithm choice}
B -->|Standard AES| C([Too heavy\nwont fit])
B -->|ASCON / LEA| D([Secure output\nfits on device])
D --> E([Encrypted sensor data])
D --> F([Authenticated message])`,
lists: {
active: ['ascon-hash256', 'ascon-xof128', 'ascon-cxof128', 'lea', 'hight'],
legacy: ['photon-beetle-hash', 'romulus-hash', 'sparkle-esch', 'xoodyak-hash'],
upcoming: ['mibs', 'klein', 'puffin', 'spongent', 'quark']
}
},
{
id: 'drbg',
example: `<span class="ex-row"><span class="ex-cmt">// HMAC-DRBG (NIST SP 800-90A)</span></span>
<span class="ex-row"></span>
<span class="ex-row">state = HMAC-DRBG.instantiate(</span>
<span class="ex-row"> entropy = <span class="ex-val">read 32 bytes from /dev/urandom</span>,</span>
<span class="ex-row"> nonce = <span class="ex-val">16 bytes</span>,</span>
<span class="ex-row"> personalization = <span class="ex-val">"app=tls,host=example.com"</span></span>
<span class="ex-row">)</span>
<span class="ex-row"></span>
<span class="ex-row">bytes = HMAC-DRBG.generate(state, n=<span class="ex-val">32</span>)</span>
<span class="ex-row"> → <span class="ex-val">0x9e8c4d... (32 unpredictable bytes for an AES key)</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// After ~2^48 outputs OR on event boundary → reseed:</span></span>
<span class="ex-row">HMAC-DRBG.reseed(state, fresh_entropy)</span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// In Linux: just use getrandom() — kernel handles entropy + DRBG.</span></span>
<span class="ex-row"><span class="ex-cmt">// In hardware: rdrand reads CPU thermal-noise TRNG.</span></span>`,
internals: `<p><b>TRNG</b> (true random) vs <b>DRBG</b> (deterministic): TRNGs measure physical entropy (thermal noise, ring-oscillator jitter, radioactive decay). DRBGs take a small entropy seed and stretch it deterministically into a long pseudorandom stream. Production systems use TRNG → entropy pool → DRBG.</p>
<p><b>CTR-DRBG</b> — AES in counter mode, fast on AES-NI hardware. Default in many TLS libraries.</p>
<p><b>HMAC-DRBG</b> — HMAC chaining. Slower than CTR-DRBG but conservative; resistant to a single block-cipher break.</p>
<p><b>Hash-DRBG</b> — raw hash chaining, simplest. Listed in SP 800-90A but less popular.</p>
<p><b>Fortuna</b> — Schneier/Ferguson design with 32 entropy pools collecting at different rates → resists state-compromise extension attacks. Used in FreeBSD's <code>/dev/random</code>.</p>
<p><b>Yarrow</b> — Fortuna's predecessor. Replaced.</p>
<p><b>RDRAND / RDSEED</b> — Intel/AMD CPU instructions exposing on-chip TRNG and DRBG respectively. Fast but distrust-by-default in some communities (no way to audit the silicon).</p>
<p><b>getrandom() / getentropy()</b> — modern syscalls (Linux, BSD, macOS). Always-blocking-until-seeded; correct default for any application code.</p>
<p><b>Dual_EC_DRBG</b> (not listed) — famously backdoored NIST DRBG. Removed from SP 800-90A in 2014.</p>`,
title: 'DRBG / RNG',
tagline: 'Generate unpredictable random bits for keys, nonces, and IVs',
desc: 'Cryptographic operations demand unpredictable randomness. True RNGs (TRNGs) harvest physical entropy — thermal noise, hardware interrupts, CPU jitter. DRBGs (Deterministic Random Bit Generators) seed from entropy then expand it deterministically. NIST SP 800-90A defines CTR-DRBG (AES-based), HMAC-DRBG, and Hash-DRBG. Reseeding prevents state exhaustion. Weak randomness is the root cause of some of history\'s most catastrophic cryptographic breaks.',
graph: `flowchart TD
A([Hardware entropy\nRDRAND / thermal / jitter]) --> B[Entropy Pool]
B --> C[Seed]
C --> D[DRBG\nCTR-DRBG / HMAC-DRBG]
D --> E([Random bits])
D -->|Reseed periodically| C
E --> F([Encryption keys])
E --> G([Nonces / IVs])
E --> H([Session tokens])`,
lists: {
active: ['ctr-drbg', 'hash-drbg', 'hmac-drbg', 'csprng-system', 'trng', 'entropy-pool', 'reseed-scheduler', 'rdrand', 'rdseed', 'jitterentropy', 'fortuna', 'nist-sp800-90b', 'nist-sp800-90c'],
legacy: ['haveged', 'yarrow', 'cryptgenrandom', 'egd', 'prngd', 'lavarnd'],
upcoming: ['chacha20-drbg', 'getrandom', 'getentropy', 'bcryptgenrandom', 'nist-randomness-beacon', 'qrng', 'blockchain-vrf']
}
},
{
id: 'zk',
example: `<span class="ex-row"><span class="ex-cmt">// Groth16 — prove "I know x s.t. sha256(x) == 0xabc...def"</span></span>
<span class="ex-row"><span class="ex-cmt">// without revealing x</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// 1. Compile circuit, run trusted setup (per-circuit):</span></span>
<span class="ex-row">(pk, vk) = Groth16.setup(circuit_preimage)</span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// 2. Prover knows witness x = "hello"</span></span>
<span class="ex-row">proof = Groth16.prove(pk, public=<span class="ex-val">target_hash</span>, witness=<span class="ex-val">"hello"</span>)</span>
<span class="ex-row"> → <span class="ex-val">3 group elements (~200 bytes total)</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// 3. Verifier — fast, milliseconds, sees only target_hash + proof</span></span>
<span class="ex-row">Groth16.verify(vk, target_hash, proof) → <span class="ex-val">true</span></span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// CKKS Homomorphic Encryption — compute on encrypted numbers</span></span>
<span class="ex-row">enc_a = CKKS.encrypt(pk, <span class="ex-val">3.14</span>)</span>
<span class="ex-row">enc_b = CKKS.encrypt(pk, <span class="ex-val">2.71</span>)</span>
<span class="ex-row">enc_c = enc_a · enc_b <span class="ex-cmt">// multiplied while encrypted</span></span>
<span class="ex-row">CKKS.decrypt(sk, enc_c) → <span class="ex-val">≈ 8.51</span></span>`,
internals: `<p>Two related but distinct capabilities, often shipped together because both run on similar lattice math.</p>
<p><b>ZK proof systems</b> let a prover convince a verifier of a statement without revealing the witness. They differ on three axes: <b>setup</b>, <b>proof size</b>, <b>verifier speed</b>, <b>post-quantum security</b>.</p>
<p><b>Groth16</b> — pairing-based SNARK. Tiniest proofs ever (~200 bytes), fastest verifier (~3 pairings). Catch: requires a <b>trusted setup ceremony per circuit</b> — if anyone keeps the toxic waste they can forge proofs. Powers Zcash, many L2s.</p>
<p><b>PLONK / Marlin / Halo2 / Plonky2</b> — universal setup (one ceremony works for any circuit). Slightly bigger proofs. Halo2 uses recursive composition + IPA commitments → no trusted setup at all.</p>
<p><b>STARK</b> — hash-based, transparent (no setup), <b>post-quantum secure</b>. Proofs ~50-200 KB, fast prover, fast verifier. Used by StarkNet, ZK-EVMs.</p>
<p><b>Bulletproofs</b> — no trusted setup, log-sized proofs, slow verifier. Used in Monero for range proofs.</p>
<p><b>KZG commitment</b> — polynomial commitment scheme used inside PLONK and Ethereum data-availability (EIP-4844 blobs).</p>
<p><b>HE (Homomorphic Encryption)</b> = compute on ciphertext. <b>BFV / BGV</b> = exact integer arithmetic. <b>CKKS</b> = approximate real-number arithmetic (great for ML on encrypted data). <b>TFHE</b> = bit-level FHE, slow but supports arbitrary boolean circuits. All based on Ring-LWE (so naturally PQ).</p>`,
title: 'ZK Proofs / HE',
tagline: 'Prove knowledge without revealing it; compute on encrypted data',
desc: 'Zero-Knowledge Proofs let a prover convince a verifier that a statement is true without revealing why. Groth16 proves "I know a valid Sudoku solution" with a 3-element proof anyone can verify in milliseconds. SNARKs power blockchain rollups, private credentials, and verifiable ML. Homomorphic Encryption (CKKS, BFV, TFHE) lets a cloud server compute on ciphertext — it adds numbers, runs ML inference, or evaluates functions entirely on encrypted data, returning an encrypted result only the key-holder can read.',
graph: `flowchart LR
A([Prover\nknows secret witness]) --> B[ZK Proof System\nGroth16 / PLONK / STARK]
B --> C([Short proof])
C --> D{Verifier}
D -->|Accepts| E([Statement true\nsecret not revealed])
F([Sensitive data]) --> G[Homomorphic Enc\nCKKS / BFV / TFHE]
G --> H([Encrypted data])
H --> I[Compute on ciphertext]
I --> J([Encrypted result])
J --> K([Decrypt — only key holder])`,
lists: {
active: ['groth16', 'plonk', 'marlin', 'halo2', 'plonky2', 'stark', 'bulletproofs', 'spartan', 'sonic', 'kzg-commitment', 'fri', 'ligero', 'dory', 'gm17', 'tfhe'],
legacy: ['pinocchio', 'supersonic'],
upcoming: ['bgv', 'ckks', 'bfv', 'gsw', 'dm-cggi', 'nova', 'supernova', 'hypernova', 'protostar', 'shplonk', 'ipa', 'brakedown', 'orion', 'stir', 'whir', 'basefold', 'gemini', 'latticefold', 'jolt', 'sp1', 'lasso', 'cairo', 'risc-zero', 'ggpr', 'bctv14', 'pghr13', 'hyrax', 'libra', 'virgo', 'fractal', 'aurora', 'zkinterface']
}
},
{
id: 'protocol',
example: `<span class="ex-row"><span class="ex-cmt">// TLS 1.3 — 1-RTT handshake</span></span>
<span class="ex-row"></span>
<span class="ex-row">client → server: ClientHello { </span>
<span class="ex-row"> random, cipher_suites=[chacha20_poly1305, aes_gcm],</span>
<span class="ex-row"> key_share = <span class="ex-val">X25519_pub_C</span>,</span>
<span class="ex-row"> signature_algorithms = [ed25519, ecdsa_p256] </span>
<span class="ex-row"> }</span>
<span class="ex-row"></span>
<span class="ex-row">server → client: ServerHello { random, key_share = <span class="ex-val">X25519_pub_S</span> }</span>
<span class="ex-row"> [encrypted from this point on:]</span>
<span class="ex-row"> { Certificate, CertificateVerify(sig), Finished }</span>
<span class="ex-row"></span>
<span class="ex-row"> <span class="ex-cmt">// Both sides: shared = X25519(my_priv, peer_pub)</span></span>
<span class="ex-row"> <span class="ex-cmt">// keys = HKDF-Expand(shared, "tls13 ...")</span></span>
<span class="ex-row"></span>
<span class="ex-row">client → server: Finished, [Application data via ChaCha20-Poly1305]</span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Noise_XX pattern is the same idea, library-free, used in WireGuard / Lightning.</span></span>`,
internals: `<p>Protocols are <b>recipes</b> assembling KEM + KDF + AEAD + signature into a full secure channel. They differ in <b>authentication model</b>, <b>round-trip count</b>, and <b>forward-secrecy properties</b>.</p>
<p><b>TLS 1.3</b> — certificate-authenticated. 1-RTT handshake, 0-RTT for resumption (with replay caveats). Standardised PQ hybrid in 2024 (X25519+ML-KEM).</p>
<p><b>Noise Protocol Framework</b> — composable handshake patterns named by two characters (<code>N</code>o-static, <code>K</code>nown-static, <code>X</code>mitted-static for initiator/responder respectively). <code>Noise_XX</code> = mutual auth via transmitted statics. <code>Noise_IK</code> = recipient's static is known upfront → 1-RTT. WireGuard uses <code>Noise_IKpsk2</code>; Lightning uses <code>Noise_XK</code>.</p>
<p><b>MLS (Messaging Layer Security)</b> — group messaging with a TreeKEM ratchet. Scales to thousands of members with logarithmic key updates. RFC 9420.</p>
<p><b>Signal Double Ratchet</b> = <code>X3DH</code> (initial async key agreement) + symmetric chain ratchet + DH ratchet. Forward secrecy <i>and</i> post-compromise security per message. Powers WhatsApp, Signal, Messenger.</p>
<p><b>PQXDH</b> = Signal's PQ-hybrid X3DH (Kyber added alongside X25519).</p>
<p><b>SPAKE2 / OPAQUE / CPace</b> = password-authenticated key exchange (PAKE). Two parties with a shared password derive a strong key with no offline-dictionary risk.</p>
<p><b>KEMTLS</b> = experimental TLS variant replacing the server signature with a KEM operation — smaller PQ handshake.</p>
<p><b>ECH (Encrypted Client Hello)</b> = encrypts the SNI in TLS 1.3 using HPKE.</p>`,
title: 'Protocol Primitives',
tagline: 'Complete handshake and session protocols built from the primitives above',
desc: 'Protocols combine key exchange, authentication, and AEAD into complete secure channels. TLS 1.3 completes in one round-trip: client sends a key share; server responds with certificate, signature, and encrypted data simultaneously. The Noise Protocol Framework defines composable patterns (XX, IK, NK…) for bespoke secure channels. Signal\'s Double Ratchet powers end-to-end encrypted messaging with per-message forward secrecy.',
graph: `flowchart TD
A([Client]) -->|ClientHello + KeyShare| B([Server])
B -->|ServerHello + Cert\n+ Signature + KeyShare| A
A --> C[ECDH / ML-KEM]
B --> C
C --> D[KDF — HKDF]
D --> E([Handshake keys])
D --> F([Application keys])
E --> G([Verify server cert])
F --> H([Encrypted channel\nTLS 1.3 / Noise / MLS])`,
lists: {
active: ['noise-nn', 'noise-kn', 'noise-nk', 'noise-kk', 'noise-nx', 'noise-xn', 'noise-xk', 'noise-kx', 'noise-in', 'noise-ik', 'noise-ix', 'noise-xx', 'noise-ikpsk2', 'signal-x3dh', 'signal-double-ratchet', 'opaque', 'spake2', 'spake2+', 'dragonfly', 'otrv4', 'mtproto', 'wireguard', 'mls', 'pqxdh', 'cpace', 'aucpace', 'kemtls', 'pq-tls-hybrid', 'ech', 'odohdtls', 'oblivious-http', 'privacy-pass', 'masque', 'edhoc', 'oscore', 'dtls12', 'dtls13', 'noise-xxfallback', 'disco', 'noisesocket', 'zrtp', 'hmqv', 'yak', 'sesame'],
legacy: ['srp', 'j-pake', 'otr', 'speke', 'curvecp', 'minimalt', 'sts'],
upcoming: []
}
},
{
id: 'pki',
example: `<span class="ex-row"><span class="ex-cmt">// X.509v3 certificate (decoded)</span></span>
<span class="ex-row">Certificate {</span>
<span class="ex-row"> version: <span class="ex-val">v3</span></span>
<span class="ex-row"> serial: <span class="ex-val">0x03ad4...</span></span>
<span class="ex-row"> issuer: <span class="ex-val">CN=Let's Encrypt R10</span></span>
<span class="ex-row"> subject: <span class="ex-val">CN=example.com</span></span>
<span class="ex-row"> not_before: <span class="ex-val">2026-01-01</span></span>
<span class="ex-row"> not_after: <span class="ex-val">2026-04-01</span></span>
<span class="ex-row"> public_key: <span class="ex-val">ed25519, 0x4eaf06...</span></span>
<span class="ex-row"> extensions: {</span>
<span class="ex-row"> subjectAltName: <span class="ex-val">[example.com, www.example.com]</span></span>
<span class="ex-row"> keyUsage: <span class="ex-val">digitalSignature, keyEncipherment</span></span>
<span class="ex-row"> extendedKeyUsage: <span class="ex-val">serverAuth, clientAuth</span></span>
<span class="ex-row"> basicConstraints: <span class="ex-val">CA:FALSE</span></span>
<span class="ex-row"> }</span>
<span class="ex-row"> signature: <span class="ex-val">ECDSA-SHA384(issuer_priv, tbs_cert)</span></span>
<span class="ex-row">}</span>
<span class="ex-row"></span>
<span class="ex-row"><span class="ex-cmt">// Browser walks: leaf → Let's Encrypt R10 → ISRG Root X1 (in trust store)</span></span>
<span class="ex-row"><span class="ex-cmt">// Then checks: revocation (OCSP), CT log presence (SCTs), name match.</span></span>`,
internals: `<p>The PKI ecosystem is a stack of <b>encoding format</b>, <b>certificate semantics</b>, <b>revocation mechanism</b>, and <b>transparency</b>.</p>
<p><b>X.509v3</b> = the certificate format. Encoded in <b>ASN.1 DER</b> (a tag-length-value binary format from 1984 telecoms standards). <code>PEM</code> = the same DER bytes wrapped in base64 with header/footer.</p>
<p><b>v1 → v3 evolution</b>: v1 had only basic fields. v3 added the <code>extensions</code> field — that's where everything important lives (SAN, KeyUsage, EKU, CRL distribution points, OCSP responder URL, etc.). v1 certs lack SAN → modern browsers reject them.</p>
<p><b>Revocation</b>: certs expire by date, but you may need to revoke earlier (key compromise). <code>CRL</code> = Certificate Revocation List, a periodic signed list of revoked serials (kilobytes-to-megabytes; browsers stopped fetching them due to bulk). <code>OCSP</code> = real-time per-cert lookup; <code>OCSP-stapling</code> = server fetches and embeds the response in TLS handshake (eliminates browser→CA latency + privacy leak).</p>
<p><b>Certificate Transparency (CT)</b> = append-only public logs of every issued cert. Browsers require ≥2 <code>SCT</code>s (signed certificate timestamps) embedded in the cert or stapled, proving public auditability.</p>
<p><b>CMS / PKCS#7</b> = signed/encrypted message format wrapping X.509. <code>S/MIME</code>, code-signing, document signing all use it.</p>
<p><b>ACME</b> (RFC 8555) = the protocol Let's Encrypt invented for automated cert issuance. SCEP/EST = older enterprise enrolment protocols.</p>
<p><b>CAdES / XAdES / PAdES</b> = long-term signature formats (CMS / XML / PDF) for legal eIDAS-grade signing with embedded timestamps and revocation evidence.</p>`,
title: 'PKI / Certificates',
tagline: 'A hierarchy of signed certificates that binds public keys to identities',
desc: 'Public Key Infrastructure solves the "whose public key is this?" problem. A trusted Certificate Authority (CA) signs certificates that bind a domain name or identity to a public key. Browsers ship with ~150 root CA certificates. A valid chain Root CA → Intermediate CA → Leaf Certificate proves the site you\'re visiting really owns the private key. CRLs and OCSP allow certificates to be revoked before they expire.',
graph: `flowchart TD
A([Root CA\nself-signed\ntrusted by browsers]) -->|Signs| B([Intermediate CA])
B -->|Signs| C([Leaf Certificate\ndomain.com + pubkey])
C --> D{Browser verifies chain}
D -->|Chain valid + not revoked| E([Trusted HTTPS])
D -->|Unknown root| F([Warning shown])
G([OCSP / CRL\nrevocation check]) --> D`,
lists: {
active: ['x509v3', 'crl', 'ocsp', 'ocsp-stapling', 'csr', 'cms', 'scep', 'est', 'acme', 'ct', 'mft', 'roa', 'tal', 'rfc822name', 'ipaddress', 'subjectaltname', 'authoritykeyid', 'subjectkeyid', 'keyusage', 'extendedkeyusage', 'basicconstraints', 'nameconstraints', 'cdp', 'aia', 'ocsp-nocheck', 'precert-poison', 'sct', 'tls-features', 'signed-timestamp', 'tsp', 'cades', 'pades', 'xades', 'asn1-der', 'asn1-cer', 'asn1-per', 'asn1-oer', 'asn1-xer'],
legacy: ['x509v1', 'asn1-ber'],
upcoming: []
}