purecrypto 0.6.29

A pure-Rust cryptography toolkit with no foreign-code dependencies, from constant-time primitives up to keys, X.509 and TLS.
Documentation
<script setup>
import { ref } from 'vue';
import { state } from '../store.js';
import ToolHash from './tools/ToolHash.vue';
import ToolHashFile from './tools/ToolHashFile.vue';
import ToolKeygen from './tools/ToolKeygen.vue';
import ToolCsr from './tools/ToolCsr.vue';
import ToolCert from './tools/ToolCert.vue';

const tabs = [
  { id: 'hash', label: 'Hash', desc: 'Digest any input under any algorithm.', comp: ToolHash },
  { id: 'file', label: 'Hash a file', desc: 'One read, every algorithm at once.', comp: ToolHashFile },
  { id: 'keygen', label: 'Key generator', desc: 'Generate a private key in any scheme.', comp: ToolKeygen },
  { id: 'csr', label: 'CSR', desc: 'Build a PKCS#10 certificate request.', comp: ToolCsr },
  { id: 'cert', label: 'X.509 analyzer', desc: 'Inspect any certificate in detail.', comp: ToolCert },
];
const active = ref('hash');
</script>

<template>
  <section id="tools" class="section">
    <div class="wrap">
      <div class="section-head">
        <p class="eyebrow">Utilities · nothing leaves your device</p>
        <h2>Tools you'd actually use.</h2>
        <p>
          Real crypto utilities backed by the same WebAssembly build — hash
          anything, generate keys in any scheme (classical or post-quantum), and
          issue certificate requests. All of it runs locally in your browser.
        </p>
      </div>

      <div class="tabs" role="tablist">
        <button
          v-for="t in tabs"
          :key="t.id"
          class="tab"
          :class="{ on: active === t.id }"
          role="tab"
          :aria-selected="active === t.id"
          @click="active = t.id"
        >
          <span class="tl">{{ t.label }}</span>
          <span class="td">{{ t.desc }}</span>
        </button>
      </div>

      <div class="panel toolwrap">
        <div v-if="state.status === 'error'" class="notice err">
          The WebAssembly module failed to load, so the tools are unavailable.
        </div>
        <div v-else-if="state.status !== 'ready'" class="notice">
          <span class="spinner"></span> Loading the purecrypto wasm build…
        </div>
        <component v-else :is="tabs.find((t) => t.id === active).comp" :key="active" />
      </div>
    </div>
  </section>
</template>

<style scoped>
.tabs {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
  margin-bottom: 20px;
}
.tab {
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-align: left;
  padding: 14px 16px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-soft);
  background: var(--ink-1);
  cursor: pointer;
  transition:
    border-color 0.16s ease,
    transform 0.16s ease;
}
.tab:hover {
  transform: translateY(-2px);
}
.tab.on {
  border-color: var(--violet);
  background: var(--violet-glow);
}
.tl {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.02rem;
  color: var(--paper);
}
.td {
  font-size: 0.78rem;
  color: var(--muted);
}
.toolwrap {
  padding: 26px;
}
.notice {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--dim);
  padding: 30px;
  justify-content: center;
}
.notice.err {
  color: #ff9c9c;
}
.spinner {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid var(--line);
  border-top-color: var(--violet);
  animation: spin 0.8s linear infinite;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
@media (max-width: 760px) {
  .tabs {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 420px) {
  .tabs {
    grid-template-columns: 1fr;
  }
  .td {
    display: none;
  }
}
</style>