From 8020fb671142dec136d17023a219b382f2d889dc Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Thu, 13 Aug 2026 13:36:01 +0200 Subject: [PATCH 1/7] chore(deps): x509-parser 0.16 -> 0.18, and thiserror 1.0 leaves the host graph MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit x509-parser 0.16 pinned the old asn1-rs 0.6 / der-parser 9 / oid-registry 0.7 chain, and every one of those still depended on thiserror 1.0. It was the ONLY thing doing so — so the host compiled two thiserror majors (and two thiserror-impl proc macros) for one crate's error types. 0.18 moves the chain to asn1-rs 0.7 + thiserror 2, which is the same major the rest of the tree already uses, and the 1.0 half disappears — for the host, on every target and including dev-dependencies: $ cargo tree -p punktfunk-host --target all -e normal,build,dev -i thiserror@1 error: package ID specification `thiserror@1` did not match any packages Scope that claim honestly: this clears the HOST graph, not the workspace. thiserror 1.0 is still built, reached by `jni` 0.21 AND by the vendored `ndk` 0.9.0, both under punktfunk-client-android. That is a different graph and a different bump. No source change was needed. The one API shift that could have reached us — asn1-rs 0.7 making `BitString::data` a `Cow<[u8]>` instead of a `&[u8]` — lands on `x509.signature_value.data.to_vec()` in gamestream/cert.rs and gamestream/pairing.rs, and `to_vec()` goes through Deref either way. Both are Moonlight pairing-hash inputs, so they are covered by the gamestream::cert tests rather than taken on faith. nom 7 and nom 8 were already both in the lock; this adds no new duplicate. Verified on CachyOS (rustc 1.96.0): cargo clippy -p punktfunk-host --locked --all-targets -- -D warnings OK cargo clippy -p punktfunk-host --locked -- -D warnings OK (shipping build: no --all-targets) cargo clippy -p punktfunk-host --no-default-features --features pyrowave --all-targets --locked -- -D warnings OK cargo test -p punktfunk-host --bins --locked 501 passed, 0 failed, 2 ignored cargo test ... gamestream::cert 3 passed cargo tree -i ring nothing to print --- Cargo.lock | 24 ++++++++++++------------ crates/punktfunk-host/Cargo.toml | 6 +++++- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba9a7be0..cc323c18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "asn1-rs" -version = "0.6.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -177,15 +177,15 @@ dependencies = [ "nom 7.1.3", "num-traits", "rusticata-macros", - "thiserror 1.0.69", + "thiserror 2.0.20", "time", ] [[package]] name = "asn1-rs-derive" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", @@ -1132,9 +1132,9 @@ dependencies = [ [[package]] name = "der-parser" -version = "9.0.0" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" dependencies = [ "asn1-rs", "displaydoc", @@ -2800,9 +2800,9 @@ dependencies = [ [[package]] name = "oid-registry" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" dependencies = [ "asn1-rs", ] @@ -6227,9 +6227,9 @@ checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" [[package]] name = "x509-parser" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" dependencies = [ "asn1-rs", "data-encoding", @@ -6238,7 +6238,7 @@ dependencies = [ "nom 7.1.3", "oid-registry", "rusticata-macros", - "thiserror 1.0.69", + "thiserror 2.0.20", "time", ] diff --git a/crates/punktfunk-host/Cargo.toml b/crates/punktfunk-host/Cargo.toml index 7294ce7f..a72f6ed9 100644 --- a/crates/punktfunk-host/Cargo.toml +++ b/crates/punktfunk-host/Cargo.toml @@ -100,7 +100,11 @@ ureq = { version = "3", default-features = false, features = [ "gzip", ] } rcgen = { version = "0.13", default-features = false, features = ["aws_lc_rs", "pem"] } -x509-parser = "0.16" +# ⚠ Do not float this back below 0.18. 0.16 was the LAST crate pulling `thiserror` 1.0 into the +# host graph (via asn1-rs 0.6 / der-parser 9 / oid-registry 0.7); 0.18 moves that chain to asn1-rs +# 0.7 + thiserror 2, so the host now links exactly one thiserror major. `cargo tree -p +# punktfunk-host -i thiserror@1` must keep reporting no match. +x509-parser = "0.18" # Only used for the plain-HTTP nvhttp listener (`bind().serve()`); HTTPS/mTLS is hand-rolled over # tokio-rustls (axum-server can't surface the peer cert), so we do NOT enable `tls-rustls` — that # feature is what pulled the unmaintained `rustls-pemfile` (security-review dep hygiene). From 4358261387b29091ed7d2e5169fc30796f062275 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Thu, 13 Aug 2026 13:40:02 +0200 Subject: [PATCH 2/7] chore(deps): rand 0.8 -> 0.9 in the host, the last crate speaking the old major MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit punktfunk-core and pf-client-core were already on 0.9; the host sat on 0.8 by drift, not by decision, so every build compiled two rand majors to satisfy six call sites. Mechanical at five of them (`thread_rng()` -> `rng()`, `gen_range` -> `random_range`); the sixth is the interesting one. `RsaPrivateKey::new` is bounded on rand_core **0.6**'s `CryptoRngCore`. rand 0.9's `ThreadRng` implements rand_core 0.9's traits — same names, different crate — so the RSA-2048 keygen in gamestream/cert.rs stopped satisfying the bound the moment the version moved. It now draws from `rsa::rand_core::OsRng`: rsa's own re-export, which is by construction the traits rsa compiled against, so the two rand_core majors never have to meet in our source. That needs `features = ["getrandom"]` on rsa (not one of its defaults) — and it must be declared HERE rather than left to feature unification, because dropping our own rand 0.8 also dropped the `std` feature that used to switch `rand_core/getrandom` on as a side effect. What this does and does not clear. The GAMESTREAM host keeps rand 0.8 + rand_chacha 0.3 — `rsa` drags them in through `num-bigint-dig`, which is not ours to move: $ cargo tree -i rand@0.8.7 rand v0.8.7 └── num-bigint-dig v0.8.6 └── rsa v0.9.10 └── punktfunk-host The NATIVE-ONLY host (--no-default-features, no rsa) now sheds both entirely — `cargo tree -p punktfunk-host --no-default-features --features pyrowave -i rand@0.8.7` and the same for rand_chacha@0.3.1 both report no match. rand_core 0.6 stays in every flavour regardless: `crypto-common` (under aes-gcm) needs it, which no rand bump can change. `windows/install.rs`'s `random_password` is the one site a Linux box cannot type-check; the edit there is the identical `thread_rng()` -> `rng()` the five compiled sites took. Verified on CachyOS (rustc 1.96.0): cargo clippy -p punktfunk-host --locked --all-targets -- -D warnings OK cargo clippy -p punktfunk-host --locked -- -D warnings OK (shipping build: no --all-targets) cargo clippy -p punktfunk-host --no-default-features --features pyrowave --all-targets --locked -- -D warnings OK cargo test -p punktfunk-host --bins --locked 501 passed, 0 failed, 2 ignored cargo test ... gamestream::cert 3 passed (incl. the fresh-install RSA-2048 keygen) cargo fmt --all --check clean --- Cargo.lock | 3 +-- crates/punktfunk-host/Cargo.toml | 14 ++++++++++++-- crates/punktfunk-host/src/gamestream/cert.rs | 10 ++++++++-- crates/punktfunk-host/src/gamestream/crypto.rs | 2 +- crates/punktfunk-host/src/mgmt_token.rs | 2 +- crates/punktfunk-host/src/native/handshake.rs | 6 +++--- crates/punktfunk-host/src/native_pairing/arming.rs | 2 +- crates/punktfunk-host/src/send_pacing.rs | 4 ++-- crates/punktfunk-host/src/windows/install.rs | 2 +- 9 files changed, 30 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc323c18..8671c2d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3645,7 +3645,7 @@ dependencies = [ "pipewire", "punktfunk-core", "quinn", - "rand 0.8.7", + "rand 0.9.5", "rcgen", "roxmltree", "rsa", @@ -3821,7 +3821,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" dependencies = [ - "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", ] diff --git a/crates/punktfunk-host/Cargo.toml b/crates/punktfunk-host/Cargo.toml index a72f6ed9..9bcb1882 100644 --- a/crates/punktfunk-host/Cargo.toml +++ b/crates/punktfunk-host/Cargo.toml @@ -78,12 +78,22 @@ tokio = { version = "1", features = ["full"] } # pairing signer (cert.rs, pairing.rs) and the legacy-client-cert leniency verifier (tls.rs). # The native planes use the P-256 identity (src/identity.rs) and never touch this crate — so a # native-only build also sheds the accepted Marvin advisory (RUSTSEC-2023-0071, .cargo/audit.toml). -rsa = { version = "0.9", optional = true } +# `getrandom` is NOT one of rsa's defaults; we ask for it because `RsaPrivateKey::new` wants an +# rng implementing rand_core **0.6**'s traits, and since our own `rand` moved to 0.9 no rng we +# hold satisfies that bound any more. The feature exposes `rsa::rand_core::OsRng`, which does — +# see the keygen in gamestream/cert.rs. Getting it from rsa's own re-export is what keeps the two +# rand_core majors from being something this crate has to name. +rsa = { version = "0.9", optional = true, features = ["getrandom"] } sha2 = { version = "0.10", features = ["oid"] } aes = "0.8" aes-gcm = "0.10" cbc = { version = "0.1", features = ["alloc"] } -rand = "0.8" +# 0.9, matching punktfunk-core and pf-client-core — the host was the last 0.8 holdout, and that +# was drift, not a pin. NOTE this does NOT take rand 0.8 out of the gamestream build: `rsa` pulls +# it transitively through `num-bigint-dig`, so 0.8 only disappears from the native-only host +# (`--no-default-features`, where `rsa` is absent). What it does buy everywhere is that OUR calls +# all speak one rand major. +rand = "0.9" hex = "0.4" # Cover-art delivery in the game library: encode Lutris's local JPEGs into `data:` URLs and decode # the Epic launcher's base64 `catcache.bin`. Cross-platform (Linux Lutris art + Windows Epic art). diff --git a/crates/punktfunk-host/src/gamestream/cert.rs b/crates/punktfunk-host/src/gamestream/cert.rs index 5b506db5..8251a345 100644 --- a/crates/punktfunk-host/src/gamestream/cert.rs +++ b/crates/punktfunk-host/src/gamestream/cert.rs @@ -86,8 +86,14 @@ fn generate() -> Result<(String, String)> { // // This path runs ONLY when no cert exists yet — a fresh install — so an upgraded box never // re-executes it. - let mut rng = rand::thread_rng(); - let priv_key = RsaPrivateKey::new(&mut rng, 2048).context("generate RSA-2048 host key")?; + // + // The rng comes from `rsa`'s OWN rand_core re-export, not from our `rand`. `RsaPrivateKey::new` + // is bounded on rand_core **0.6**'s `CryptoRngCore`, and since the host moved to rand 0.9 its + // `ThreadRng` implements rand_core 0.9's traits instead — a different trait of the same name, + // so it no longer satisfies the bound. `rsa::rand_core::OsRng` is the OS CSPRNG under the + // exact traits `rsa` compiled against, which keeps the two rand_core majors from meeting. + let priv_key = RsaPrivateKey::new(&mut rsa::rand_core::OsRng, 2048) + .context("generate RSA-2048 host key")?; let key_pem = priv_key .to_pkcs8_pem(LineEnding::LF) .context("encode host key as PKCS#8 PEM")? diff --git a/crates/punktfunk-host/src/gamestream/crypto.rs b/crates/punktfunk-host/src/gamestream/crypto.rs index 53d1a589..4e0a9cb7 100644 --- a/crates/punktfunk-host/src/gamestream/crypto.rs +++ b/crates/punktfunk-host/src/gamestream/crypto.rs @@ -12,7 +12,7 @@ use sha2::{Digest, Sha256}; /// `n` cryptographically-random bytes. pub fn random() -> [u8; N] { let mut b = [0u8; N]; - rand::thread_rng().fill_bytes(&mut b); + rand::rng().fill_bytes(&mut b); b } diff --git a/crates/punktfunk-host/src/mgmt_token.rs b/crates/punktfunk-host/src/mgmt_token.rs index ee1c6435..fdf2b098 100644 --- a/crates/punktfunk-host/src/mgmt_token.rs +++ b/crates/punktfunk-host/src/mgmt_token.rs @@ -59,7 +59,7 @@ fn load_or_generate_impl(env_var: &str, file: &str) -> Result { } } let mut buf = [0u8; 32]; - rand::thread_rng().fill_bytes(&mut buf); + rand::rng().fill_bytes(&mut buf); let token = hex::encode(buf); write_token(&path, env_var, &token)?; tracing::info!(path = %path.display(), "generated and persisted API token (owner-only)"); diff --git a/crates/punktfunk-host/src/native/handshake.rs b/crates/punktfunk-host/src/native/handshake.rs index 60afb95b..afb53a78 100644 --- a/crates/punktfunk-host/src/native/handshake.rs +++ b/crates/punktfunk-host/src/native/handshake.rs @@ -502,14 +502,14 @@ pub(super) async fn negotiate( let shard_payload = wire_mtu::negotiated_shard_payload(conn, hello.max_shard_payload).await; let mut key = [0u8; 16]; - rand::thread_rng().fill_bytes(&mut key); + rand::rng().fill_bytes(&mut key); // Fresh per-session salt alongside the fresh key. GCM nonce uniqueness only *requires* one // of the two to be unique per session (the nonce is salt || sequence under the session // key), but a constant salt would make a key-reuse bug catastrophic instead of merely // wrong — this keeps the second line of defense real. Negotiated via Welcome, so clients // just follow. let mut salt = [0u8; 4]; - rand::thread_rng().fill_bytes(&mut salt); + rand::rng().fill_bytes(&mut salt); // Session AEAD: ChaCha20-Poly1305 when the client asked for it (VIDEO_CAP_CHACHA20 — the // soft-AES armv7 targets, whose GCM decrypt caps at ~100 Mbps) and the operator // kill-switch allows (PUNKTFUNK_CHACHA20, default on — pure rollout safety; perf-only, @@ -520,7 +520,7 @@ pub(super) async fn negotiate( let chacha = client_wants_chacha && pf_host_config::config().chacha20; let key_chacha = chacha.then(|| { let mut k = [0u8; 32]; - rand::thread_rng().fill_bytes(&mut k); + rand::rng().fill_bytes(&mut k); k }); tracing::info!( diff --git a/crates/punktfunk-host/src/native_pairing/arming.rs b/crates/punktfunk-host/src/native_pairing/arming.rs index 8230bc9a..c628b099 100644 --- a/crates/punktfunk-host/src/native_pairing/arming.rs +++ b/crates/punktfunk-host/src/native_pairing/arming.rs @@ -35,7 +35,7 @@ pub enum PinAttempt { fn random_pin() -> String { use rand::Rng; - format!("{:04}", rand::thread_rng().gen_range(0..10_000u32)) + format!("{:04}", rand::rng().random_range(0..10_000u32)) } /// A snapshot of the arming window for the management API: `(armed, pin, expires_in_secs)`. diff --git a/crates/punktfunk-host/src/send_pacing.rs b/crates/punktfunk-host/src/send_pacing.rs index ae205e54..68e4b0c6 100644 --- a/crates/punktfunk-host/src/send_pacing.rs +++ b/crates/punktfunk-host/src/send_pacing.rs @@ -288,9 +288,9 @@ pub(crate) fn inject_video_drop(packets: &mut Vec) -> u64 { return 0; } use rand::Rng; - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let before = packets.len(); - packets.retain(|_| rng.gen_range(0..100) >= pct); + packets.retain(|_| rng.random_range(0..100) >= pct); (before - packets.len()) as u64 } diff --git a/crates/punktfunk-host/src/windows/install.rs b/crates/punktfunk-host/src/windows/install.rs index 931b9976..ab16acb7 100644 --- a/crates/punktfunk-host/src/windows/install.rs +++ b/crates/punktfunk-host/src/windows/install.rs @@ -801,7 +801,7 @@ fn random_password() -> String { use base64::Engine; use rand::RngCore; let mut b = [0u8; 24]; - rand::thread_rng().fill_bytes(&mut b); + rand::rng().fill_bytes(&mut b); base64::engine::general_purpose::STANDARD .encode(b) .chars() From 677b8ceb412ae5dd24fa7712acc452587da25b6a Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Thu, 13 Aug 2026 13:42:53 +0200 Subject: [PATCH 3/7] chore(deps): base64 0.22 -> 0.23 in the host and pf-update-check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ureq 3 already pulls 0.23, so the tree compiled both minors purely because our two direct declarations named the older one. The API we use — `Engine`, `engine::general_purpose::STANDARD`, `encode`/`decode` — is unchanged in 0.23; no source edits. Both are declared `default-features = false, features = ["std"]` rather than taking the defaults. 0.23 added `simd-unsafe` (hand-written AVX2/NEON engines) as a DEFAULT-ON feature, and ureq declares base64 with default features off, so today that code is not in the tree. Accepting the defaults here would unify the feature on and quietly add an unsafe SIMD engine to every artifact as a side effect of a currency bump. Whether to enable it is a perf question deserving a measurement and its own commit; this one changes versions, not exposure. `std` covers every call site (encode to `String`, decode to `Vec`). base64 0.22 does NOT leave the tree: `rcgen` -> `pem` 3.0.6 is now its sole remaining consumer, and it stays one after the rcgen 0.14 bump later in this batch — 0.14 still depends on `pem` "3.0.2", which resolves to the same 3.0.6, which still uses base64 0.22. Clearing that last copy is upstream's move (a `pem` release on 0.23), not ours. Verified on CachyOS (rustc 1.96.0): cargo clippy -p punktfunk-host -p pf-update-check --locked --all-targets -- -D warnings OK cargo clippy -p punktfunk-host -p pf-update-check --locked -- -D warnings OK (shipping build) cargo test -p punktfunk-host --bins --locked 501 passed, 0 failed, 2 ignored cargo test -p pf-update-check --locked 32 passed, 0 failed cargo fmt --all --check clean --- Cargo.lock | 4 ++-- crates/pf-update-check/Cargo.toml | 4 +++- crates/punktfunk-host/Cargo.toml | 8 +++++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8671c2d4..cb8c3293 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3201,7 +3201,7 @@ version = "0.27.0" dependencies = [ "anyhow", "aws-lc-rs", - "base64 0.22.1", + "base64 0.23.1", "serde", "serde_json", "ureq", @@ -3614,7 +3614,7 @@ dependencies = [ "aws-lc-rs", "axum", "axum-server", - "base64 0.22.1", + "base64 0.23.1", "cbc", "futures-util", "hex", diff --git a/crates/pf-update-check/Cargo.toml b/crates/pf-update-check/Cargo.toml index 90df57d7..525e2f34 100644 --- a/crates/pf-update-check/Cargo.toml +++ b/crates/pf-update-check/Cargo.toml @@ -33,7 +33,9 @@ serde_json = "1" # runner. Naming it here makes the crate build standalone instead of relying on who else is in # the selection. aws-lc-rs = { version = "1", features = ["prebuilt-nasm"] } -base64 = "0.22" +# Feature selection matched to ureq's (and punktfunk-host's) on purpose — 0.23's default-on +# `simd-unsafe` engine stays off, so a currency bump doesn't quietly add unsafe SIMD to the tree. +base64 = { version = "0.23", default-features = false, features = ["std"] } # Small, sync, bundles webpki roots — no system cert store dependency, which matters on the # Deck (Decky's embedded Python has no usable roots either; see clients/decky/main.py). # ⚠ `rustls-no-provider`, NEVER the default `rustls` feature — that one pulls `_ring`, which would diff --git a/crates/punktfunk-host/Cargo.toml b/crates/punktfunk-host/Cargo.toml index 9bcb1882..fdb2d290 100644 --- a/crates/punktfunk-host/Cargo.toml +++ b/crates/punktfunk-host/Cargo.toml @@ -97,7 +97,13 @@ rand = "0.9" hex = "0.4" # Cover-art delivery in the game library: encode Lutris's local JPEGs into `data:` URLs and decode # the Epic launcher's base64 `catcache.bin`. Cross-platform (Linux Lutris art + Windows Epic art). -base64 = "0.22" +# `default-features = false` + `std` deliberately: 0.23 added a default-ON `simd-unsafe` feature +# (hand-written AVX2/NEON engines). ureq already declares base64 exactly this way, so taking the +# defaults here would unify the feature ON and pull that unsafe code into every build as a side +# effect of a version bump. Turning it on is a perf decision worth making on purpose, with a +# measurement — not one to inherit silently. `std` covers everything we call (`Engine::encode`, +# `decode` to a `Vec`). +base64 = { version = "0.23", default-features = false, features = ["std"] } # Blocking HTTP for the library cover-art warmer (no-auth GOG api.gog.com + Xbox displaycatalog), # run on a background thread off the hot path. `ureq` is small + sync (no tokio here) and bundles # webpki roots (no system cert dependency). Cross-platform so the fetch/parse code is compiled + From 99c3a47bbf0d00dac7671898a228a00e07e77d6a Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Thu, 13 Aug 2026 13:50:37 +0200 Subject: [PATCH 4/7] chore(deps): libloading 0.8 -> 0.9 across the five crates that dlopen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All five declarations move together (pf-encode twice — Linux and Windows — plus pf-client-core, pf-zerocopy and punktfunk-host), because a split would have compiled two copies of a crate whose whole job is holding a process-wide dlopen handle. No source changes. 0.9 replaces the concrete parameter types with sealed traits — `Library::new(impl AsFilename)` and `Library::get(impl AsSymbolName)` — and both cover what our 16 call sites already pass: `&str` literals for the sonames (`libnvidia-encode.so.1`, `libva.so.2`, `libnvidia-ml.so.1`, `libcuda.so.1`) and `&[u8; N]` NUL-terminated byte literals for the symbols, which 0.9 implements explicitly alongside `&[u8]`. MSRV rises to 1.88; the workspace pins 1.96. libloading 0.8 does not leave the lock, and shouldn't: what remains is `clang-sys` under `bindgen`, reached only as a BUILD-dependency of ffmpeg-sys-next / libspa-sys / pyrowave-sys. That copy runs at build time and is linked into nothing we ship. Verified on CachyOS (rustc 1.96.0): cargo clippy --workspace --all-targets --locked -- -D warnings OK cargo clippy -p pf-encode --all-targets --locked --features nvenc,vulkan-encode,pyrowave -- -D warnings OK (the only leg that compiles enc/linux/nvenc_cuda.rs, where the `lib.get(b"…\0")` calls live) cargo clippy -p punktfunk-host -p pf-encode -p pf-zerocopy -p pf-client-core --locked -- -D warnings OK (shipping build) cargo test -p punktfunk-host --bins --locked 501 passed, 0 failed, 2 ignored cargo test -p pf-encode --locked 33 passed, 5 ignored cargo test -p pf-zerocopy --locked 40 passed cargo fmt --all --check clean --- Cargo.lock | 26 ++++++++++++++++++-------- crates/pf-client-core/Cargo.toml | 2 +- crates/pf-encode/Cargo.toml | 4 ++-- crates/pf-zerocopy/Cargo.toml | 2 +- crates/punktfunk-host/Cargo.toml | 2 +- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb8c3293..750dec27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -147,7 +147,7 @@ version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" dependencies = [ - "libloading", + "libloading 0.8.9", ] [[package]] @@ -805,7 +805,7 @@ checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a" dependencies = [ "glob", "libc", - "libloading", + "libloading 0.8.9", ] [[package]] @@ -1039,7 +1039,7 @@ version = "0.16.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17200eb07e7d85a243aa1bf4569a7aa998385ba98d14833973a817a63cc86e92" dependencies = [ - "libloading", + "libloading 0.8.9", ] [[package]] @@ -2324,7 +2324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading", + "libloading 0.8.9", ] [[package]] @@ -2404,6 +2404,16 @@ dependencies = [ "windows-link 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "libloading" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" +dependencies = [ + "cfg-if", + "windows-link 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libm" version = "0.2.16" @@ -3003,7 +3013,7 @@ dependencies = [ "ash", "async-channel", "libc", - "libloading", + "libloading 0.9.0", "mdns-sd", "openh264", "opus", @@ -3088,7 +3098,7 @@ dependencies = [ "ash", "ffmpeg-next", "libc", - "libloading", + "libloading 0.9.0", "libvpl-sys", "nvidia-video-codec-sdk", "openh264", @@ -3279,7 +3289,7 @@ dependencies = [ "ash", "khronos-egl", "libc", - "libloading", + "libloading 0.9.0", "serde", "serde_json", "tempfile", @@ -3624,7 +3634,7 @@ dependencies = [ "hyper-util", "if-addrs 0.13.4", "libc", - "libloading", + "libloading 0.9.0", "log", "mac_address", "mdns-sd", diff --git a/crates/pf-client-core/Cargo.toml b/crates/pf-client-core/Cargo.toml index a2c67214..9ee6c000 100644 --- a/crates/pf-client-core/Cargo.toml +++ b/crates/pf-client-core/Cargo.toml @@ -141,7 +141,7 @@ pf-vaadec = { path = "../pf-vaadec" } # libva itself is dlopen'd, never linked (see `video_vaapi_native`'s module docs): the # container can then compile and clippy the whole rung without `libva-dev`, and a machine # without a VAAPI runtime gets a clean refusal instead of a packaging dependency. -libloading = "0.8" +libloading = "0.9" # The gamescope overlay watcher (`overlay_focus`): read two CARDINAL properties off a # gamescope root window and block on PropertyNotify. `default-features = false` keeps the # pure-Rust `RustConnection` — no libxcb link, so no new C dependency on any client package diff --git a/crates/pf-encode/Cargo.toml b/crates/pf-encode/Cargo.toml index 4313fa1f..8c03a5f0 100644 --- a/crates/pf-encode/Cargo.toml +++ b/crates/pf-encode/Cargo.toml @@ -54,7 +54,7 @@ libc = "0.2" # the dep stays unconditional to mirror the host's Linux target — unused-but-declared is harmless). ash = "0.38" # `libnvidia-encode.so.1` is dlopen'd at runtime for the direct-SDK NVENC/CUDA backend. -libloading = "0.8" +libloading = "0.9" # Direct-SDK NVENC (raw `sys::nvEncodeAPI` types; entry points resolved at runtime). `ci-check` = # vendored bindings, no CUDA toolkit at build. nvidia-video-codec-sdk = { version = "0.4", features = ["ci-check"], optional = true } @@ -67,7 +67,7 @@ nvidia-video-codec-sdk = { version = "0.4", features = ["ci-check"], optional = # AMD (AMF) + Intel (QSV) hardware encode via libavcodec (behind `amf-qsv`; link-imports FFmpeg). ffmpeg-next = { version = "9", optional = true } # `libnvidia-encode`/`nvEncodeAPI64.dll` resolved at runtime; the NVENC status→cause table dlopen. -libloading = "0.8" +libloading = "0.9" # Native Intel QSV (VPL): vendored static MIT dispatcher + bindgen'd C API, only under `qsv`. libvpl-sys = { path = "../libvpl-sys", optional = true } # PyroWave (opt-in wired-LAN wavelet codec) — vendored codec + bindgen'd C API, only under diff --git a/crates/pf-zerocopy/Cargo.toml b/crates/pf-zerocopy/Cargo.toml index 16df1add..d9014114 100644 --- a/crates/pf-zerocopy/Cargo.toml +++ b/crates/pf-zerocopy/Cargo.toml @@ -20,7 +20,7 @@ tracing = "0.1" libc = "0.2" # `libcuda.so.1` is dlopen'd at runtime (NOT link-time) so one Linux binary runs on NVIDIA # (zero-copy via CUDA) AND on AMD/Intel (VAAPI, no NVIDIA driver present) — see `cuda::ffi`. -libloading = "0.8" +libloading = "0.9" # EGL imports the PipeWire dmabuf, CUDA maps it (`dynamic` = load the NVIDIA libEGL at runtime). khronos-egl = { version = "6", features = ["dynamic"] } # Vulkan bridge for LINEAR dmabufs (gamescope): VK_EXT_external_memory_dma_buf import, diff --git a/crates/punktfunk-host/Cargo.toml b/crates/punktfunk-host/Cargo.toml index fdb2d290..9bdf668d 100644 --- a/crates/punktfunk-host/Cargo.toml +++ b/crates/punktfunk-host/Cargo.toml @@ -208,7 +208,7 @@ pipewire = "0.9" rusqlite = { version = "0.40", features = ["bundled"] } # `libcuda.so.1` is dlopen'd at runtime (NOT link-time) so one Linux binary runs on NVIDIA # (zero-copy via CUDA) AND on AMD/Intel (VAAPI, no NVIDIA driver present) — see `zerocopy::cuda`. -libloading = "0.8" +libloading = "0.9" [target.'cfg(target_os = "windows")'.dependencies] # Windows host backends. `windows` covers the Win32/CCD APIs the SudoVDA virtual-display backend From 2718b7d4bdb1f3290b692092efe1ca36b8338029 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Thu, 13 Aug 2026 14:01:27 +0200 Subject: [PATCH 5/7] chore(deps): mdns-sd 0.20 -> 0.21 and if-addrs 0.13 -> 0.15, together MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One commit because splitting them accomplishes nothing: mdns-sd 0.20 ALREADY depends on if-addrs 0.15, so while our own five crates declared 0.13 the tree carried both copies no matter which of the two moved first. Moving them together is what collapses it: $ cargo tree -d | grep '^if-addrs' (no output) Neither needed a source change. mdns-sd 0.21's public API is purely additive over 0.20.3 — the sole new item is `ServiceDaemon::set_max_packet_size`, and `ServiceInfo`'s surface is byte-identical — so `ServiceDaemon`/`ServiceInfo`/ `ServiceEvent`/`ResolvedService` behave as before at all six call sites (host discovery + gamestream mdns, pf-client-core, and the Android, Windows and probe clients). if-addrs 0.15 keeps 0.13's `Interface`/`IfAddr` shape, and we only ever read those. The one real change is a FEATURE, not a version. if-addrs has `link-local`, and mdns-sd declares if-addrs with it on. Once our crates share that single copy, unification turns it on for our calls too — meaning `get_if_addrs()` now also reports fe80:: interfaces (and, on Windows, 169.254.x.x). Rather than inherit that silently, punktfunk-core and punktfunk-host now NAME the feature. Two reasons: it is what every real build gets anyway, so a standalone `cargo test -p punktfunk-core` should not enumerate a different set of NICs than the host does; and for the consumer here — Wake-on-LAN — it is the behaviour we want, since a NIC is wake-capable whether or not it currently holds a routable address. Verified on CachyOS (rustc 1.96.0): cargo clippy --workspace --all-targets --locked -- -D warnings OK cargo test --workspace --locked OK, 0 failed cargo test -p punktfunk-host --bins --locked 501 passed, 0 failed, 2 ignored cargo test ... gamestream::cert 3 passed cargo fmt --all --check clean (One `cargo test --workspace` attempt failed with E0463 "can't find crate for pf_frame" in a doc-test. That is the target dir having only clippy's .rmeta for a crate a doc-test wants to LINK, not anything in this change; a plain re-run after cargo test built the rlibs was green.) --- Cargo.lock | 20 +++++--------------- clients/android/native/Cargo.toml | 2 +- clients/probe/Cargo.toml | 2 +- clients/windows/Cargo.toml | 2 +- crates/pf-client-core/Cargo.toml | 2 +- crates/punktfunk-core/Cargo.toml | 7 ++++++- crates/punktfunk-host/Cargo.toml | 7 +++++-- 7 files changed, 20 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 750dec27..2d75eac2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2086,16 +2086,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "if-addrs" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b2eeee38fef3aa9b4cc5f1beea8a2444fc00e7377cafae396de3f5c2065e24" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "if-addrs" version = "0.15.0" @@ -2528,13 +2518,13 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "mdns-sd" -version = "0.20.3" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86dbb9f00c8c367f75ed3a775d3eb31d0375a72f58275ef64a1bc53c255a2ce2" +checksum = "ba97b4c886eea3c2823388120d92063c011ac866919ffc4200a0e4b1642a54a5" dependencies = [ "fastrand", "flume", - "if-addrs 0.15.0", + "if-addrs", "log", "mio", "socket-pktinfo", @@ -3582,7 +3572,7 @@ dependencies = [ "criterion", "fec-rs", "hmac", - "if-addrs 0.13.4", + "if-addrs", "libc", "opus", "proptest", @@ -3632,7 +3622,7 @@ dependencies = [ "http-body-util", "hyper", "hyper-util", - "if-addrs 0.13.4", + "if-addrs", "libc", "libloading 0.9.0", "log", diff --git a/clients/android/native/Cargo.toml b/clients/android/native/Cargo.toml index 74facf00..4c38ef0c 100644 --- a/clients/android/native/Cargo.toml +++ b/clients/android/native/Cargo.toml @@ -25,7 +25,7 @@ log = "0.4" # `NsdManager` system daemon with one tested browse path. Pure Rust (socket2/if-addrs/mio), so it # cross-compiles to the Android targets AND builds on the host (the JNI seam links into # `cargo build --workspace`). Kotlin keeps only the Wi-Fi `MulticastLock` + permission UX. -mdns-sd = "0.20" +mdns-sd = "0.21" # Android-only deps. Gated so `cargo build --workspace` on the Linux/macOS dev boxes + CI still # compiles this crate (as a host cdylib) — the Android-framework glue (logging, AMediaCodec + AAudio diff --git a/clients/probe/Cargo.toml b/clients/probe/Cargo.toml index bd8b7a0e..7f14a802 100644 --- a/clients/probe/Cargo.toml +++ b/clients/probe/Cargo.toml @@ -24,7 +24,7 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } # LAN host discovery (`--discover`): browse the native `_punktfunk._udp` mDNS service the host # advertises (same crate/version the host advertises with). -mdns-sd = "0.20" +mdns-sd = "0.21" # Opus: multistream DECODE of the host's audio plane (the surround validator) + `--mic-test`'s # encoder. libopus is already in the graph via `punktfunk-core`'s quic feature; this exposes the # name directly. Cross-platform (cmake-vendored), so the probe builds + validates everywhere. diff --git a/clients/windows/Cargo.toml b/clients/windows/Cargo.toml index 55bf7f05..762ede90 100644 --- a/clients/windows/Cargo.toml +++ b/clients/windows/Cargo.toml @@ -89,7 +89,7 @@ windows = { git = "https://github.com/microsoft/windows-rs", rev = "acb5a1a74410 # (see the `gamepad` field in app/); the spawned punktfunk-session does the actual forwarding. SDL3 # itself (built from source via the bundled CMake on Windows) is pulled transitively by # pf-client-core with the same `build-from-source,hidapi` features, so it is not a direct dep here. -mdns-sd = "0.20" +mdns-sd = "0.21" async-channel = "2" serde_json = "1" tracing = "0.1" diff --git a/crates/pf-client-core/Cargo.toml b/crates/pf-client-core/Cargo.toml index 9ee6c000..0947df69 100644 --- a/crates/pf-client-core/Cargo.toml +++ b/crates/pf-client-core/Cargo.toml @@ -89,7 +89,7 @@ libc = "0.2" # with libavcodec (`pf-encode`); nothing in this crate does. opus = "0.3" -mdns-sd = "0.20" +mdns-sd = "0.21" # PyroWave decode (the opt-in wired-LAN wavelet codec, design/pyrowave-codec-plan.md # §4.5) — pure Vulkan compute on the presenter's shared device, so it builds wherever the diff --git a/crates/punktfunk-core/Cargo.toml b/crates/punktfunk-core/Cargo.toml index 028a5b11..a7484ec3 100644 --- a/crates/punktfunk-core/Cargo.toml +++ b/crates/punktfunk-core/Cargo.toml @@ -55,7 +55,12 @@ zeroize = "1" # Interface enumeration for Wake-on-LAN: computes each NIC's subnet-directed broadcast so a # magic packet reaches the host's L2 segment on multi-homed clients (VPN/docker/multiple LANs), # not just the default route. Tiny, cross-platform (getifaddrs / GetAdaptersAddresses), no cmake. -if-addrs = "0.13" +# `link-local` is named EXPLICITLY, not inherited. mdns-sd declares if-addrs with it, so any build +# containing both (every host and every client) unifies it on regardless — and a crate whose +# enumeration silently changes depending on who else is in the selection is the worst of both. On +# means fe80::/169.254 interfaces are enumerated too, which for WoL is the behaviour we want: a NIC +# is wake-capable whether or not it currently holds a routable address. +if-addrs = { version = "0.15", features = ["link-local"] } # Crypto backend is aws-lc-rs, and rustls/quinn/rcgen must all name it: they each select a # backend independently, so one dissenter pulls a SECOND crypto stack in via feature unification. diff --git a/crates/punktfunk-host/Cargo.toml b/crates/punktfunk-host/Cargo.toml index 9bdf668d..0b06c801 100644 --- a/crates/punktfunk-host/Cargo.toml +++ b/crates/punktfunk-host/Cargo.toml @@ -68,11 +68,14 @@ tracing-log = "0.2" # tracing-log bridge with `ignore_crate("wasapi")`). Already in the tree transitively. log = "0.4" axum = "0.8" -mdns-sd = "0.20" +mdns-sd = "0.21" # Wake-on-LAN: report the host's wake-capable NIC MAC(s) to clients via the mDNS `mac` TXT record. # `mac_address` reads a NIC's hardware address; `if-addrs` maps the routed IP to its interface name. mac_address = "1" -if-addrs = "0.13" +# `link-local` named explicitly for the same reason as in punktfunk-core: mdns-sd (right above) +# turns it on by unification anyway, and `wake_macs` should not enumerate a different set of NICs +# depending on which other crates share the build. +if-addrs = { version = "0.15", features = ["link-local"] } tokio = { version = "1", features = ["full"] } # GameStream-only (behind the `gamestream` feature): the Moonlight RSA-2048 identity generator + # pairing signer (cert.rs, pairing.rs) and the legacy-client-cert leniency verifier (tls.rs). From deb83ecc48ba0ae842f4e390ac0ad019885a1390 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Thu, 13 Aug 2026 14:09:52 +0200 Subject: [PATCH 6/7] chore(deps): rcgen 0.13 -> 0.14 in core and the host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both declarations keep `default-features = false, features = ["aws_lc_rs", "pem"]`, which stays load-bearing in 0.14: `ring` is still in rcgen's DEFAULT feature set, so dropping `default-features = false` would drag the backend this tree deliberately left back in. Verified after the bump — `cargo tree -i ring` finds nothing on x86_64-unknown-linux-gnu, x86_64-pc-windows-msvc, aarch64-apple-darwin or aarch64-linux-android. One breaking change reached us. `CertifiedKey`'s key field was renamed `key_pair` -> `signing_key` (the struct is now generic, `CertifiedKey`), which hits the two `generate_simple_self_signed` callers in core's quic/endpoint.rs — the dev/test server endpoint and `generate_identity`. Both are a field rename; `KeyPair` still provides `serialize_der`/`serialize_pem`. Everything the GAMESTREAM identity depends on survives unchanged, which is what this bump's precondition was about: `KeyPair::from_pkcs8_pem_and_sign_algo`, `PKCS_RSA_SHA256`, `CertificateParams::new`, `date_time_ymd`, `self_signed`, `Certificate::pem`. The split in gamestream/cert.rs is therefore untouched — the RSA-2048 key is still minted by the `rsa` crate and handed to rcgen only to load and self-sign, because rcgen cannot generate an RSA key on the backend we use. That path is asserted, not assumed: cargo test -p punktfunk-host --bins --locked gamestream::cert 3 passed, 0 failed generate_mints_a_loadable_rsa2048_identity ok (fresh-install keygen) moonlight_shaped_peer_completes_a_tls12_mutual_handshake ok tls13_negotiates_the_post_quantum_group ok (X25519MLKEM768 by name) Verified on CachyOS (rustc 1.96.0): cargo clippy --workspace --all-targets --locked -- -D warnings OK cargo clippy -p punktfunk-host -p punktfunk-core --locked -- -D warnings OK (shipping build) cargo test --workspace --locked 78 test binaries, all ok, 0 failed cargo fmt --all --check clean --- Cargo.lock | 24 ++++++++++++++++------ crates/punktfunk-core/Cargo.toml | 2 +- crates/punktfunk-core/src/quic/endpoint.rs | 4 ++-- crates/punktfunk-host/Cargo.toml | 2 +- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d75eac2..98406863 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -522,7 +522,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec", + "bit-vec 0.8.0", ] [[package]] @@ -531,6 +531,15 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -3473,7 +3482,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" dependencies = [ "bit-set", - "bit-vec", + "bit-vec 0.8.0", "bitflags 2.13.1", "num-traits", "rand 0.9.5", @@ -3966,14 +3975,15 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.13.2" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +checksum = "091e7a8e7d86e6feb87a27ce8e2cba29d49eff9507afeebefab7eeb2ca667fb4" dependencies = [ "aws-lc-rs", "pem", "rustls-pki-types", "time", + "x509-parser", "yasna", ] @@ -6231,6 +6241,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" dependencies = [ "asn1-rs", + "aws-lc-rs", "data-encoding", "der-parser", "lazy_static", @@ -6270,10 +6281,11 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "yasna" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" dependencies = [ + "bit-vec 0.9.1", "time", ] diff --git a/crates/punktfunk-core/Cargo.toml b/crates/punktfunk-core/Cargo.toml index a7484ec3..4b5bb996 100644 --- a/crates/punktfunk-core/Cargo.toml +++ b/crates/punktfunk-core/Cargo.toml @@ -77,7 +77,7 @@ quinn = { version = "0.11", optional = true, default-features = false, features ] } rustls = { version = "0.23", optional = true, default-features = false, features = ["aws_lc_rs", "prefer-post-quantum", "std"] } # `generate_simple_self_signed` is backend-agnostic, so the swap is transparent here. -rcgen = { version = "0.13", optional = true, default-features = false, features = ["aws_lc_rs", "pem"] } +rcgen = { version = "0.14", optional = true, default-features = false, features = ["aws_lc_rs", "pem"] } rustls-pki-types = { version = "1", optional = true } # `rustls-no-provider`, NOT the default `rustls` feature — ureq's `rustls` feature body pulls # `_ring`, which would drag the whole ring backend back into a tree that has deliberately moved to diff --git a/crates/punktfunk-core/src/quic/endpoint.rs b/crates/punktfunk-core/src/quic/endpoint.rs index def498e4..3f605abd 100644 --- a/crates/punktfunk-core/src/quic/endpoint.rs +++ b/crates/punktfunk-core/src/quic/endpoint.rs @@ -131,7 +131,7 @@ pub fn server(addr: std::net::SocketAddr) -> anyhow_result::Result anyhow_result::Result<(String, String)> { let cert = rcgen::generate_simple_self_signed(vec!["punktfunk-client".into()]) .map_err(|e| anyhow_result::Error::msg(format!("self-signed cert: {e}")))?; - Ok((cert.cert.pem(), cert.key_pair.serialize_pem())) + Ok((cert.cert.pem(), cert.signing_key.serialize_pem())) } /// Fingerprint of the client certificate a connection presented (host side), if any. diff --git a/crates/punktfunk-host/Cargo.toml b/crates/punktfunk-host/Cargo.toml index 0b06c801..cfe2b797 100644 --- a/crates/punktfunk-host/Cargo.toml +++ b/crates/punktfunk-host/Cargo.toml @@ -118,7 +118,7 @@ ureq = { version = "3", default-features = false, features = [ "rustls-webpki-roots", "gzip", ] } -rcgen = { version = "0.13", default-features = false, features = ["aws_lc_rs", "pem"] } +rcgen = { version = "0.14", default-features = false, features = ["aws_lc_rs", "pem"] } # ⚠ Do not float this back below 0.18. 0.16 was the LAST crate pulling `thiserror` 1.0 into the # host graph (via asn1-rs 0.6 / der-parser 9 / oid-registry 0.7); 0.18 moves that chain to asn1-rs # 0.7 + thiserror 2, so the host now links exactly one thiserror major. `cargo tree -p From bd987d373ee4dbce2e23a0fbf21633372c5c803e Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Thu, 13 Aug 2026 14:14:25 +0200 Subject: [PATCH 7/7] chore(deps): criterion 0.5 -> 0.8 (dev-only, benches) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dev-dependency of punktfunk-core only — it ships in nothing. `default-features = false, features = ["cargo_bench_support"]` carries over unchanged; that feature still exists in 0.8 and still keeps plotters/rayon out of a headless CI run. One source change, and it is a lint issue rather than an API one. `criterion::black_box` survives in 0.8 but is `#[deprecated]` — it now just forwards to `std::hint::black_box` — and benches ARE compiled by `cargo clippy --workspace --all-targets -- -D warnings`, so keeping the criterion import would have turned a deprecation warning into a failed lint gate. The bench imports the std one directly. What CI actually consumes from criterion is the on-disk result layout, so that was checked rather than assumed: 0.8 still writes `target/criterion///new/estimates.json`, and the key scripts/bench/compare.py reads — `median.point_estimate` — is still there: $ cargo bench -p punktfunk-core --bench pipeline -- --warm-up-time 1 --measurement-time 3 ... 12/12 benchmarks reported, e.g. pipeline/gf16/1048576 thrpt: [537 MiB/s 540 MiB/s 542 MiB/s] $ find target/criterion -name estimates.json | wc -l 24 $ python3 -c 'import json; print(json.load(open(".../crypto/seal/new/estimates.json"))["median"]["point_estimate"])' 817.96 Verified on CachyOS (rustc 1.96.0): cargo clippy -p punktfunk-core --all-targets --locked -- -D warnings OK (this is what compiles the bench) cargo clippy --workspace --all-targets --locked -- -D warnings OK cargo bench -p punktfunk-core --bench pipeline --locked -- --test 12/12 Success cargo bench -p punktfunk-core --bench pipeline --locked -- --warm-up-time 1 --measurement-time 3 OK (CI's exact line) cargo test -p punktfunk-core --locked 210 + 8 + 1 passed, 0 failed cargo fmt --all --check clean --- Cargo.lock | 58 +++++++++++------------ crates/punktfunk-core/Cargo.toml | 2 +- crates/punktfunk-core/benches/pipeline.rs | 6 ++- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 98406863..97018ff2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloca" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" +dependencies = [ + "cc", +] + [[package]] name = "android_log-sys" version = "0.3.2" @@ -505,7 +514,7 @@ dependencies = [ "bitflags 2.13.1", "cexpr", "clang-sys", - "itertools 0.13.0", + "itertools", "log", "prettyplease", "proc-macro2", @@ -950,23 +959,22 @@ dependencies = [ [[package]] name = "criterion" -version = "0.5.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" dependencies = [ + "alloca", "anes", "cast", "ciborium", "clap", "criterion-plot", - "is-terminal", - "itertools 0.10.5", + "itertools", "num-traits", - "once_cell", "oorandom", + "page_size", "regex", "serde", - "serde_derive", "serde_json", "tinytemplate", "walkdir", @@ -974,12 +982,12 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.5.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" dependencies = [ "cast", - "itertools 0.10.5", + "itertools", ] [[package]] @@ -2144,32 +2152,12 @@ dependencies = [ "generic-array", ] -[[package]] -name = "is-terminal" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.61.2", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -2886,6 +2874,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "pango" version = "0.22.8" diff --git a/crates/punktfunk-core/Cargo.toml b/crates/punktfunk-core/Cargo.toml index 4b5bb996..0e56af4e 100644 --- a/crates/punktfunk-core/Cargo.toml +++ b/crates/punktfunk-core/Cargo.toml @@ -126,7 +126,7 @@ windows-sys = { version = "0.59", features = [ proptest = "1" # Tier-1 microbenchmarks (benches/pipeline.rs). default-features off → no plotters/HTML (headless # CI just needs the measurement + target/criterion/**/estimates.json for the regression compare). -criterion = { version = "0.5", default-features = false, features = ["cargo_bench_support"] } +criterion = { version = "0.8", default-features = false, features = ["cargo_bench_support"] } [[bench]] name = "pipeline" diff --git a/crates/punktfunk-core/benches/pipeline.rs b/crates/punktfunk-core/benches/pipeline.rs index f875f61b..e4276fa7 100644 --- a/crates/punktfunk-core/benches/pipeline.rs +++ b/crates/punktfunk-core/benches/pipeline.rs @@ -10,11 +10,15 @@ //! The GPU capture/NVENC encode path is deliberately out of scope here (no GPU in CI) — that's the //! Tier-3 stream benchmark on a self-hosted GPU runner. Run locally with `cargo bench -p punktfunk-core`. -use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; use punktfunk_core::config::{Config, FecConfig, FecScheme, ProtocolPhase, Role}; use punktfunk_core::crypto::{SessionCrypto, SessionKey}; use punktfunk_core::session::Session; use punktfunk_core::transport::loopback_pair; +// NOT `criterion::black_box`: it still exists in 0.8 but is deprecated, and now just forwards to +// this one. Benches compile under `--all-targets -D warnings`, so importing criterion's would fail +// the lint gate rather than merely warn. +use std::hint::black_box; const TAG_LEN: usize = 16; // AEAD authentication tag (GCM and Poly1305 share the size) const SHARD: usize = punktfunk_core::config::mtu1500_shard_payload(); // one MTU-safe data shard