# Hashing and Checksums

> StringZilla for Rust

These free functions cover a byte checksum, seeded and unseeded 64-bit hashes, and a multi-seed hash that fills an output slice in one pass.

```rust
pub fn bytesum<T: AsRef<[u8]>>(text: T) -> u64;
pub fn hash<T: AsRef<[u8]>>(text: T) -> u64;
pub fn hash_with_seed<T: AsRef<[u8]>>(text: T, seed: u64) -> u64;
pub fn hash_multiseed_into<T: AsRef<[u8]>>(text: T, seeds: &[u64], out: &mut [u64]) -> Result<(), Status>;
```

`bytesum` is an order-insensitive byte sum; `hash` / `hash_with_seed` are order-sensitive AES-based 64-bit hashes.
`hash_multiseed_into` hashes one input under many seeds in a single pass, handy for MinHash, Count-Min sketches, and Bloom/cuckoo filters; it returns `Status::UnexpectedDimensions` if `out.len() != seeds.len()`:

```rust
use stringzilla as sz;

assert_eq!(sz::bytesum("hi"), 209);
assert_ne!(sz::hash("Hello"), sz::hash("World"));
assert_eq!(sz::hash_with_seed("Hello", 42), sz::hash_with_seed("Hello", 42));

let seeds = [1u64, 2, 3, 4];
let mut out = [0u64; 4];
sz::hash_multiseed_into("token", &seeds, &mut out).unwrap();
```

These are also available as `StringZillableUnary` methods on any `AsRef<[u8]>`:

```rust
use stringzilla::StringZillableUnary;

assert_eq!(b"Hello".sz_bytesum(), 500);
assert_ne!(b"Hello".sz_hash(), b"World".sz_hash());
```

### Incremental Hashing

`Hasher` is an incremental AES-based hasher implementing `core::hash::Hasher`:

```rust
use stringzilla::Hasher;

let mut hasher = Hasher::new(123);
hasher.update(b"Hello, ").update(b"world!");
assert_eq!(hasher.digest(), Hasher::new(123).update(b"Hello, world!").digest());
```

`Hasher` API: `new(seed)`, `update(&mut self, &[u8]) -> &mut Self`, `digest(&self) -> u64`, plus the full `core::hash::Hasher` trait.

With the `std` feature, `BuildSzHasher` plugs the AES-based hash into the standard `HashMap` and `HashSet` as their hasher, replacing the default SipHash.
For string keys this swaps a scalar hash for StringZilla's vectorized one while keeping the entire collection API unchanged.
The seed defaults to `0` and is deterministic across runs, so pass a random seed through `with_seed` when you want per-process resistance to hash-flooding:

```rust
use std::collections::{HashMap, HashSet};
use stringzilla::BuildSzHasher;

let mut counts: HashMap<&str, i32, BuildSzHasher> = HashMap::with_hasher(BuildSzHasher::with_seed(0));
for word in ["apple", "banana", "apple"] { *counts.entry(word).or_insert(0) += 1; }
assert_eq!(counts["apple"], 2);

let mut seen: HashSet<&str, BuildSzHasher> = HashSet::with_hasher(BuildSzHasher::with_seed(42));
seen.insert("apple");
seen.insert("banana");
assert!(seen.contains("apple"));
assert_eq!(seen.len(), 2);
```

### SHA-256 and HMAC

`hmac_sha256` computes a keyed HMAC-SHA-256 over a message, returning a 32-byte tag.
`hmac_sha256_multistate` authenticates many messages under one key at once — a batch of tokens or webhook bodies sharing a secret — running both the message pass and HMAC's outer wrap through the lane-parallel kernels.
It allocates nothing, so it works under `no_std`: `states` is scratch of one state per message, reused for both passes, and only `tags` is written for keeps.

```rust
pub fn hmac_sha256(key: &[u8], message: &[u8]) -> Sha256Digest;
pub fn hmac_sha256_multistate<Element: AsRef<[u8]>>(
    key: &[u8],
    messages: &[Element],
    states: &mut [Sha256],
    tags: &mut [Sha256Digest],
) -> Result<(), Status>;
```

`Sha256` supports one-shot and incremental hashing, returning a 32-byte digest:

