This document defines all technical constraints, interfaces, coding conventions, and architectural budgets that apply to every contribution in the CryptoViz codebase. README.md remains the primary developer reference; this document is the contributor-facing engineering specification.
See docs/ARCHITECTURE.md for the layer overview and a map of every release-grade contract document, including per-contribution-type checklists, the simulation-vs-live-data policy, and the error taxonomy.
| Rule | Rationale | Violation Consequence |
|---|---|---|
output: 'export' |
Enables fully static build files hosted on Vercel Edge CDN with zero server runtime overhead. | Next.js compilation failure on deploy; PR is automatically rejected. |
No runtime fetch() |
All API data calls must resolve at build time. Runtime queries to third-party endpoints break static guarantees. | Blocked by browser Content Security Policy (CSP); runtime error. |
| Worker-isolated math | Heavily taxing cryptographic equations must execute inside a background Web Worker thread. | Main UI thread locks up, causing browser frame rate drop; PR is rejected. |
| No Unsafe JavaScript | eval(), new Function(), innerHTML, and dangerouslySetInnerHTML create Cross-Site Scripting (XSS) vectors. |
Static analysis security scans fail; immediate PR rejection. |
| Strict TypeScript | Catch compiler errors early to avoid runtime calculation and parity mismatches. | TypeScript typecheck CI job fails; build block. |
Automated axe-core |
Ensures code remains usable by people using assistive technologies. | Accessibility check job fails; PR blocked. |
| CSP Script Nonces | Prevents execution of injected inline script attacks. | Security header checks fail at deployment. |
Every cryptographic module under lib/cipher/[category]/[cipher].ts must implement and export the following typescript types:
export type CipherErrorCode =
| 'INPUT_REQUIRED'
| 'INPUT_TOO_LONG'
| 'INVALID_KEY'
| 'INVALID_PADDING'
| 'ALGORITHM_UNSUPPORTED'
| 'WORKER_TIMEOUT';
export class CipherError extends Error {
constructor(public code: CipherErrorCode, message: string) {
super(message);
this.name = 'CipherError';
}
}
export interface CipherStep {
index: number;
label: string;
inputState: string;
outputState: string;
highlight?: number[];
note?: string;
matrix?: string[][] | string;
table?: { key: string; value: string }[];
isMilestone?: boolean;
}
export interface CipherMetadata {
name: string;
securityStatus: 'secure' | 'legacy' | 'deprecated' | 'broken';
yearDesigned?: number;
standardBody?: string;
breakingComplexity?: string;
}
export interface CipherResult {
output: string;
outputEncoding?: 'utf8' | 'hex' | 'base64';
steps: CipherStep[];
metadata: CipherMetadata;
durationMs: number;
}
export interface CipherOptions {
instrument?: boolean;
encoding?: 'utf8' | 'hex' | 'base64';
mode?: 'demo' | 'real';
[key: string]: any;
}Every module must export pure encrypt/decrypt methods and standard test vectors:
export function encrypt(input: string, key: string, options?: CipherOptions): CipherResult;
export function decrypt(input: string, key: string, options?: CipherOptions): CipherResult;
export const TEST_VECTORS: Array<{
input: string;
key: string;
expected: string;
description?: string;
}>;To optimize worker performance, modules must branch based on the options.instrument flag:
instrument === true: Runs the instrumented code path, populating detailed intermediate round states into thesteps[]array.instrument === false(or undefined): Runs the high-performance path, returning the final output quickly with an emptystepsarray.
| Condition | Error Code | Message Format |
|---|---|---|
Input is undefined, null, or "" |
INPUT_REQUIRED |
"Input message is required." |
| Input byte size exceeds 4096 bytes | INPUT_TOO_LONG |
"Input exceeds maximum allowed size of 4096 bytes." |
| Key matches incorrect length/format | INVALID_KEY |
"Invalid key format: [specific reason]" |
To prevent browser memory exhaustion during animation, the steps[] trace array must adhere to the following budgets:
| Cipher Category | Mode / Input Size | Maximum Step Limit |
|---|---|---|
| Classical | Full trace (Input < 100 chars) | 1 step per char / block |
| Classical | Summary trace (Input >= 100 chars) | Max 50 steps total |
| Symmetric (DES/AES) | Hex Input (all sizes) | 1 step per round + final block |
| Hash (SHA-2/MD5) | Short inputs | 1 step per compression round |
| Asymmetric (RSA) | Demo mode | Max 30 exponentiation steps |
- Fast Path latency: < 5ms for block ciphers on 1 KB payloads.
- Instrumented Path latency: < 100ms for full round details.
All computations run off-thread via lib/workers/cipher.worker.ts.
interface WorkerRequest {
id: string; // Unique nanoid
action: 'encrypt' | 'decrypt';
cipherId: string;
input: string;
key: string;
options?: CipherOptions;
}
interface WorkerResponse {
id: string;
success: boolean;
result?: CipherResult;
error?: string;
}- Manages Web Worker thread initialization and cleanup on component unmount.
- Tracks active requests in a
Mapkeyed byidto resolve promises asynchronously. - Enforces a 10-second timeout budget; if exceeded, the worker is terminated and a
WORKER_TIMEOUTerror is raised.
Cipher engines run inside the Worker's isolated global context. They must not access DOM variables:
- No
windowordocumentcalls. - No
localStorageorsessionStorageusage. - No network
fetch()orXMLHttpRequestrequests. - No imports of server-only node libraries.
All styling uses Tailwind CSS v4 utility classes and CSS custom properties defined in app/globals.css.
For detailed visualizer component development patterns, including prop contracts, rendering conventions, and accessibility requirements, see the Visualizer Development Guide.
| Rule Category | Correct Approach | Incorrect Approach |
|---|---|---|
| Class Merging | className={cn('text-sm', isActive && 'text-teal-600')} |
className={'text-sm ' + (isActive ? 'text-teal-600' : '')} |
| Color System | bg-card, text-foreground, border-border |
bg-[#ffffff], text-[#1a1a1a], border-zinc-200 |
| Theme Support | dark:bg-zinc-900 bg-white |
Hardcoding single-theme background configurations |
| Animations | motion wrappers for layout transitions |
Arbitrary GSAP scripts or complex CSS transitions |
| Arbitrary Values | w-[32rem] /* Sidebar wide bounds */ |
w-[512px] (no explaining comments) |
| Font Settings | font-mono for keys, binary, and hex maps |
font-sans for raw hexadecimal lists |
| CSS Assets | Define styles inside components via Tailwind | Creating separate .css modules per folder |
- Coverage Gate: 80% line coverage threshold on
lib/cipher/**. - Properties Checked: known-answer vectors, empty input, size limits, and invalid keys.
- Fuzzing (fast-check):
- Symmetric ciphers: 500 iterations of round-trip encryption/decryption.
- Classical ciphers: 1000 iterations of random inputs to verify no engine crashes occur.
- Test File Location:
tests/unit/[category]/[cipher].test.ts.
- Environments: Verified on Chromium and Firefox.
- Required Core Paths: Visualizing a cipher step-by-step, parsing an MDX document, and applying filters to resources.
- Timing Safety: Avoid
page.waitForTimeout(). Always assert visibility using locator states. - Security Auditing: Inject XSS payloads (e.g.
<script>alert(1)</script>) into inputs and verify they render safely as sanitized text rather than executing. Verify security headers invercel.jsonare returned by checking HTTP responses.
- Compliance Gate: Zero violations allowed for
criticalandseriousimpact levels. - Log Output: Save
moderateandminorwarnings intotests/a11y/violations-log.json.
| Security Check | How to Verify | CI Gate Status |
|---|---|---|
| Sanitize Outputs | Render all dynamic values (cipher output, step notes, user input) as React text nodes so JSX escapes them automatically. Never pass dynamic content to dangerouslySetInnerHTML. |
Fail review if dynamic content is rendered as raw HTML. |
| Key Clearance | Ensure sensitive keys are cleared on component unmount. | Validated in manual code review. |
| No Unsafe Logic | Verify zero usage of eval, innerHTML, and constructor functions. |
Checked by static analysis rules. |
| CSP Compliance | Verify worker-src blob: and security nonces in vercel.json. |
Checked by E2E security tests. |
| Dependency Scans | Run dependency auditing to check for known CVEs. | npm audit runs on pull requests. |
| Secure Input Limits | Ensure input size is restricted to a maximum of 4096 bytes. | Validated in unit test suite. |
| Metric | Budget | Fail Threshold | How Measured |
|---|---|---|---|
| Main JS Bundle | < 120 KB gzipped | > 150 KB gzipped | npm run check:budgets |
| LCP (Largest Contentful Paint) | < 1.2s | > 2.5s | Playwright Core Web Vitals |
| CLS (Cumulative Layout Shift) | < 0.05 | > 0.1 | Playwright Core Web Vitals |
| INP (Interaction to Next Paint) | < 100ms | > 200ms | Playwright Core Web Vitals |
| Lighthouse Performance | ≥ 90 | < 80 | Lighthouse CI Action |
| Lighthouse Accessibility | ≥ 95 | < 90 | Lighthouse CI Action |
| Category | Package | Reason / Purpose |
|---|---|---|
| Crypto | @noble/hashes |
Secure, audited SHA-2, MD5, and HMAC implementations. |
| Crypto | @noble/curves |
Highly optimized Elliptic Curve P-256 signatures. |
| UI | @radix-ui/* |
Unstyled accessible base controls. |
| Animation | motion |
React transitions and step animations. |
| Banned Package | Banned Reason | Allowed Alternative |
|---|---|---|
crypto-js |
Legacy, unaudited, slow performance | @noble/hashes / WebCrypto |
forge |
Bulky size, unmaintained | WebCrypto |
gsap |
Heavy bundle size, license restrictions | motion (Framer) |
jest |
Slow startup, configuration overhead | vitest |
@mui/material |
Heavy CSS footprint, style override difficulties | Tailwind CSS v4 + Radix UI |
contentlayer |
Unmaintained project | next-mdx-remote |
algolia |
Requires a server runtime | pagefind (WASM) |
pnpm / yarn / bun |
Non-standard lockfile fragmentation and resolution disparity | npm (v9.x+) with authoritative package-lock.json |
To ensure reproducible builds, deterministic CI execution, and eliminate multi-lockfile drift, npm is the authoritative package manager for CryptoViz.
- Exclusive CLI Usage: All contributors and CI pipelines must use standard
npmcommands (npm install,npm test,npm run build). - No Alternative Lockfiles:
pnpm-lock.yaml,yarn.lock, andbun.lockbare strictly prohibited in the repository tree. Automated CI checks reject any PR containing alternative lockfiles. - Deterministic Overrides: Transitive security patches and dependency pins are configured exclusively via the
"overrides"block inpackage.jsonand committed topackage-lock.json. - CI Caching: GitHub Actions workflows utilize
actions/setup-nodewithcache: 'npm'keyed onpackage-lock.json.
- Compliance standard: WCAG 2.1 AA.
ByteHeatmapRequirements: Every cell in the byte grid must contain an accessible label:aria-label="Byte ${index}: ${hex} (${changed ? 'changed' : 'unchanged'})"StepAnimatorRequirements: Play/pause buttons need dynamic ARIA labels. The scrub slider must setaria-valuemin="0",aria-valuemax="${steps.length - 1}", andaria-valuenow="${currentStep}".PlayfairGridRequirements: Highlighted cells must setaria-selected="true".- Keyboard Navigation: Users must be able to focus and navigate all grids using
Taband arrow keys. - Motion Reduction: If
prefers-reduced-motionis active, theStepAnimatormust disable transitions and display states immediately. - Focus Management: Focus must move to the output container once calculations finish.
- Frontmatter Validation: Checked via Zod schemas at build time.
- Dynamic Links: Link ciphers using backticks (e.g.
`[caesar]`), which are parsed and styled byrehype-cipher-link. - Callout Containers: Standardized syntax for warnings and notes:
> [!NOTE] > This is a note callout.
- Depth: Markdown headings inside MDX should start at
h2(##). Theh1heading is generated automatically from the frontmatter title. - Static Assets: All image files must be saved in the
/publicpath and specify descriptivealttext. External image hosting is prohibited. - Language Tags: Code fences must specify language tags. Use
tsinstead oftypescriptfor brevity.
Every resource object added to content/resources.ts must match the Resource interface:
export interface Resource {
id: string;
title: string;
url: string;
source: string;
description: string;
tags: ResourceTag[];
readingTime: number;
type: 'article' | 'paper' | 'tool' | 'video' | 'course';
addedAt: string;
}- URLs: Must use the
https://protocol. - Freshness: Content should be published within the last 3 years, except for seminal papers.
- Access: Note paywalled content explicitly.
- Authority: Prefer primary sources (NIST specifications, RFC drafts) over third-party summaries.
| Type | When to use |
|---|---|
feat |
Adding new features or ciphers. |
fix |
Resolving bugs or compilation failures. |
docs |
Writing MDX files or system documentation. |
style |
Adjusting CSS, layouts, or animations. |
refactor |
Restructuring code without changing behavior. |
test |
Writing unit or E2E tests. |
security |
Adjusting CSP policies or patching vulnerabilities. |
chore |
Updating configuration files or dependencies. |
| Scope | Directories / Files Covered |
|---|---|
cipher |
lib/cipher/ engines. |
docs |
content/docs/ and app/(docs)/. |
resources |
content/resources.ts and app/(resources)/. |
ui |
components/ and style utilities. |
worker |
lib/workers/ thread files. |
ci |
.github/workflows/ YAML actions. |
config |
Config files (tsconfig.json, next.config.ts). |
| Contribution Type | Branch Prefix | Example Branch Name |
|---|---|---|
| Features | feat/ |
feat/cipher-atbash |
| Bug Fixes | fix/ |
fix/worker-timeout |
| Documentation | docs/ |
docs/tls-handshake |
| Housekeeping | chore/ |
chore/update-deps |
When reviewing open pull requests, maintainers resolve merge conflicts in this order:
- Security Fixes: Addressing security issues (any severity). Ensures user security.
- Build-breaking Bugs: Resolving compilation or export failures. Keeps the build system stable.
- Cipher Correctness: Fixing incorrect engine calculations. Ensures accurate educational outputs.
- Accessibility Violations: Resolving critical or serious accessibility violations. Maintains usability for all.
- Performance Regressions: Fixing core web vital or bundle size regressions. Ensures fast page loads.
- New Cipher Implementations: Onboarding new visualizer ciphers. Expands platform features.
- New MDX Content: Onboarding new educational articles. Expands platform content.
- UI Polish: Applying cosmetic layout adjustments. Improves user experience.
- New Resource Entries: Onboarding external reference links. Expands learning resources.