-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
156 lines (156 loc) · 8.4 KB
/
Copy pathindex.html
File metadata and controls
156 lines (156 loc) · 8.4 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
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#08111f" media="(prefers-color-scheme: dark)" />
<meta name="theme-color" content="#f4efe4" media="(prefers-color-scheme: light)" />
<meta
name="description"
content="Browser-based educational lab for HAWK, the lattice signature scheme withdrawn from NIST's post-quantum process in July 2026 after an AI-discovered key-recovery attack. Integer-only Gaussian sampling, side-by-side comparison with Falcon and ML-DSA, and a live run of the attack that ended it."
/>
<meta property="og:type" content="website" />
<meta property="og:title" content="crypto-lab-hawk" />
<meta
property="og:description"
content="Browser-based educational lab for HAWK lattice signatures, withdrawn from NIST's PQ process in July 2026 — with the key-recovery attack runnable in the browser."
/>
<meta name="twitter:card" content="summary" />
<link
rel="icon"
type="image/svg+xml"
href="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23070f1c'/%3E%3Cpath d='M14 50 L26 14 L34 32 L42 14 L54 50' fill='none' stroke='%2300d4ff' stroke-width='4' stroke-linejoin='round' stroke-linecap='round'/%3E%3Ccircle cx='32' cy='30' r='2.5' fill='%23ffd700'/%3E%3C/svg%3E"
/>
<script>
// Dark is the only theme. Pin it before first paint, and overwrite any
// 'light' a visitor stored back when the header carried a theme toggle.
(function () {
try {
localStorage.setItem('theme', 'dark');
} catch (e) {}
document.documentElement.setAttribute('data-theme', 'dark');
})();
</script>
<title>crypto-lab-hawk — integer-only lattice signatures</title>
</head>
<body>
<style>
.cl-topbar{
/* The bar is always dark (#0b1512) regardless of page theme, so header
text must always be light. Mix each lab's --accent toward near-white so
the hue still tints the brand but contrast stays >=4.5:1 on the bar even
when a lab's accent is dark (e.g. a light-theme #1a56db). */
--cl-ink: color-mix(in srgb, var(--accent, #35d6bb) 60%, #eafff8);
display:flex;align-items:center;justify-content:space-between;gap:1rem;
padding:.7rem clamp(.9rem,3vw,2rem);
background:#0b1512;
border-bottom:1px solid color-mix(in srgb, var(--accent, #35d6bb) 22%, transparent);
font-family:ui-monospace,"SFMono-Regular",Menlo,Consolas,monospace;
position:sticky;top:0;z-index:1000;
}
.cl-brand{display:flex;align-items:center;gap:.8rem;text-decoration:none}
.cl-badge{
flex:0 0 auto;display:grid;place-items:center;width:40px;height:40px;
border:1.5px solid var(--accent, #35d6bb);border-radius:10px;
color:var(--cl-ink);font-weight:700;font-size:.95rem;letter-spacing:.05em;
}
.cl-brand-text{display:flex;flex-direction:column;line-height:1.15}
.cl-title{color:#eafff8;font-weight:700;font-size:1.05rem;letter-spacing:.12em}
.cl-sub{color:#5e8b80;font-size:.72rem;letter-spacing:.04em}
.cl-actions{display:flex;align-items:center;gap:.5rem}
.cl-btn{
display:inline-flex;align-items:center;gap:.4rem;
padding:.5rem .85rem;border-radius:10px;
border:1px solid color-mix(in srgb, var(--accent, #35d6bb) 38%, transparent);
background:transparent;color:var(--cl-ink);cursor:pointer;
font:inherit;font-size:.78rem;font-weight:700;letter-spacing:.1em;
text-transform:uppercase;text-decoration:none;transition:background .15s,border-color .15s,color .15s;
}
.cl-btn:hover{
background:color-mix(in srgb, var(--accent, #35d6bb) 14%, transparent);
border-color:var(--accent, #35d6bb);color:#eafff8;
}
.cl-btn svg{width:15px;height:15px}
.cl-icon{padding:.5rem .6rem;font-size:.95rem}
/* Skip-to-content link: first focusable element so keyboard users can bypass
this sticky header (WCAG 2.4.1). Hidden until focused. Fixed light-on-dark
pair (not --accent, which can be a dark hue on some labs) keeps contrast AA. */
.cl-skip-link{
position:absolute;left:.5rem;top:-3rem;z-index:1001;
padding:.55rem 1rem;border-radius:0 0 10px 10px;
background:#eafff8;color:#0b1512;
font-family:ui-monospace,"SFMono-Regular",Menlo,Consolas,monospace;
font-weight:700;font-size:.8rem;letter-spacing:.04em;text-decoration:none;
transition:top .15s ease;
}
.cl-skip-link:focus{top:0;outline:2px solid var(--accent,#35d6bb);outline-offset:2px;}
/* Dark is the only theme, so hide any in-page theme toggle a lab still
ships. The element stays in the DOM so the lab's theme JS keeps working. */
body :is(#theme-toggle,#themeToggle,.theme-toggle,.theme-toggle-btn,[data-theme-toggle]){display:none!important}
@media(max-width:560px){
.cl-sub{display:none}
.cl-btn span{display:none}
.cl-btn svg{margin:0}
}
/* cl-a11y-touch: WCAG 2.5.5 target size on touch pointers only, so the
bar keeps its density on desktop where a mouse is precise. */
@media (pointer: coarse){
/* Height is free -- it costs no horizontal room, so every touch target
gets the full 44px vertically. */
.cl-btn,.cl-icon{min-height:44px}
}
/* Width only where the bar can afford it. Below ~380px, three 44px-wide
buttons plus the brand overflow the viewport, and forcing horizontal
scroll would trade a 2.5.5 (AAA) gain for a 1.4.10 reflow failure.
The buttons stay ~31px wide there, comfortably over the 24px 2.5.8 (AA) floor. */
@media (pointer: coarse) and (min-width: 380px){
.cl-btn,.cl-icon{min-width:44px}
}
</style>
<a class="cl-skip-link" href="#app">Skip to content</a>
<header class="cl-topbar" role="banner" aria-label="Crypto Lab">
<a class="cl-brand" href="https://crypto-lab.systemslibrarian.dev/" aria-label="Crypto Lab home">
<span class="cl-badge">CL</span>
<span class="cl-brand-text">
<span class="cl-title">CRYPTO LAB</span>
<span class="cl-sub">systemslibrarian.dev</span>
</span>
</a>
<nav class="cl-actions" aria-label="Crypto Lab navigation">
<a class="cl-btn" href="https://crypto-lab.systemslibrarian.dev/" aria-label="Crypto Lab menu">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
<span>Menu</span>
</a>
<a class="cl-btn" href="https://github.com/systemslibrarian/crypto-lab-hawk" target="_blank" rel="noopener" aria-label="View this project on GitHub">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.2.8-.6v-2c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1.1-.7 0-.7 0-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.3 1.2a11.4 11.4 0 0 1 6 0C17.3 5 18.3 5.3 18.3 5.3c.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.3c0 .4.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z"/></svg>
<span>GitHub</span>
</a>
</nav>
</header>
<script>
(function () {
// A page may have only one banner landmark. This shared site header is it;
// demote any banner a lab also declared on its own page header (explicit
// role="banner", or an implicit <header> child of <body>) so landmarks stay unique.
function dedupeBanner() {
var bar = document.querySelector('.cl-topbar');
if (!bar) return;
document.querySelectorAll('[role="banner"]').forEach(function (el) {
if (el !== bar) el.setAttribute('role', 'group');
});
Array.prototype.forEach.call(document.querySelectorAll('header'), function (el) {
if (el === bar || el.hasAttribute('role')) return;
// <header> only implies banner when it is NOT scoped inside sectioning content.
// Checking closest() catches heroes nested in #app, which body.children missed.
if (el.closest('main, article, aside, nav, section')) return;
el.setAttribute('role', 'group');
});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', dedupeBanner);
else dedupeBanner();
})();
</script>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>