Open-source project
RustCrypto/utils avatar
RustCrypto/utils

RustCrypto utils: the small crates every RustCrypto algorithm leans on

Utility crates used in RustCrypto

685 stars173 forksRustLicense varies

At a glance

What is it?
The RustCrypto utils repository is a workspace of fifteen utility crates that the rest of the RustCrypto ecosystem depends on, from block buffering and padding to constant-time helpers and zeroization. They are individually boring, individually load-bearing, and governed by a lint set that turns a large part of the RustCrypto style into a compiler check.
Who is it for?
Adopt the RustCrypto utils crates when you are building a Rust cryptographic primitive or a protocol implementation on top of one, since block-buffer, block-padding, inout and zeroize are the pieces that would otherwise be reinvented badly. Do not reach for them as a general purpose toolkit, since each one is narrow and some exist purely to make a compiler or a CPU do the right thing.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A workspace of fifteen crates, each with one job

This repository contains various utility crates used in the RustCrypto project, and the crate table in the README is the best map of what that means in practice.

blobby is a decoder of the simple de-duplicated binary blob storage format, and wycheproof2blb is a utility for converting Wycheproof test vectors to the blobby format, which is how a project like this gets standard test data into a shape it can replay cheaply.

block-buffer is a fixed size buffer for block processing of data, block-padding is for padding and unpadding of messages divided into blocks, and inout provides custom reference types for code generic over in-place and buffer-to-buffer modes of operation. Those three together are the spine of the collection: a block cipher or hash is written once against an abstract buffer type, and the caller chooses whether it runs in place or through a separate buffer.

sponge-cursor is a cursor for sponge-based absorption and squeezing, which is the interface a Keccak-style construction needs. digest-io provides std::io-compatibility wrappers for traits defined in the digest crate, and the repository also carries a digest-io-async directory that is not in the crate table.

The rest are smaller and more specialised: cmov for conditional move intrinsics, cpubits for compile-time detection heuristics for the optimal word size to use for the target CPU, cpufeatures as a lightweight and efficient alternative to the is_x86_feature_detected! macro, ctutils as a constant-time utility library with selection and equality testing support targeting cryptographic applications, dit for enabling or disabling the Data Independent Timing feature on AArch64 CPUs, dbl for double operation in a Galois Field, hex-literal as a macro for converting hexadecimal strings to a byte array at compile time, and zeroize for securely zeroing memory while avoiding compiler optimisations.

The lint table is the project’s style guide

The most interesting file in the repository is the workspace Cargo.toml, because the lint configuration is long and specific. It is worth reading as a statement of what RustCrypto considers acceptable in cryptographic code.

The clippy lints include borrow_as_ptr, cast_lossless, cast_possible_truncation, cast_possible_wrap, cast_precision_loss and cast_sign_loss, checked_conversions, doc_markdown, implicit_saturating_sub, manual_assert, map_unwrap_or, missing_errors_doc, missing_panics_doc, mod_module_files, must_use_candidate, ptr_as_ptr, redundant_closure_for_method_calls, ref_as_ptr, return_self_not_must_use, semicolon_if_nothing_returned, trivially_copy_pass_by_ref, std_instead_of_alloc, std_instead_of_core, undocumented_unsafe_blocks, unnecessary_safety_comment, unwrap_in_result and unwrap_used. The rust lints add missing_copy_implementations, missing_debug_implementations, missing_docs, trivial_casts, trivial_numeric_casts, unused_lifetimes and unused_qualifications.

Several of those are about safety discipline rather than style. undocumented_unsafe_blocks means every unsafe block has to say why it is sound, which is a review convention enforced by the compiler. unwrap_used and unwrap_in_result mean panicking paths have to be explicit. missing_errors_doc and missing_panics_doc mean the public API has to state its failure modes.

The profile is also tuned. The dev profile sets opt-level = 2, so debugging a build of a cryptographic library does not silently run at opt-level 0, where the generated code looks nothing like the code that ships.

The point for an adopter is that these lints are not decoration. They are the mechanism by which a set of independent contributors, none of whom owns the whole ecosystem, keep a shared style. A crate that violates them will not pass the workspace checks, and the checks are in the manifest rather than in a wiki page that can drift.

Why zeroize and constant-time helpers are separate crates

Three of the crates exist because of properties that the Rust compiler and optimiser will otherwise work against, and separating them is the interesting design decision in the collection.

zeroize is for securely zeroing memory while avoiding compiler optimisations. The problem it solves is specific: a plain assignment of zeros to a buffer is dead code as far as the optimiser is concerned, so it can be removed, and a secret that was supposed to be wiped stays in memory. zeroize provides the means to make the wipe happen and stay. The repository also has a zeroize_derive directory, and the workspace patches it locally through the patch.crates-io section, alongside cmov:

toml
[patch.crates-io]
cmov = { path = "cmov" }
zeroize_derive = { path = "zeroize_derive" }

ctutils is a constant-time utility library with selection and equality testing support targeting cryptographic applications. Constant time means the duration of an operation does not depend on the secret value, which is what stops a timing side channel. dit handles the Data Independent Timing feature on AArch64 CPUs, and cmov provides conditional move intrinsics, which is the primitive you reach for when a compiler will not emit a branchless select for you.

cpubits is the quiet one. It provides compile-time detection heuristics for the optimal word size to use for the target CPU, which matters for implementations that are generic over the machine word size, and cpufeatures gives a lighter alternative to the standard macro for runtime feature detection.

The separation is the point. A crate that mixes zeroization, constant-time selection and a runtime feature detector is a crate with a large API surface and a large audit surface. As separate crates, each one can be reviewed, replaced or not used at all, and a project that only needs block-buffer and block-padding never pulls in the AArch64 or x86 specific code.

