noble-hashes

repository·main·Indexed 21 days ago

https://github.com/paulmillr/noble-hashes

An audited, minimal, 0-dependency JavaScript implementation of cryptographic primitives including SHA-2, SHA-3, BLAKE (1, 2, 3), RIPEMD, HMAC, HKDF, PBKDF2, and Scrypt. Designed for high security and auditability, it features hand-optimized code for JS engines and supports both one-shot hashing and streaming updates via .create().

Tokens
13.7K
Snippets
65
Records
73
Agent score
72%

What's inside @noble/hashes

  1. Overview of noble-hashes

    main
    noble-hashes is a minimal, audited, and high-performance JavaScript implementation of various cryptographic primitives, including hash functions, Message Authentication Codes (MACs), and Key Derivation Functions (KDFs). It is designed for high security and auditability, featuring hand-optimized code for JS engines and a small footprint (approx. 2.7KB gzipped for SHA-256).
  2. Security and Constant-timeness considerations

    main

    Constant-timeness

    The library targets algorithmic constant time. However, because it is a JavaScript library, achieving true constant-time resistance is extremely difficult due to the behavior of JIT compilers and Garbage Collectors. If your application requires absolute timing attack resistance, it is recommended to use low-level languages (like Rust or C) and libraries rather than JavaScript.

    Memory Safety

    The library attempts to mitigate memory exposure by sharing state buffers and zeroing them out after each call. However, users should be aware of several inherent JavaScript risks:

    • Immutable Strings: If sensitive data (like passwords) is handled as a JS string, it cannot be zeroed out in memory.
    • Async Execution: Using await can write internal variables to memory, and there are no guarantees regarding when code chunks execute, potentially leaving data exposed for an attacker to read.
    • Input Buffers: Data from files or reused application buffers may persist in memory.
  3. Install @noble/hashes

    main

    You can install the library using npm or add it via JSR for Deno. For React Native environments, you may need to provide a polyfill for getRandomValues (e.g., react-native-get-random-values). A standalone noble-hashes.js file is also available for direct use.

    npm install @noble/hashes
    
    deno add jsr:@noble/hashes
  4. Verify noble-hashes supply chain security

    main

    To ensure the integrity of the code you are using, follow these verification steps:

    1. Verify Commit Signatures: All commits are signed with PGP keys. Check signatures to prevent forgery.
    2. Verify Releases: Releases are made via token-less GitHub CI and Trusted Publishing. Verify the provenance logs for authenticity.
    3. Dependency Check: The package has 0 production dependencies, minimizing supply-chain risk.
  5. Upgrade to noble-hashes v2.x

    main

    When upgrading to version 2.0 or later, note the following breaking changes:

    • ESM-only: The package is now ESM-only. On Node.js v20.19+, ESM can be loaded from CommonJS.
    • Explicit Extensions: You must use the .js extension for all module imports to ensure compatibility with native browsers without transpilers.
      • Old: @noble/hashes/sha3
      • New: @noble/hashes/sha3.js
    • Strict Input Types: Only Uint8Array is allowed as hash input. Passing a string will result in a validation error. To convert strings to bytes, use utils.utf8ToBytes.
    • Module Reorganization:
      • sha256, sha512 $\rightarrow$ @noble/hashes/sha2.js
      • blake2b, blake2s $\rightarrow$ @noble/hashes/blake2.js
      • ripemd160, sha1, md5 $\rightarrow$ @noble/hashes/legacy.js
      • _assert $\rightarrow$ @noble/hashes/utils.js
    • WebCrypto: The internal crypto module has been removed; use the built-in WebCrypto API instead.
    • TypeScript: Compilation target has been bumped from es2020 to es2022.
  6. Use sub-imports for @noble/hashes to optimize bundle size

    main

    To ensure small application sizes, do not use import * from '@noble/hashes'. Instead, use specific sub-imports for the modules you need (e.g., @noble/hashes/sha2.js, @noble/hashes/sha3.js, etc.).

    // Error: do not do this
    // import * from '@noble/hashes'; 
    
    // Correct: use sub-imports
    import { sha256 as noble_sha256 } from '@noble/hashes/sha2.js';
    const hash = noble_sha256(Uint8Array.from([0xca, 0xfe, 0x01, 0x23]));
  7. Use BLAKE3 as an Extendable Output Function (XOF)

    main

    BLAKE3 supports variable-length output. If you need more bytes than the default digest length, you can use the XOF features.

    1. Via blake3() helper: Set the dkLen property in the options object.
    2. Via _BLAKE3 instance: After calling update(), you can call .xof(bytes) to get a specific number of bytes, or .xofInto(out) to write the output into an existing Uint8Array.
  8. Use Blake1 hash functions

    main

    Blake1 is a legacy hash function. It is rarely used today; it is recommended to use blake2 or blake3 instead. The library provides four variants: blake224, blake256, blake384, and blake512. Each function can be used to hash a single message or to create a hasher instance for incremental updates.

    import { blake256 } from '@noble/hashes/blake1';
    
    // Single-shot hashing
    const digest = blake256(new Uint8Array([97, 98, 99]));
    
    // Incremental hashing
    const hasher = blake256();
    hasher.update(new Uint8Array([97, 98]));
    hasher.update(new Uint8Array([99]));
    const finalDigest = hasher.digest();
  9. Import submodules from @noble/hashes

    main

    The root module of @noble/hashes cannot be imported directly. To use the library, you must import specific hash functions, MACs, or KDFs from their respective submodules. This ensures a minimal bundle size by only including the code you actually need.

    Common submodules include:

    • @noble/hashes/sha2.js: SHA-2 family (sha256, sha384, etc.)
    • @noble/hashes/sha3.js: SHA-3 and Keccak (sha3_256, keccak_256, shake128, etc.)
    • @noble/hashes/sha3-addons.js: SHA-3 extensions (cshake, kmac, etc.)
    • @noble/hashes/blake3.js: BLAKE3
    • @noble/hashes/blake2.js: BLAKE2 (blake2b, blake2s)
    • @noble/hashes/hmac.js: HMAC
    • @noble/hashes/hkdf.js: HKDF
    • @noble/hashes/pbkdf2.js: PBKDF2
    • @noble/hashes/scrypt.js: scrypt
    • @noble/hashes/legacy.js: Legacy hashes (md5, ripemd160, sha1)
    • @noble/hashes/utils.js: Utility functions
    import { sha256 } from '@noble/hashes/sha2.js';
    import { sha3_256 } from '@noble/hashes/sha3.js';
    import { blake3 } from '@noble/hashes/blake3.js';
    import { hmac } from '@noble/hashes/hmac.js';
  10. Use ESKDF (Experimental)

    main

    The eskdf.js module is an experimental KDF for deriving application-specific child keys from a username + password pair. It is built on scrypt, pbkdf2, and hkdf with fixed work factors.

    Note: This is non-standard. For new designs, prefer Scrypt or Argon2.

    import { eskdf } from '@noble/hashes/eskdf.js';
    
    const kdf = await eskdf('example-university', 'beginning-new-example');
    console.log(kdf.fingerprint);
    const key = kdf.deriveChildKey('aes', 0);
    kdf.expire();
  11. Use Argon2 for password-based key derivation

    main

    The argon2.js module implements Argon2 (RFC 9106).

    Warning: Argon2 can be slow in JS because there is no fast Uint64Array. It is suggested to use Scrypt instead, as being 5x slower than native code gives brute-force attackers a larger advantage.

    import { argon2d, argon2i, argon2id } from '@noble/hashes/argon2.js';
    
    const arg1 = argon2id('password', 'saltsalt', { t: 2, m: 65536, p: 1, maxmem: 2 ** 32 - 1 });