Repository navigation
dryoc v2.0.0
dryoc 2.0 is a backward-incompatible major release. It adds post-quantum key encapsulation (ML-KEM-768, X-Wing) and post-quantum sealed boxes, Python bindings on PyPI, no_std support with std/alloc features, in-crate cryptographic primitives with runtime-detected SIMD backends (plus WebAssembly simd128 kernels), and a more consistent Rust API. serde is now enabled by default.
The wire formats did not change: boxes, AEAD envelopes, signed messages, secret streams, password-hash strings, and serde and wincode encodings written by 1.x read the same in 2.0, and 2.0 writes the same bytes. The minimum supported Rust version is still 1.89.
Full Changelog: v1.0.0...v2.0.0
Upgrading: nearly every breaking change is a compile error. Bump the version, build, and look each error up in UPGRADING.md. A short list of changes that still compile is repeated below.
Breaking Changes
Cargo features
serdeis now a default feature; remove it fromfeatures.wincodeis renamed towincode_0_6and moves to wincode 0.6. The encoded bytes are unchanged.u64_backendis removed; it did nothing.- The crate is
#![no_std]with newstd(default, impliesalloc) andallocfeatures.default-features = falsenow builds without allocation; addstd(orallocon targets withoutstd) to keep 1.x behavior. Withoutalloc,Vec*types,*_to_vec/*_to_vecbox,randombytes_buf,pwhashandclassic::crypto_pwhashare unavailable.Error::Ioneedsstd. Withoutstd, SIMD kernels are selected at compile time from target features instead of detected at runtime, and bare-metal targets need a customgetrandombackend. nightlyno longer enablesprotected; add it explicitly when needed.
API cleanup
gen/r#gennames are removed (generate);*_with_defaultsconstructors are replaced byStack*type aliases withgenerate().KeyPair::new(),SigningKeyPair::new(), theirDefaultimpls andnew_locked_keypair()(all-zero secret keys) are removed.ByteArray<N>/MutByteArray<N>(andNewByteArray) are no longer implemented for&[u8],[u8]orVec<u8>; convert runtime-length bytes withTryFromand handleError::InvalidLength.DryocBox::unseal/unseal_to_vecbecomeopen/open_to_vec;DryocBox::from_parts/into_partsswitch to wire order(epk, tag, data); redundantnew_with_*/with_*box constructors are replaced byfrom_parts/from_bytes;AeadEnvelope::seal_to_vecbecomesseal_to_vecbox;SigningKeyPair::signreturnsSignedMessageinfallibly;IncrementalSigneris renamedEd25519phSignerwith infalliblefinalize;Hmac/Auth/OnetimeAuthborrow the key; secret-streamTagbecomes a#[non_exhaustive]enum (Message/Push/Rekey/Final,try_from,&[u8]associated data,pull::<Out, _>order); KX moves tokx::StackSession::new_client/new_server; HKDFextract/expandargument order changes;GenericHash/PwHashdefault constructors are replaced byDefaultGenericHash/VecPwHash/Config::interactive(); output-first generic parameter order everywhere (Auth::compute::<Mac, _, _>,Sha256::compute::<Out, _>,push::<Out, _>, ...); several traits are now sealed (HmacVariant,HkdfVariant,Mode,ProtectMode,LockMode).- Classic
crypto_secretbox_open_detached,crypto_box_open_detachedandcrypto_box_open_detached_afternmtake ciphertext before MAC, like libsodium. - Algorithm modules no longer re-export
dryoc::types; importdryoc::types::*where glob imports previously supplied the traits.
Changes that still compile
Check by hand; the compiler will not flag these. See UPGRADING.md for details.
- Detached open with a 16-byte ciphertext: an old-order call compiles but fails authentication at runtime.
crypto_generichash/GenericHashaccept libsodium's full ranges (1-64 byte output, 0-64 byte key);Some(&[])now means no key.- Protected-memory deserialization returns an error on allocation/locking failure instead of panicking.
- New
#[must_use]on constructors, digests and MACs warns under-D warnings. - CPU detection without
stdis compile-time (see above).
Highlights
- Post-quantum: ML-KEM-768 and X-Wing KEMs (Classic + Rustaceous), SHAKE and TurboSHAKE XOFs, and HPKE/X-Wing sealed boxes with an approved, documented format and profile.
- Python: PyO3
abi3bindings shipped asdryocon PyPI (manylinux, musllinux, macOS, Windows wheels, free-threaded builds, sdist), with stub docs and a PyNaCl-oracle test suite. - Performance: in-crate primitives with runtime-detected SIMD (AVX2/AVX-512, NEON/SVE2, SHA2/SHA3 extensions) entered through CPU feature tokens, faster AArch64 kernels across ML-KEM, X25519/Ed25519, AEADs, Keccak and Argon2, WASM
simd128backends, and refreshed Xeon 6975P-C benchmarks against libsodium 1.0.22. no_std+alloc/stdsplit withgetrandomdirectly (theranddependency is gone);serdeon by default;protectedhardened (serde, soundness) and decoupled fromnightly.- Security hardening: kernel secret-residue wiping sweeps at every opt level, wiped verify/box/kx/signing-key paths, full-range generichash lengths, Argon2 limits and secret handling, low-order key rejection paths kept intact.
- Docs: new
UPGRADING.md(1.x -> 2.0) andCOMPATIBILITY.md, streamlined README and crate docs, unsafe-code inventory on its own rustdoc page, sealed-box format approval record, kernel wiping policy. - Tooling:
release.pytags releases and bumps versions with lockfile refresh; nextest suites, focused Miri checks, fuzz smoke runs, SemVer checks, and faster/slimmer CI jobs.
Pull Requests
Features
- In-crate crypto primitives with runtime-detected SIMD backends (#152)
- SHAKE and TurboSHAKE extendable-output functions (#160)
- ML-KEM-768 and X-Wing key encapsulation (#161)
- Post-quantum sealed boxes with HPKE and X-Wing (#163)
no_stdsupport with std and alloc features (#178)- WASM simd128 backends (#186)
- Enable serde by default (#189)
- PyO3 bindings and PyPI release workflow (#191)
- Release.py helper for tagging releases (#193)
Breaking API cleanup
- Shared helpers, deduplicated impls, and removal of deprecated gen aliases (2.0.0) (#153)
- Remove unused u64_backend feature (#172)
- Remove all-zero keypair constructors and Default impls (#174)
- Rename wincode feature to wincode_0_6 (#175)
- Restrict ByteArray to fixed-size storage (#176)
- Rename box open verbs and drop redundant box constructors (#201)
- Match libsodium argument order in classic detached open (#203)
- Make fallibility, input bounds and MAC key passing consistent (#204)
- Simplify serde derives and protection modes (#200)
- Generate every Vec box schema from one macro (#207)
Security and correctness
- Serialize the fixed-size views of box fields (#167)
- Stream-kernel wiping per the kernel wiping policy (#168)
- Wipe Poly1305 hot-loop copies and document kernel wiping scope (#169)
- Harden serde deserialization and protected-memory soundness (#180)
- Wipe secret residue in verify, box, kx and signing-key paths (#181)
- Accept libsodium's full output and key length ranges in generichash (#182)
- Address Argon2 limits and secret handling in pwhash (#183)
- Wipe kernel secret residue and require avx2 with avx512f (#184)
- Enter target-feature kernels through CPU feature tokens (#185)
- Keep kernel secrets out of helpers outlined at any opt-level (full sweep) (#188)
- Copy bytearray inputs under their critical section (Python) (#192)
- Correct the simd128 kernels' wiping notes (#209)
- Use getrandom directly and drop rand (#179)
- Safe StackByteArray views; sealed-box doc follow-ups (#177)
- Build with nightly after allocator_api stabilization (#165)
Performance
- Faster AArch64 kernels across ML-KEM, X25519/Ed25519, AEADs, Keccak and Argon2 (#194)
- Refresh Xeon 6975P-C numbers against libsodium 1.0.22 (#195)
Tests
- Expand known-answer coverage and differential fuzzing (#154)
- Check native compatibility against libsodium 1.0.22 (#162)
- Wasm known answers and serde coverage for XOF, KEM and sealed boxes (#170)
- Secretstream limits and broader fuzz coverage (#171)
- Route libsodium oracle calls through native_test_util (#202)
- Share ChaCha20/Salsa20 kernel test helpers (#205)
- Share Edwards fixtures, KAT parser, BLAKE2b loader and hex helpers (#214)
Documentation
- Reword module and crate documentation (#156)
- Nightly toolchain floor and kernel wiping policy (#166)
- Record sealed-box format approval and HPKE profile (#173)
- Tighten README, lib.rs, and BENCHMARKS prose (#196)
- Gate alloc-only examples so doctests pass without alloc (#211)
- Move the unsafe code inventory to its own rustdoc page (#216)
- Shorten README unsafe code footnote to a link to the inventory (#217)
- Streamline README and crate-level docs (#218)
- Document every public API member in the .pyi stubs (#220)
- Tone down README marketing copy to sentence case (#223)
- Move dryoc-vs-libsodium differences to COMPATIBILITY.md (#224)
- Add UPGRADING.md for moving from dryoc 1.x to 2.0 (#225)
CI and maintenance
- Bump version (#149)
- Use nextest for test suites (#150)
- Bump deps (#155)
- Replace Rust caching with mr boxington (#157)
- Fuzz smoke run, kebab-case fuzz targets, all-jobs-pass gate (#158)
- Add focused Miri memory-safety checks (#159)
- Enable serde by default (#189)
- Speed up wasm32 test jobs (#190)
- Add --bump major|minor|patch to release.py (#197)
- Dedupe nextest setup and Python helpers (#198)
- Lint and type-check all Python code with ruff and ty (#199)
- Publish musllinux wheels and fix the PyPI summary (#219)
- Cut redundant jobs and speed up the slowest tests (#221)
- Run fuzz targets in parallel, build CI test wheels without LTO (#222)