[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-81837":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":15,"stars7d":15,"stars30d":15,"stars90d":16,"forks30d":16,"starsTrendScore":13,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":19,"hasPages":19,"topics":21,"createdAt":10,"pushedAt":10,"updatedAt":26,"readmeContent":27,"aiSummary":28,"trendingCount":16,"starSnapshotCount":16,"syncStatus":14,"lastSyncTime":29,"discoverSource":30},81837,"hpke-ng","symbolicsoft\u002Fhpke-ng","symbolicsoft","Faster, Smaller, Harder HPKE for Rust","https:\u002F\u002Fsymbolic.software\u002Fblog\u002F2026-05-08-hpke-ng\u002F",null,"Rust",28,3,2,1,0,44.41,"Apache License 2.0",false,"main",[22,23,24,25],"crypto","cryptography","hpke","rust","2026-06-12 04:01:35","# hpke-ng\n\n[![CI](https:\u002F\u002Fgithub.com\u002Fsymbolicsoft\u002Fhpke-ng\u002Factions\u002Fworkflows\u002Fci.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fsymbolicsoft\u002Fhpke-ng\u002Factions)\n[![License](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-Apache--2.0%20OR%20MIT-blue)](#license)\n\nA clean-slate Rust implementation of [HPKE (RFC 9180)](https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc9180.html) with type-driven ciphersuite selection.\n\n> Read the announcement: **[hpke-ng: Faster, Smaller, Harder HPKE for Rust](https:\u002F\u002Fsymbolic.software\u002Fblog\u002F2026-05-08-hpke-ng\u002F)** — for the full design rationale, benchmarks, and migration notes.\n\n```rust\nuse hpke_ng::*;\nuse rand_core::OsRng;\n\ntype Suite = Hpke\u003CDhKemX25519HkdfSha256, HkdfSha256, ChaCha20Poly1305>;\n\nlet mut os = OsRng;\nlet mut rng = os.unwrap_mut();\nlet (sk_r, pk_r) = DhKemX25519HkdfSha256::generate(&mut rng)?;\nlet (enc, ct)  = Suite::seal_base(&mut rng, &pk_r, b\"info\", b\"aad\", b\"hello\")?;\nlet pt         = Suite::open_base(&enc, &sk_r, b\"info\", b\"aad\", &ct)?;\nassert_eq!(pt, b\"hello\");\n# Ok::\u003C_, hpke_ng::HpkeError>(())\n```\n\n## Why a new HPKE crate?\n\n`hpke-ng` exists because three friction points in the existing Rust HPKE story kept producing real bugs and real overhead:\n\n1. **Provider abstraction overhead.** A trait-based pluggable backend pushes dispatch costs into hot paths and inflates the `Hpke` struct to hundreds of bytes — for a value the type system already knows.\n2. **Struct-owned PRNG hazard.** When the `Hpke` instance owns its RNG, cloning silently aliases randomness state. The fix is structural: don't own it.\n3. **Type-system gaps.** `Option\u003C&[u8]>` for mode-specific parameters turns missing-PSK and wrong-mode into runtime errors that should be compile errors.\n\nThe design takes one position on each: **no provider abstraction, no owned RNG, type parameters instead of mode enums.** The math is a solved problem; the surrounding library is where the engineering still has slack.\n\n## Design highlights\n\n- **Type-parameterized API.** `Hpke\u003CK, F, A>` is zero-sized; the ciphersuite lives in the type system. Mismatched primitives are compile errors.\n- **Four explicit methods per mode.** `seal_base`, `seal_psk`, `seal_auth`, `seal_auth_psk` — no `Option\u003C&[u8]>` parameters for required-by-mode arguments.\n- **Auth restricted to DHKEMs at the type level.** `Hpke::\u003CXWingDraft06, ...>::seal_auth(...)` does not compile.\n- **Export-only restricted at the type level.** `Hpke::\u003C_, _, ExportOnly>::seal_base(...)` does not compile; only `*_export*` methods are available.\n- **Type-tagged keys.** Private keys carry their KEM in their type, so passing a `DhKemP256` key into an X25519 suite is rejected by the compiler, not at runtime.\n- **Caller-provided RNG.** No PRNG owned by the configuration; cloning cannot alias randomness.\n- **Structural nonce-reuse prevention.** `Context` is non-cloneable and refuses to encrypt at `seq == u64::MAX`.\n- **`no_std` + `alloc`** by default. `std` feature for `std::error::Error` impl on `HpkeError`.\n- **One provider stack.** All primitives from RustCrypto-org crates.\n\n## Compile-time guarantees\n\n| Operation                                | Elsewhere       | hpke-ng                        |\n|------------------------------------------|-----------------|--------------------------------|\n| Calling `seal_auth` on a non-DH KEM      | Runtime error   | Compile error                  |\n| Using a wrong-KEM private key            | Runtime mismatch| Compile error (type-tagged)    |\n| Base-mode call with a PSK supplied       | Runtime error   | Compile error (no PSK param)   |\n| Encrypt with an `ExportOnly` AEAD        | Runtime error   | Compile error                  |\n\n## Supported ciphersuites\n\n| Component | Variants |\n|---|---|\n| KEMs | `DhKemX25519HkdfSha256`, `DhKemX448HkdfSha512`, `DhKemP256HkdfSha256`, `DhKemP384HkdfSha384`, `DhKemP521HkdfSha512`, `DhKemK256HkdfSha256` |\n| KEMs (post-quantum, `pq` feature) | `XWingDraft06`, `MlKem768`, `MlKem1024` |\n| KDFs | `HkdfSha256`, `HkdfSha384`, `HkdfSha512` |\n| AEADs | `Aes128Gcm`, `Aes256Gcm`, `ChaCha20Poly1305`, `ExportOnly` |\n| Modes | Base, Psk, Auth, AuthPsk |\n\n## Performance\n\nAcross **132 head-to-head benchmarks** against the two major Rust HPKE libraries — `hpke-rs` and `rust-hpke` — `hpke-ng` lands **100 wins, 12 ties, 20 losses**. Broken out: vs `hpke-rs` (76 cells) it's **63W \u002F 8T \u002F 5L**; vs `rust-hpke` (56 cells; no standalone ML-KEM-768\u002FML-KEM-1024, no secp256k1 support) it's **37W \u002F 4T \u002F 15L**. The largest deltas are on the post-quantum decap path — ML-KEM-768 and ML-KEM-1024 land 53–55% faster, X-Wing decap 37% faster — because `hpke-ng` caches the expanded FIPS 203 decapsulation key in the `PrivateKey` while `hpke-rs` rebuilds it from the seed on every `setup_receiver`. The same idea applied to classical KEMs — caching the recipient's serialized public key alongside the secret — eliminates a redundant base-point scalar multiplication on every decap, lifting **X25519 decap to −41% vs `hpke-rs` \u002F −31% vs `rust-hpke`**, ML-KEM encap to 38–40%, X-Wing encap to 16% vs `hpke-rs` and to roughly parity vs `rust-hpke`. X-Wing `setup_receiver` is also roughly equivalent to `rust-hpke`'s (which wraps raw decap in full HPKE setup). Single-shot open is **26–42% faster vs `hpke-rs`** and **22–35% faster vs `rust-hpke`** across payload sizes; AES-128-GCM single-shot seal 6–22% faster against both across payloads ≤ 16 KiB. **Export is 72–76% faster vs `hpke-rs`** across all five output lengths — the largest sustained delta in the suite (`rust-hpke` excluded: its `export()` API allocates in a way that would bias the comparison). Post-setup `Context::seal` at 64 B is 14% faster vs `hpke-rs` and tied with `rust-hpke`. **End-to-end roundtrip on a 1 KiB message is 30% faster vs both libraries.**\n\nMemory and binary footprint:\n\n| Quantity                                       | hpke-rs   | hpke-ng                     |\n|------------------------------------------------|-----------|-----------------------------|\n| `Hpke\u003CK, F, A>` struct                         | 320 bytes | **0 bytes** (`PhantomData`) |\n| `Context\u003C_, _, ChaCha20Poly1305>` struct       | 400 bytes | **88 bytes**                |\n| `Context\u003C_, _, ExportOnly>` struct             | n\u002Fa       | **56 bytes**                |\n| `Context\u003C_, _, Aes128Gcm>` struct              | 400 bytes | 792 bytes                   |\n| `Context\u003C_, _, Aes256Gcm>` struct              | 400 bytes | 1,048 bytes                 |\n| Minimal release binary                         | 561 KB    | **392 KB** (~30% smaller)   |\n\nThe AES-GCM `Context` rows are larger than `hpke-rs` because the cipher's expanded round keys + GHash table are cached inline — that is what eliminates the per-call AES key-schedule cost in `Context::seal`. Streaming applications using AES-GCM trade memory for throughput here; ChaCha20-Poly1305 is unaffected.\n\nBuild with `RUSTFLAGS=\"-C target-cpu=native\"` for AES-NI \u002F SHA-NI where available. The `[profile.bench]` in `Cargo.toml` enables `lto = \"thin\"` and `codegen-units = 1`. For head-to-head numbers, run `cargo bench --features comparative --bench comparative` locally; the comparative bench loads both `hpke-rs` (with its `experimental` feature so the post-quantum KEM stubs are wired up) and `rust-hpke` (pinned to a v0.14 pre-release commit for X-Wing support) as dev-dependencies, and produces side-by-side criterion results for every supported ciphersuite. KEM-op rows for `hpke-rs` and `rust-hpke` carry an `_via_setup_*` suffix because neither library exposes raw `encap` \u002F `decap` separable from setup; the suffix marks rows that are explicitly *not* apples-to-apples with `hpke-ng`'s bare-operation rows.\n\n## Security posture\n\nThe library responds to two classes of issue observed in prior implementations:\n\n- **Zero shared-secret check (RFC 9180 §7.1.4).** Enforced for X25519 and X448 using `subtle::ConstantTimeEq`.\n- **Nonce counter wraparound.** Prevented structurally: `Context` uses a `u64` sequence number, refuses to encrypt at `u64::MAX`, and is non-cloneable so a counter cannot fork.\n\nThe post-DH all-zeros check is constant-time. `Context` cannot be `Clone`d, so two ciphertexts cannot be produced under the same `(key, nonce)` from two copies of the same context.\n\n## Constant-time considerations\n\nThis crate composes RustCrypto primitives. Constant-time properties are inherited from those crates:\n\n| Primitive | CT property |\n|---|---|\n| X25519, X448 | CT by construction. |\n| P-256, P-384, P-521, secp256k1 | CT in `arithmetic` mode (pinned). |\n| HKDF-SHA-{256,384,512} | CT (deterministic; no secret-dependent branches). |\n| ChaCha20-Poly1305 | CT by construction. |\n| AES-128-GCM, AES-256-GCM | **CT only with hardware AES-NI\u002FPCLMULQDQ.** Prefer `ChaCha20Poly1305` on platforms without these instructions. |\n| ML-KEM, X-Wing | CT per upstream documentation; both crates are pre-1.0. |\n\n## Testing\n\n```bash\ncargo test                                             # library + roundtrip\ncargo test --features pq                               # + post-quantum tests\ncargo test --features pq --test compile_fail           # + compile-time invariant tests\ncargo test --features pq,kat-internals                 # + RFC 9180 KAT\ncargo test --features pq,differential,kat-internals    # + cross-impl differential vs hpke-rs\n```\n\nTo regenerate the compile-fail `.stderr` fixtures after an intentional change (e.g. a toolchain bump), run:\n```bash\nTRYBUILD=overwrite cargo test --features pq --test compile_fail\n```\nThis rewrites the fixtures unconditionally and should not be used as the normal test invocation.\n\nCoverage includes 59 macro-generated roundtrip tests across every ciphersuite × mode combination, four `cargo-fuzz` targets (panics treated as bugs), differential testing against `hpke-rs` for wire-format interop, compile-fail tests that lock in type-system invariants (`Context` is non-cloneable, `ExportOnly` cannot seal, PQ KEMs cannot authenticate), and unit tests that directly verify the RFC 9180 §5.2 nonce derivation formula (`nonce = base_nonce XOR I2OSP(seq, Nn)`) across specific sequence number boundary values. The full suite (without differential) runs in under two seconds.\n\n## Migration from `hpke-rs`\n\nThree mechanical steps, typically under an hour for a real codebase:\n\n1. Define a `type Suite = Hpke\u003CK, F, A>;` alias for the ciphersuite you use.\n2. Replace `hpke.seal(...)` calls with the explicit mode method: `Suite::seal_base`, `seal_psk`, `seal_auth`, or `seal_auth_psk`.\n3. Thread `&mut rng` through call sites — the configuration no longer owns one.\n\nSee the [announcement post](https:\u002F\u002Fsymbolic.software\u002Fblog\u002F2026-05-08-hpke-ng\u002F) for a worked example.\n\n## Authors\n\nhpke-ng is a joint project between [Nadim Kobeissi](https:\u002F\u002Fnadim.computer) and [Daniel Dia](https:\u002F\u002Fdanieldia.me).\n\n## License\n\nLicensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT license](LICENSE-MIT) at your option.\n","symbolicsoft\u002Fhpke-ng 是一个针对 Rust 语言的高性能、轻量级 HPKE（混合公钥加密）实现。该项目通过类型驱动的密码套件选择机制，提供了一个简洁且高效的 API，避免了现有实现中的性能开销和潜在错误源，如提供者抽象开销、结构拥有的伪随机数生成器风险以及类型系统中的漏洞。核心功能包括类型参数化的 API、模式特定方法的明确定义、编译时类型检查以防止不匹配的密码原语使用等。适用于需要高效安全通信的应用场景，特别是对性能和安全性有较高要求的 Rust 项目。","2026-06-11 04:06:54","CREATED_QUERY"]