js-sha256

A fast, zero-dependency SHA-256/SHA-224 hashing library for JavaScript with built-in UTF-8 support and HMAC.

Library
npm
v1.0.0
975 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
61 /100 Good
Development Activity 52
Maintenance 32
Community 72
Maturity 60
Momentum 28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
60 /100 Good
Architecture 75
Code Quality 70
Innovation 55
Learning Curve 40

js-sha256 is a lightweight, zero-dependency implementation of the SHA-256 and SHA-224 hash algorithms for JavaScript, with native UTF-8 string encoding built directly into the hashing loop rather than relying on external encoding utilities. It ships as dual ESM/CommonJS packages with dedicated Node.js, browser, and UMD builds, and automatically delegates to Node’s built-in crypto module when running server-side for maximum performance, while falling back to a hand-optimized pure-JavaScript implementation in browsers and other environments.

Beyond straight hashing, the library bundles HMAC-SHA256/SHA224 support, a chainable create()/update() streaming API for hashing data incrementally, and multiple output formats (hex, byte array, digest, ArrayBuffer) so it can slot into crypto pipelines, checksum tools, or client-side authentication flows without extra glue code.

What You Get

  • Standalone sha256()/sha224() one-shot hashing functions plus HMAC equivalents (sha256.hmac(), sha224.hmac())
  • A streaming create()/update() API for hashing data incrementally across multiple chunks
  • Four output formats from the same hash object: hex(), array()/digest(), and arrayBuffer()
  • Dual ESM/CommonJS builds plus a UMD/minified browser bundle and TypeScript type declarations (index.d.ts)
  • Automatic native crypto delegation on Node.js, with a dependency-free pure-JS fallback for browsers

Common Use Cases

  • Generating file/content checksums client-side before upload, without a server round-trip
  • Computing HMAC-SHA256 signatures for API request authentication in browser-based apps
  • Hashing data in size-constrained frontend bundles where WebCrypto’s async API is awkward to use
  • Cross-environment hashing utilities that need identical output whether running in Node.js or a browser

Under The Hood

Architecture

The library is organized around a single core module (src/core.mjs) implementing the Sha256 constructor function as a prototype-based state machine (block-buffering, update/hash/finalize lifecycle), wrapped by lightweight factory functions (createMethod, createHmacMethod) that produce the public sha256/sha224 API surface exposing one-shot, streaming, and HMAC variants. src/index.mjs re-exports from core.mjs for the default ESM entry, while src/node.mjs is a parallel, structurally distinct implementation (a NodeHasher class wrapping Node’s crypto.createHash/createHmac) selected via package.json’s exports “node” condition; src/cjs.mjs, node-cjs.mjs, and umd.mjs are thin build-time wrappers bundled by rollup.config.mjs into build/. The notable design decision is two parallel hashing engines — pure-JS and native crypto — rather than one shared abstraction, so a change to the compression loop in core.mjs has no effect on Node’s runtime behavior since node.mjs is an entirely separate code path.

Tech Stack

The package has zero runtime dependencies; devDependencies are limited to @playwright/test, @rollup/plugin-terser, c8 for coverage, mocha, and rollup for bundling. rollup.config.mjs produces multiple bundle targets (ESM, CJS, Node CJS, minified UMD) matching the package.json exports map, targeting both Node.js (via native crypto) and browsers (via the UMD/ESM bundle). TypeScript types are shipped as a hand-written static index.d.ts rather than compiled from TypeScript source. The CI pipeline (.github/workflows/ci.yml) packs the npm artifact on Node 24 and then re-runs the runtime test suite against that artifact across Node 16 through 24 to validate cross-version compatibility.

Code Quality

Tests are organized with mocha (tests/core-test.mjs, tests/node-test.mjs, tests/hmac-test.js, tests/test.js) plus a dist-test.mjs that validates the built artifacts, and Playwright covers browser-specific behavior (tests/browser, playwright.config.mjs, including classic and module Web Worker scenarios). c8 collects coverage scoped explicitly to the core source files. Error handling is minimal but deliberate: formatMessage throws on an invalid input type, and update()/finalize() throw a FINALIZE_ERROR once a hash has already been finalized, guarding against accidental reuse. There is no TypeScript source to type-check against the hand-written declaration file, and no linter or formatter configuration is present in the repo, though the multi-version Node CI and separate node/browser/dist suites give reasonable confidence for a library of this scope.

What Makes It Unique

Rather than a novel algorithm, js-sha256’s differentiator is a hand-inlined, loop-unrolled SHA-256 compression function (visible in Sha256.prototype.hash, unrolled in groups of four rounds with manually tracked rotate/majority/choice terms and a special-cased first round to skip redundant reads) tuned for raw JS engine speed without WASM or native bindings, combined with automatic dual-mode dispatch to Node’s native crypto module when available. That combination gives consistent hash output across environments while getting near-native performance server-side and reasonable performance in pure JavaScript client-side — a solid but incremental performance-engineering choice rather than a groundbreaking one; comparable unrolling techniques appear in several other JS hash libraries.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers