npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

eq-safe-login-crypto

v0.1.0

Published

eq_safe_login_crypto 的 WASM + TypeScript 包装:SHA-512 / Argon2 / Ed25519 / ML-DSA

Readme

eq-safe-login-crypto-wasm-wrappers

eq_safe_login_crypto(Rust no_std 密码学原语库)编译为 WASM,并提供完整 TypeScript 包装器的工程包。

  • Rust 侧src/lib.rs):把 eq_safe_login_crypto 的 SHA-512 / HMAC-SHA512 / HKDF-SHA512 / Argon2 / Ed25519 / ML-DSA 通过 #[unsafe(no_mangle)] extern "C" 导出为可被 JS 调用的 FFI。
  • JS 侧wrappers/):在 FFI 之上提供两层 API —— 同步包装器与异步包装器。对外提供的产物是异步包装器,仅支持浏览器;异步包装器是对同步包装器的进一步封装。
  • 构建脚本build.mjs):用 esbuild 产出 异步包装器ESM / IIFE 两种发布形态。

算法覆盖

| 模块 | 算法 | 标准 | 关键导出 | | ----------- | ---------------------------- | ------------- | -------------------------------------------------- | | SHA-512 | SHA-512 | FIPS 180-4 | sha512(data) / createSha512() 增量哈希 | | HMAC-SHA512 | HMAC-SHA512 | RFC 2104 | createHmacSha512(key) 增量 MAC | | HKDF-SHA512 | HKDF-SHA512 Expand | RFC 5869 §2.3 | hkdfSha512Expand(prk, info, len) | | Argon2 | Argon2d / Argon2i / Argon2id | RFC 9106 | argon2Hash(params) | | Ed25519 | Ed25519 | RFC 8032 | ed25519PublicFromSeed / ed25519Sign / verify | | ML-DSA | ML-DSA-44 / -65 / -87 | FIPS 204 | mldsaKeygen / mldsaSign / mldsaVerify |

API 设计

异步包装器(async/

  • 所有方法返回 Promise计算在 Web Worker 中进行,不阻塞主线程。
  • 工厂 loadAsync(options?) 加载 WASM、启动 Worker、返回 AsyncModule
  • 适用于浏览器主线程。
  • 增量 SHA-512 通过 AsyncSha512 暴露,实际状态保存在 Worker,主线程持有句柄 id。
  • 增量 HMAC-SHA512 通过 AsyncHmacSha512 暴露,模式与 AsyncSha512 一致。
import { loadAsync } from "./dist/index.min.mjs";

const client = await loadAsync();
const hash = await client.sha512(new TextEncoder().encode("abc"));

const hasher = await client.createSha512();
await hasher.update(chunk1);
await hasher.update(chunk2);
const digest = await hasher.finalize();

// HMAC-SHA512 增量
const hmac = await client.createHmacSha512(key);
await hmac.update(data);
const tag = await hmac.finalize();

// HKDF-SHA512 派生独立子密钥
const edSeed = await client.hkdfSha512Expand(
  prk,
  new TextEncoder().encode("ed25519-seed"),
  32,
);
const mldsaSeed = await client.hkdfSha512Expand(
  prk,
  new TextEncoder().encode("mldsa-seed"),
  32,
);

client.destroy(); // 终止 Worker,reject 所有 pending Promise

资源管理约定

| 资源 | 创建 | 释放 | | ----------------- | ---------------------------- | ------------------------------------ | | AsyncModule | loadAsync() | destroy()(terminate Worker) | | AsyncSha512 | client.createSha512() | 必须调用 finalize()destroy() | | AsyncHmacSha512 | client.createHmacSha512(k) | 必须调用 finalize()destroy() |

调用 destroy() 后再使用相应实例会抛出异常;destroy() 幂等。

构建

前置要求

  • Rust 工具链 + wasm32-unknown-unknown target(项目根 .cargo/config.toml 已设默认 target)
  • Node.js ≥ 18
  • npm / pnpm

构建命令

pnpm install

# 1. 仅构建 WASM(cargo build --release + 复制 .wasm 到 dist/)
pnpm build:wasm

# 2. 仅构建 TS 包装器(需要先有 dist/index.wasm)
pnpm build:wrappers

# 3. 一步构建 WASM + 包装器
pnpm build

构建产物(dist/

| 文件 | 说明 | | ---------------------- | -------------------------------------------------- | | index.wasm | WASM 模块 | | worker.min.js | Worker(IIFE,经典 Worker) | | index.min.js | 主线程入口(IIFE,<script>) | | index-bundled.min.js | 单文件版本(IIFE,内联 WASM + Worker,零外部文件) | | worker.min.mjs | Worker(ESM,模块 Worker) | | index.min.mjs | 主线程入口(ESM,<script type="module">) | | inline-wa.mjs | WASM 内联加载器(ESM,把 WASM base64 编码) |

如果使用 IIFE 方式加载模块,需要: index.wasmworker.min.jsindex.min.js

如果使用 ESM 方式加载模块,需要: index.wasmworker.min.mjsindex.min.mjs

如果不方便设置 wasm 文件的 MIME 类型,有两种解决方案:

  1. 直接以 IIFE 方式加载 index-bundled.min.js,无需任何其它文件,WASM 和 Worker 都内嵌在脚本里。

  2. 以 ESM 方式加载模块,但是额外准备 inline-wa.mjs,在 loadAsync 前先加载 WASM 模块:

    import { loadAsync } from "./dist/index.min.mjs";
    import { loadInlineWASM } from "./dist/inline-wa.mjs";
    
    const wa = await loadInlineWASM();
    const client = await loadAsync({ wasmModule: wa });
    // ...

浏览器中使用的三种方式

1. ESM(推荐用于现代浏览器)

<script type="module">
  import { loadAsync } from "./dist/index.min.mjs";
  const client = await loadAsync();
  // ...
</script>

需要同目录下存在 index.wasmworker.min.mjs

2. IIFE(用于传统 <script>

<script src="./dist/index.min.js"></script>
<script>
  EQSafeLoginCrypto.loadAsync().then((client) => {
    // ...
  });
</script>

需要同目录下存在 index.wasmworker.min.js

3. 单文件部署(内联,零外部依赖)

<script src="./dist/index-bundled.min.js"></script>
<script>
  EQSafeLoginCrypto.loadAsync().then((client) => {
    // ...
  });
</script>

无需任何额外文件,WASM 和 Worker 都内联在脚本里。

开发

pnpm typecheck     # tsc --noEmit
pnpm test          # vitest run(需要先 pnpm build:wasm)
pnpm test:watch    # vitest watch 模式
pnpm e2e           # 启动 http://localhost:8765 浏览器端到端测试

单元测试位于 wrappers-tests,使用 vitest 运行。

E2E 测试位于 e2e/index.html,在真实浏览器中验证两种发布形态(IIFE / ESM)以及 wasm 的两种加载方式,覆盖 SHA-512 / HMAC-SHA512 / HKDF-SHA512 / Argon2 / Ed25519 / ML-DSA 全部算法,并通过页面上的高精度时钟直观验证 Argon2 计算不阻塞主线程。

依赖关系

  • Rust 侧依赖上级目录的 eq_safe_login_crypto crate
  • JS 侧零运行时依赖