fnv1a32 function

int fnv1a32(
  1. String input
)

Computes a deterministic 32-bit FNV-1a hash over input.

FNV-1a (Fowler–Noll–Vo 1a) is a lightweight, non-cryptographic hash algorithm optimized for fast execution and high dispersion over arbitrary strings.

Determinism across SSR and Web Platforms

In Bloom JS Native, fnv1a32 is the mathematical foundation for Scoped CSS. Server-Side Rendering (running on the Dart VM) and browser client DOM mounting (compiled to JavaScript via dart2js or WebAssembly via dart2wasm) MUST compute bit-for-bit identical hashes for identical stylesheet inputs. If hashing diverged between 64-bit VM integers and JavaScript 32-bit bitwise semantics, class names emitted during SSR (renderToHtml) would not match those generated during client hydration (mount), causing broken CSS styling and hydration mismatches.

This implementation guarantees identical output across all runtimes by explicitly masking all bitwise shifts, additions, and XOR operations with 0xFFFFFFFF across both the low and high bytes of each character code unit.

Used internally by ScopedCss.compile and scopedCss to derive 7-character hex suffixes.

final hash = fnv1a32('.card { color: #6366f1; }');
final hex = hash.toRadixString(16).padLeft(8, '0').substring(0, 7);
print('Scoped hash: $hex');

Implementation

int fnv1a32(String input) {
  var hash = 0x811c9dc5;
  for (var i = 0; i < input.length; i++) {
    final code = input.codeUnitAt(i);
    hash ^= (code & 0xFF);
    // 32-bit multiplication by FNV prime 16777619 (0x01000193) via bitwise shifts:
    // 16777619 = 1 + (1<<1) + (1<<4) + (1<<7) + (1<<8) + (1<<24)
    hash = (hash +
            (hash << 1) +
            (hash << 4) +
            (hash << 7) +
            (hash << 8) +
            (hash << 24)) &
        0xFFFFFFFF;
    final high = code >> 8;
    if (high != 0) {
      hash ^= (high & 0xFF);
      hash = (hash +
              (hash << 1) +
              (hash << 4) +
              (hash << 7) +
              (hash << 8) +
              (hash << 24)) &
          0xFFFFFFFF;
    }
  }
  return hash & 0xFFFFFFFF;
}