Skip to content

Support allocation free usage of bcrypt#95

Merged
Keats merged 4 commits intoKeats:masterfrom
PrismaPhonic:peter/stack-based
Feb 28, 2026
Merged

Support allocation free usage of bcrypt#95
Keats merged 4 commits intoKeats:masterfrom
PrismaPhonic:peter/stack-based

Conversation

@PrismaPhonic
Copy link
Contributor

@PrismaPhonic PrismaPhonic commented Feb 25, 2026

In embedded, no_std, or latency-sensitive environments, every heap allocation matters. The existing API forces allocations in places that don't inherently need them - most notably during verify, where data was being encoded and decoded purely to pass through heap-allocated fields that existed only as an internal implementation detail.

This PR eliminates those unnecessary allocations while leaving the existing public API unchanged. The internal representation was always an implementation detail, and callers are not affected.

For callers who want to go further and avoid heap allocation entirely on the output side too this adds new _bytes variants of every public hash function.

HashParts also gains a write_for_version method that accepts any fmt::Write sink, allowing callers to write the hash string directly into stack-allocated string types (e.g. from arrayvec or heapless) without any intermediate heap allocation.

This doesn't need to be dynamically allocated. The logic is relatively
simple - ensure it starts as a null terminated string, but truncate at
72 bytes. We can simply zero fill a stack buffer (thereby ensuring the
last byte is a null byte) and then copy into it up until that last byte
if we are not truncating, and including the last byte if we are,
preserving the previous behavior with no dynamic allocation.
@PrismaPhonic PrismaPhonic marked this pull request as draft February 25, 2026 19:26
@PrismaPhonic PrismaPhonic marked this pull request as ready for review February 25, 2026 19:49
HashParts previously stored base64-encoded salt and hash as heap-allocated
Strings. They are now stored as raw bytes ([u8; 16] and [u8; 23]).
Encoding and decoding of base64 happens with slices now rather than
internally allocating as well.

This change aims to provide a way for callers to avoid dynamic
allocation entirely, if desired, while maintaining existing public
method signatures for backwards compatibility.

It adds similar methods to public methods that already existed that
allow callers to do the same thing (retreive salt, get bcrypt format
string, etc.) in allocation free ways.
Adds allocation free variants of all public hashing functions, to
provide a mechanism for users to use bcrypt fully alloc free if they
want.
This removes a vec usages (just used to split the incoming hash string
into it's parts) with a solution that avoids allocating.
@PrismaPhonic
Copy link
Contributor Author

I just realized I forgot one spot: split_hash had a Vec usage for string splitting on $. I pushed up on extra commit which switches to alloc free parsing of the hash string

@Keats Keats merged commit e9a8394 into Keats:master Feb 28, 2026
5 checks passed
@Keats
Copy link
Owner

Keats commented Feb 28, 2026

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants