SipHash NAPI
Overview
Section titled “Overview”SipHash NAPI is a native Node.js addon that brings SipHash-2-4 — a fast, secure hash function designed to resist hash-flooding DoS attacks — to JavaScript and TypeScript. The hashing is implemented in Rust and exposed to Node.js/Bun through napi-rs bindings, delivering native-speed 64-bit hashing with a clean three-function API.
SipHash is widely used as the default hasher in Rust’s HashMap and Python’s dict. This package makes the same algorithm available to Node.js developers who need a fast, non-cryptographic hash for content deduplication, cache keying, or hash table construction.
Features
Section titled “Features”- Native Rust Performance — The core SipHash-2-4 algorithm runs as compiled Rust via the
siphashercrate, with zero JavaScript overhead in the hot path - Streaming File Hashing —
siphashFile()reads files in 8 KiB chunks, hashing arbitrarily large files without loading them into memory - Keyed Hashing —
siphashWithKey()accepts a 128-bit key as twobiginthalves, enabling per-instance keying to defend against hash-flooding attacks - 8-Target Cross-Compilation — Pre-built binaries for macOS (x64/arm64), Linux glibc (x64/arm64), Linux musl (x64/arm64), and Windows (x64/arm64) via a CI matrix
- TypeScript-First — Ships with auto-generated
.d.tsdeclarations; all functions returnbigintfor full 64-bit precision - Multi-Runtime — Works across CommonJS, ESM, and Bun with automatic platform/architecture detection at load time
The entire public surface is three functions exported from lib.rs:
#[napi]pub fn siphash(data: Buffer) -> BigInt { let mut hasher = SipHasher::new(); hasher.write(data.as_ref()); BigInt::from(hasher.finish())}
#[napi]pub fn siphash_with_key(data: Buffer, key0: BigInt, key1: BigInt) -> Result<BigInt> { let (_, k0, _) = key0.get_u128(); let (_, k1, _) = key1.get_u128(); let mut hasher = SipHasher::new_with_keys(k0 as u64, k1 as u64); hasher.write(data.as_ref()); Ok(BigInt::from(hasher.finish()))}
#[napi]pub fn siphash_file(path: String) -> Result<BigInt> { let mut file = std::fs::File::open(&path) .map_err(|e| Error::from_reason(format!("failed to open {path}: {e}")))?; let mut hasher = SipHasher::new(); let mut buf = [0u8; 8192]; loop { let n = file.read(&mut buf) .map_err(|e| Error::from_reason(format!("failed to read {path}: {e}")))?; if n == 0 { break; } hasher.write(&buf[..n]); } Ok(BigInt::from(hasher.finish()))}On the JavaScript side, usage is straightforward:
import { siphash, siphashWithKey, siphashFile } from "@jadujoel/siphash-napi";
// Hash a buffer with the default (0, 0) keyconst hash = siphash(Buffer.from("hello")); // bigint
// Hash with a custom 128-bit keyconst keyed = siphashWithKey(Buffer.from("hello"), 1n, 2n);
// Stream-hash a file without loading it into memoryconst fileHash = siphashFile("/path/to/large-file.bin");Build & Release Pipeline
Section titled “Build & Release Pipeline”The release binary is optimized with LTO and symbol stripping (Cargo.toml profile):
[profile.release]lto = truestrip = "symbols"A GitHub Actions CI matrix builds all 8 targets in parallel, then runs smoke tests on Ubuntu, macOS, and Windows. The publish workflow triggers on version tags and uses napi pre-publish to push per-platform npm packages under the @jadujoel scope.
Testing
Section titled “Testing”The project includes a smoke test suite in smoke/index.ts that verifies:
- Deterministic output for identical inputs
- Different inputs produce different hashes
- Empty buffer handling
- Keyed hashing produces distinct results from default-key hashing
- File hashing matches buffer hashing for the same content
- Proper error throwing for nonexistent files
The CI pipeline also runs a quick inline smoke test (node -e "...") on each platform after artifact download.
Tech Stack
Section titled “Tech Stack”| Language | Rust, TypeScript |
| Binding Layer | napi-rs (N-API v6) |
| Hash Implementation | siphasher crate v1 |
| Platform | Node.js, Bun |
| CI/CD | GitHub Actions (build matrix × 8 targets) |
| Package | @jadujoel/siphash-napi on npm |
Source Code
Section titled “Source Code”The source code is available on the project’s GitHub repository.