[package] name = "libsoliton" version.workspace = true edition.workspace = true rust-version.workspace = true license.workspace = true repository.workspace = true homepage.workspace = true authors.workspace = true description = "Core cryptographic library for the LO protocol — hybrid post-quantum key exchange, signatures, ratchet, and storage encryption" categories = ["cryptography"] keywords = ["post-quantum", "x-wing", "ed25519", "double-ratchet", "ml-kem"] [lib] name = "soliton" # All dependencies are exact-pinned (=x.y.z) for supply-chain attack prevention # and reproducible builds. Cargo.lock alone is insufficient — it can be # regenerated, losing the pin. Exact versions here are the source of truth. # # RC dependencies: sha3, hmac, hkdf (0.11/0.13-rc), kem (0.3.0-pre), # ml-dsa (0.1.0-rc). These are the RustCrypto PQ ecosystem — stable releases # are pending upstream FIPS 203/204 finalization. Exact pins prevent silent # updates; track https://github.com/RustCrypto for stable releases. # # sha3 0.10.x has no `zeroize` feature — the feature was added in 0.11.x rc. # Since HMAC and HKDF use Sha3_256 as a keyed state (containing key material), # we must use sha3 0.11.x rc to get ZeroizeOnDrop on the hash state. # # Transitive dep pins (not imported directly): # # keccak 0.2.0 (2026-03-16) removed the `p1600` function in favor of a new # `Keccak` struct API. sha3 0.11.0-rc.7 still calls `keccak::p1600` and # fails to compile against keccak 0.2.0. Pin to the last version with the # old API. Remove once sha3 publishes an rc compatible with keccak 0.2.0. # # digest 0.11.2 (2026-03-13) and crypto-common 0.2.1 (2026-02-25) removed # `BlockSizes` (re-exported as `digest::common::BlockSizes`); digest 0.11.2 # also changed `Clone` handling in `(Reset)MacTraits`. sha3 0.11.0-rc.7 # imports `BlockSizes`; hmac/hkdf 0.13.0-rc.5 require `Hmac: Clone`. # Pin to the snapshot versions published on the same day as sha3/hmac/hkdf rc. # Remove once sha3/hmac/hkdf publish versions compatible with the new APIs. [dependencies] zeroize = { workspace = true } thiserror = { workspace = true } ruzstd = "=0.8.2" sha3 = { version = "=0.11.0-rc.7", features = ["zeroize"] } hmac = { version = "=0.13.0-rc.5", features = ["zeroize"] } hkdf = "=0.13.0-rc.5" keccak = "=0.2.0-rc.2" digest = "=0.11.0-rc.11" crypto-common = "=0.2.0-rc.15" chacha20poly1305 = { workspace = true } # chacha20poly1305 propagates chacha20/zeroize but NOT poly1305/zeroize. # This explicit dependency activates zeroization of the Poly1305 r,s key # pair and accumulator state after each AEAD operation. poly1305 = { workspace = true } argon2 = { version = "=0.5.3", features = ["zeroize"] } # No explicit backend selected: auto-detection picks fiat_u64_backend (formally # verified constant-time field arithmetic) on 64-bit stable, fiat_u32_backend on # 32-bit, simd on nightly x86_64 with AVX2. All backends are constant-time. curve25519-dalek = { version = "=4.1.3", features = ["zeroize"] } subtle = { workspace = true } # Three getrandom versions in the dep tree: 0.2 (multiple transitive), 0.3 (direct), # 0.4 (tempfile transitive). All use the same OS syscall; the duplication is # unavoidable until upstream crates align on a single version. getrandom = "=0.3.4" # Pinned to 2.2.0: 2.2.1 pulls newer digest transitive deps that break zeroize # feature propagation through ml-kem/ml-dsa. Do not bump without verifying the # full zeroize feature chain across the dependency tree. ed25519-dalek = { version = "=2.2.0", default-features = false, features = ["zeroize", "std"] } # ml-kem/ml-dsa depend on rc digest/sha3/signature stacks (0.11.x/0.11.x/3.x) # while ed25519-dalek/chacha20poly1305 use stable stacks (0.10.x/0.10.x/2.x). # This causes ~15 duplicate crate pairs (digest, sha2, sha3, block-buffer, # crypto-common, hybrid-array, signature, etc). Unavoidable until ml-kem/ml-dsa # publish against the stable digest stack. Does not affect correctness — the two # stacks are isolated at the type level and never share state. ml-kem = { version = "=0.2.3", features = ["zeroize", "deterministic"] } kem = "=0.3.0-pre.0" ml-dsa = { version = "=0.1.0-rc.7", features = ["zeroize"] } # rand_core is pulled transitively by ml-kem (0.6) and ml-dsa (0.10). # Deterministic/seed-based APIs + getrandom are used to avoid RNG trait issues. [target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies] getrandom = { version = "=0.3.4", features = ["wasm_js"] } # ml-kem → rand_core 0.6 → getrandom 0.2.17. On wasm32-unknown-unknown, # getrandom 0.2 without the `js` feature produces a compile_error!. This # dependency exists solely to activate the feature — soliton never imports # getrandom_02 directly. Cargo unifies features by package name (not alias). getrandom_02 = { package = "getrandom", version = "=0.2.17", features = ["js"] } [features] # Enables internal accessors for white-box integration testing only. # Not part of the public API — never enable in production. test-utils = [] [dev-dependencies] # Self-reference with test-utils so integration tests can call test-only accessors # (e.g. RatchetState::root_key_bytes). Has no effect on normal library builds. libsoliton = { path = ".", features = ["test-utils"] } hex-literal = "=1.1.0" hex = "=0.4.3" proptest = "=1.10.0" # Used exclusively in the parallel streaming benchmark (stream_encrypt_*mib_parallel). # Provides a pre-warmed thread pool so b.iter() measures encryption throughput, # not thread spawn cost. Dev-only — never compiled into the library. rayon = "=1.11.0" # ml-dsa is a direct dependency, re-declared here so integration tests can call # sign_internal directly to produce deterministic F.27 test vectors (pinned rnd). ml-dsa = { version = "=0.1.0-rc.7", features = ["zeroize"] } [[bench]] name = "bench" harness = true [build-dependencies] # sha2 0.10 (stable) for build-time wordlist hash verification only. # Build scripts run on the host and don't link into the final binary. sha2 = "=0.10.9"