```rust
use stringzilla::{Sha256, hmac_sha256};

let digest = Sha256::hash(b"Hello, world!");
assert_eq!(digest.len(), 32);

let mut hasher = Sha256::new();
hasher.update(b"Hello, ").update(b"world!");
assert_eq!(hasher.digest(), digest);

let mac = hmac_sha256(b"secret_key", b"important message");
assert_eq!(mac.len(), 32);
```

`Sha256` API: `new()`, `update(&mut self, &[u8]) -> &mut Self`, `digest(&self) -> Sha256Digest`, `hash(&[u8]) -> Sha256Digest`, where `Sha256Digest` is `[u8; SHA256_DIGEST_LENGTH]`.

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.
`sha256_multistate_update` advances one hasher per message, taking anything that dereferences to bytes, so a `Vec<String>` needs no intermediate slice of slices.
Use `sha256_multistate_update_by(&mut states, &records, |record| record.payload.as_bytes())` when each message is a field of a larger element.

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 `argsort` arranges.

```rust
use stringzilla as sz;

let texts: Vec<String> = vec!["alpha".into(), "beta".into()];
let mut states = vec![sz::Sha256::new(); texts.len()];
let mut digests = vec![[0u8; 32]; texts.len()];

sz::sha256_multistate_update(&mut states, &texts).unwrap();
sz::sha256_multistate_digest(&states, &mut digests).unwrap();
assert_eq!(digests[0], sz::Sha256::hash(b"alpha"));
```

`use stringzilla::Aes256CtrKey;`

`use stringzilla::Aes256GcmKey;`

`use stringzilla::Aes256GcmEncryptor;`

`use stringzilla::Aes256GcmDecryptor;`

`use stringzilla::Hasher;`

`use stringzilla::Sha256;`

`use stringzilla::BuildSzHasher;`

`use stringzilla::*;`

## Sha256Digest