The workspace shape and the two excluded crates

The workspace manifest lists eighteen members and excludes two directories, and the reason for the exclusion is stated in the file itself: the digest-io and digest-io-async directories result in circular dependencies, so they are excluded from the workspace.

That exclusion is worth pausing on, because it is the kind of thing that trips up a first-time contributor. The directories exist in the repository, the README lists digest-io among the published crates, and yet it is not a workspace member. The consequence is that digest-io is built and released outside the workspace, with its own dependency resolution, and a change to it does not get the workspace's shared lint and profile settings applied in the same way as the members do.

The workspace also uses resolver = 3, which is the modern setting for a workspace with edition 2021 and later members, and it inherits a single set of lints across the members, which is what makes the lint table in the previous section apply everywhere.

For a user, the practical takeaway is that each crate is published to crates.io independently, with its own documentation on docs.rs, so you depend on the crates you need rather than on this repository. You are not pulling a workspace into your build, you are pulling one or two small libraries.

The licence is worth reading closely. All crates are licensed under either the Apache License, Version 2.0 or the MIT license, at your option. The contribution terms match that: unless a contributor explicitly states otherwise, any contribution intentionally submitted for inclusion in the work, as defined in the Apache-2.0 licence, shall be dual licensed as above, without any additional terms or conditions.

Where the collection is the wrong choice

The first limitation is that these are not general purpose building blocks. block-padding implements padding schemes for cryptographic messages, not the padding you want for a network protocol or a database page. inout is for code that has to be generic over in-place and buffer-to-buffer operation, which is a constraint you impose when writing a cipher or a hash, not something a general application needs. Adding them for a task they were not designed for means fighting their trait bounds rather than using them.

The second limitation is that some crates are close to the hardware and only make sense on some hardware. cmov is conditional move intrinsics, cpubits is about optimal word size for the target CPU, dit is specifically about AArch64 CPUs and the Data Independent Timing feature, and cpufeatures is described as an alternative to the is_x86_feature_detected! macro. A portable codebase that pulls these in for the benefit of one architecture has taken on a dependency it may not want.

The third limitation is that this collection does not do cryptography. It holds the plumbing that cryptographic crates sit on: buffers, padding rules, sponge cursors, digest I/O adapters, and the memory hygiene primitives. If your need is a hash function, a cipher or a signature scheme, those live in other RustCrypto repositories, and this one only helps if you are writing one yourself or assembling one from parts.

The real alternative is to write the small parts yourself, which for a general application is often the right answer. A buffer type for a fixed block size is a page of code, and a zeroing helper that the optimiser can defeat is a bug you have written yourself. The reason to use the RustCrypto versions is not that they are large, it is that they have been looked at by people who work on cryptographic code, that zeroize in particular encodes a guarantee about the optimiser that is easy to get wrong, and that the block-buffer and inout abstractions have a specific shape designed to let one cipher implementation serve both in-place and buffer-to-buffer callers without a copy. For an application that just needs to hash a password or encrypt a file with a library that already handles this, adding these crates is overhead, and a well-maintained high-level crypto crate is the better dependency.

Editorial conclusion

Adopt the RustCrypto utils crates when you are building a Rust cryptographic primitive or a protocol implementation on top of one, since block-buffer, block-padding, inout and zeroize are the pieces that would otherwise be reinvented badly. Do not reach for them as a general purpose toolkit, since each one is narrow and some exist purely to make a compiler or a CPU do the right thing. Before you pin versions, check the workspace's lint set and the zeroize derive crate, and read SECURITY.md, since a security-relevant change to zeroize or to the constant-time helpers deserves a different review than an ordinary dependency bump.

Frequently asked questions

What is the RustCrypto utils repository?

It contains various utility crates used in the RustCrypto project, published individually to crates.io with documentation on docs.rs. The collection covers block buffers, block padding, in-place and buffer-to-buffer reference types, sponge cursors, digest I/O adapters, constant-time helpers, CPU feature detection and secure memory zeroing.

Which crates in RustCrypto utils handle constant-time operations?

ctutils is the constant-time utility library with selection and equality testing support targeting cryptographic applications, cmov provides conditional move intrinsics, and dit wraps enabling or disabling the Data Independent Timing feature on AArch64 CPUs. zeroize handles secure memory clearing, while cpubits provides compile-time heuristics for the optimal word size on the target CPU.

What licence applies to the RustCrypto utils crates?

All crates are licensed under either the Apache License, Version 2.0 or the MIT license, at your option. The contribution terms state that any contribution intentionally submitted for inclusion, as defined in the Apache-2.0 licence, shall be dual licensed as above without any additional terms or conditions.

Why are digest-io and digest-io-async not workspace members?

The workspace manifest excludes both directories, and the comment in the file gives the reason: they result in circular dependencies. Both directories exist in the repository, and digest-io is listed in the crate table, so it is published separately from the workspace members.

How does the RustCrypto utils workspace enforce its code style?

Through workspace lint tables in the root Cargo.toml. The clippy set includes undocumented_unsafe_blocks, unwrap_used, unwrap_in_result, missing_errors_doc, missing_panics_doc and a set of cast and pointer lints, and the rust set includes missing_docs, missing_copy_implementations, trivial_casts and unused_qualifications. The dev profile also sets opt-level = 2.

Official sources

  1. Issues
  2. README
  3. RustCrypto/utils on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rustcrypto-utils.svg)](https://hysenlabs.com/projects/rustcrypto-utils)

Was this useful?