Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
RustCrypto trait implementations backed by wolfCrypt.
This crate is #![no_std] (with alloc). It wraps wolfCrypt's C
implementations behind standard RustCrypto trait interfaces so they
can be used as drop-in backends in generic Rust crypto code.
What implements RustCrypto traits
| Module | Trait(s) implemented | Types |
|---|---|---|
[digest] |
Digest, Update, FixedOutput, Reset |
Sha256, Sha384, Sha512, … |
[hmac] |
Mac (via KeyInit + Update + FixedOutput + MacMarker) |
WolfHmacSha256, … |
[cmac] |
Mac |
WolfCmacAes128, WolfCmacAes256 |
[aead] |
AeadInPlace, KeyInit |
Aes128Gcm, Aes256Gcm, ChaCha20Poly1305 |
[cipher] |
BlockCipher, BlockEncrypt/Decrypt, StreamCipher, KeyInit/KeyIvInit |
AES-ECB/CTR/CBC/CFB, WolfChaCha20 |
[des3] |
BlockEncryptMut, BlockDecryptMut, KeyIvInit |
DesEde3CbcEnc, DesEde3CbcDec |
[poly1305] |
Mac |
WolfPoly1305 |
[ed25519] |
Signer, Verifier (using ed25519::Signature) |
Ed25519SigningKey, Ed25519VerifyingKey |
[ed448] |
Signer, Verifier |
Ed448SigningKey, Ed448VerifyingKey |
[ecdsa] |
Signer, Verifier |
EcdsaSigningKey<P256>, EcdsaVerifyingKey<P256>, … |
[rsa] |
Signer, Verifier |
RsaPrivateKey, RsaPublicKey |
[mldsa] |
Signer, Verifier |
MlDsa44SigningKey, MlDsa65SigningKey, …; MlDsaSignature<L> |
[rand] |
TryRng, TryCryptoRng (Rng + CryptoRng via blanket impl) |
WolfRng |
What uses a bespoke (non-trait) API
| Module | Why no trait | API shape |
|---|---|---|
[hkdf] |
The hkdf crate provides a concrete struct, not a trait |
new() / extract() / expand() — same method names as hkdf::Hkdf |
[pbkdf2] |
pbkdf2::pbkdf2_hmac requires CoreProxy; our EVP digests can't satisfy Sync |
pbkdf2_hmac_sha256(password, salt, rounds, &mut out) |
[keywrap] |
No RustCrypto trait exists for AES Key Wrap | aes_wrap_key() / aes_unwrap_key() |
[dh] |
No RustCrypto trait for classic DH | DhSecret::generate() / compute_shared_secret() |
[ecdh] |
No RustCrypto trait for raw ECDH | X25519StaticSecret, NistEcdhSecret<C>, etc. |
[mlkem] |
No RustCrypto trait for ML-KEM | MlKemDecapsulationKey / MlKemEncapsulationKey |
For HKDF and PBKDF2, our [digest] types are compatible with the standard
crates via hkdf::SimpleHkdf<Sha256> and hmac::SimpleHmac<Sha256>
respectively — see each module's docs for examples.
Panics vs Result in constructors
Several RustCrypto traits define infallible constructors that return Self
rather than Result<Self, _>:
digest::Digest::new(Default::default)cipher::KeyInit::newaead::KeyInit::new
Because these signatures leave no room for a Result, our implementations
assert! on the wolfCrypt return code and panic on failure. In practice
this means a panic only on OOM or a fundamental library-init failure — never
on user-supplied input of the correct length. Fallible alternatives
(new_from_slice, generate, from_seed, etc.) return Result wherever
the trait or our own API allows it.
Buffer size limit
wolfCrypt's C API uses u32 (or c_int) for buffer lengths. This crate
casts Rust usize lengths to u32 at each FFI boundary. On 64-bit
targets, buffers larger than 4 GB (u32::MAX) will panic rather than
silently truncate.
In practice, single-call buffers of 4 GB+ are extremely rare in cryptographic operations. If you need to process data of that size, feed it incrementally through the streaming / update APIs.
RustCrypto trait ecosystem gaps
Implementing the RustCrypto traits on top of a C FFI backend exposed several design limitations that pure-Rust implementations never hit. This section documents each gap and the workaround used in this crate, both as guidance for contributors and as a reference for anyone proposing upstream improvements.
1. Infallible constructors for fallible operations
KeyInit::new, Digest::new (via Default) return Self, not
Result. Any FFI backend can fail for reasons beyond the caller's
control — OOM in the C allocator, hardware device unavailable, library
not initialized. The trait gives no way to report this.
Workaround: We assert! on the wolfCrypt return code. In practice
this panics only on OOM or device-init failure, never on valid input.
Fallible alternatives (new_from_slice, generate, from_seed)
return Result wherever the trait allows.
2. No ZeroizeOnDrop bound on key types
KeyInit creates types holding secret key material, but the trait
doesn't require ZeroizeOnDrop or any cleanup guarantee. Each
implementor must remember to add it manually — an easy thing to miss.
Workaround: We manually implement Drop with zeroize calls on
every type that holds key material (AES key schedules, ChaCha20Poly1305
keys, HKDF PRKs, keywrap temporaries). The zeroize_aes_key helper
centralizes the pattern for opaque C structs.
3. AeadInPlace is the only AEAD trait
There is no Aead variant with separate input and output buffers.
wolfCrypt's one-shot ChaCha20-Poly1305 API (wc_ChaCha20Poly1305_Encrypt)
required separate buffers, which would have forced a heap allocation
per encrypt/decrypt call.
Workaround: We switched to wolfCrypt's streaming ChaCha20-Poly1305
API (wc_ChaCha20Poly1305_Init / UpdateData / Final), which
supports input == output pointers. This eliminated the allocation
entirely. A backend with no in-place path (e.g., a DMA-based hardware
accelerator) would have no such escape hatch.
4. No HKDF or PBKDF2 traits
The hkdf and pbkdf2 crates provide concrete implementations, not
traits. There is no way to supply an alternative backend through trait
implementation.
Workaround: Our HKDF module exposes a bespoke API with method names
matching hkdf::Hkdf (new, extract, expand). Our PBKDF2 module
exposes standalone functions matching pbkdf2::pbkdf2_hmac's signature.
For callers that need the actual hkdf or pbkdf2 crate types, our
digest types compose with hkdf::SimpleHkdf<Sha256> and
hmac::SimpleHmac<Sha256> — see each module's docs for examples.
5. The CoreProxy cliff
The digest crate has two tiers: high-level (Digest, Update,
FixedOutput) and low-level (CoreProxy, UpdateCore,
FixedOutputCore). Our EVP-based digests implement the high-level
tier, but pbkdf2::pbkdf2_hmac requires CoreProxy (low-level),
which opaque FFI wrappers cannot satisfy.
Workaround: Callers needing pbkdf2_hmac should use
hmac::SimpleHmac<Sha256> (which bridges from high-level digest to
low-level HMAC) or use our native pbkdf2_hmac_sha256 function, which
calls wolfCrypt's wc_PBKDF2 in a single FFI call.
6. pbkdf2::pbkdf2 requires Sync unconditionally
The function signature has PRF: Sync even when the parallel feature
is disabled. Our EVP-based digest types are !Sync (correctly —
EVP_MD_CTX has interior mutable state), so
pbkdf2::<SimpleHmac<Sha256>>(...) does not compile.
Workaround: Use our native pbkdf2_hmac_sha256 function instead.
This is a candidate for an upstream fix (the Sync bound should be
conditional on the parallel feature).
7. SignatureEncoding::Repr assumes fixed-size signatures
The trait works naturally for Ed25519 (Repr = [u8; 64]) but
post-quantum signatures are variable-length — ML-DSA-87 is 4627 bytes.
We use Repr = Box<[u8]>, which works but means the signature cannot
be stack-allocated and loses compile-time size guarantees.
Workaround: Accepted as-is. As PQC becomes standard across the RustCrypto ecosystem, this will likely be revisited upstream.
8. Interior mutability for FFI verification calls
wolfCrypt's C API requires *mut pointers even for logically read-only
operations like signature verification and public-key export. The
RustCrypto Verifier::verify trait takes &self, so we cannot pass
&mut self to the FFI.
Workaround: Signing and verifying key types wrap their C key handle
in UnsafeCell (see ed25519.rs, ed448.rs, ecdsa.rs, rsa.rs,
mldsa.rs, lms.rs, aead.rs, cipher/ccm.rs). This lets us
obtain *mut from &self for FFI calls. UnsafeCell also makes the
type !Sync, which is correct — wolfCrypt key handles are not
thread-safe. Each UnsafeCell usage has a SAFETY comment at the call
site explaining why single-threaded access is guaranteed.
Testing
This crate's in-tree tests (tests/) cover only functionality that has
no pure-Rust counterpart for cross-validation: classic DH, NIST-curve
ECDH, and RSA encryption.
The bulk of correctness testing lives in the wolfcrypt-conformance
crate (a sibling workspace member). That suite cross-validates every
algorithm against pure-Rust RustCrypto implementations, NIST CAVP/SHAVS
vectors, Wycheproof edge-case vectors, and RFC known-answer tests.
Always run the conformance suite after modifying this crate: