COOLJAPAN
← All posts

OxiCrypto 0.3.0 Released — All 12 FIPS 205 SLH-DSA Parameter Sets, TLS 1.3 AEAD Negotiation, and a Bcrypt Panic-DoS Fixed

OxiCrypto 0.3.0 completes the FIPS 205 SLH-DSA parameter-set matrix (all 12 of 12), ships a new negotiate_aead TLS 1.3 cipher-suite resolver alongside negotiate_mac/negotiate_sig/negotiate_kex, adds coverage-guided fuzzing across AEAD/MAC/PQ/KDF, gives every sub-crate a runnable example, and fixes a byte/char-boundary panic-DoS in bcrypt verification — the sovereign Pure Rust cryptography layer for the COOLJAPAN ecosystem.

release oxicrypto pure-rust cooljapan noffi cryptography post-quantum tls fuzzing

FIPS 205 defines twelve SLH-DSA parameter sets. OxiCrypto shipped ten of them for two releases straight — the pinned slh-dsa dependency had the last two the whole time, nobody had wired them up.

Today we released OxiCrypto 0.3.0 — the release that closes that gap, completes the TLS 1.3 cipher-suite negotiation quartet with a new negotiate_aead, adds coverage-guided fuzzing across four previously-untested crates (and fixes a fifth that turned out not to even build), gives every sub-crate that lacked one a runnable example, and closes a panic-DoS in bcrypt hash verification.

No OpenSSL. No BoringSSL. No ring, no aws-lc-rs in the default closure. No FFI. No -sys crates. OxiCrypto 0.3.0 still compiles to a single static binary (or WASM) with zero apt-get install and no C toolchain — exactly as it has since 0.2.0.

Why OxiCrypto 0.3.0 is a game changer

Even a mature Pure Rust crypto stack accumulates quiet gaps once you look for them:

OxiCrypto 0.3.0 ends all of that.

Technical Deep Dive: parameter-set completion, the fourth negotiation leg, and a fuzz suite that builds

  1. SLH-DSA completion (oxicrypto-pq). The pinned slh-dsa 0.2.0-rc.5 dependency already implemented Shake192s/Shake192f; OxiCrypto’s own impl_slh_dsa_param! macro just hadn’t been pointed at them yet. Wiring them through gives every one of FIPS 205’s twelve (hash family × size × speed) combinations — SHA2/SHAKE, 128/192/256-bit, small/fast — a matching SlhDsa* type in the crate.
  2. negotiate_aeadoxicrypto-aead::tls. TlsCipherSuite covers the five TLS 1.3 suites, with from_iana_name/wire_code for parsing and serializing the wire identifier, and aead_name_for_suite as a pure naming helper. negotiate_aead maps Aes128GcmSha256/Aes256GcmSha384/Chacha20Poly1305Sha256/Aes128CcmSha256 to their AEAD implementations, and returns CryptoError::UnsupportedAlgorithm — not a silently wrong 16-byte-tag substitute — for Aes128Ccm8Sha256, whose 8-byte truncated tag this crate doesn’t yet implement. The module mirrors oxicrypto_mac::negotiate_mac, oxicrypto_sig::negotiate_sig, and oxicrypto_kex::negotiate_kex exactly, so a TLS 1.3 stack now resolves every leg of a cipher suite through the same pattern.
  3. The fuzz suite. fuzz_sealed_box_open_no_panic and fuzz_key_unwrap_no_panic (oxicrypto-aead) exercise open_box and the RFC 3394 aes{128,256}_key_unwrap. fuzz_hmac_truncated_no_panic (oxicrypto-mac) is a direct regression guard for the truncated-HMAC panics fixed back in 0.2.1. fuzz_pq_key_share_from_wire (oxicrypto-pq) round-trips PqKeyShare::from_wire/decode-re-encode. fuzz_bcrypt_verify_no_panic (oxicrypto-kdf) is a direct regression guard for the bcrypt fix below. Each fuzz/Cargo.toml carries its own [workspace] table — the exact thing oxicrypto-hash’s pre-existing fuzz crate was missing, which is why cargo metadata from inside it had been failing with “current package believes it’s in a workspace when it’s not.”
  4. The bcrypt fix and the PQ wire-format hardening. bcrypt_verify/parse_bcrypt_string/extract_hash_part previously validated only the byte length of a hash string before indexing into it as &str (&hash_part[..22] and similar). A multi-byte character straddling that offset panicked with Rust’s “byte index N is not a char boundary” instead of erroring. The fix, ensure_ascii_hash, is justified because bcrypt’s modular-crypt format and base64 alphabet are ASCII-only by definition — so rejecting non-ASCII input outright is correct, not merely defensive. Separately, PqKeyShare::to_wire used to compute its 2-byte wire length field as len as u16, which wraps silently for a payload over 65535 bytes; it’s now Result-returning and rejects that case with CryptoError::Encoding. No currently-defined PqGroup produces a payload anywhere near that size, but the encode helpers accept arbitrary caller-supplied byte slices, so the bound wasn’t guaranteed by the type system.

Getting Started

cargo add oxicrypto
[dependencies]
oxicrypto = "0.3.0"

# Post-quantum primitives (off by default):
oxicrypto = { version = "0.3.0", features = ["pq-preview"] }

Hashing:

use oxicrypto::{blake3, sha256, sha512};

let digest = sha256(b"hello world");
let digest = sha512(b"hello world");
let digest = blake3(b"hello world");

Resolving a TLS 1.3 cipher suite straight to an AEAD — the new part in 0.3.0:

use oxicrypto_aead::{negotiate_aead, TlsCipherSuite};

let aead = negotiate_aead(TlsCipherSuite::Aes256GcmSha384)?;
assert_eq!(aead.name(), "AES-256-GCM");
assert_eq!(aead.key_len(), 32);
assert_eq!(aead.nonce_len(), 12);
assert_eq!(aead.tag_len(), 16);

Every sub-crate now has a runnable, headline-API example:

cargo run -p oxicrypto-aead --example aead_basics
cargo run -p oxicrypto-sig --example sig_basics
cargo run -p oxicrypto-pq --example pq_basics --features pq-preview

What’s New in 0.3.0

Tips

This is the foundation

OxiCrypto depends on nothing — it’s the foundation layer the rest of the COOLJAPAN cryptography stack stands on. It is already depended on by:

Around it sit sibling Pure Rust projects removing their own native dependency from the floor of the ecosystem — OxiArc (compression, replacing zip/flate2/zstd), OxiBLAS, OxiFFT, and OxiZ (the Pure Rust SMT solver).

Repository: https://github.com/cool-japan/oxicrypto

Star the repo if you want a post-quantum signature portfolio with no gaps, a TLS 1.3 negotiation surface with no leg left unresolved, and cryptographic parsers that reject bad input instead of panicking on it.

The era of a “complete” crypto crate quietly missing two parameter sets nobody checked for is over. Pure Rust cryptography is here — complete, fuzzed, and sovereign.

KitaSan at COOLJAPAN OÜ August 6, 2026

↑ Back to all posts