@preeternal/react-native-file-hash
v2.0.2
Published
Native streaming hash for React Native: MD5, SHA-1/224/256/384/512, XXH3, BLAKE3 (hash/HMAC/keyed). TurboModules, no UI freezes.
Downloads
1,146
Maintainers
Readme
@preeternal/react-native-file-hash
Fast, native-first hashing for React Native with switchable engines (native / zig)
One API for file hashing, string hashing, HMAC, and keyed BLAKE3 on iOS and Android.
Used for:
- verifying large downloads
- caching and deduplication
- content integrity checks
- secure file authentication
Supports out of the box:
- Broad hash coverage:
MD5,SHA-1,SHA-224,SHA-256,SHA-384,SHA-512,SHA-512/224,SHA-512/256,XXH3-64,XXH3-128,BLAKE3 - Built-in HMAC coverage:
HMAC-SHA-224,HMAC-SHA-256,HMAC-SHA-384,HMAC-SHA-512,HMAC-MD5,HMAC-SHA-1 - Keyed
BLAKE3when you provide akey(32 bytes after decoding)
For files, hashing streams data in chunks and does not load the whole file into
memory.
Output format is fixed: both fileHash and stringHash return lowercase hex
digest strings.
Built for concurrent use: both platforms create independent hash state per
call. iOS uses a dedicated OperationQueue (up to 2 concurrent tasks), Android
uses coroutines; in zig engine, stringHash uses one-shot C ABI, while
fileHash uses one-shot path hashing with a streaming fallback for provider and
URL-backed files.
Features
- ✅ One API, two engines: native or Zig
- ✅ Streaming file hashing (no full-file buffering)
- ✅ Runs hashing work off the JS thread
- ✅ Works with both old and new React Native architecture
- ✅ Supports provider-backed files (
content://, security-scoped URLs)
When to use which algorithm
| Algorithm | Use case | Notes |
| ------------------------ | ----------------------------------------- | -------------------------------------------------------------- |
| MD5 | Legacy compatibility | Not secure, only for compatibility-sensitive workflows |
| SHA-1 | Legacy systems | Not collision-resistant |
| SHA-224 | Reduced-size SHA-2 | iOS native uses CommonCrypto; zig uses Zig core |
| SHA-256 | General-purpose cryptographic hashing | Good balance of speed and security |
| SHA-384/512 | Strong cryptographic guarantees | Slower, larger output |
| HMAC-SHA-224/256/384/512 | Authenticating data with a shared secret | Prefer HMAC-SHA-256 for new integrations |
| HMAC-MD5 / HMAC-SHA-1 | Legacy protocol compatibility | Avoid for new designs |
| XXH3-64 | Fast non-cryptographic hashing | Best for checksums, caching, deduplication |
| XXH3-128 | Fast non-cryptographic hashing, wider tag | Lower accidental collision rate than XXH3-64; still not crypto |
| BLAKE3 | Modern high-performance crypto hash | Supports keyed hashing (BLAKE3 + key) |
Output lengths
| Algorithm | Output length | | ---------------------- | ------------------------ | | MD5 / HMAC-MD5 | 16 bytes (32 hex chars) | | SHA-1 / HMAC-SHA-1 | 20 bytes (40 hex chars) | | SHA-224 / HMAC-SHA-224 | 28 bytes (56 hex chars) | | SHA-256 / HMAC-SHA-256 | 32 bytes (64 hex chars) | | SHA-384 / HMAC-SHA-384 | 48 bytes (96 hex chars) | | SHA-512 / HMAC-SHA-512 | 64 bytes (128 hex chars) | | SHA-512/224 | 28 bytes (56 hex chars) | | SHA-512/256 | 32 bytes (64 hex chars) | | XXH3-64 | 8 bytes (16 hex chars) | | XXH3-128 | 16 bytes (32 hex chars) | | BLAKE3 | 32 bytes (64 hex chars) |
Installation
Using npm
npm install @preeternal/react-native-file-hashUsing yarn
yarn add @preeternal/react-native-file-hashUsing Bun
bun add @preeternal/react-native-file-hashLinking
For React Native 0.60 and above, the module is linked automatically. For older versions, you might need to link it manually.
For iOS
cd ios && bundle exec pod installFor Android
We enable 16KB page alignment when the linker supports -Wl,-z,max-page-size=16384 to satisfy Google Play requirements on 16KB page size devices. Tested with NDK 27.1.x. If your NDK/toolchain does not recognize the flag, the build will continue without 16KB alignment, so upgrade your NDK to get 16KB-aligned binaries.
Engine Selection (native / zig)
Default engine is native:
- iOS: Swift implementation (+ native C for BLAKE3/XXH3)
- Android: Kotlin implementation (+ native C for BLAKE3/XXH3)
If no engine flag is provided, native is used.
The selected engine is resolved at build time; only that engine is linked into
the final native binary, and the unused engine is not shipped in your app
bundle.
On Android, when engine=zig, this package currently routes
SHA-224 / SHA-256 and HMAC-SHA-224 / HMAC-SHA-256 through the native
pipeline by default. Current shipped Zig Android prebuilts are generic (without
-Dcpu=...+sha2), and this fallback removes the main SHA-2 latency cliff.
XXH3-128 is currently available only in native engine.
Android (react_native_file_hash_engine)
Set in app android/gradle.properties:
react_native_file_hash_engine=zigiOS (ZFH_ENGINE)
Set in app ios/Podfile before pod install:
ENV['ZFH_ENGINE'] ||= 'native' # set 'zig' to switch engineFor package users: Zig prebuilts are shipped with release artifacts, so no local Zig toolchain or manual prebuild step is required.
Expo users
Expo Gois not supported (this library contains native code).- Use
expo prebuild/ Development Build / EAS Build. - Engine selection is intended to be configured in
app.jsonvia config plugin:
{
"expo": {
"plugins": [["@preeternal/react-native-file-hash", { "engine": "zig" }]]
}
}- If
engineis omitted, default isnative. - Plugin behavior (prebuild):
- sets Android
react_native_file_hash_engine - sets iOS
ZFH_ENGINEinPodfile
- sets Android
- Plugin is bundled with the package (
app.plugin.js). - Manual fallback (if needed): set the same values in
android/gradle.propertiesandios/Podfile.
Usage
All functions are asynchronous and run on native background threads. They are safe to use with large files and will not block the UI.
import { fileHash, stringHash } from '@preeternal/react-native-file-hash';
// Get SHA-256 hash for a file
try {
const sha256 = await fileHash('file:///path/to/your/file.txt', 'SHA-256');
console.log('SHA-256:', sha256);
} catch (e) {
console.error(e);
}
// Get MD5 hash for a file
try {
const md5 = await fileHash('file:///path/to/your/file.txt', 'MD5');
console.log('MD5:', md5);
} catch (e) {
console.error(e);
}
// Other algorithms
await fileHash('file:///path/to/your/file.txt', 'SHA-1');
await fileHash('file:///path/to/your/file.txt', 'SHA-224');
await fileHash('file:///path/to/your/file.txt', 'SHA-384');
await fileHash('file:///path/to/your/file.txt', 'SHA-512');
await fileHash('file:///path/to/your/file.txt', 'SHA-512/224');
await fileHash('file:///path/to/your/file.txt', 'SHA-512/256');
await fileHash('file:///path/to/your/file.txt', 'XXH3-64');
await fileHash('file:///path/to/your/file.txt', 'XXH3-128');
await fileHash('file:///path/to/your/file.txt', 'BLAKE3');
// Hash a string (small payloads only; for large data prefer fileHash to avoid keeping everything in JS memory)
const sha256String = await stringHash('hello world', 'SHA-256');
// For base64 input
const blake3String = await stringHash('<base64>', 'BLAKE3', 'base64');
// HMAC
const hmacSha256 = await fileHash('file:///path/to/file', 'HMAC-SHA-256', {
key: 'super-secret',
keyEncoding: 'utf8', // 'utf8' | 'hex' | 'base64'
});
// Keyed BLAKE3 (32-byte key)
const blake3Keyed = await fileHash('file:///path/to/file', 'BLAKE3', {
key: '<32-byte-key-hex-or-base64>',
keyEncoding: 'hex',
});API
fileHash(filePath, algorithm?, options?)
Computes the hash of the file at the given filePath using the specified
algorithm.
The input should be a local file URI or a platform-provided document URI:
- Android: supports regular
file://paths andcontent://URIs (for example, from the system document picker / SAF). - iOS: prefers regular local
file://URLs and also supports provider-backed / security-scoped file URLs (for example, from Files / iCloud document picker) when the app has access to them.
The function streams file data in fixed-size chunks and never loads the whole file into memory.
filePath: A local file URI or platform-provided document URI.algorithm: Optional, default'SHA-256'.options:key?: stringkeyEncoding?: 'utf8' | 'hex' | 'base64'(default'utf8')
Behavior:
- HMAC algorithms are selected via
algorithm(HMAC-SHA-*,HMAC-MD5,HMAC-SHA-1) and requirekey. BLAKE3withkeyuses keyed hashing and requires a 32-byte key after decoding.BLAKE3withoutkeyuses regular hashing.- Legacy
modeoption is not supported and returnsE_INVALID_ARGUMENT. - For non-HMAC and non-BLAKE3 algorithms, passing
keyreturnsE_INVALID_ARGUMENT. - For
engine=zig,XXH3-128returns an explicit unsupported-algorithm error.
- HMAC algorithms are selected via
Returns:
Promise<string>(lowercase hex digest).
stringHash(text, algorithm?, encoding?, options?)
Hashes a small string payload. For large data prefer fileHash to stream from disk and avoid extra memory usage.
text: Input string.algorithm: Same set asfileHash.encoding:'utf8'(default) or'base64'.options: Same asfileHash.- Returns:
Promise<string>(lowercase hex digest).
hashString(text, algorithm?, encoding?, options?) (deprecated)
Deprecated alias for stringHash(...). It remains available for migration and
will be removed in a future major release.
⚠️ Note >
stringHashis intended only for small payloads. For files or large buffers always preferfileHashto avoid excessive memory usage in JavaScript.
Breaking changes
Compared to v1.1.3 and earlier:
hashString(...)renamed tostringHash(...).hashString(...)currently works as a deprecated alias and will be removed in a future major release.moderemoved fromHashOptionsand now rejected withE_INVALID_ARGUMENT.- HMAC moved to dedicated algorithms (
HMAC-SHA-*,HMAC-MD5,HMAC-SHA-1). BLAKE3keyed hashing is inferred automatically whenkeyis provided.
Examples
Hash a large file efficiently
import { fileHash } from '@preeternal/react-native-file-hash';
const hash = await fileHash('file:///path/to/large-video.mp4', 'XXH3-128');Native implementations
- Zig core (optional engine): Preeternal/zig-files-hash
- XXH3 / XXH128: Cyan4973/xxHash
- BLAKE3: BLAKE3-team/BLAKE3
Licenses: xxHash is BSD 2-Clause; the C implementation of BLAKE3 is CC0 (public domain). See third_party/xxhash/LICENSE and third_party/blake3/LICENSE_CC0 (plus accompanying Apache-2.0 notices in third_party/blake3).
Performance note: XXH3/BLAKE3 are noticeably slower in Debug (no/low optimization, sanitizer flags, and SIMD may be disabled on simulators). Measure on real devices with Release builds for realistic throughput.
Zig engine vs Native engine
Full benchmark results are available in BENCHMARKS.md.
In short:
- Zig engine performs competitively with native on many algorithms.
- Current data already shows Zig wins in part of the matrix (for example iOS
SHA-256,SHA-224,HMAC-SHA-256,XXH3-64) while native wins others. - Android SHA-2 (
SHA-224/SHA-256and matching HMAC variants) currently uses native fallback in shipped Zig setup to avoid generic SHA-2 slowdown. - Size impact remains small in tests (
+0.49%APK /+0.42%AAB on Android; iOS app and main binary were slightly smaller with Zig engine).
Contributing
Contributions are welcome. If you have an idea for a new algorithm, engine capability, or API feature, start a GitHub Discussion first. For bugs and concrete work items, open an issue.
License
MIT
This project is licensed under the MIT License. See the LICENSE file for details.
Made with create-react-native-library
