From 2c39662b88cf53c87af9f9b557433b16f27513bf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 08:35:15 +0000 Subject: [PATCH 1/3] chore(ore-rs): release v0.9.0 --- Cargo.lock | 2 +- packages/ore-rs/CHANGELOG.md | 103 +++++++++++++++++++++++++++++++++++ packages/ore-rs/Cargo.toml | 2 +- 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 607b1d90..46ec6113 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -457,7 +457,7 @@ dependencies = [ [[package]] name = "ore-rs" -version = "0.8.4" +version = "0.9.0" dependencies = [ "aes", "block-modes", diff --git a/packages/ore-rs/CHANGELOG.md b/packages/ore-rs/CHANGELOG.md index 4cfb3d06..7452c6ce 100644 --- a/packages/ore-rs/CHANGELOG.md +++ b/packages/ore-rs/CHANGELOG.md @@ -7,6 +7,109 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Benchmarks + +- black-box every result and input, and record the effect +- criterion bench for the Bit6 PRP builder alone + +### CI + +- make the default harness set fit CI; time-limit the job + +### Documentation + +- document the legacy zero-run seed leakage +- restate A1 on a correct exposure model; correct A4's read paths +- correct the CMAC spec, and recommend Bit6 for new data +- u128/i128 fit neither scheme; stop recommending OreAes128 for them +- every ciphertext reveals the exact plaintext length + +### Features + +- 6-bit block width scheme (OreAes128Bit6) with v2 wire format +- CMAC accumulator primitive + LemireFyPrp::from_stream (PR 6 foundation) +- chained-prefix variable-length scheme + string encryption (PR 6) + +### Fixes + +- derive scheme-separated PRF keys and bind the block index +- refuse malformed lengths in the legacy raw comparator +- refuse oversized raw symbols before scanning them + +### Miscellaneous + +- update the detached lockfiles to orderable-bytes 0.2 + +### Performance + +- bulk unary encoding, allocation-free encrypt path, hardware AES on aarch64 +- NEON and AVX2 kernels for indicator and hash-bit masks +- Bit6 PRP via fixed-draw Fisher-Yates (closes timing channel) +- vectorize GF(2^128) doubling in the sigma-MMO hash + +### Refactoring + +- width abstraction, seed/tag separation, template RO keys +- derive BlockWidth::DOMAIN from BITS +- address #80 self-review (shared bit-packer, drop dead code) +- from_stream delegates to one from_stream_with +- reuse lemire_draw and the reference builder in the isolation hooks + +### Testing + +- pin compatibility vectors and bench baseline for ORE v2 refactor +- name the generator's real output path +- pin cross-nonce comparison fixtures +- pin v2 Bit6 wire-format vectors +- pin cross-nonce comparison fixtures +- property tests for ORE comparator, left/full consistency, and CMAC accumulator +- pin wire-format vectors +- libFuzzer targets for the ciphertext parsers and comparators +- dudect timing benches for the comparators and encryptors +- kani harnesses for the pure building blocks +- run the two exhaustive-length Kani harnesses only with kani-full +- prove order preservation across different lengths +- round-trip Right::from_slice for Bit6 and legacy +- prove lemire_draw itself; test every swap of the shipped builders on their targets + +### Ct-taint + +- refuse a vacuous pass; cover more types and the raw entry points + +### Fuzz + +- check that the raw comparator and the typed Ord agree + +### Harden + +- assert gather length; precise dispatch cfg (#81 self-review) +- real length asserts; set_bit assigns +- count=0 guard, shared encoder, ct bit-extract, opaque Debug (#82 review) +- restore the #81 review hardening that #82 overwrote +- build the Bit6 permutation with no secret-dependent address +- reject out-of-domain symbols; assert the 64-lane mask length +- read permute/invert tables obliviously; latch the comparator's block +- scrub the stack after each encryption +- size the scrub by optimisation level, not debug_assertions +- zeroize L/ro, Branch enum, count guard, single-key init, left-query comparator (#83 review) +- encrypt the mixed state in place in absorb and finalize +- oblivious tag and bit reads, string length guard, symbol checks; correct at-rest leakage docs +- scrub the stack after each encryption; wipe the decomposed string +- latch first differing block in legacy and Bit6 typed comparators; accept zero-block legacy input +- zeroize the latched first-difference copies +- typed in-domain Symbol; infallible permute; drop taint suppressions + +### Ore + +- harden PRP/comparator constant-time, add N<=64 guard +- resolve A1 — adopt BHKR sigma-MMO for the 1-bit hash H + +### Style + +- rustfmt +- rustfmt the orderable-bytes 0.2 port + + ### Documentation - refresh crates.io/docs.rs-facing docs and crate metadata diff --git a/packages/ore-rs/Cargo.toml b/packages/ore-rs/Cargo.toml index 501b6aed..576bef02 100644 --- a/packages/ore-rs/Cargo.toml +++ b/packages/ore-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ore-rs" -version = "0.8.4" +version = "0.9.0" authors = [ "Dan Draper ", "James Sadler ", From a0b26a70a93cf888563893a03c25cdcccbe3301e Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Mon, 12 Oct 2026 19:51:50 +1100 Subject: [PATCH 2/3] chore(ore-rs): release v0.9.0-rc.1 as a pre-release Pre-release for testing with external projects before 0.9.0. - Version 0.9.0-rc.1 instead of 0.9.0. - release-plz: git_release_type = "auto", so the GitHub release is marked as a pre-release. - cliff.toml: the changelog template had no version heading, so every release since 0.3.0 was appended under [Unreleased]. It now writes '## [version] - date'. This release gets its own section, and the earlier un-headed entries are grouped under '[0.8.4] and earlier'. --- Cargo.lock | 2 +- cliff.toml | 5 +++++ packages/ore-rs/CHANGELOG.md | 7 +++++++ packages/ore-rs/Cargo.toml | 2 +- release-plz.toml | 2 ++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46ec6113..2d10547f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -457,7 +457,7 @@ dependencies = [ [[package]] name = "ore-rs" -version = "0.9.0" +version = "0.9.0-rc.1" dependencies = [ "aes", "block-modes", diff --git a/cliff.toml b/cliff.toml index 2a144b94..f5d9fef4 100644 --- a/cliff.toml +++ b/cliff.toml @@ -1,6 +1,11 @@ [changelog] header = "" body = """ +{% if version %}\ +## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{% else %}\ +## [Unreleased] +{% endif %}\ {% for group, commits in commits | group_by(attribute="group") %} ### {{ group | upper_first }} {% for commit in commits %} diff --git a/packages/ore-rs/CHANGELOG.md b/packages/ore-rs/CHANGELOG.md index 7452c6ce..a4e0e499 100644 --- a/packages/ore-rs/CHANGELOG.md +++ b/packages/ore-rs/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.9.0-rc.1] - 2026-10-12 + +Pre-release for testing with external projects. The Bit6 (`scheme::bit2_w6`) and chained +wire formats are not frozen yet: do not store their ciphertexts until 0.9.0. ### Benchmarks @@ -109,6 +113,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - rustfmt - rustfmt the orderable-bytes 0.2 port +## [0.8.4] and earlier + +Entries for 0.4.0 to 0.8.4, which were released without per-version headings. ### Documentation diff --git a/packages/ore-rs/Cargo.toml b/packages/ore-rs/Cargo.toml index 576bef02..b192f01d 100644 --- a/packages/ore-rs/Cargo.toml +++ b/packages/ore-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ore-rs" -version = "0.9.0" +version = "0.9.0-rc.1" authors = [ "Dan Draper ", "James Sadler ", diff --git a/release-plz.toml b/release-plz.toml index 3d1b1ada..90414059 100644 --- a/release-plz.toml +++ b/release-plz.toml @@ -2,6 +2,8 @@ changelog_config = "cliff.toml" git_tag_enable = true git_release_enable = true +# Mark GitHub releases of versions like 0.9.0-rc.1 as pre-releases. +git_release_type = "auto" publish = true semver_check = false From 47b28a9f5268114d25cebf38f6c0a5827eaf9609 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Mon, 12 Oct 2026 19:59:45 +1100 Subject: [PATCH 3/3] docs(changelog): highlight the Bit6 and chained schemes in 0.9.0-rc.1 --- packages/ore-rs/CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/packages/ore-rs/CHANGELOG.md b/packages/ore-rs/CHANGELOG.md index a4e0e499..b10e9643 100644 --- a/packages/ore-rs/CHANGELOG.md +++ b/packages/ore-rs/CHANGELOG.md @@ -11,6 +11,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Pre-release for testing with external projects. The Bit6 (`scheme::bit2_w6`) and chained wire formats are not frozen yet: do not store their ciphertexts until 0.9.0. +### Highlights + +**New: `OreAes128Bit6` (`scheme::bit2_w6`), a 6-bit block scheme, recommended for new data.** + +- **Smaller and faster.** Plaintexts are split into 6-bit blocks, so each block costs 64 + random-oracle evaluations instead of 256 and stores an 8-byte right block instead of 32. + A `u64` ciphertext is 295 bytes (legacy: 408). Encrypting a `u64` measured 8.6 µs + against 25.1 µs for the legacy scheme, both with hardware AES on an Apple M1 Max + (`docs/benchmarks/2026-06-13-bit6-prp-results.md`). +- **Less leakage than the legacy scheme.** PRP seeds bind the block index and the block + count, so a ciphertext no longer reveals its runs of zero bytes (for an integer, its + order of magnitude). A comparison reveals the order and the first differing 6-bit block. +- **Key separation.** PRF keys are derived from the caller's keys under scheme-specific + labels, so using the same keys for both schemes can't expose Bit6 masking keys + through legacy ciphertexts. +- **v2 wire format.** A 4-byte header carries the format version, scheme id and block + count. Parsers and the raw comparator reject bad headers, lengths and out-of-domain + symbols instead of panicking. +- **Side-channel hardening.** The permutation is built with no secret-dependent memory + addresses, table reads and the comparator are constant-time scans, and the stack an + encryption used is zeroed afterwards so PRP seeds and tables don't linger in memory. +- **Coverage.** `bool`, integers up to 64 bits, `char`, `f32` and `f64` (at most 14 + blocks). `Decimal` stays on `OreAes128`. `u128`/`i128` are supported by neither scheme + (#105). + +**New: chained-prefix scheme (`scheme::chained`) for variable-length data and strings.** +Per-block secrets come from a CMAC accumulator over the prefix, so plaintexts aren't +limited to 14 blocks. Every ciphertext reveals the exact plaintext length; padding is +tracked in #104. + +**Legacy `OreAes128`.** Ciphertexts are byte-for-byte unchanged (pinned by compatibility +vectors). Encryption is much faster (hardware AES on aarch64 and bulk encoding: a `u64` +went from 381 µs to 25.1 µs in the same benchmarks), the comparator is hardened, and +malformed input is refused. The README now documents the scheme's zero-run leakage. + +**Hardware AES on ARM.** On aarch64, including Apple Silicon, the `aes` crate uses +hardware AES only when built with `--cfg aes_armv8`. Downstream projects must set it in +their own build configuration (see the README); without it, AES falls back to software +and is far slower. + ### Benchmarks - black-box every result and input, and record the effect