One SHA256 digest, as produced by [`Sha256::digest`](#digest) and [`sha256_multistate_digest`](#sha256_multistate_digest).

```rust
pub type Sha256Digest = [u8; 32];
```

## Aes256CtrKey

Expanded AES-256 round-key schedule for counter mode, the construction named AES-256-CTR.

```rust
pub struct Aes256CtrKey
```

Counter mode is unauthenticated and seekable: the keystream at a byte offset depends on nothing
but the key, the nonce and that offset, so a caller may decrypt the middle of a file without
touching its start. Reusing a nonce under one key exposes the exclusive-or of two plaintexts.

Mirrors `sz_aes256_key_t`, and carries none of the Galois hash powers counter mode never reads.

Implements: `Drop`, `Debug`

## new

Expands a 32-byte secret into the AES-256 round-key schedule.

```rust
pub fn new(secret: &[u8; 32]) -> Self
```

## xor_into

Exclusive-ors `text` against the keystream starting at `byte_offset`, writing `output`.

```rust
pub fn xor_into(
    &self,
    nonce: &[u8; 12],
    byte_offset: u64,
    text: &[u8],
    output: &mut [u8],
) -> Result<(), Status>
```

Counter mode is its own inverse, so this call both encrypts and decrypts.

Returns [`Status::UnexpectedDimensions`](https://www.unum.cloud/docs/stringzilla/rust/types.md#UnexpectedDimensions) if `output` is not as long as `text`.

## xor_in_place

Exclusive-ors `text` against the keystream starting at `byte_offset`, in place.

```rust
pub fn xor_in_place(&self, nonce: &[u8; 12], byte_offset: u64, text: &mut [u8])
```

Counter mode is its own inverse, so this call both encrypts and decrypts.

## Aes256GcmKey

Expanded AES-256 schedule plus the Galois hash subkey powers, the construction named AES-256-GCM.

```rust
pub struct Aes256GcmKey
```

Authentication costs the ability to seek, so this mode transforms whole messages or bounded
chunks in order. Reusing a nonce under one key exposes the hash subkey, from which every message
under that key can be forged.

Mirrors `sz_aes256_gcm_key_t`.

Implements: `Drop`, `Debug`

## new

Expands a 32-byte secret into a schedule and the Galois hash subkey powers.

```rust
pub fn new(secret: &[u8; 32]) -> Self
```

## encrypt_into

Encrypts `text` into `output`, returning the tag over the ciphertext and `associated`.

```rust
pub fn encrypt_into(
    &self,
    nonce: &[u8; 12],
    associated: &[u8],
    text: &[u8],
    output: &mut [u8],
) -> Result<[u8; 16], Status>
```

The associated bytes are authenticated but not encrypted, such as a routing header.

Returns [`Status::UnexpectedDimensions`](https://www.unum.cloud/docs/stringzilla/rust/types.md#UnexpectedDimensions) if `output` is not as long as `text`.

## encrypt_in_place

Encrypts `text` in place, returning the tag over the ciphertext and `associated`.

```rust
pub fn encrypt_in_place(&self, nonce: &[u8; 12], associated: &[u8], text: &mut [u8]) -> [u8; 16]
```

## decrypt_into

Verifies `tag` and decrypts `text` into `output`, which holds the plaintext only on success.

```rust
pub fn decrypt_into(
    &self,
    nonce: &[u8; 12],
    associated: &[u8],
    text: &[u8],
    output: &mut [u8],
    tag: &[u8; 16],
) -> Result<(), Status>
```

A rejected tag, [`Status::AuthenticationFailed`](https://www.unum.cloud/docs/stringzilla/rust/types.md#AuthenticationFailed), leaves `output` zeroed, so a caller who
drops the error still cannot read forged plaintext. The comparison takes the same time
wherever the tag first differs.

Returns [`Status::UnexpectedDimensions`](https://www.unum.cloud/docs/stringzilla/rust/types.md#UnexpectedDimensions), writing nothing, if `output` is not as long as
`text`.

## decrypt_in_place

Verifies `tag` and decrypts `text` in place, which holds the plaintext only on success.

```rust
pub fn decrypt_in_place(
    &self,
    nonce: &[u8; 12],
    associated: &[u8],
    text: &mut [u8],
    tag: &[u8; 16],
) -> Result<(), Status>
```

A rejected tag, [`Status::AuthenticationFailed`](https://www.unum.cloud/docs/stringzilla/rust/types.md#AuthenticationFailed), zeroes `text`, destroying the ciphertext
it arrived with.

## Aes256GcmEncryptor

Seals a message delivered in chunks under Galois/counter mode, or GCM, accumulating its tag as it goes.

```rust
pub struct Aes256GcmEncryptor
```

A chunk boundary is invisible to the result, so any chunking produces the ciphertext and tag a
single [`Aes256GcmKey::encrypt_into`](#encrypt_into) would.

Mirrors `sz_aes256_gcm_encryptor_t`, whose address every call below passes.

Implements: `Drop`

## new

Begins a chunked encryption under `key` and `nonce`, copying `key` in so this cannot outlive it.

```rust
pub fn new(key: &Aes256GcmKey, nonce: &[u8; 12]) -> Self
```

## *

Absorbs associated data, which is authenticated but not encrypted.

```rust
pub fn associate(&mut self, associated: &[u8]) -> &mut Self
```

All of it must be absorbed before the first chunk of the message.

## encrypt_into

Encrypts one chunk into `output` and folds its ciphertext into the running tag.

```rust
pub fn encrypt_into(&mut self, text: &[u8], output: &mut [u8]) -> Result<&mut Self, Status>
```

Returns [`Status::UnexpectedDimensions`](https://www.unum.cloud/docs/stringzilla/rust/types.md#UnexpectedDimensions), absorbing nothing, if `output` is not as long as
`text`.

## encrypt_in_place

Encrypts one chunk in place and folds its ciphertext into the running tag.

```rust
pub fn encrypt_in_place(&mut self, text: &mut [u8]) -> &mut Self
```

## digest

Returns the tag over everything encrypted so far, leaving the encryptor ready for more.

```rust
pub fn digest(&self) -> [u8; 16]
```

## Aes256GcmDecryptor

Opens a message delivered in chunks under Galois/counter mode, or GCM, accumulating its tag as it goes.

```rust
pub struct Aes256GcmDecryptor
```

Every emitted byte leaves this type unauthenticated, which is why the methods that emit
them say so in their names. Only [`Aes256GcmDecryptor::verify`](#verify) tells the caller whether
they were genuine.

Mirrors `sz_aes256_gcm_decryptor_t`, whose address every call below passes.

Implements: `Drop`

## new

Begins a chunked decryption under `key` and `nonce`, copying `key` in so this cannot outlive it.

```rust
pub fn new(key: &Aes256GcmKey, nonce: &[u8; 12]) -> Self
```

## decrypt_unverified_into

Decrypts one chunk into `output` and folds its ciphertext into the running tag.

```rust
pub fn decrypt_unverified_into(
    &mut self,
    text: &[u8],
    output: &mut [u8],
) -> Result<&mut Self, Status>
```

The emitted bytes are __not authenticated__. Nothing has yet checked that this ciphertext is
genuine, so the caller owns that risk: buffer the output until [`Self::verify`](#verify) succeeds and
discard it if it does not. A streaming decryption cannot avoid this, which is why the name
says so. Callers who can hold the whole message should use [`Aes256GcmKey::decrypt_into`](#decrypt_into),
which emits nothing until the tag has matched.

Returns [`Status::UnexpectedDimensions`](https://www.unum.cloud/docs/stringzilla/rust/types.md#UnexpectedDimensions), absorbing nothing, if `output` is not as long as
`text`.

## decrypt_unverified_in_place

Decrypts one chunk in place and folds its ciphertext into the running tag.

```rust
pub fn decrypt_unverified_in_place(&mut self, text: &mut [u8]) -> &mut Self
```

The emitted bytes are __not authenticated__, exactly as in
[`Self::decrypt_unverified_into`](#decrypt_unverified_into), and in place they also overwrite the ciphertext a failed
[`Self::verify`](#verify) would have to discard.

## verify

Checks `tag` against everything absorbed so far, in time independent of where it differs, returning [`Status::AuthenticationFailed`](https://www.unum.cloud/docs/stringzilla/rust/types.md#AuthenticationFailed) on a mismatch.

```rust
pub fn verify(&self, tag: &[u8; 16]) -> Result<(), Status>
```

Until this returns `Ok`, every byte the decryptor emitted is an attacker's to choose.

## Hasher

Incremental hasher state for StringZilla's 64-bit hash.

```rust
pub struct Hasher
```

Use `Hasher::new(seed)` to construct, then call `update(&mut self, data)`
zero or more times, and finally call `digest(&self)` to read the current
hash value without consuming the state.

Implements: `Debug`, `Clone`, `Copy`, `PartialEq`, `Default`, [`Hasher`](#Hasher)

## new

Creates a new hasher initialized with `seed`.

```rust
pub fn new(seed: u64) -> Self
```

## *

Updates the hasher with more data.

```rust
pub fn update(&mut self, data: &[u8]) -> &mut Self
```

## digest

Returns the current hash value without consuming the state.

```rust
pub fn digest(&self) -> u64
```

## Sha256

Incremental SHA256 hasher state for cryptographic hashing.

```rust
pub struct Sha256(_);
```

Examples: One-shot hashing:

```
use stringzilla::Sha256;
let digest = Sha256::hash(b"Hello, world!");
assert_eq!(digest.len(), 32); // 256 bits = 32 bytes
```

Incremental hashing:

```
use stringzilla::Sha256;
let mut hasher = Sha256::new();
hasher.update(b"Hello, ");
hasher.update(b"world!");
let digest = hasher.digest();
assert_eq!(digest, Sha256::hash(b"Hello, world!"));
```

Implements: `Debug`, `Clone`, `Copy`, `Default`

## new

Creates a new SHA256 hasher with the initial state.

```rust
pub fn new() -> Self
```

## digest

Returns the current SHA256 digest, leaving the hasher able to accept more data.

```rust
pub fn digest(&self) -> Sha256Digest
```

## hash

Convenience method to hash data in one call.

```rust
pub fn hash(data: &[u8]) -> Sha256Digest
```

## BuildSzHasher

BuildHasher for constructing [`Hasher`](#Hasher) instances, enabling use with HashMap/HashSet.

```rust
pub struct BuildSzHasher
```

By default uses seed 0 for deterministic hashing across runs and platforms.
If you need DOS-resistant randomized seeding, consider wrapping this in your
application with a per-process random seed.

- `seed` `u64`: The seed every built hasher starts from.

Implements: `Debug`, `Clone`, `Copy`, `Default`, `BuildHasher`

## with_seed

Builds a hasher factory with the given seed.

```rust
pub const fn with_seed(seed: u64) -> Self
```

## sha256_multistate_update

Advances many independent SHA256 states at once, one message per lane.

```rust
pub fn sha256_multistate_update<Element: AsRef<[u8]>>(
    states: &mut [Sha256],
    chunks: &[Element],
) -> Result<(), Status>
```

Hashing a single message is a serial dependency chain, so no instruction set can speed it
up. Independent messages do compress in parallel lanes: sixteen at a time on AVX-512, eight
on AVX2. Feed at least a few kilobytes per lane per call, since shorter chunks never reach
the lane-parallel path.

Borrows the caller's storage throughout and allocates nothing. Accepts anything that
dereferences to bytes, so a `Vec<String>` or `Vec<Vec<u8>>` needs no intermediate
slice-of-slices. See [`sha256_multistate_update_by`](#sha256_multistate_update_by) for messages that do not sit in
one contiguous slice.

Errors: Returns [`Status::UnexpectedDimensions`](https://www.unum.cloud/docs/stringzilla/rust/types.md#UnexpectedDimensions) if `chunks` does not have exactly one entry per lane.

Examples: ```
use stringzilla as sz;

let mut states = vec![sz::Sha256::new(); 2];
let heads: Vec&#x3C;String> = vec!["Hello, ".into(), "Goodbye, ".into()];
let tails: Vec&#x3C;String> = vec!["world!".into(), "world!".into()];
sz::sha256_multistate_update(&#x26;mut states, &#x26;heads).unwrap();
sz::sha256_multistate_update(&#x26;mut states, &#x26;tails).unwrap();

let mut digests = vec![[0u8; 32]; 2];
sz::sha256_multistate_digest(&#x26;states, &#x26;mut digests).unwrap();
assert_eq!(digests[0], sz::Sha256::hash(b"Hello, world!"));
assert_eq!(digests[1], sz::Sha256::hash(b"Goodbye, world!"));
```

## sha256_multistate_update_by

Advances many independent SHA256 states at once, taking each lane's next chunk as a byte-slice `key` of the matching element of `chunks`.

```rust
pub fn sha256_multistate_update_by<Element, Key>(
    states: &mut [Sha256],
    chunks: &[Element],
    key: Key,
) -> Result<(), Status>
where
    Key: Fn(&Element) -> &[u8],
```

`key` runs inside the C call, where a panic cannot unwind and aborts the process.

Errors: Returns [`Status::UnexpectedDimensions`](https://www.unum.cloud/docs/stringzilla/rust/types.md#UnexpectedDimensions) if `chunks` does not have exactly one entry per lane.

Examples: ```
use stringzilla as sz;

struct Record { payload: &#x26;'static str }
let records = [Record { payload: "alpha" }, Record { payload: "beta" }];

let mut states = vec![sz::Sha256::new(); 2];
sz::sha256_multistate_update_by(&#x26;mut states, &#x26;records, |record| record.payload.as_bytes()).unwrap();

let mut digests = vec![[0u8; 32]; 2];
sz::sha256_multistate_digest(&#x26;states, &#x26;mut digests).unwrap();
assert_eq!(digests[0], sz::Sha256::hash(b"alpha"));
```

## sha256_multistate_digest

Writes each lane's digest into caller-provided storage, leaving every lane able to accept more data.

```rust
pub fn sha256_multistate_digest(
    states: &[Sha256],
    digests: &mut [Sha256Digest],
) -> Result<(), Status>
```

Errors: Returns [`Status::UnexpectedDimensions`](https://www.unum.cloud/docs/stringzilla/rust/types.md#UnexpectedDimensions) if `digests` does not have exactly one entry per lane.

## hmac_sha256

Computes HMAC-SHA256, the Hash-based Message Authentication Code, for the given key and message.

```rust
pub fn hmac_sha256(key: &[u8], message: &[u8]) -> Sha256Digest
```

#### Returns

A 32-byte HMAC-SHA256 digest

Arguments: - `key` - The secret key (can be any length, will be hashed if > 64 bytes)

- `message` - The message to authenticate

Examples: ```
use stringzilla::hmac_sha256;
let key = b"secret_key";
let message = b"important message";
let mac = hmac_sha256(key, message);
assert_eq!(mac.len(), 32);
```

## hmac_sha256_multistate

Authenticates many messages under one key at once, one message per lane.

```rust
pub fn hmac_sha256_multistate<Element: AsRef<[u8]>>(
    key: &[u8],
    messages: &[Element],
    states: &mut [Sha256],
    tags: &mut [Sha256Digest],
) -> Result<(), Status>
```

Authenticating one message is a serial dependency chain, but independent messages compress in
parallel lanes - sixteen at a time on AVX-512, eight on AVX2 - and both the message pass and
HMAC's outer wrap ride those same kernels. Intended for batches of short messages, such as
tokens or webhook bodies sharing a secret; there is no streaming form, since the message
never spans calls.

Borrows the caller's storage throughout and allocates nothing, so it works under `no_std`.
`states` is scratch of one state per message, reused for both passes; only `tags` is
written for keeps.

Errors: Returns [`Status::UnexpectedDimensions`](https://www.unum.cloud/docs/stringzilla/rust/types.md#UnexpectedDimensions) unless `messages`, `states` and `tags` all have the
same length.

Examples: ```
use stringzilla as sz;

let messages: Vec&#x3C;String> = vec!["alpha".into(), "beta".into()];
let mut states = vec![sz::Sha256::new(); messages.len()];
let mut tags = vec![[0u8; 32]; messages.len()];

sz::hmac_sha256_multistate(b"secret", &#x26;messages, &#x26;mut states, &#x26;mut tags).unwrap();
assert_eq!(tags[0], sz::hmac_sha256(b"secret", b"alpha"));
```

## bytesum

Computes the checksum value of unsigned bytes in a given byte slice `text`.

```rust
pub fn bytesum<Text>(text: Text) -> u64
where
    Text: AsRef<[u8]>,
```

This function is useful for verifying data integrity and detecting changes in
binary data, such as files or network packets.

#### Returns

A `u64` representing the checksum value of the input byte slice.

Arguments: - `text`: The byte slice to compute the checksum for.

## hash_with_seed

Computes a 64-bit AES-based hash value for a given byte slice `text`.

```rust
pub fn hash_with_seed<Text>(text: Text, seed: u64) -> u64
where
    Text: AsRef<[u8]>,
```

This function is designed to provide a high-quality hash value for use in
hash tables, data structures, and cryptographic applications.
Unlike the bytesum function, the hash function is order-sensitive.

#### Returns

A `u64` representing the hash value of the input byte slice.

Arguments: - `text`: The byte slice to compute the checksum for.

- `seed`: A 64-bit value that acts as the seed for the hash function.

## hash

Computes a 64-bit AES-based hash value for a given byte slice `text`.

```rust
pub fn hash<Text>(text: Text) -> u64
where
    Text: AsRef<[u8]>,
```

This function is designed to provide a high-quality hash value for use in
hash tables, data structures, and cryptographic applications.
Unlike the bytesum function, the hash function is order-sensitive.

#### Returns

A `u64` representing the hash value of the input byte slice.

Arguments: - `text`: The byte slice to compute the checksum for.

## hash_multiseed_into

Hashes one byte slice under many seeds at once, writing the results into `out`.

```rust
pub fn hash_multiseed_into<Text>(text: Text, seeds: &[u64], out: &mut [u64]) -> Result<(), Status>
where
    Text: AsRef<[u8]>,
```

Equivalent to `out[i] = hash_with_seed(text, seeds[i])`, 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).

Arguments: - `text`: The byte slice to hash.

- `seeds`: The 64-bit seeds to hash under.

- `out`: The output buffer, filled with one hash per seed. Must be the same length as `seeds`.

Errors: Returns [`Status::UnexpectedDimensions`](https://www.unum.cloud/docs/stringzilla/rust/types.md#UnexpectedDimensions) if `out.len() != seeds.len()`.

## AES256_KEY_LENGTH

Bytes in an AES-256 secret key.

```rust
pub const AES256_KEY_LENGTH: usize = 32;
```

## AES256_NONCE_LENGTH

Bytes in the nonce both AES-256 modes accept, the width NIST SP 800-38D recommends.

```rust
pub const AES256_NONCE_LENGTH: usize = 12;
```

## AES256_TAG_LENGTH

Bytes in a Galois/counter mode, or GCM, authentication tag.

```rust
pub const AES256_TAG_LENGTH: usize = 16;
```

## SHA256_DIGEST_LENGTH

Bytes in a SHA256 digest, fixed by FIPS 180-4.

```rust
pub const SHA256_DIGEST_LENGTH: usize = 32;
```

## SHA256_BLOCK_LENGTH

Bytes in a SHA256 message block, fixed by FIPS 180-4.

```rust
pub const SHA256_BLOCK_LENGTH: usize = 64;
```

