sz.hash(text, seed=0) — seeded 64-bit AES-accelerated hash, returned as an unsigned int.
This differs from Python’s built-in hash(), which returns a platform-dependent Py_hash_t.
sz.hash_multiseed(text, seeds, out=None) — hash one string under many seeds at once. seeds is a contiguous buffer of uint64, such as a numpy.uint64 array or array('Q', ...); plain int lists are not accepted.
Returns a tuple of ints, or fills the optional contiguous uint64out buffer in place and returns None.
This is much faster than looping hash for short strings under many seeds, and is useful for feature hashing, Count-Min sketches, Bloom/cuckoo filters, and MinHash/LSH.
sz.bytesum(text) — additive checksum of the individual byte values, as an int.
sz.sha256(text) — 32-byte SHA-256 digest as bytes.
sz.hmac_sha256(key, message) — 32-byte HMAC-SHA256 digest as bytes.
hash, hash_multiseed, bytesum, and sha256 are also available as String methods.
import stringzilla as szimport numpy as npsz.hash("hello") # seeded 64-bit valuesz.hash("hello", seed=42) # a different valueassert sz.bytesum("abc") == 294assert sz.sha256("abc").hex()[:8] == "ba7816bf"assert len(sz.hmac_sha256(b"key", b"message")) == 32seeds = np.arange(8, dtype=np.uint64)assert len(sz.hash_multiseed("hello", seeds)) == 8 # tuple of 8 ints
Digesting one message is a serial dependency chain, but independent messages compress in parallel lanes — sixteen at a time on AVX-512, eight on AVX2. Sha256s(lanes) holds one hasher per lane, with update(chunks) taking exactly one chunk per lane and digest(out=None), hexdigest(), reset(), copy() and len() behaving as on Sha256.
Lanes are workers rather than messages: lanes[i] reads one as a Sha256, and lanes[i] = sz.Sha256() retires a finished lane while the others keep streaming.
sz.hmac_sha256(key, message, out=None) takes either one message or a collection, authenticating a batch of tokens sharing a secret through the same kernels.
Both accept a Strings, read in place, and an out buffer of bytes — a (count, 32)numpy.uint8 matrix receives one digest per row with no allocation, since that is byte-for-byte the layout the kernel writes.
The GIL is released around the kernel, so several threads digest concurrently.
Lanes advance in lockstep within a group, so a group costs as much as its longest message.
Every length is handled correctly, but throughput is best when messages of similar length share a group, which Strings.argsort arranges.
import numpy as npimport stringzilla as sztexts = sz.Strings(["alpha", "beta", "gamma"])lanes = sz.Sha256s(len(texts))digests = np.empty((len(lanes), sz.Sha256.digest_length), np.uint8)lanes.update(texts).digest(out=digests)tags = sz.hmac_sha256(b"secret", texts) # one 32-byte tag per messageassert tags[0] == sz.hmac_sha256(b"secret", "alpha")
API
Types
AuthenticationErrorRaised when a Galois/counter mode tag does not authenticate the bytes it accompanies.
The 32-byte secret is expanded once into a round-key schedule the object holds and wipes when it is collected.
Raises:
ValueError: If the secret is not exactly 32 bytes long.
Note:
A nonce must never repeat under one secret; reuse exposes the exclusive-or of two texts.
The 32-byte secret is expanded once into a schedule and the Galois hash powers, also called GHASH, and is wiped on collection.
Raises:
ValueError: If the secret is not exactly 32 bytes long.
Note:
Reusing a nonce here exposes the hash subkey, after which every message can be forged.
Chunk boundaries are invisible to the result. Opening a message uses Aes256GcmDecryptor, a separate type because the tag absorbs ciphertext in both directions, which is the output when sealing and the input when opening. Copies the key, so it cannot outlive it.
Absorb bytes that are authenticated but not encrypted, and return self for chaining.
All associated data must be absorbed before the first message chunk.
Returns:
Aes256GcmEncryptor: The same object, enabling sealed.associate(a).associate(b).
Example:
Absorb bytes that are authenticated but not encrypted, and return self for chaining.
All associated data must be absorbed before the first message chunk.
Returns:
Aes256GcmDecryptor: The same object, enabling opened.associate(a).associate(b).
Example:
key, nonce = sz.Aes256GcmKey(bytes(32)), bytes(12)
ciphertext, tag = key.encrypt(b'body', nonce, b'head')
opened = sz.Aes256GcmDecryptor(key, nonce).associate(b'head')
opened.decrypt_unverified(ciphertext)
b'body'
Parameters
datastr | bytes
The same associated bytes the sender authenticated.
Decrypt one chunk and absorb its ciphertext into the running tag. The bytes returned are
not yet authenticated: nothing has checked that this ciphertext is genuine, so buffer them
until verify() succeeds rather than acting on them.
Returns:
bytes: The unverified plaintext chunk, as long as data.
Example:
key, nonce = sz.Aes256GcmKey(bytes(32)), bytes(12)
ciphertext, tag = key.encrypt(b'hello', nonce)
opened = sz.Aes256GcmDecryptor(key, nonce)
opened.decrypt_unverified(ciphertext)
b'hello'
Hashing a single message is a serial dependency chain no instruction set can speed
up, but independent messages compress in parallel lanes: sixteen at a time on
AVX-512, eight on AVX2. Feed at least a few kilobytes per lane per call, as shorter
chunks never reach the lane-parallel path.
Lanes are workers rather than messages: assigning lanes[i] = sz.Sha256() retires a
finished lane and starts the next message in it, leaving every other lane streaming.
Writable, C-contiguous buffer of bytes holding at least
len(lanes) * 32 of them - a (len(lanes), 32) numpy.uint8 matrix receives one
digest per row with zero allocation. Defaults to None.
def hash(
text: _StringLike,
seed: int = 0,
/,
*,
capabilities: Capability | None = None,
) -> int
This function can be called as a method on a String object or as a standalone function.
Args:
text (String or str or bytes): The string to hash, positional-only when standalone.
seed (int, optional): The seed value for hashing. Defaults to 0. Can be positional or keyword.
capabilities (Capability, optional): Capabilities to run, defaulting to the CPU's enabled ones.
Returns:
int: The hash value as an unsigned 64-bit integer. This differs from Python's
built-in hash() which returns a Py_hash_t and may be platform-dependent.
Raises:
TypeError: If the argument is not string-like or incorrect number of arguments is provided.
Signature:
Equivalent to tuple(hash(text, s) for s in seeds), but normalizes the input into AES
blocks once and replays the cheap per-seed rounds - markedly faster for short strings under
many seeds (feature hashing, Count-Min sketches, Bloom/cuckoo filters, MinHash/LSH).
Returns:
tuple[int, ...] | None: Tuple of 64-bit hashes, or None when writing into out.
Parameters
text_StringLike
The string to hash, positional-only when standalone.
seeds_Buffer
Contiguous 64-bit seeds, e.g. numpy.uint64 array or array('Q', ...).
Plain int lists are not accepted - wrap them in array('Q', seeds) or numpy.
out_Buffer | None
A contiguous buffer of at least len(seeds) elements.
If given, it is filled in place and None returned; otherwise a tuple of ints is returned.
This function can be called as a method on a String object or as a standalone function.
Args:
text (String or str or bytes): The string to hash.
capabilities (Capability, optional): Capabilities to run, defaulting to the CPU's enabled ones.
Returns:
int: The checksum of individual byte values in a string.
Raises:
TypeError: If the argument is not string-like or incorrect number of arguments is provided.
Examples
>>> sz.bytesum('abc')294
sha256Compute SHA256 cryptographic hash of the input data.
This function can be called as a method on a String object or as a standalone function.
Args:
text (String or str or bytes): The input data to hash.
capabilities (Capability, optional): Capabilities to run, defaulting to the CPU's enabled ones.
Returns:
bytes: The 32-byte (256-bit) SHA256 digest.
Raises:
TypeError: If the argument is not string-like or incorrect number of arguments is provided.
Compute the HMAC-SHA256 authentication code of one message, or of many under one key.
Authenticating one message is a serial dependency chain no instruction set can speed up, but
independent messages compress in parallel lanes: sixteen at a time on AVX-512, eight on
AVX2. Pass a Strings of messages - a batch of tokens or requests sharing a secret - and both
the message pass and the outer wrap run lane-parallel.
Returns:
bytes: The 32-byte tag, for a single string-like message.
list[bytes]: One tag per message, in order, for a collection.
buffer: out itself, when an output buffer is given.
Example:
Writable, C-contiguous buffer of bytes holding at least 32 per
message - a (len(message), 32) numpy.uint8 matrix receives one tag per row with
zero allocation. Defaults to None.