From 8f9c9fbc8968646bf56950c37707efcabe30b30d Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Wed, 21 Oct 2026 19:21:39 +1100 Subject: [PATCH 1/8] chore(stack-encrypt)!: move to vitaminc 0.8, clww-ore 0.6 and ore-rs 0.10 vitaminc 0.8 seals a fixed-width None as a typed null padded to the length of a Some, which #1298 needs before an optional field can be sealed without showing which rows are absent. Stack Encrypt could not take it on its own: cllw-ore and ore-rs pinned vitaminc-ore 0.6. Their move to vitaminc 0.8 (clww-ore, renamed, and ore-rs 0.10) is cipherstash/ore.rs#132, stacked on #131 and #130, and not yet released, so both come from git at that PR's head until they are on crates.io. What moves: - Order terms encrypt through clww-ore's ClwwOre/ClwwOpe and ore-rs's single BlockOre, opened as vitaminc-ore OrderSpaces. Every ORE, OPE and block ORE term changes (clww-ore's keystream fix and scheme names, BlockOre's key label). Wire formats, this crate's key domains, ciphertexts and equality terms do not; the fixtures and pins re-freeze their order terms only. - Every Sink implements typed_null. Sinks that forward (the frame writers) pass it on; the value model holds a typed null of its own types and refuses a uuid's, as it refuses a uuid. - A null keeps no equality term. vitaminc-normalize 0.8 derives one; it is dropped so absent values keep a SQL NULL until #1298 decides otherwise. - vitaminc-ore 0.7 puts the text marker byte in front itself, so block ORE's 1024-byte ceiling now counts it in the encoding stack-encrypt checks. Refs #1298. Claude-Session: https://claude.ai/code/session_01XQN1QpaWVDGjHEg39KEJF3 --- .github/dependabot.yml | 20 +- AGENTS.md | 10 +- Cargo.lock | 185 +++++++++--------- Cargo.toml | 40 ++-- languages/golang/CHANGELOG.md | 6 + languages/golang/auth/guest/Cargo.lock | 94 ++++----- languages/golang/auth/guest/Cargo.toml | 2 +- languages/golang/encrypt/guest/Cargo.lock | 171 ++++++++-------- languages/golang/encrypt/guest/Cargo.toml | 6 +- .../golang/encrypt/guest/tests/native_ops.rs | 2 +- .../golang/encrypt/guest/tests/support/mod.rs | 8 +- .../golang/stashgen/enginetest/enginetest.go | 4 +- packages/eql/Cargo.lock | 173 ++++++++-------- packages/eql/crates/eql-bindings/Cargo.toml | 2 +- .../crates/eql-bindings/src/v4/plaintext.rs | 3 + packages/eql/tests/encryption/Cargo.toml | 2 +- .../fixtures/v4_ordered_queries.json | 20 +- .../encryption/fixtures/v4_ordered_rows.json | 120 ++++++------ packages/stack-encrypt/CHANGELOG.md | 30 +++ packages/stack-encrypt/Cargo.toml | 10 +- packages/stack-encrypt/fuzz/Cargo.lock | 165 ++++++++-------- packages/stack-encrypt/fuzz/Cargo.toml | 4 +- packages/stack-encrypt/src/codes.rs | 2 +- packages/stack-encrypt/src/dynamic/kind.rs | 4 +- packages/stack-encrypt/src/dynamic/mod.rs | 4 +- packages/stack-encrypt/src/dynamic/term.rs | 31 ++- .../stack-encrypt/src/dynamic/test_frame.rs | 8 +- .../stack-encrypt/src/dynamic/value_frame.rs | 174 +++++++++++++++- packages/stack-encrypt/src/op/mod.rs | 2 +- packages/stack-encrypt/src/sem/mod.rs | 161 +++++++-------- .../stack-encrypt/tests/fixtures/README.md | 2 +- .../tests/fixtures/query_operators.json | 18 +- .../tests/fixtures/record_lowering.json | 16 +- .../tests/fixtures/stored_rows_v1.json | 58 +++--- .../tests/fixtures/value_kinds.json | 26 +-- packages/stack-encrypt/tests/frozen_bytes.rs | 10 +- packages/stack-encrypt/tests/ore_block.rs | 6 +- packages/stack-encrypt/tests/roundtrip.rs | 48 +++++ packages/stack-encrypt/tests/term_bytes.rs | 24 ++- .../ui/order_term_of_an_8_bit_integer.stderr | 4 +- packages/stack-guest-abi/src/value.rs | 9 +- .../dependabot-eql-inherited-ignores.test.mjs | 6 +- 42 files changed, 976 insertions(+), 714 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3b16d3955..3f77563cd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -226,8 +226,9 @@ updates: # stack-encrypt behind its optional `stack-encrypt` feature. Those crates # declare these `{ workspace = true }`, so their requirements come from # the root Cargo.toml even when built here. The root entry below ignores - # them because they move by hand with cipherstash-suite: the root - # manifest pins recipher and cllw-ore with `=`, and so does the Go guest. + # them because they move by hand: the root manifest pins recipher with + # `=`, and so does the Go guest, and takes clww-ore and ore-rs from + # cipherstash/ore.rs at one revision until they are released. # Without these lines this entry bumped them in this lockfile and, to # satisfy the exact pins, rewrote the root Cargo.toml without touching # the root Cargo.lock or the guest's pin, breaking every root `--locked` @@ -238,7 +239,8 @@ updates: # scripts/__tests__/dependabot-eql-inherited-ignores.test.mjs fails when # the root entry ignores a crate this entry does not. - dependency-name: "recipher" - - dependency-name: "cllw-ore" + - dependency-name: "clww-ore" + - dependency-name: "ore-rs" - dependency-name: "zerokms-protocol" - dependency-name: "vitaminc*" # Major bumps are reviewed and applied manually, not by Dependabot. @@ -292,13 +294,17 @@ updates: ignore: # Released from cipherstash-suite: stack-auth's API carries their types, # so they move in lockstep with the suite, by hand. The guests pin them - # with `=`; the root Cargo.toml pins recipher and cllw-ore with `=`, and - # gives cts-common and zerokms-protocol caret requirements. + # with `=`; the root Cargo.toml pins recipher with `=`, and gives + # cts-common and zerokms-protocol caret requirements. - dependency-name: "cts-common" - dependency-name: "zerokms-protocol" - dependency-name: "recipher" - - dependency-name: "cllw-ore" - # vitaminc is pinned at 0.5.0 across the crates and the guests; the + # The order schemes, from cipherstash/ore.rs, moved by hand with + # vitaminc: the root Cargo.toml takes them from git at one revision + # until clww-ore 0.6 and ore-rs 0.10 are released. + - dependency-name: "clww-ore" + - dependency-name: "ore-rs" + # vitaminc is pinned at 0.8.0 across the crates and the guests; the # guests' `ValueFrame: Decrypt` bound fails if two versions resolve. - dependency-name: "vitaminc*" # Major bumps are reviewed and applied manually, not by Dependabot. diff --git a/AGENTS.md b/AGENTS.md index 6e0c3a090..c0cf10b4d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -685,10 +685,12 @@ monorepo, which is where the silent failures are. ## Working on the Rust crates The stack-* crates came from `cipherstash/cipherstash-suite`, which still owns -`cipherstash-client`, `cts-common`, `zerokms-protocol`, `recipher` and -`cllw-ore`. Here those come from crates.io, and `Cargo.lock` holds their -exact versions. In the root `Cargo.toml`, `recipher` and `cllw-ore` are -pinned with `=`. `cts-common` and `zerokms-protocol` take caret +`cipherstash-client`, `cts-common`, `zerokms-protocol` and `recipher`. Here +those come from crates.io, and `Cargo.lock` holds their exact versions. In the +root `Cargo.toml`, `recipher` is pinned with `=`. The order schemes, `clww-ore` +(formerly `cllw-ore`) and `ore-rs`, live in `cipherstash/ore.rs`; until +clww-ore 0.6 and ore-rs 0.10 are released, the root `Cargo.toml` takes them +from git at one revision, which also stops `stack-encrypt` publishing. `cts-common` and `zerokms-protocol` take caret requirements, because the published `stack-auth` inherits them, and an exact pin would stop the suite sharing one `cts-common` with it. diff --git a/Cargo.lock b/Cargo.lock index 8f144b18b..79b6a621f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -521,10 +521,9 @@ dependencies = [ ] [[package]] -name = "cllw-ore" -version = "0.5.2-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb4a774d070a6c2b52175b98273cd7193c61e1bda39c1a98b50b7a2d91375a" +name = "clww-ore" +version = "0.6.0" +source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" dependencies = [ "blake3", "hex", @@ -532,7 +531,7 @@ dependencies = [ "thiserror 1.0.69", "unicode-normalization", "vitaminc-ore", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] @@ -981,7 +980,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1480,7 +1479,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.2", "tokio", "tower-service", "tracing", @@ -2138,7 +2137,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2258,32 +2257,25 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" -[[package]] -name = "orderable-bytes" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7d30b72ffca73d9936fe5fc80a9c9520c73f5b4f64839a810211903d5ace3c" - [[package]] name = "ore-rs" version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1d6cb8c1249643266bd60269547c93d3cd263d5385f1262902bbb295ff9a5e" +source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" dependencies = [ "aes", "block-modes", "byteorder", "hex", "num", - "orderable-bytes", - "rand 0.8.6", - "rand_chacha 0.3.1", + "rand 0.10.1", "subtle-ng", "thiserror 1.0.69", + "vitaminc-context 0.8.0", "vitaminc-hmac", "vitaminc-ore", "vitaminc-prf", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] @@ -2508,7 +2500,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.5.10", + "socket2 0.6.2", "thiserror 2.0.18", "tokio", "tracing", @@ -2547,7 +2539,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.2", "tracing", "windows-sys 0.60.2", ] @@ -2864,7 +2856,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2921,7 +2913,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3310,8 +3302,8 @@ dependencies = [ "tracing-subscriber", "url", "uuid", - "vitaminc 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc 0.8.0", + "vitaminc-protected 0.8.0", "web-time", "zeroize", "zerokms-protocol", @@ -3333,7 +3325,7 @@ dependencies = [ "tempfile", "tokio", "url", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] @@ -3361,7 +3353,7 @@ name = "stack-encrypt" version = "0.3.0" dependencies = [ "base64ct", - "cllw-ore", + "clww-ore", "miette", "ore-rs", "serde", @@ -3373,14 +3365,14 @@ dependencies = [ "tokio", "trybuild", "uuid", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "vitaminc-aead-frame", - "vitaminc-encrypt 0.6.1", + "vitaminc-encrypt 0.8.0", "vitaminc-hmac", "vitaminc-normalize", "vitaminc-ore", "vitaminc-prf", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", "zerokms-protocol", ] @@ -3406,9 +3398,9 @@ dependencies = [ "proptest", "serde_json", "thiserror 1.0.69", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "vitaminc-aead-frame", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] @@ -3441,8 +3433,8 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc 0.8.0", + "vitaminc-protected 0.8.0", "zeroize", "zerokms-protocol", ] @@ -3595,7 +3587,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.5", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -4204,16 +4196,16 @@ dependencies = [ [[package]] name = "vitaminc" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5c15b6c25efcb9a6111f7108ab8101947a7bf7e9af3ff6d6a73358a1ace0da" +checksum = "ea37168a603d605732d0bf0672586139ab91736f767d7b85e173c84dcee19054" dependencies = [ - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", - "vitaminc-encrypt 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", - "vitaminc-traits 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", + "vitaminc-encrypt 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", + "vitaminc-traits 0.8.0", ] [[package]] @@ -4233,18 +4225,18 @@ dependencies = [ [[package]] name = "vitaminc-aead" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b8c5c4ced92545dce5fd7cf04581d08210def174cc81475cf227fa2506c5b7" +checksum = "e9bb97fd543ee6a2b168e257ec69d0d274a775b1eaa3f856b5ac2941b01891c1" dependencies = [ "bytes", "futures-util", "serde", "thiserror 2.0.18", - "vitaminc-aead-derive 0.6.1", - "vitaminc-context 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-aead-derive 0.8.0", + "vitaminc-context 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] @@ -4261,9 +4253,9 @@ dependencies = [ [[package]] name = "vitaminc-aead-derive" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c546497a972d0f0498f2f8d5f537c514bad82df8662951c63d0c80023808900" +checksum = "0845a44c07ddc882ed47a0e92e04fc83496220f054b589ad0cbd215c5009e5b7" dependencies = [ "proc-macro2", "quote", @@ -4272,12 +4264,12 @@ dependencies = [ [[package]] name = "vitaminc-aead-frame" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35992a269bcaa5b201f1938e54bfbf167bfa6fe975d83cbdbdb54c2a363c5ef" +checksum = "3b0299777255171712a296d59164691dc1e93d10bddaab6e248fede1790dfd2e" dependencies = [ "serde", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "zeroize", ] @@ -4293,12 +4285,12 @@ dependencies = [ [[package]] name = "vitaminc-context" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4c4bc2bd9811253eb427657565a45bd4826e2379e93ee1c4d00c808a769882" +checksum = "a630079ba2d50680ee5048addd430eda30613559809dd6d383551e6d3d299826" dependencies = [ "mutants", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", ] [[package]] @@ -4317,71 +4309,72 @@ dependencies = [ [[package]] name = "vitaminc-encrypt" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0923694602855b33a296d9af473e282e8096c1cfe1b30b8695d3b6651717fc5" +checksum = "db45e073f92ae8ca27f8fe14270bc34c75e767559c2347098dacca95180d1ddd" dependencies = [ "aes-gcm", "aws-lc-rs", - "vitaminc-aead 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] [[package]] name = "vitaminc-hmac" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd361f626e95cbe770b9d012e4a86c43cfefe4aefb3d5b3ed9339a83085bdc53" +checksum = "b5fa0ae8bbad85ae30fb5c91b0b72b694d59bf2c2c1e7ad799eda66fdbd67e7c" dependencies = [ "hmac", "sha2 0.11.0", "vitaminc-prf", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] [[package]] name = "vitaminc-normalize" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214b2a9d085924c3bc3c91f3ba74238e8848bf54990e5f48f170c71fbacea07a" +checksum = "f5a2d8875e0b8b35b7a4f9dd698bbd13c989837cea564b5a4cbb5371b78fa937" dependencies = [ "thiserror 2.0.18", "unicode-general-category", "unicode-normalization", - "vitaminc-aead 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-protected 0.8.0", ] [[package]] name = "vitaminc-ore" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed88c54b5f06f2177ecbfb7666812adf645406f6fb555f4e2f0fd7fa218e71c4" +checksum = "f05518b4d35cb0c592dad59afb11b8e883ea252449b9ae47ff5ddeff0ed49f75" dependencies = [ "thiserror 2.0.18", "unicode-general-category", "unicode-normalization", - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", "vitaminc-normalize", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", + "zeroize", ] [[package]] name = "vitaminc-prf" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2715cca25006b4656223bc932ab4fd7f70d387aa4ec63a4e2ef33aa8cd2b3a5" +checksum = "916688478273ca3e5c6805b355534ce9263688391cd4ab23b08bef760039d325" dependencies = [ "mutants", "thiserror 2.0.18", - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", "vitaminc-normalize", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", ] [[package]] @@ -4403,9 +4396,9 @@ dependencies = [ [[package]] name = "vitaminc-protected" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1bb76dd473f5aa89b844f92018ebe3041deb8e5390e7061cca4283d959ff855" +checksum = "a6edc22562a9bbff0ba9704a2c43670b2c7cb1637524c045c3ba6436ed00917f" dependencies = [ "bitvec", "digest 0.11.3", @@ -4414,7 +4407,7 @@ dependencies = [ "serde_bytes", "subtle", "thiserror 2.0.18", - "vitaminc-protected-derive 0.6.1", + "vitaminc-protected-derive 0.8.0", "zeroize", ] @@ -4431,9 +4424,9 @@ dependencies = [ [[package]] name = "vitaminc-protected-derive" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7478ed160c019059746e75fc613563dcdcd5266d155a34601d29377a1c4afc3" +checksum = "a7cce3a7d0ce6f57c0e82345f20e87f3737cccd3a70aec2a2ab49f68a3a5e24a" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4458,16 +4451,16 @@ dependencies = [ [[package]] name = "vitaminc-random" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b477af7c01c3d9ef2647e46952ad3df7f246b3f806b1d4009ee83beecec613a" +checksum = "8bb253f783ce6f31a55a92f5a9f0526109b8caa6a465edb94244fd344a078c11" dependencies = [ "chacha20", "getrandom 0.4.2", "rand 0.10.1", "thiserror 2.0.18", - "vitaminc-protected 0.6.1", - "vitaminc-random-derives 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random-derives 0.8.0", "zeroize", ] @@ -4484,9 +4477,9 @@ dependencies = [ [[package]] name = "vitaminc-random-derives" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5a0de8da428c6789dc067a578a0462e411099721d616736cf29e1622230c35" +checksum = "df0b3615936d6dded4b775856f4b0fa229d745d183f0b3754ac80035f16c27d9" dependencies = [ "proc-macro2", "quote", @@ -4511,17 +4504,17 @@ dependencies = [ [[package]] name = "vitaminc-traits" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a900f0edcacd49c8557ab54722175869fec66926054a6fbdc53a05069db3c922" +checksum = "1e9098ee4b13446ef959583ee2f3c384df571b453179104f7b4960ffddf65ee9" dependencies = [ "anyhow", "bytes", "rmp-serde", "serde", "thiserror 2.0.18", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] @@ -4779,7 +4772,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 01b7861bc..20a9ccda9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,20 +76,22 @@ stack-profile = { path = "./packages/stack-profile", version = "0.43.0" } # cts-common and zerokms-protocol take caret requirements because the # published stack-auth inherits them: an exact pin would stop the suite # unifying stack-auth with a later compatible cts-common, and a second copy -# breaks the shared Crn, Region and WorkspaceId types. recipher and cllw-ore -# feed only unpublished crates, so they stay exact. +# breaks the shared Crn, Region and WorkspaceId types. recipher feeds +# only unpublished crates, so it stays exact. cts-common = { version = "0.43.0", default-features = false } zerokms-protocol = "0.12.31" recipher = "=0.3.1" -# cllw-ore's `vitaminc` feature implements vitaminc-ore's `OrderScheme`, -# which Stack Encrypt's order terms are encrypted through. It first ships -# in a pre-release, and Cargo resolves a pre-release only when named. -cllw-ore = { version = "=0.5.2-rc.1", default-features = false, features = ["vitaminc"] } -# ore-rs's `vitaminc` feature implements the same traits for block ORE: -# `Bit6BlockOre` (fixed width up to ten bytes) and `ChainedBlockOre` +# The two order-preserving schemes Stack Encrypt's order terms encrypt +# through. Both implement vitaminc-ore's `OrderScheme` against vitaminc 0.8: +# `clww-ore` (cllw-ore renamed) for CLWW ORE and OPE, and ore-rs for block +# ORE, `Bit6BlockOre` (fixed width up to ten bytes) and `ChainedBlockOre` # (variable length), the 6-bit schemes EQL v4's `_ord_ore` domains store. -# Both wire formats are frozen as of 0.9.0. ore-rs feeds only stack-encrypt. -ore-rs = { version = "0.9.0", default-features = false, features = ["vitaminc"] } +# vitaminc is a plain dependency of both from here, not a feature. +# UNRELEASED: both come from cipherstash/ore.rs#132 (stacked on #131 and +# #130) until clww-ore 0.6.0 and ore-rs 0.10.0 reach crates.io; then these +# become exact version pins. +clww-ore = { git = "https://github.com/cipherstash/ore.rs", rev = "6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4", default-features = false } +ore-rs = { git = "https://github.com/cipherstash/ore.rs", rev = "6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4", default-features = false } # External dependencies, with the suite's feature lists. base64 = "0.22.0" @@ -136,18 +138,18 @@ web-time = "1.1" zeroize = { version = "1.8.1", features = ["derive"] } # This is needed because lock_api 0.4.6 was breaking things and the branch forces the use of 0.4.12 temp-env = { git = "https://github.com/cipherstash/temp-env", branch = "main" } -vitaminc = { version = "0.6.1", features = ["random", "protected", "encrypt"] } -vitaminc-aead = "0.6.1" +vitaminc = { version = "0.8.0", features = ["random", "protected", "encrypt"] } +vitaminc-aead = "0.8.0" # The transport frame and ciphertext codec every language binding carries # across its FFI boundary. Optional in stack-encrypt (the `dynamic` feature). -vitaminc-aead-frame = "0.6.1" -vitaminc-encrypt = "0.6.1" -vitaminc-hmac = "0.6.1" +vitaminc-aead-frame = "0.8.0" +vitaminc-encrypt = "0.8.0" +vitaminc-hmac = "0.8.0" # Normalized equality terms (Unicode 16 NFC text, one integer encoding for # every width), which `vitaminc-prf`'s `normalize` feature derives over. -vitaminc-normalize = "0.6.1" +vitaminc-normalize = "0.8.0" # The text order key: the system ADR-0002's fold, pinned to Unicode 16, # which text ORE and OPE terms are derived over (ADR-0009). -vitaminc-ore = "0.6.1" -vitaminc-prf = { version = "0.6.1", features = ["normalize"] } -vitaminc-protected = "0.6.1" +vitaminc-ore = "0.8.0" +vitaminc-prf = { version = "0.8.0", features = ["normalize"] } +vitaminc-protected = "0.8.0" diff --git a/languages/golang/CHANGELOG.md b/languages/golang/CHANGELOG.md index 68a877461..ac917da20 100644 --- a/languages/golang/CHANGELOG.md +++ b/languages/golang/CHANGELOG.md @@ -12,6 +12,12 @@ listed under **Breaking**. Releases are tagged `languages/golang/vX.Y.Z`. ### Breaking +- **Every order term changes: re-derive stored `ore`, `ope` and + `ore_block` index terms.** The engine moved to vitaminc 0.8, clww-ore 0.6 + (formerly cllw-ore) and ore-rs 0.10, and both order schemes now derive + different terms for the same value, so a query term no longer compares + with an order term stored before. Ciphertexts and equality terms are + unchanged. - **An `int8`, `int16`, `uint8` or `uint16` sealed field seals at its own width; run stashgen again.** It used to seal as a 32-bit integer. Values stored before do not decrypt under the regenerated declaration: the diff --git a/languages/golang/auth/guest/Cargo.lock b/languages/golang/auth/guest/Cargo.lock index ce1a5e7eb..fd1ccb4c5 100644 --- a/languages/golang/auth/guest/Cargo.lock +++ b/languages/golang/auth/guest/Cargo.lock @@ -1847,8 +1847,8 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc 0.8.0", + "vitaminc-protected 0.8.0", "web-time", "zeroize", "zerokms-protocol", @@ -1867,7 +1867,7 @@ dependencies = [ "stack-profile", "tempfile", "url", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] @@ -1878,9 +1878,9 @@ dependencies = [ "miette", "serde_json", "thiserror 1.0.69", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "vitaminc-aead-frame", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] @@ -2299,16 +2299,16 @@ dependencies = [ [[package]] name = "vitaminc" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5c15b6c25efcb9a6111f7108ab8101947a7bf7e9af3ff6d6a73358a1ace0da" +checksum = "ea37168a603d605732d0bf0672586139ab91736f767d7b85e173c84dcee19054" dependencies = [ - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", - "vitaminc-encrypt 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", - "vitaminc-traits 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", + "vitaminc-encrypt 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", + "vitaminc-traits 0.8.0", ] [[package]] @@ -2328,18 +2328,18 @@ dependencies = [ [[package]] name = "vitaminc-aead" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b8c5c4ced92545dce5fd7cf04581d08210def174cc81475cf227fa2506c5b7" +checksum = "e9bb97fd543ee6a2b168e257ec69d0d274a775b1eaa3f856b5ac2941b01891c1" dependencies = [ "bytes", "futures-util", "serde", "thiserror 2.0.20", - "vitaminc-aead-derive 0.6.1", - "vitaminc-context 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-aead-derive 0.8.0", + "vitaminc-context 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] @@ -2356,9 +2356,9 @@ dependencies = [ [[package]] name = "vitaminc-aead-derive" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c546497a972d0f0498f2f8d5f537c514bad82df8662951c63d0c80023808900" +checksum = "0845a44c07ddc882ed47a0e92e04fc83496220f054b589ad0cbd215c5009e5b7" dependencies = [ "proc-macro2", "quote", @@ -2367,11 +2367,11 @@ dependencies = [ [[package]] name = "vitaminc-aead-frame" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35992a269bcaa5b201f1938e54bfbf167bfa6fe975d83cbdbdb54c2a363c5ef" +checksum = "3b0299777255171712a296d59164691dc1e93d10bddaab6e248fede1790dfd2e" dependencies = [ - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", ] [[package]] @@ -2386,12 +2386,12 @@ dependencies = [ [[package]] name = "vitaminc-context" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4c4bc2bd9811253eb427657565a45bd4826e2379e93ee1c4d00c808a769882" +checksum = "a630079ba2d50680ee5048addd430eda30613559809dd6d383551e6d3d299826" dependencies = [ "mutants", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", ] [[package]] @@ -2410,15 +2410,15 @@ dependencies = [ [[package]] name = "vitaminc-encrypt" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0923694602855b33a296d9af473e282e8096c1cfe1b30b8695d3b6651717fc5" +checksum = "db45e073f92ae8ca27f8fe14270bc34c75e767559c2347098dacca95180d1ddd" dependencies = [ "aes-gcm", "aws-lc-rs", - "vitaminc-aead 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] @@ -2441,9 +2441,9 @@ dependencies = [ [[package]] name = "vitaminc-protected" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1bb76dd473f5aa89b844f92018ebe3041deb8e5390e7061cca4283d959ff855" +checksum = "a6edc22562a9bbff0ba9704a2c43670b2c7cb1637524c045c3ba6436ed00917f" dependencies = [ "bitvec", "digest 0.11.3", @@ -2452,7 +2452,7 @@ dependencies = [ "serde_bytes", "subtle", "thiserror 2.0.20", - "vitaminc-protected-derive 0.6.1", + "vitaminc-protected-derive 0.8.0", "zeroize", ] @@ -2469,9 +2469,9 @@ dependencies = [ [[package]] name = "vitaminc-protected-derive" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7478ed160c019059746e75fc613563dcdcd5266d155a34601d29377a1c4afc3" +checksum = "a7cce3a7d0ce6f57c0e82345f20e87f3737cccd3a70aec2a2ab49f68a3a5e24a" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2496,16 +2496,16 @@ dependencies = [ [[package]] name = "vitaminc-random" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b477af7c01c3d9ef2647e46952ad3df7f246b3f806b1d4009ee83beecec613a" +checksum = "8bb253f783ce6f31a55a92f5a9f0526109b8caa6a465edb94244fd344a078c11" dependencies = [ "chacha20", "getrandom 0.4.3", "rand 0.10.3", "thiserror 2.0.20", - "vitaminc-protected 0.6.1", - "vitaminc-random-derives 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random-derives 0.8.0", "zeroize", ] @@ -2522,9 +2522,9 @@ dependencies = [ [[package]] name = "vitaminc-random-derives" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5a0de8da428c6789dc067a578a0462e411099721d616736cf29e1622230c35" +checksum = "df0b3615936d6dded4b775856f4b0fa229d745d183f0b3754ac80035f16c27d9" dependencies = [ "proc-macro2", "quote", @@ -2549,17 +2549,17 @@ dependencies = [ [[package]] name = "vitaminc-traits" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a900f0edcacd49c8557ab54722175869fec66926054a6fbdc53a05069db3c922" +checksum = "1e9098ee4b13446ef959583ee2f3c384df571b453179104f7b4960ffddf65ee9" dependencies = [ "anyhow", "bytes", "rmp-serde", "serde", "thiserror 2.0.20", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] diff --git a/languages/golang/auth/guest/Cargo.toml b/languages/golang/auth/guest/Cargo.toml index df3ce1563..8ffa0937d 100644 --- a/languages/golang/auth/guest/Cargo.toml +++ b/languages/golang/auth/guest/Cargo.toml @@ -48,7 +48,7 @@ zeroize = { version = "1", features = ["derive"] } serde_json = "1" tempfile = "3" # `Controlled::risky_ref`, to read a codec value back in the tests. -vitaminc-protected = "0.6.0" +vitaminc-protected = "0.8.0" [profile.release] # Smaller .wasm; the guest is IO-bound on the FFI copy and the file reads, diff --git a/languages/golang/encrypt/guest/Cargo.lock b/languages/golang/encrypt/guest/Cargo.lock index f9bc1224b..ffd0125f1 100644 --- a/languages/golang/encrypt/guest/Cargo.lock +++ b/languages/golang/encrypt/guest/Cargo.lock @@ -350,10 +350,9 @@ dependencies = [ ] [[package]] -name = "cllw-ore" -version = "0.5.2-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb4a774d070a6c2b52175b98273cd7193c61e1bda39c1a98b50b7a2d91375a" +name = "clww-ore" +version = "0.6.0" +source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" dependencies = [ "blake3", "hex", @@ -361,7 +360,7 @@ dependencies = [ "thiserror 1.0.69", "unicode-normalization", "vitaminc-ore", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] @@ -724,7 +723,7 @@ dependencies = [ "stack-encrypt", "thiserror 2.0.20", "ts-rs", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "zeroize", ] @@ -1457,32 +1456,25 @@ dependencies = [ "libc", ] -[[package]] -name = "orderable-bytes" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7d30b72ffca73d9936fe5fc80a9c9520c73f5b4f64839a810211903d5ace3c" - [[package]] name = "ore-rs" version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1d6cb8c1249643266bd60269547c93d3cd263d5385f1262902bbb295ff9a5e" +source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" dependencies = [ "aes", "block-modes", "byteorder", "hex", "num", - "orderable-bytes", - "rand 0.8.8", - "rand_chacha 0.3.1", + "rand 0.10.2", "subtle-ng", "thiserror 1.0.69", + "vitaminc-context 0.8.0", "vitaminc-hmac", "vitaminc-ore", "vitaminc-prf", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] @@ -2151,8 +2143,8 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc 0.8.0", + "vitaminc-protected 0.8.0", "web-time", "zeroize", "zerokms-protocol", @@ -2163,7 +2155,7 @@ name = "stack-encrypt" version = "0.3.0" dependencies = [ "base64ct", - "cllw-ore", + "clww-ore", "miette", "ore-rs", "serde", @@ -2172,14 +2164,14 @@ dependencies = [ "stack-kms", "thiserror 1.0.69", "uuid", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "vitaminc-aead-frame", - "vitaminc-encrypt 0.6.1", + "vitaminc-encrypt 0.8.0", "vitaminc-hmac", "vitaminc-normalize", "vitaminc-ore", "vitaminc-prf", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] @@ -2208,9 +2200,9 @@ dependencies = [ "stack-guest-abi", "stack-kms", "uuid", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "vitaminc-aead-frame", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", "zerokms-protocol", ] @@ -2222,9 +2214,9 @@ dependencies = [ "miette", "serde_json", "thiserror 1.0.69", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "vitaminc-aead-frame", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] @@ -2250,8 +2242,8 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc 0.8.0", + "vitaminc-protected 0.8.0", "zeroize", "zerokms-protocol", ] @@ -2726,16 +2718,16 @@ dependencies = [ [[package]] name = "vitaminc" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5c15b6c25efcb9a6111f7108ab8101947a7bf7e9af3ff6d6a73358a1ace0da" +checksum = "ea37168a603d605732d0bf0672586139ab91736f767d7b85e173c84dcee19054" dependencies = [ - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", - "vitaminc-encrypt 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", - "vitaminc-traits 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", + "vitaminc-encrypt 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", + "vitaminc-traits 0.8.0", ] [[package]] @@ -2755,18 +2747,18 @@ dependencies = [ [[package]] name = "vitaminc-aead" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b8c5c4ced92545dce5fd7cf04581d08210def174cc81475cf227fa2506c5b7" +checksum = "e9bb97fd543ee6a2b168e257ec69d0d274a775b1eaa3f856b5ac2941b01891c1" dependencies = [ "bytes", "futures-util", "serde", "thiserror 2.0.20", - "vitaminc-aead-derive 0.6.1", - "vitaminc-context 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-aead-derive 0.8.0", + "vitaminc-context 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] @@ -2783,9 +2775,9 @@ dependencies = [ [[package]] name = "vitaminc-aead-derive" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c546497a972d0f0498f2f8d5f537c514bad82df8662951c63d0c80023808900" +checksum = "0845a44c07ddc882ed47a0e92e04fc83496220f054b589ad0cbd215c5009e5b7" dependencies = [ "proc-macro2", "quote", @@ -2794,12 +2786,12 @@ dependencies = [ [[package]] name = "vitaminc-aead-frame" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35992a269bcaa5b201f1938e54bfbf167bfa6fe975d83cbdbdb54c2a363c5ef" +checksum = "3b0299777255171712a296d59164691dc1e93d10bddaab6e248fede1790dfd2e" dependencies = [ "serde", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "zeroize", ] @@ -2815,12 +2807,12 @@ dependencies = [ [[package]] name = "vitaminc-context" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4c4bc2bd9811253eb427657565a45bd4826e2379e93ee1c4d00c808a769882" +checksum = "a630079ba2d50680ee5048addd430eda30613559809dd6d383551e6d3d299826" dependencies = [ "mutants", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", ] [[package]] @@ -2839,71 +2831,72 @@ dependencies = [ [[package]] name = "vitaminc-encrypt" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0923694602855b33a296d9af473e282e8096c1cfe1b30b8695d3b6651717fc5" +checksum = "db45e073f92ae8ca27f8fe14270bc34c75e767559c2347098dacca95180d1ddd" dependencies = [ "aes-gcm", "aws-lc-rs", - "vitaminc-aead 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] [[package]] name = "vitaminc-hmac" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd361f626e95cbe770b9d012e4a86c43cfefe4aefb3d5b3ed9339a83085bdc53" +checksum = "b5fa0ae8bbad85ae30fb5c91b0b72b694d59bf2c2c1e7ad799eda66fdbd67e7c" dependencies = [ "hmac", "sha2 0.11.0", "vitaminc-prf", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] [[package]] name = "vitaminc-normalize" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214b2a9d085924c3bc3c91f3ba74238e8848bf54990e5f48f170c71fbacea07a" +checksum = "f5a2d8875e0b8b35b7a4f9dd698bbd13c989837cea564b5a4cbb5371b78fa937" dependencies = [ "thiserror 2.0.20", "unicode-general-category", "unicode-normalization", - "vitaminc-aead 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-protected 0.8.0", ] [[package]] name = "vitaminc-ore" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed88c54b5f06f2177ecbfb7666812adf645406f6fb555f4e2f0fd7fa218e71c4" +checksum = "f05518b4d35cb0c592dad59afb11b8e883ea252449b9ae47ff5ddeff0ed49f75" dependencies = [ "thiserror 2.0.20", "unicode-general-category", "unicode-normalization", - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", "vitaminc-normalize", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", + "zeroize", ] [[package]] name = "vitaminc-prf" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2715cca25006b4656223bc932ab4fd7f70d387aa4ec63a4e2ef33aa8cd2b3a5" +checksum = "916688478273ca3e5c6805b355534ce9263688391cd4ab23b08bef760039d325" dependencies = [ "mutants", "thiserror 2.0.20", - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", "vitaminc-normalize", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", ] [[package]] @@ -2925,9 +2918,9 @@ dependencies = [ [[package]] name = "vitaminc-protected" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1bb76dd473f5aa89b844f92018ebe3041deb8e5390e7061cca4283d959ff855" +checksum = "a6edc22562a9bbff0ba9704a2c43670b2c7cb1637524c045c3ba6436ed00917f" dependencies = [ "bitvec", "digest 0.11.3", @@ -2936,7 +2929,7 @@ dependencies = [ "serde_bytes", "subtle", "thiserror 2.0.20", - "vitaminc-protected-derive 0.6.1", + "vitaminc-protected-derive 0.8.0", "zeroize", ] @@ -2953,9 +2946,9 @@ dependencies = [ [[package]] name = "vitaminc-protected-derive" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7478ed160c019059746e75fc613563dcdcd5266d155a34601d29377a1c4afc3" +checksum = "a7cce3a7d0ce6f57c0e82345f20e87f3737cccd3a70aec2a2ab49f68a3a5e24a" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2980,16 +2973,16 @@ dependencies = [ [[package]] name = "vitaminc-random" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b477af7c01c3d9ef2647e46952ad3df7f246b3f806b1d4009ee83beecec613a" +checksum = "8bb253f783ce6f31a55a92f5a9f0526109b8caa6a465edb94244fd344a078c11" dependencies = [ "chacha20", "getrandom 0.4.3", "rand 0.10.2", "thiserror 2.0.20", - "vitaminc-protected 0.6.1", - "vitaminc-random-derives 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random-derives 0.8.0", "zeroize", ] @@ -3006,9 +2999,9 @@ dependencies = [ [[package]] name = "vitaminc-random-derives" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5a0de8da428c6789dc067a578a0462e411099721d616736cf29e1622230c35" +checksum = "df0b3615936d6dded4b775856f4b0fa229d745d183f0b3754ac80035f16c27d9" dependencies = [ "proc-macro2", "quote", @@ -3033,17 +3026,17 @@ dependencies = [ [[package]] name = "vitaminc-traits" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a900f0edcacd49c8557ab54722175869fec66926054a6fbdc53a05069db3c922" +checksum = "1e9098ee4b13446ef959583ee2f3c384df571b453179104f7b4960ffddf65ee9" dependencies = [ "anyhow", "bytes", "rmp-serde", "serde", "thiserror 2.0.20", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] diff --git a/languages/golang/encrypt/guest/Cargo.toml b/languages/golang/encrypt/guest/Cargo.toml index e39ab37b0..4117a0d65 100644 --- a/languages/golang/encrypt/guest/Cargo.toml +++ b/languages/golang/encrypt/guest/Cargo.toml @@ -66,8 +66,8 @@ zerokms-protocol = "=0.12.31" # against (see the comment in packages/stack-encrypt/Cargo.toml). A # different version here fails at the `ValueFrame: Decrypt` bound, since the # aead crate would be duplicated. -vitaminc-aead-frame = { version = "0.6.1", features = ["serde"] } -vitaminc-protected = "0.6.1" +vitaminc-aead-frame = { version = "0.8.0", features = ["serde"] } +vitaminc-protected = "0.8.0" futures = { version = "0.3", default-features = false, features = ["executor"] } serde = "1" @@ -77,7 +77,7 @@ zeroize = "1" [dev-dependencies] # The test tree (`tests/support`) walks values through vitaminc's sinks. -vitaminc-aead = "0.6.1" +vitaminc-aead = "0.8.0" stack-kms = { path = "../../../../packages/stack-kms", default-features = false, features = ["test-support"] } # For minting a valid client-key fixture in the config tests. recipher = "=0.3.1" diff --git a/languages/golang/encrypt/guest/tests/native_ops.rs b/languages/golang/encrypt/guest/tests/native_ops.rs index c386c6e37..57ba01223 100644 --- a/languages/golang/encrypt/guest/tests/native_ops.rs +++ b/languages/golang/encrypt/guest/tests/native_ops.rs @@ -330,7 +330,7 @@ fn guest_terms_match_the_native_sem_derivations() { .expect("native"); assert_eq!(eq_bytes, native_bytes.as_bytes()); - // Variable-width CLLW output for strings: the text behind cllw-ore's + // Variable-width CLLW output for strings: the text behind clww-ore's // one marker byte, eight bytes a plaintext byte. let ore_s = block_on(ops::term( &cipher.default_keyset(), diff --git a/languages/golang/encrypt/guest/tests/support/mod.rs b/languages/golang/encrypt/guest/tests/support/mod.rs index 37a91fa3b..17e0fa4f1 100644 --- a/languages/golang/encrypt/guest/tests/support/mod.rs +++ b/languages/golang/encrypt/guest/tests/support/mod.rs @@ -11,8 +11,8 @@ use vitaminc_aead::frame::{FrameError, FrameWriteError}; use vitaminc_aead::plaintext::{ - visit_map, visit_seq, Error as _, Float, Int, Logical, MapSink, Physical, SeqSink, Sink, - SourceError, + visit_map, visit_seq, Error as _, FixedType, Float, Int, Logical, MapSink, Physical, SeqSink, + Sink, SourceError, }; use vitaminc_aead::{to_frame, DecodeError, Decrypt, Encrypt, Frame}; use vitaminc_protected::{Controlled, Protected}; @@ -273,6 +273,10 @@ impl Sink for TreeSink { Ok(self.0.put(value)) } + fn typed_null(self, _: FixedType) -> Result { + Ok(self.0.put(Tree::Null)) + } + fn seq(self, _: Option) -> Result, DecodeError> { Ok(TreeSeq { out: self.0, diff --git a/languages/golang/stashgen/enginetest/enginetest.go b/languages/golang/stashgen/enginetest/enginetest.go index 61be14f85..44f5e97b8 100644 --- a/languages/golang/stashgen/enginetest/enginetest.go +++ b/languages/golang/stashgen/enginetest/enginetest.go @@ -241,7 +241,7 @@ func eightBit(t stashgen.GoType) bool { // floats, text and bytes. Not over a boolean or an 8-bit integer, whose // order term would reveal which rows are true, or each row's rank among 256 // values; and not yet over a decimal, date or timestamp, whose order terms -// wait for new cllw-ore and ore-rs releases (#1236). The JSON index is not +// wait for new clww-ore and ore-rs releases (#1236). The JSON index is not // in the engine yet. func indexApplies(name stashgen.IndexName, t stashgen.GoType) error { switch name { @@ -263,7 +263,7 @@ func indexApplies(name stashgen.IndexName, t stashgen.GoType) error { case stashgen.KindString, stashgen.KindBytes, stashgen.KindFloat: return nil case stashgen.KindDecimal, stashgen.KindDate, stashgen.KindTimestamp: - return fmt.Errorf("an order index on a decimal, date or timestamp waits for new cllw-ore and ore-rs releases (#1236)") + return fmt.Errorf("an order index on a decimal, date or timestamp waits for new clww-ore and ore-rs releases (#1236)") } if integer(t) && !eightBit(t) { return nil diff --git a/packages/eql/Cargo.lock b/packages/eql/Cargo.lock index a7012b2a1..265c16b21 100644 --- a/packages/eql/Cargo.lock +++ b/packages/eql/Cargo.lock @@ -570,7 +570,7 @@ dependencies = [ "chrono", "cipherstash-config", "cipherstash-core", - "cllw-ore 0.4.2", + "cllw-ore", "cts-common 0.42.3", "derive_more 1.0.0", "dirs", @@ -582,7 +582,7 @@ dependencies = [ "log", "miette", "opaque-debug", - "orderable-bytes 0.1.1", + "orderable-bytes", "ore-rs 0.8.3", "percent-encoding", "rand 0.8.6", @@ -650,7 +650,7 @@ dependencies = [ "blake3", "chrono", "hex", - "orderable-bytes 0.1.1", + "orderable-bytes", "rust_decimal", "subtle", "thiserror 1.0.69", @@ -658,10 +658,9 @@ dependencies = [ ] [[package]] -name = "cllw-ore" -version = "0.5.2-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb4a774d070a6c2b52175b98273cd7193c61e1bda39c1a98b50b7a2d91375a" +name = "clww-ore" +version = "0.6.0" +source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" dependencies = [ "blake3", "hex", @@ -669,7 +668,7 @@ dependencies = [ "thiserror 1.0.69", "unicode-normalization", "vitaminc-ore", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] @@ -1209,7 +1208,7 @@ dependencies = [ "stack-encrypt", "thiserror 2.0.20", "ts-rs", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "zeroize", ] @@ -1252,7 +1251,7 @@ dependencies = [ "stack-kms", "tokio", "uuid", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", ] [[package]] @@ -2667,12 +2666,6 @@ dependencies = [ "rust_decimal", ] -[[package]] -name = "orderable-bytes" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7d30b72ffca73d9936fe5fc80a9c9520c73f5b4f64839a810211903d5ace3c" - [[package]] name = "ore-rs" version = "0.8.3" @@ -2686,7 +2679,7 @@ dependencies = [ "hex", "lazy_static", "num", - "orderable-bytes 0.1.1", + "orderable-bytes", "rand 0.8.6", "rand_chacha 0.3.1", "rust_decimal", @@ -2698,23 +2691,22 @@ dependencies = [ [[package]] name = "ore-rs" version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1d6cb8c1249643266bd60269547c93d3cd263d5385f1262902bbb295ff9a5e" +source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" dependencies = [ "aes", "block-modes", "byteorder", "hex", "num", - "orderable-bytes 0.2.1", - "rand 0.8.6", - "rand_chacha 0.3.1", + "rand 0.10.1", "subtle-ng", "thiserror 1.0.69", + "vitaminc-context 0.8.0", "vitaminc-hmac", "vitaminc-ore", "vitaminc-prf", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] @@ -4254,8 +4246,8 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc 0.8.0", + "vitaminc-protected 0.8.0", "web-time", "zeroize", "zerokms-protocol", @@ -4266,7 +4258,7 @@ name = "stack-encrypt" version = "0.3.0" dependencies = [ "base64ct", - "cllw-ore 0.5.2-rc.1", + "clww-ore", "miette", "ore-rs 0.9.0", "serde", @@ -4275,14 +4267,14 @@ dependencies = [ "stack-kms", "thiserror 1.0.69", "uuid", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "vitaminc-aead-frame", - "vitaminc-encrypt 0.6.1", + "vitaminc-encrypt 0.8.0", "vitaminc-hmac", "vitaminc-normalize", "vitaminc-ore", "vitaminc-prf", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] @@ -4317,8 +4309,8 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc 0.8.0", + "vitaminc-protected 0.8.0", "zeroize", "zerokms-protocol", ] @@ -5083,16 +5075,16 @@ dependencies = [ [[package]] name = "vitaminc" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5c15b6c25efcb9a6111f7108ab8101947a7bf7e9af3ff6d6a73358a1ace0da" +checksum = "ea37168a603d605732d0bf0672586139ab91736f767d7b85e173c84dcee19054" dependencies = [ - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", - "vitaminc-encrypt 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", - "vitaminc-traits 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", + "vitaminc-encrypt 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", + "vitaminc-traits 0.8.0", ] [[package]] @@ -5125,9 +5117,9 @@ dependencies = [ [[package]] name = "vitaminc-aead" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b8c5c4ced92545dce5fd7cf04581d08210def174cc81475cf227fa2506c5b7" +checksum = "e9bb97fd543ee6a2b168e257ec69d0d274a775b1eaa3f856b5ac2941b01891c1" dependencies = [ "bytes", "chrono", @@ -5135,10 +5127,10 @@ dependencies = [ "rust_decimal", "serde", "thiserror 2.0.20", - "vitaminc-aead-derive 0.6.1", - "vitaminc-context 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-aead-derive 0.8.0", + "vitaminc-context 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] @@ -5155,9 +5147,9 @@ dependencies = [ [[package]] name = "vitaminc-aead-derive" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c546497a972d0f0498f2f8d5f537c514bad82df8662951c63d0c80023808900" +checksum = "0845a44c07ddc882ed47a0e92e04fc83496220f054b589ad0cbd215c5009e5b7" dependencies = [ "proc-macro2", "quote", @@ -5166,12 +5158,12 @@ dependencies = [ [[package]] name = "vitaminc-aead-frame" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35992a269bcaa5b201f1938e54bfbf167bfa6fe975d83cbdbdb54c2a363c5ef" +checksum = "3b0299777255171712a296d59164691dc1e93d10bddaab6e248fede1790dfd2e" dependencies = [ "serde", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "zeroize", ] @@ -5187,12 +5179,12 @@ dependencies = [ [[package]] name = "vitaminc-context" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4c4bc2bd9811253eb427657565a45bd4826e2379e93ee1c4d00c808a769882" +checksum = "a630079ba2d50680ee5048addd430eda30613559809dd6d383551e6d3d299826" dependencies = [ "mutants", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", ] [[package]] @@ -5225,71 +5217,72 @@ dependencies = [ [[package]] name = "vitaminc-encrypt" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0923694602855b33a296d9af473e282e8096c1cfe1b30b8695d3b6651717fc5" +checksum = "db45e073f92ae8ca27f8fe14270bc34c75e767559c2347098dacca95180d1ddd" dependencies = [ "aes-gcm", "aws-lc-rs", - "vitaminc-aead 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] [[package]] name = "vitaminc-hmac" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd361f626e95cbe770b9d012e4a86c43cfefe4aefb3d5b3ed9339a83085bdc53" +checksum = "b5fa0ae8bbad85ae30fb5c91b0b72b694d59bf2c2c1e7ad799eda66fdbd67e7c" dependencies = [ "hmac 0.13.0", "sha2 0.11.0", "vitaminc-prf", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] [[package]] name = "vitaminc-normalize" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214b2a9d085924c3bc3c91f3ba74238e8848bf54990e5f48f170c71fbacea07a" +checksum = "f5a2d8875e0b8b35b7a4f9dd698bbd13c989837cea564b5a4cbb5371b78fa937" dependencies = [ "thiserror 2.0.20", "unicode-general-category", "unicode-normalization", - "vitaminc-aead 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-protected 0.8.0", ] [[package]] name = "vitaminc-ore" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed88c54b5f06f2177ecbfb7666812adf645406f6fb555f4e2f0fd7fa218e71c4" +checksum = "f05518b4d35cb0c592dad59afb11b8e883ea252449b9ae47ff5ddeff0ed49f75" dependencies = [ "thiserror 2.0.20", "unicode-general-category", "unicode-normalization", - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", "vitaminc-normalize", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", + "zeroize", ] [[package]] name = "vitaminc-prf" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2715cca25006b4656223bc932ab4fd7f70d387aa4ec63a4e2ef33aa8cd2b3a5" +checksum = "916688478273ca3e5c6805b355534ce9263688391cd4ab23b08bef760039d325" dependencies = [ "mutants", "thiserror 2.0.20", - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", "vitaminc-normalize", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", ] [[package]] @@ -5326,9 +5319,9 @@ dependencies = [ [[package]] name = "vitaminc-protected" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1bb76dd473f5aa89b844f92018ebe3041deb8e5390e7061cca4283d959ff855" +checksum = "a6edc22562a9bbff0ba9704a2c43670b2c7cb1637524c045c3ba6436ed00917f" dependencies = [ "bitvec", "digest 0.11.3", @@ -5337,7 +5330,7 @@ dependencies = [ "serde_bytes", "subtle", "thiserror 2.0.20", - "vitaminc-protected-derive 0.6.1", + "vitaminc-protected-derive 0.8.0", "zeroize", ] @@ -5365,9 +5358,9 @@ dependencies = [ [[package]] name = "vitaminc-protected-derive" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7478ed160c019059746e75fc613563dcdcd5266d155a34601d29377a1c4afc3" +checksum = "a7cce3a7d0ce6f57c0e82345f20e87f3737cccd3a70aec2a2ab49f68a3a5e24a" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -5406,16 +5399,16 @@ dependencies = [ [[package]] name = "vitaminc-random" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b477af7c01c3d9ef2647e46952ad3df7f246b3f806b1d4009ee83beecec613a" +checksum = "8bb253f783ce6f31a55a92f5a9f0526109b8caa6a465edb94244fd344a078c11" dependencies = [ "chacha20", "getrandom 0.4.2", "rand 0.10.1", "thiserror 2.0.20", - "vitaminc-protected 0.6.1", - "vitaminc-random-derives 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random-derives 0.8.0", "zeroize", ] @@ -5443,9 +5436,9 @@ dependencies = [ [[package]] name = "vitaminc-random-derives" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5a0de8da428c6789dc067a578a0462e411099721d616736cf29e1622230c35" +checksum = "df0b3615936d6dded4b775856f4b0fa229d745d183f0b3754ac80035f16c27d9" dependencies = [ "proc-macro2", "quote", @@ -5486,17 +5479,17 @@ dependencies = [ [[package]] name = "vitaminc-traits" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a900f0edcacd49c8557ab54722175869fec66926054a6fbdc53a05069db3c922" +checksum = "1e9098ee4b13446ef959583ee2f3c384df571b453179104f7b4960ffddf65ee9" dependencies = [ "anyhow", "bytes", "rmp-serde", "serde", "thiserror 2.0.20", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] diff --git a/packages/eql/crates/eql-bindings/Cargo.toml b/packages/eql/crates/eql-bindings/Cargo.toml index 0e4be7dab..4e12db75c 100644 --- a/packages/eql/crates/eql-bindings/Cargo.toml +++ b/packages/eql/crates/eql-bindings/Cargo.toml @@ -57,7 +57,7 @@ thiserror = { version = "2", optional = true } # and decimal plaintexts (`v4::plaintext`) describe themselves with, and # vitaminc's range checks for them. The version Stack Encrypt uses, so the # traits are the ones it calls. -vitaminc-aead = { version = "0.6.0", optional = true } +vitaminc-aead = { version = "0.8.0", optional = true } # The `chrono` and `rust_decimal` features: conversions between those # crates' types and `v4::plaintext`'s. chrono = { version = "0.4.44", optional = true, default-features = false } diff --git a/packages/eql/crates/eql-bindings/src/v4/plaintext.rs b/packages/eql/crates/eql-bindings/src/v4/plaintext.rs index de602810c..7af87f6ad 100644 --- a/packages/eql/crates/eql-bindings/src/v4/plaintext.rs +++ b/packages/eql/crates/eql-bindings/src/v4/plaintext.rs @@ -481,6 +481,9 @@ mod tests { }, )) } + fn typed_null(self, ty: vitaminc_aead::FixedType) -> Result { + Ok((ty.logical(), None)) + } fn seq(self, _: Option) -> Result { unreachable!("a plaintext here is a scalar") } diff --git a/packages/eql/tests/encryption/Cargo.toml b/packages/eql/tests/encryption/Cargo.toml index 6ee6ec13c..8ee6acd08 100644 --- a/packages/eql/tests/encryption/Cargo.toml +++ b/packages/eql/tests/encryption/Cargo.toml @@ -31,7 +31,7 @@ stack-encrypt = { path = "../../../stack-encrypt", default-features = false, fea # `plaintext::Sink`, for a plaintext type with its own `Encrypt` impl; and # chrono's and rust_decimal's own sources, which seal the leaf a date, # timestamp or decimal from any other producer seals. -vitaminc-aead = { version = "0.6.0", features = ["chrono", "rust_decimal"] } +vitaminc-aead = { version = "0.8.0", features = ["chrono", "rust_decimal"] } chrono = { version = "0.4.44", default-features = false, features = ["std"] } rust_decimal = { version = "1", default-features = false, features = ["std"] } stack-kms = { path = "../../../stack-kms", default-features = false, features = ["test-support"] } diff --git a/packages/eql/tests/encryption/fixtures/v4_ordered_queries.json b/packages/eql/tests/encryption/fixtures/v4_ordered_queries.json index a494c0791..f0e20d5a3 100644 --- a/packages/eql/tests/encryption/fixtures/v4_ordered_queries.json +++ b/packages/eql/tests/encryption/fixtures/v4_ordered_queries.json @@ -2,43 +2,43 @@ "_comment": "The v4 query operands eql-bindings derives for one plaintext of each OPE-ordered type under FakeDataKeySource's index key (keyset nil), read by the Go SDK's hermetic test; regenerate with EQL_UPDATE_FIXTURES=1, do not edit.", "floor": { "plaintext": -3, - "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"floor\"},\"op\":\"0068773fbf20d83c18c9e2c158d14a9601d12eab933e59d10e163110e4f030377b\"}" + "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"floor\"},\"op\":\"00ef8ea3833a80e22d0add60fdbcf250c26a3ce5ca10d6bb890804e19e4458fb1b\"}" }, "handle": { "plaintext": "carol", - "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"handle\"},\"hm\":\"30fca14a65e5695fc96bd9fc7e3747afe79c7ff2993d532e3ad97f8e8b95ffac\",\"op\":\"00e169c8297d7be0a24e597d20e140b6a098c488dda2a5fab8b1a7071ff703df7f0880519d1ea23890b5c6a01066f62633\"}" + "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"handle\"},\"hm\":\"30fca14a65e5695fc96bd9fc7e3747afe79c7ff2993d532e3ad97f8e8b95ffac\",\"op\":\"0050d344117a1ebd003b5c7a95186c8d46a9bb20ff555f86bdd726ffb033a113b8daae3b210a878df9b37e0f48f6cd9b97\"}" }, "level": { "plaintext": 10, - "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"level\"},\"op\":\"0159d19c111791f639ba0638692ca6f6c53ecac713e356a7e8bf95fc2d839691f4\"}" + "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"level\"},\"op\":\"0175ce2d2193c247e19cdeeaf00c3aa33f8f41ae2ae07ea8f54907726ef81d76c6\"}" }, "mean": { "plaintext": 0.0, - "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"mean\"},\"op\":\"017bc9729378e320ff0c1504dc995074a7db7b05d24bed8a923f6944899e4517d213bba21ee639bb01063902e92cad61b3f3b0755b0dacc66fa5188b434c455360\"}" + "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"mean\"},\"op\":\"0092c35e5c06045d306925d152beb010ac631de046e645a8fc36d9809494f97d17931a4e97b083f7725796c282b7aaa3c6a483634026a4ef01c14c9ec5f7d48743\"}" }, "pace": { "plaintext": -0.5, - "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"pace\"},\"op\":\"00028af974e429d69504e291c6615487c98d3abbaf6a36a012b22bd60ddb569ba83f09243bb5f22d9df419926a7b9e31c7c4411c822471fd427c7a74ac57df0482\"}" + "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"pace\"},\"op\":\"00fc1eaf0613a705488a607f2415941128f4675696e63176b0747adb930727be4c77852c13c8ecf605cffa93d0ae8c0a39e23d295e17f8d87e78996a4d49fd9ea0\"}" }, "points": { "plaintext": 5000000000, - "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"points\"},\"op\":\"0124da6c76e6a9d3572f27a08b17b843e6581a23213f34fea500706db6d0edf539fee6624d544ab352bbfcd0987056c61e7e2b808fcb36eef07e673ec3639e4235\"}" + "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"points\"},\"op\":\"00cee5592b12ad2e56642aea465a82520c4975a84e5e423871fd8c293684946167de3bf467704da5d857f93dd27c836494e7a208adad194349f0c37e05a0f60156\"}" }, "score": { "plaintext": 9.75, - "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"score\"},\"op\":\"00cf2820721cd8c187f434f8986fd01c7eb126c713b0619086b0ca6d0b2120f8d322bbc60d5e40ac640ec49f271c0894a6965ab22b7da190f2e2af8f157a7b503f\"}" + "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"score\"},\"op\":\"0130440c006ce9cfd5eaae7c256850391359737687b73654638245f850c248cdc5b048baf4ea157de1a7ba1da432b34ce8db6242944a1487c8650b12ed349aff2d\"}" }, "speed": { "plaintext": 2.5, - "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"speed\"},\"op\":\"00bbc2ac417a8cb6a4b5b69c9f81223f9016f7ffc9e250417dd5afa5cfd4844dac6f9f72bf972a4aba57ae0f7e64bc7ce315095aab620f1f0f7a567d525837af8c\"}" + "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"speed\"},\"op\":\"00eb900ca25552ce78eaef5e2496345a98454225f1b19c906a2e7aeb3c52c3fe559b518926897a71ef5b835ae2d445d30274ac3b4bca05c2cba135065fd0581e42\"}" }, "table": "rankings", "title": { "plaintext": "Mango", - "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"title\"},\"hm\":\"5d14d6d4a7e93c15cf6b7a0e92dc102adbfcbfb7c0492ad09d6b1938bafb748b\",\"op\":\"00344fe120b7abb89fdad4d2ace56e65d225dc12e1f08841a86ad18728afb74d36c3bdd298ed9a2e94e98a2e9328a2fa76\"}" + "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"title\"},\"hm\":\"5d14d6d4a7e93c15cf6b7a0e92dc102adbfcbfb7c0492ad09d6b1938bafb748b\",\"op\":\"00e162e4c13c10a383ee7c6728a616e1e72458a7cc35c5204061bf8f01800520009adea5aca7256ecb6b5a1f95ebfa4fcd\"}" }, "total": { "plaintext": -1, - "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"total\"},\"op\":\"007152e605e2cc13823bd1379c7733939403474f5dfe1a65fa73eb63ea134f4a0505668fc80076fb24aaefd4763b1d1a2be9bf875178cf8f4abdbdce276f071ed9\"}" + "query": "{\"v\":4,\"i\":{\"t\":\"rankings\",\"c\":\"total\"},\"op\":\"00fd575c3250caeb1c5e8c45e48cd4ad8ef38eec0d52d6fd9fcf6f53c01dc212fcb747d609ddf4585907072d7fbd9bf29b59314a2d30ef33f1ac857c803ac46bfb\"}" } } diff --git a/packages/eql/tests/encryption/fixtures/v4_ordered_rows.json b/packages/eql/tests/encryption/fixtures/v4_ordered_rows.json index 4fa6224dc..df4e74565 100644 --- a/packages/eql/tests/encryption/fixtures/v4_ordered_rows.json +++ b/packages/eql/tests/encryption/fixtures/v4_ordered_rows.json @@ -24,8 +24,8 @@ "t": "rankings", "c": "floor" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAABn4yMF67G89OFjQZZuk7z/IAAPy1eGXRyPxy1IfAwzQCPlOMdditoc/8fNRNI2Iw3VQwJX+YR4eii1fcxB+KJtUD2cDQHwylkneQqa8OgbYJYiWTc=", - "op": "0068773fbf20d83c18c9e2c158d14a9601d12eab933e59d10e16311064f92eac47" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAABn4yMF67G89OFjQZZuk7z/IAAPy1eGXRyPxy1IfAwzQCPlOMdditoc/8fNRNI2Iw3VQwIhfD8X+LyBXblvBGC1Q/kdEYIykJtiVAHJNsxdd1zYZa4=", + "op": "00ef8ea3833a80e22d0add60fdbcf250c26a3ce5ca10d6bb890804e11d195873ca" }, "handle": { "v": 4, @@ -33,9 +33,9 @@ "t": "rankings", "c": "handle" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACao1GJ/o4L0iCBtDrzF6P4IADDycFng7kuIpwyCSaqaE7ZJDE3q+nAEKaMK9GelLdntgK3RJEIWuJIwJoaqe10CfLP0ObM8l+bgj/harYScfipBL4g", + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACao1GJ/o4L0iCBtDrzF6P4IADDycFng7kuIpwyCSaqaE7ZJDE3q+nAEKaMK9GelLdntgLJdSlPOHWMhcHTWO+5eJy3AF44nkyCWMGGQKN/Qed7/tIM", "hm": "fd9e4ef66848b4dada73e4262e85c9994af16aff271638ef9ec695d460e55076", - "op": "00e169c8297d7be0a24e597d20e14036df866a797b2cf54c44b7ae8b5540f7055f407ed6f91137efd272331b242fbe1ba1" + "op": "0050d344117a1ebd003b5c7a95186c0cce8cae73d41b805057c1556cc9f73db8a1f22dcacb3e5ab8338ecc626442777727" }, "level": { "v": 4, @@ -43,8 +43,8 @@ "t": "rankings", "c": "level" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAADOELB7oFk4gGnte9gWUzX+IAA/eO5LaKSJjCCWDqc30OLhtVNEMuxqU8YpeFdvKCq/zwJuoJAKC6CVvRXxddKK93rVWrvRV5ZLBIdjTRO5wEkx4/M=", - "op": "00da028bda7156e277d149180f09a615bb7f3f45efabe00137a04f5514176bc162" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAADOELB7oFk4gGnte9gWUzX+IAA/eO5LaKSJjCCWDqc30OLhtVNEMuxqU8YpeFdvKCq/zwLuB6l4GFEiXv/2htTgSFpLfaI2cRPk9M+9B3ok7lo6rkw=", + "op": "00f5d91a01200de0844df8783c2d15dfdf97f7c4f87e8f6ad805176cebd107229c" }, "mean": { "v": 4, @@ -52,8 +52,8 @@ "t": "rankings", "c": "mean" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAXtGGpXlAfrs+IrloNwZO2IACelhdo3FYPTm2Ee6gu3+WpSHxU3IZtSHO2tiiQdtYltALT0WMwiFSu9v/C372nHnQ9Y2F5lQ+SJ9a6UGl7q1Wnzg6OavYb", - "op": "00fbce95d005970edd747e9dbff02f9824d8fedff874593ae7ddceabb8034978ead8b5f3a99c55793ed7912cb85f2cb5b600cc608ead9edfbf551e4d1544fff0d7" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAXtGGpXlAfrs+IrloNwZO2IACelhdo3FYPTm2Ee6gu3+WpSHxU3IZtSHO2tiiQdtYltAJX+0j9IhUaijB4dqlS+SG3qGRRu1nri+3gV41uMGoMoOUbAwFf", + "op": "00133b8c54873d85f5eaf7c183624349adc12dcbbcc4291a6f8e31094f14060c103eeb3c7d545c62cfa70dd25f653e2da48780132093791404f2c976705ee3bc21" }, "pace": { "v": 4, @@ -61,8 +61,8 @@ "t": "rankings", "c": "pace" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAADbT5WtnwkRYMqrlrr5MYHyIAB3uJpHJLZ4qKadvcMBxL3zAMxDkh86LddqQyvJSQAvugKLD9zlce2vNCOnYmInd4TrsCm94ahuAenaAUtKbFc5Fhk=", - "op": "00020a960d8eb4ca100a36cdccaca4b2685bcd7b343e092f8133a320b1d0cb6ec85408fb3485228c62b3512f97dc9b86ff4021b728ce7aec0b99f5bbe72a3fd870" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAADbT5WtnwkRYMqrlrr5MYHyIAB3uJpHJLZ4qKadvcMBxL3zAMxDkh86LddqQyvJSQAvugJ669D9q6TZ1FI15X6hAVDOQZuAdyz7Ay4wXuY36yN7TFk=", + "op": "00fb9f213ea5a10eb43eaef0edc90db2a3f576a0a8901321fbb89c943817c02fa904d20cad736d408a5481a3887e00887a136216bb81087d454fbdaad8b3e8b8b4" }, "points": { "v": 4, @@ -70,8 +70,8 @@ "t": "rankings", "c": "points" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAADE2rUct3jjTKCWivCCCvn+IACDxItrcNhNJjpoOqJKOryPLgDOg+vvfrH4031ThcjDcgL2v4cWtT1QKjil3dECXavlyHzUuyoinNxTfIYEdhSNTtbKxK1z", - "op": "00a53e38612eddc330547218dda2f5ee376e718061a8ea3af479e8473fadca71aef7476bd681e502cb239d515f23f7ef925e386904bfa7dcea145d06c9bcec551b" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAADE2rUct3jjTKCWivCCCvn+IACDxItrcNhNJjpoOqJKOryPLgDOg+vvfrH4031ThcjDcgI7lsGi2gJ2KZcFANTqV9hLIjpOKOiAYp2WvSBa0GEN51Paq4Qn", + "op": "004ecb0a9b8bd21d9848013f225125ec9d37cea82e538107d3db76018ec8c2e7e69cc93c308135012b6c6ee70fcc1034f0f4321531a15eba19077e1ed4befca8f9" }, "score": { "v": 4, @@ -79,8 +79,8 @@ "t": "rankings", "c": "score" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAdcnRvoEEyjJO4SJ0QoQxyIAAWeon6kK0bnzHkJPNFV77QcE9ws0SBOC8udyFu1wQVVQJ2t+3/Rkek59/J7fRQYHVLNvDLxukNBbokL5IOQCiE/3SVDWb0", - "op": "004e3516c0d33a94c4ba52f438645a422d570ec9e8ff91214f13848b1eb09310c1a23351ac149e998374c4baea8eaf9247fcf7465dd3a946be01332c42889aeb49" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAdcnRvoEEyjJO4SJ0QoQxyIAAWeon6kK0bnzHkJPNFV77QcE9ws0SBOC8udyFu1wQVVQLtGJGpfzsg2eTZUQL4htIucnQL62igrzjSlzDNXG80DniqHFV9", + "op": "00afc8f4046464970d69b4b34bc9303e7866cd00efeb86f8fd6976d2c00ac383945a7b54d8a621a2638789295b09b260425c29a6d014946d998e60240ad879f82d" }, "speed": { "v": 4, @@ -88,8 +88,8 @@ "t": "rankings", "c": "speed" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACQhhB1srtFMhmPGNU3YdsWIADsfyGa4Tr54eU6CvZPZuGD26cBMDuzAO68y/GPMEqBTALILPPKyY05f6gsuB1SdbmqiH4qDmgFT5U58X3BsRGNNfM=", - "op": "003c173a74a6502886339a78c9c32c6aae7ebde1d06257855d71e33b84651ef15d77ddbbc7980a6fa7634fb604fd5b2f52c248e3531b61f181a2a9662ae051aaff" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACQhhB1srtFMhmPGNU3YdsWIADsfyGa4Tr54eU6CvZPZuGD26cBMDuzAO68y/GPMEqBTAJLKQ3WrwQrp0BbNSrDN3OP5DzjCYO63Vhk9wp7YQn2AnU=", + "op": "006bcb16a0ca276cd520f79e701a76fe4b1a06b2f8ecd90c6487fc940c6a63ff747c349d78adddd438e89a3e768c78b6f3e4e302376b3a3de2c92c310badd1fdc7" }, "title": { "v": 4, @@ -97,9 +97,9 @@ "t": "rankings", "c": "title" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAABDsM58wLdL/OmzeE1bqk6fIAAZc0G+IFRon1pJAfT2YQm7ENl+LSkdnO6ABKfec8JJOwIZax/COEcTjpdSfUvH35SFQKaypGbuq36W7Qkriuu7eEkm", + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAABDsM58wLdL/OmzeE1bqk6fIAAZc0G+IFRon1pJAfT2YQm7ENl+LSkdnO6ABKfec8JJOwJZgVaehkmapHYafVjSDwng75pAJ8YDT9Kv7DmeKEPM1hpK", "hm": "3bb29d6ed8db30040350b25bdb47263cb156666c5214d96f991850a4672eefc0", - "op": "00344fe120b7abb89fdad4d2ac644367e74b2ca4e6a9b6d4115e85b5966136c35ca2f2645bf578d8d1fe730b1465312f27" + "op": "00e162e4c13c10a383ee7c6728250b0eb0c36a318747a05e1e7d6ff33cb6f61ab79572440b6621f4ce04239540926a68ae" }, "total": { "v": 4, @@ -107,8 +107,8 @@ "t": "rankings", "c": "total" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAATWgrbBtfjqeFUZIJyCg/TIADRzWl3oad1fwHQ28RfJWb4tEsJ+2+pskxX7xjJHYOtxwKaanS7nY7gY/0rP/z1BlJQivmSTGhqkM8GGU3HYF54RbD163HI", - "op": "007152e605e2cc13823bd1379c7733939403474f5dfe1a65fa73eb63ea134f4a0505668fc80076fb24aaefd4763b1d1a2be9bf875178cf8f4abdbdce26ef1e3d98" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAATWgrbBtfjqeFUZIJyCg/TIADRzWl3oad1fwHQ28RfJWb4tEsJ+2+pskxX7xjJHYOtxwLdAPtpEOMcAXRDIR9kmKUiRe73mn23YxY+3BtvYCI8++G436N7", + "op": "00fd575c3250caeb1c5e8c45e48cd4ad8ef38eec0d52d6fd9fcf6f53c01dc212fcb747d609ddf4585907072d7fbd9bf29b59314a2d30ef33f1ac857c7fbad66d47" } } }, @@ -133,8 +133,8 @@ "t": "rankings", "c": "floor" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAD8EXObyO8iZAsGLtyoF8OzIAAUnZe1c/yU3tUu7btj/FmcuWh0G3VlpdjE4Y1DYkuXYwKjI6FNx98wap6YRPYq0Pr6xumDkjkem3g1aD9Bd15gGJE=", - "op": "0068773fbf20d83c18c9e2c158d14a9601d12eab933e59d10e163110e4f030377b" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAD8EXObyO8iZAsGLtyoF8OzIAAUnZe1c/yU3tUu7btj/FmcuWh0G3VlpdjE4Y1DYkuXYwLl8xnxSTGfLOWZDiGjdF0qIcjcXXOvmIP1m7tLH4LJpcg=", + "op": "00ef8ea3833a80e22d0add60fdbcf250c26a3ce5ca10d6bb890804e19e4458fb1b" }, "handle": { "v": 4, @@ -142,9 +142,9 @@ "t": "rankings", "c": "handle" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAJSAHc0qCJ5PzM6mX2ijrQIAAOAb/DTu0ioK8DD+OJLmo37ro6p5goGfRbZvv+4GZmmwLyq1pNP+xziI6NvqEt7inQUrLLPhDVG8j3/FIywLlE/SJx", + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAJSAHc0qCJ5PzM6mX2ijrQIAAOAb/DTu0ioK8DD+OJLmo37ro6p5goGfRbZvv+4GZmmwKTQzbkIcjT3E5PAkhfC5UHbKSYYb0TCfy7/EORy+L7cDey", "hm": "28fe3661678ecdba7c98355d901c9a8a591c1175c1d7b403bd3d1ec949c8b2e0", - "op": "00e169c8297d7be0a24e597d20e140b6a098c488dda2a5fab8b1a7071ff703df7f0880519d1ea23890b5c6a01066f62633" + "op": "0050d344117a1ebd003b5c7a95186c8d46a9bb20ff555f86bdd726ffb033a113b8daae3b210a878df9b37e0f48f6cd9b97" }, "level": { "v": 4, @@ -152,8 +152,8 @@ "t": "rankings", "c": "level" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAhOR6KLBknqtSBVRnlASoSIAAkxpt5V1/27p77EpAoxlp3ceWsCtSnFCzVx1mJZ9TRkwK8xMXduV+d2TMvfn7+P2QF8EnlLYAiRPNnN29ANmoVSts=", - "op": "0159d19c111791f639ba0638692ca6f6c53ecac713e356a7e8bf95fc2d839691f4" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAhOR6KLBknqtSBVRnlASoSIAAkxpt5V1/27p77EpAoxlp3ceWsCtSnFCzVx1mJZ9TRkwLr8RWhmJeqR5s8BUwbq3sR5N2gvxQYgbkhFLM9axg+RhM=", + "op": "0175ce2d2193c247e19cdeeaf00c3aa33f8f41ae2ae07ea8f54907726ef81d76c6" }, "mean": { "v": 4, @@ -161,8 +161,8 @@ "t": "rankings", "c": "mean" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAipqSO612avBu8ILwcZ4zfIAClyVXmOu93Sq1j8QZEePtr9Yn/DaGkc/jIzWIJfzRtqwJ1jc06IDRZmX8wTBKbh4NQUgAPFduL3qFTTmzXxfzmMverhaSn", - "op": "017bc9729378e320ff0c1504dc995074a7db7b05d24bed8a923f6944899e4517d213bba21ee639bb01063902e92cad61b3f3b0755b0dacc66fa5188b434c455360" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAipqSO612avBu8ILwcZ4zfIAClyVXmOu93Sq1j8QZEePtr9Yn/DaGkc/jIzWIJfzRtqwIbCtmwIzeVEc2VCTj+1xGmguNhfULa/iNUFBEUAbtUUyiRuBer", + "op": "0092c35e5c06045d306925d152beb010ac631de046e645a8fc36d9809494f97d17931a4e97b083f7725796c282b7aaa3c6a483634026a4ef01c14c9ec5f7d48743" }, "pace": { "v": 4, @@ -170,8 +170,8 @@ "t": "rankings", "c": "pace" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACSUbSNa21Cz2EdccB0dU93IAB5ZsgjlyQaH70IyAEmbajCC+g5pPkdckAlAyLzt31TpwJZCCAoMewAOd8y+7jLdEfzU5mQ3zdV4dpjHzvMNoIl6q0=", - "op": "00028af974e429d69504e291c6615487c98d3abbaf6a36a012b22bd60ddb569ba83f09243bb5f22d9df419926a7b9e31c7c4411c822471fd427c7a74ac57df0482" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACSUbSNa21Cz2EdccB0dU93IAB5ZsgjlyQaH70IyAEmbajCC+g5pPkdckAlAyLzt31TpwJ5G3FdyU2ViJtvOmzHefh/cXKnbGvYLKSexOEZugwjayw=", + "op": "00fc1eaf0613a705488a607f2415941128f4675696e63176b0747adb930727be4c77852c13c8ecf605cffa93d0ae8c0a39e23d295e17f8d87e78996a4d49fd9ea0" }, "points": { "v": 4, @@ -179,8 +179,8 @@ "t": "rankings", "c": "points" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAD7BDP9k+0Hn5JvKavkeIEeIACwwz3ffvBIoUS+WhQi678dNUBCkgT8GduW9s20XVgb7AKy1BxwBvFhYdWu8TjON31J/XFZE6F1lgnSVZLat6Po+utVYHS2", - "op": "0124da6c76e6a9d3572f27a08b17b843e6581a23213f34fea500706db6d0edf539fee6624d544ab352bbfcd0987056c61e7e2b808fcb36eef07e673ec3639e4235" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAD7BDP9k+0Hn5JvKavkeIEeIACwwz3ffvBIoUS+WhQi678dNUBCkgT8GduW9s20XVgb7AJ6q3dJ6UqJVclXtZWuwlUcdyULkPBZCBjiuTHchJ3nMD26EXv7", + "op": "00cee5592b12ad2e56642aea465a82520c4975a84e5e423871fd8c293684946167de3bf467704da5d857f93dd27c836494e7a208adad194349f0c37e05a0f60156" }, "score": { "v": 4, @@ -188,8 +188,8 @@ "t": "rankings", "c": "score" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAC8mEb7pUk1HxVAoAej3DB3IABYatmLY126M9pYkSV/txgFWt8Dn0gqikv85rJxYY3DsAK7P9SKYcuFN3NNXWdqAQ301cj85RYYFUnxeu9PUP6Hv3Rc0TAf", - "op": "00cf2820721cd8c187f434f8986fd01c7eb126c713b0619086b0ca6d0b2120f8d322bbc60d5e40ac640ec49f271c0894a6965ab22b7da190f2e2af8f157a7b503f" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAC8mEb7pUk1HxVAoAej3DB3IABYatmLY126M9pYkSV/txgFWt8Dn0gqikv85rJxYY3DsAI8PIShjXpBDo4onnXH7fmRbS8SHt3bd1H+PDezRvi+nk8obBa5", + "op": "0130440c006ce9cfd5eaae7c256850391359737687b73654638245f850c248cdc5b048baf4ea157de1a7ba1da432b34ce8db6242944a1487c8650b12ed349aff2d" }, "speed": { "v": 4, @@ -197,8 +197,8 @@ "t": "rankings", "c": "speed" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAu+yQLbuCeiI1Kc93l5gM9IABDnI3BuN2mIRVGQNCz+OT9g1NBNpy73iq+RyQMrDq2SgLdiotIJVKFxL7zjyPD19PobupEvKh4GhfipnC5MhqxmUc=", - "op": "00bbc2ac417a8cb6a4b5b69c9f81223f9016f7ffc9e250417dd5afa5cfd4844dac6f9f72bf972a4aba57ae0f7e64bc7ce315095aab620f1f0f7a567d525837af8c" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAu+yQLbuCeiI1Kc93l5gM9IABDnI3BuN2mIRVGQNCz+OT9g1NBNpy73iq+RyQMrDq2SgImHrG0RwQ2frkco90AQLcPjtI91WY0YiqoX6uJeqJ8Lbw=", + "op": "00eb900ca25552ce78eaef5e2496345a98454225f1b19c906a2e7aeb3c52c3fe559b518926897a71ef5b835ae2d445d30274ac3b4bca05c2cba135065fd0581e42" }, "title": { "v": 4, @@ -206,9 +206,9 @@ "t": "rankings", "c": "title" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAB8xVf2YzyG2GIJsjlxprEhIAARLofbMnEJkC3zRNC1Liyue93ywxEK707OQBNyU3GRRAIR6N/Yy+L9m18gSMba81M6XZu9nnwSMGCjCFmC6FtEdAC0", + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAB8xVf2YzyG2GIJsjlxprEhIAARLofbMnEJkC3zRNC1Liyue93ywxEK707OQBNyU3GRRAI/IBd/bqkuJs3D5EnYeLpVziX7o356LElM+8Q6HJy7eCFL", "hm": "96c9b4169dddc5b00a92aca4f2141eaa81586bb3c0459c9621c6152a938bccc2", - "op": "00344fe120b7abb89fdad4d2ace56e65d225dc12e1f08841a86ad18728afb74d36c3bdd298ed9a2e94e98a2e9328a2fa76" + "op": "00e162e4c13c10a383ee7c6728a616e1e72458a7cc35c5204061bf8f01800520009adea5aca7256ecb6b5a1f95ebfa4fcd" }, "total": { "v": 4, @@ -216,8 +216,8 @@ "t": "rankings", "c": "total" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAABsGQzdwhlf/5JQSTVnel1lIADu5SaW0n7eTUy2k1WrssfM1qoPuD3RSy12zQc69AvRNwKYqTPivNDeEnZygzTBpFhBGNtG92Y0Kltt9qEE0OEUYseWMu0H", - "op": "007152e605e2cc13823bd1379c7733939403474f5dfe1a65fa73eb63ea134f4a0505668fc80076fb24aaefd4763b1d1a2be9bf875178cf8f4abdbdce276f071ed9" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAABsGQzdwhlf/5JQSTVnel1lIADu5SaW0n7eTUy2k1WrssfM1qoPuD3RSy12zQc69AvRNwKOzeJ9+3J/ByVsOrY7S30QJL9A+FlCiaAdoPf2VktL+Lb9ry+a", + "op": "00fd575c3250caeb1c5e8c45e48cd4ad8ef38eec0d52d6fd9fcf6f53c01dc212fcb747d609ddf4585907072d7fbd9bf29b59314a2d30ef33f1ac857c803ac46bfb" } } }, @@ -242,8 +242,8 @@ "t": "rankings", "c": "floor" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAahRXPLhcOhZalhxaRKtwfIACZJ24pqBpQ/xkQSjuIcUV0/DY8mrP3JugbZIjLooy/agJXmfRZQv8gd+32H9A96zYw31oM8RyIVpR/HrQbVP/a6vM=", - "op": "00e7a865a4a6a28052352a8eb6c1265f682958013daa3f37fce5f07022a097aa85" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAahRXPLhcOhZalhxaRKtwfIACZJ24pqBpQ/xkQSjuIcUV0/DY8mrP3JugbZIjLooy/agKO2U99zlAApptBhithXBT1INauyAg+b7UXv1msrRVyvZ0=", + "op": "016f0e9c2c834418ca75f76b50bb475005bdf8e0aa1a1df3f57756822461aef5e7" }, "handle": { "v": 4, @@ -251,9 +251,9 @@ "t": "rankings", "c": "handle" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACAaXkgSLAngfKw540Hh/cyIABUzHBgSmtLU4FEA1PiYLaeQb+T1nu8+sQyX6e1dXFFnAJ8t2RiTgBT5L5jai/lA/1J1ipI8gx72xi4G78HNRc8LzU=", + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACAaXkgSLAngfKw540Hh/cyIABUzHBgSmtLU4FEA1PiYLaeQb+T1nu8+sQyX6e1dXFFnALMyqIxYkgj8YN7szI+qQheecz6RZOqkNsTb44XAPK6/+0=", "hm": "ec1d4753450fceec15afd623ce671fff76c236cbbbc81af81cef9e694a493ac8", - "op": "00e169c8297d7be0a24e597d20e1c094556c47b21bced759dd8e83e5a075f1b02cf50ad54f524ee158" + "op": "0050d344117a1ebd003b5c7a9518ec8c749ab82d4dff1c76f829db088f31bc9d8d38bb1e156aa75fd9" }, "level": { "v": 4, @@ -261,8 +261,8 @@ "t": "rankings", "c": "level" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAxIHgvAEtydMinzMsMC9maIABcXRm4Ec9fNHs/VMPHO2YcFzhLBtvGDaO5/vL94Up4DwKIvL/fnqO4f4Bu9W6FNibpKRmt9aQmi/P+igsXeqf1LXc=", - "op": "0159d19c111791f639ba0638692ca6f6c53ecac713e356a7e8c016099dca23df54" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAAxIHgvAEtydMinzMsMC9maIABcXRm4Ec9fNHs/VMPHO2YcFzhLBtvGDaO5/vL94Up4DwK6DcVon2MqGVSmg/n+w2hAqzujhL73JzDK3/HLvog0TOw=", + "op": "0175ce2d2193c247e19cdeeaf00c3aa33f8f41ae2ae07ea8f549881a7c90d46b04" }, "mean": { "v": 4, @@ -270,8 +270,8 @@ "t": "rankings", "c": "mean" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAA3MuHYMxBxol/l3CWUUdMwIACBix0i7ecA6Ldg1y72uB17y+CSAZFHm7KMBeJIDB9SSQJr4639om/GxjhRNe96mH/k6IVqzDKdy1vQcaiHL6M/rhySzCh1", - "op": "017c49c16621a2476ed2e40c07fd2d0b35d8f722f0b0e7bca5a4681d69a349806e3554d39f0d13392b43cfe477aed64f8d13ba4fb8e786dbb8c60b454a8a50197c" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAAA3MuHYMxBxol/l3CWUUdMwIACBix0i7ecA6Ldg1y72uB17y+CSAZFHm7KMBeJIDB9SSQJ/4geqcL6NU2f9TlBQcromWddycp68Qm1ctDG0x0tDOxgDPy98", + "op": "009343d48b97e8026b9fe25b8c3b2393370d2ccc79dd58a123e184f7b005e3a7370ab0c27eb4cfabc90a1b6ad2ec43d0d1d6916fc62f15bd516a5c892a9030d9a8" }, "pace": { "v": 4, @@ -279,8 +279,8 @@ "t": "rankings", "c": "pace" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAADsocba1ACUuZab/S3cR0ewIACbWZ1UAMwA6rnu+PuFd4RCwsXLXgkmZwavUB2HQ5lIMAKNgBydDXntlpuWxH4iE3ALX8ukrBS2pqIyrliA+pyNHzI=", - "op": "00822a022b1129809c146cada9cd22fa5208b482279f0e58376d67e7619bf3c39ab962520422fd56d4c43422be205365bfe363bf466ba709ced360af209fdf2c8c" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAADsocba1ACUuZab/S3cR0ewIACbWZ1UAMwA6rnu+PuFd4RCwsXLXgkmZwavUB2HQ5lIMAKhysHRdK+xHkMRf4AzRjvhY7aQh2Ou3lveRx7rFtlUVj0=", + "op": "017b1ab81d18c03ddbf803bc41253de9e293609ab35dc3f700c0689973d65e0ae063f07959247b4033650e9a21afa5298fe9a1e39254a94de0634a097fc1f3a9c0" }, "points": { "v": 4, @@ -288,8 +288,8 @@ "t": "rankings", "c": "points" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACyINaK+oMYBWGqilpz+Y8WIAAAAwXxsCfja/ehP5So7kKPSpDckgOjdWAFkQ0JFNatGgIjwqEjrceceNJS9EXjqbF+syMBx0UeigKdwBZvpKg1VJUetU8L", - "op": "0124da6c76e6a9d3572f27a08b17b843e6581a23213f34fea500706db6d0edf539ff65903adb0c33d49877a8393f339203152f20ddbf199339e4e940bf5754b804" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACyINaK+oMYBWGqilpz+Y8WIAAAAwXxsCfja/ehP5So7kKPSpDckgOjdWAFkQ0JFNatGgIfCpCjNW8aci+3rkdftjLwPVl6fRHGf6wv/rudqQMtQEvmvEUU", + "op": "00cee5592b12ad2e56642aea465a82520c4975a84e5e423871fd8c293684946167debc28206a3fcea85fcfe571cf1a01a65f3d51c5aac8a3e2ebe865a37132398f" }, "score": { "v": 4, @@ -297,8 +297,8 @@ "t": "rankings", "c": "score" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAADLJrDpNuSIT1MzDrC3NqkdIADeidZb+K23yM3QNYs+J9lmB9ImCm/0mFW58UkeELUnfgLrLahFD5GGGpELE5j98cbiAvLw/UzqRHXRZdjAzrhSGvAhJpcP", - "op": "00cf2820721cd8c187f4b49ef818bca2626025cd2725b90a8daab1fff0d28e46031a6cf188bff7fd4095aac4fd74613c395a909cb2f6ee863ff59d364234862a3a" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAADLJrDpNuSIT1MzDrC3NqkdIADeidZb+K23yM3QNYs+J9lmB9ImCm/0mFW58UkeELUnfgJWtZCvurIZKVjUreUpZbPutDYzXJvwyIAEiSaMDQsgpwFsvCPa", + "op": "0130440c006ce9cfd5eb2d2edfd7836896f991265d5e67513a2a1476e8da2275d206a174a6ce14b5a72f94f6bc4966db9495725e6a997237e7e75548ea926e5899" }, "speed": { "v": 4, @@ -306,8 +306,8 @@ "t": "rankings", "c": "speed" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACgW67nY8FTYuEOauFB2JqpIAB5N3v5rvteb1kWiSLlblOJ9Bvwa4mzUHOFsJbqvqlsrQL8ByKpYorieYyq9NnIkuVxcznI5zABTlD5OzN1KGkjl+M=", - "op": "00bbc2ac417a8cb6a4b5b71c87a011af4b942767664acfa469bbd491bf66466451a9ee3aac2b56a2f81fcdb0a2b6c84725f60ad5bb727b2c14eda1eb054fb92592" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACgW67nY8FTYuEOauFB2JqpIAB5N3v5rvteb1kWiSLlblOJ9Bvwa4mzUHOFsJbqvqlsrQJmEl1nhMbRkyf7S99+hyGQk0RG2UQ34c9Z6LsTgVgjAWw=", + "op": "00eb900ca25552ce78eaefde93eb9ebe09ef5cdb3ca91e12f8e706c381ab05982150cfc83d382b9917822162f9cf5d6d9d23c4530f3d833ab0409948390d4e6a64" }, "title": { "v": 4, @@ -315,9 +315,9 @@ "t": "rankings", "c": "title" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACoLw9QzYPeYb2lWmo5koQrIAAWqW7Qj+fimzpnYilKdFOpSi5wedGlAhzFUlLDVfQXrgI200vJrAyvuyAWRolG7M4tS7aNYBt3umCJUE7DlkMSjIO3fe+U", + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAACoLw9QzYPeYb2lWmo5koQrIAAWqW7Qj+fimzpnYilKdFOpSi5wedGlAhzFUlLDVfQXrgJhR0LzF3WwvU7TFJI7z/16xtPBFEO2wXC6fEz2XODBz9SjPqBd", "hm": "0784eaafee80c50e6a9856e256e99dd536f50c9668cba8bfef433b7bf75e22d0", - "op": "00344fe120b7abb89fdad4d32c82054f71be09c4ac588f34f122f9c53b1fdf516a7cd4f4017f13ffd88a1757c19da753ff8eb398b6832378da3944d7e286e6cb345a82887f75e76591" + "op": "00e162e4c13c10a383ee7c67a933435cadea8adcd88446abcafaf146d817a68b7e423e6efbc2f3ef98d1eae17bacf00f8a3f4439769da3bcabc60d1de9b3ccb95b9f8b1a7996cebf75" }, "total": { "v": 4, @@ -325,8 +325,8 @@ "t": "rankings", "c": "total" }, - "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAADqzuNSUCG8WYJqEd0qG67nIAAN5uG4KA4yAHLXuPwfwCvXit4ti1MjxU/VymYIyK+Q9AKCtwW2fHKhvHt8T3IIrxXZAUpi7B02kqV6TuyK+8SRr5pGIgLH", - "op": "00f029fe2d68c79a0ca72ec21e5352a77673be1b39fae030898356ddae1d2cf9f0d771411be2b36c41f5215db20a3f965b37a8a6f7ff1e80c3be894eeb226759a2" + "c": "stack-encrypt:1:AQAAAAAAAAAAAAAAAAAAAADqzuNSUCG8WYJqEd0qG67nIAAN5uG4KA4yAHLXuPwfwCvXit4ti1MjxU/VymYIyK+Q9AJcWBbxC+8wtEUUWOrss1eS/RTvqSlS5Qx72TSTWC/tVwxgg4St", + "op": "017c32c0ff05fac9eda05acbab7e34f5b0cdcfe16e60ec414b9180b114241969a3384bbc2c96a02606bca28486b3d83c00b044eaee11b23a6a3f60e4dcb9616ea6" } } } diff --git a/packages/stack-encrypt/CHANGELOG.md b/packages/stack-encrypt/CHANGELOG.md index 76a369a06..e4108a40b 100644 --- a/packages/stack-encrypt/CHANGELOG.md +++ b/packages/stack-encrypt/CHANGELOG.md @@ -218,6 +218,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Breaking +- **stack-encrypt requires the vitaminc 0.8 crates, clww-ore 0.6 and + ore-rs 0.10.** A crate that names a vitaminc type stack-encrypt takes or + returns moves to 0.8 with it. What changes for a caller: + - **Every order term changes.** cllw-ore is now `clww-ore`. Its + keystream was fixed, and its schemes' names (`clww-ore`, `clww-ope`), + which every term's salt binds, changed, so ORE and OPE terms written + before do not compare with new ones. Block ORE goes through ore-rs's + single `BlockOre` scheme, which keys its 6-bit and chained engines + under a new label, so its terms change too. The wire formats, the key + domains of this crate and every sealed ciphertext and equality term are + unchanged: a stored row still opens, and its order terms are re-derived. + `tests/fixtures/stored_rows_v1.json`'s order terms were re-frozen. + - `sem::OreCllw8VariableV1` and `sem::OpeCllw8VariableV1` are renamed + `OreClww8VariableV1` and `OpeClww8VariableV1`, as clww-ore names them. + - **A sealed `None` of a fixed-width type is as long as a `Some`.** + vitaminc 0.8 seals it as a typed null, padded to the type's leaf length, + so absent values no longer show in the length of their ciphertexts. A + reader on vitaminc 0.7 or older refuses a typed null, so upgrade + readers before writers; every null written before still opens. The + `dynamic` feature's sinks carry a typed null through the value model, + and the frame a binding receives holds the plain null. + - **A null still has no equality term.** vitaminc-normalize 0.8 derives + one; this crate drops it, so an absent value keeps a SQL `NULL` in its + equality column, as before, until the index terms of a null are decided + (#1298). + - **Block ORE's text ceiling is unchanged, but counted the new way.** + `vitaminc-ore` puts the marker byte in front of text itself now, and + ore-rs's 1024-byte ceiling counts it, so the fold is still at most 1023 + bytes. + - **`IndexSpec` has a fifth variant, `OreBlock`** (the block ORE index above). The enum is exhaustive on purpose, since a binding has to be taught each index, so a `match` over it needs an arm for `OreBlock`. The diff --git a/packages/stack-encrypt/Cargo.toml b/packages/stack-encrypt/Cargo.toml index 2cfc02e0a..7334e521f 100644 --- a/packages/stack-encrypt/Cargo.toml +++ b/packages/stack-encrypt/Cargo.toml @@ -37,8 +37,8 @@ vitaminc-hmac = { workspace = true } # number whatever its width, text in Unicode 16 NFC. Match text is # normalized by the same crate before it is tokenized. vitaminc-normalize = { workspace = true } -# The order targets (`OrderTarget`) and the scheme traits cllw-ore's -# `vitaminc` feature implements, which order terms encrypt through. +# The order targets (`OrderTarget`) and the scheme traits clww-ore and +# ore-rs implement, which order terms encrypt through. vitaminc-ore = { workspace = true } vitaminc-prf = { workspace = true } vitaminc-protected = { workspace = true } @@ -49,9 +49,9 @@ serde = { workspace = true } # `Descriptor`: the base64 rendering of a non-textual context for ZeroKMS. base64ct = { version = "1.7", features = ["alloc"] } -cllw-ore = { workspace = true } -# Block ORE (`OreBlock`): ore-rs's 6-bit schemes through the same -# vitaminc-ore traits cllw-ore implements. +clww-ore = { workspace = true } +# Block ORE (`OreBlock`): ore-rs's `BlockOre`, its 6-bit schemes behind +# the same vitaminc-ore traits clww-ore implements. ore-rs = { workspace = true } # Every error derives `miette::Diagnostic` (a code, and help where a caller # can act) and gives its structured fields as a `serde_json` map through diff --git a/packages/stack-encrypt/fuzz/Cargo.lock b/packages/stack-encrypt/fuzz/Cargo.lock index ac5eabd82..e36effd00 100644 --- a/packages/stack-encrypt/fuzz/Cargo.lock +++ b/packages/stack-encrypt/fuzz/Cargo.lock @@ -359,10 +359,9 @@ dependencies = [ ] [[package]] -name = "cllw-ore" -version = "0.5.2-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb4a774d070a6c2b52175b98273cd7193c61e1bda39c1a98b50b7a2d91375a" +name = "clww-ore" +version = "0.6.0" +source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" dependencies = [ "blake3", "hex", @@ -370,7 +369,7 @@ dependencies = [ "thiserror 1.0.69", "unicode-normalization", "vitaminc-ore", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] @@ -1468,32 +1467,25 @@ dependencies = [ "libc", ] -[[package]] -name = "orderable-bytes" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7d30b72ffca73d9936fe5fc80a9c9520c73f5b4f64839a810211903d5ace3c" - [[package]] name = "ore-rs" version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1d6cb8c1249643266bd60269547c93d3cd263d5385f1262902bbb295ff9a5e" +source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" dependencies = [ "aes", "block-modes", "byteorder", "hex", "num", - "orderable-bytes", - "rand 0.8.6", - "rand_chacha 0.3.1", + "rand 0.10.1", "subtle-ng", "thiserror 1.0.69", + "vitaminc-context 0.8.0", "vitaminc-hmac", "vitaminc-ore", "vitaminc-prf", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] @@ -2067,8 +2059,8 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc 0.8.0", + "vitaminc-protected 0.8.0", "web-time", "zeroize", "zerokms-protocol", @@ -2079,7 +2071,7 @@ name = "stack-encrypt" version = "0.3.0" dependencies = [ "base64ct", - "cllw-ore", + "clww-ore", "miette", "ore-rs", "serde", @@ -2088,14 +2080,14 @@ dependencies = [ "stack-kms", "thiserror 1.0.69", "uuid", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "vitaminc-aead-frame", - "vitaminc-encrypt 0.6.1", + "vitaminc-encrypt 0.8.0", "vitaminc-hmac", "vitaminc-normalize", "vitaminc-ore", "vitaminc-prf", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] @@ -2116,8 +2108,8 @@ dependencies = [ "libfuzzer-sys", "stack-encrypt", "uuid", - "vitaminc-aead 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-protected 0.8.0", ] [[package]] @@ -2142,8 +2134,8 @@ dependencies = [ "tracing", "url", "uuid", - "vitaminc 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc 0.8.0", + "vitaminc-protected 0.8.0", "zeroize", "zerokms-protocol", ] @@ -2588,16 +2580,16 @@ dependencies = [ [[package]] name = "vitaminc" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5c15b6c25efcb9a6111f7108ab8101947a7bf7e9af3ff6d6a73358a1ace0da" +checksum = "ea37168a603d605732d0bf0672586139ab91736f767d7b85e173c84dcee19054" dependencies = [ - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", - "vitaminc-encrypt 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", - "vitaminc-traits 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", + "vitaminc-encrypt 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", + "vitaminc-traits 0.8.0", ] [[package]] @@ -2617,18 +2609,18 @@ dependencies = [ [[package]] name = "vitaminc-aead" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b8c5c4ced92545dce5fd7cf04581d08210def174cc81475cf227fa2506c5b7" +checksum = "e9bb97fd543ee6a2b168e257ec69d0d274a775b1eaa3f856b5ac2941b01891c1" dependencies = [ "bytes", "futures-util", "serde", "thiserror 2.0.18", - "vitaminc-aead-derive 0.6.1", - "vitaminc-context 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-aead-derive 0.8.0", + "vitaminc-context 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] @@ -2645,9 +2637,9 @@ dependencies = [ [[package]] name = "vitaminc-aead-derive" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c546497a972d0f0498f2f8d5f537c514bad82df8662951c63d0c80023808900" +checksum = "0845a44c07ddc882ed47a0e92e04fc83496220f054b589ad0cbd215c5009e5b7" dependencies = [ "proc-macro2", "quote", @@ -2656,12 +2648,12 @@ dependencies = [ [[package]] name = "vitaminc-aead-frame" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35992a269bcaa5b201f1938e54bfbf167bfa6fe975d83cbdbdb54c2a363c5ef" +checksum = "3b0299777255171712a296d59164691dc1e93d10bddaab6e248fede1790dfd2e" dependencies = [ "serde", - "vitaminc-aead 0.6.1", + "vitaminc-aead 0.8.0", "zeroize", ] @@ -2677,12 +2669,12 @@ dependencies = [ [[package]] name = "vitaminc-context" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4c4bc2bd9811253eb427657565a45bd4826e2379e93ee1c4d00c808a769882" +checksum = "a630079ba2d50680ee5048addd430eda30613559809dd6d383551e6d3d299826" dependencies = [ "mutants", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", ] [[package]] @@ -2701,71 +2693,72 @@ dependencies = [ [[package]] name = "vitaminc-encrypt" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0923694602855b33a296d9af473e282e8096c1cfe1b30b8695d3b6651717fc5" +checksum = "db45e073f92ae8ca27f8fe14270bc34c75e767559c2347098dacca95180d1ddd" dependencies = [ "aes-gcm", "aws-lc-rs", - "vitaminc-aead 0.6.1", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] [[package]] name = "vitaminc-hmac" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd361f626e95cbe770b9d012e4a86c43cfefe4aefb3d5b3ed9339a83085bdc53" +checksum = "b5fa0ae8bbad85ae30fb5c91b0b72b694d59bf2c2c1e7ad799eda66fdbd67e7c" dependencies = [ "hmac", "sha2 0.11.0", "vitaminc-prf", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", "zeroize", ] [[package]] name = "vitaminc-normalize" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214b2a9d085924c3bc3c91f3ba74238e8848bf54990e5f48f170c71fbacea07a" +checksum = "f5a2d8875e0b8b35b7a4f9dd698bbd13c989837cea564b5a4cbb5371b78fa937" dependencies = [ "thiserror 2.0.18", "unicode-general-category", "unicode-normalization", - "vitaminc-aead 0.6.1", - "vitaminc-protected 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-protected 0.8.0", ] [[package]] name = "vitaminc-ore" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed88c54b5f06f2177ecbfb7666812adf645406f6fb555f4e2f0fd7fa218e71c4" +checksum = "f05518b4d35cb0c592dad59afb11b8e883ea252449b9ae47ff5ddeff0ed49f75" dependencies = [ "thiserror 2.0.18", "unicode-general-category", "unicode-normalization", - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", "vitaminc-normalize", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", + "zeroize", ] [[package]] name = "vitaminc-prf" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2715cca25006b4656223bc932ab4fd7f70d387aa4ec63a4e2ef33aa8cd2b3a5" +checksum = "916688478273ca3e5c6805b355534ce9263688391cd4ab23b08bef760039d325" dependencies = [ "mutants", "thiserror 2.0.18", - "vitaminc-aead 0.6.1", - "vitaminc-context 0.6.1", + "vitaminc-aead 0.8.0", + "vitaminc-context 0.8.0", "vitaminc-normalize", - "vitaminc-protected 0.6.1", + "vitaminc-protected 0.8.0", ] [[package]] @@ -2787,9 +2780,9 @@ dependencies = [ [[package]] name = "vitaminc-protected" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1bb76dd473f5aa89b844f92018ebe3041deb8e5390e7061cca4283d959ff855" +checksum = "a6edc22562a9bbff0ba9704a2c43670b2c7cb1637524c045c3ba6436ed00917f" dependencies = [ "bitvec", "digest 0.11.3", @@ -2798,7 +2791,7 @@ dependencies = [ "serde_bytes", "subtle", "thiserror 2.0.18", - "vitaminc-protected-derive 0.6.1", + "vitaminc-protected-derive 0.8.0", "zeroize", ] @@ -2815,9 +2808,9 @@ dependencies = [ [[package]] name = "vitaminc-protected-derive" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7478ed160c019059746e75fc613563dcdcd5266d155a34601d29377a1c4afc3" +checksum = "a7cce3a7d0ce6f57c0e82345f20e87f3737cccd3a70aec2a2ab49f68a3a5e24a" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2842,16 +2835,16 @@ dependencies = [ [[package]] name = "vitaminc-random" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b477af7c01c3d9ef2647e46952ad3df7f246b3f806b1d4009ee83beecec613a" +checksum = "8bb253f783ce6f31a55a92f5a9f0526109b8caa6a465edb94244fd344a078c11" dependencies = [ "chacha20", "getrandom 0.4.2", "rand 0.10.1", "thiserror 2.0.18", - "vitaminc-protected 0.6.1", - "vitaminc-random-derives 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random-derives 0.8.0", "zeroize", ] @@ -2868,9 +2861,9 @@ dependencies = [ [[package]] name = "vitaminc-random-derives" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5a0de8da428c6789dc067a578a0462e411099721d616736cf29e1622230c35" +checksum = "df0b3615936d6dded4b775856f4b0fa229d745d183f0b3754ac80035f16c27d9" dependencies = [ "proc-macro2", "quote", @@ -2895,17 +2888,17 @@ dependencies = [ [[package]] name = "vitaminc-traits" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a900f0edcacd49c8557ab54722175869fec66926054a6fbdc53a05069db3c922" +checksum = "1e9098ee4b13446ef959583ee2f3c384df571b453179104f7b4960ffddf65ee9" dependencies = [ "anyhow", "bytes", "rmp-serde", "serde", "thiserror 2.0.18", - "vitaminc-protected 0.6.1", - "vitaminc-random 0.6.1", + "vitaminc-protected 0.8.0", + "vitaminc-random 0.8.0", "zeroize", ] diff --git a/packages/stack-encrypt/fuzz/Cargo.toml b/packages/stack-encrypt/fuzz/Cargo.toml index 90a6eaebc..f04dcd487 100644 --- a/packages/stack-encrypt/fuzz/Cargo.toml +++ b/packages/stack-encrypt/fuzz/Cargo.toml @@ -17,9 +17,9 @@ cargo-fuzz = true [dependencies] # `Controlled`, to take a passthrough node's frame out of its wrapper: the # same line stack-encrypt builds on. -vitaminc-protected = "0.6.1" +vitaminc-protected = "0.8.0" # The sinks the record harness writes its plans and passthroughs through. -vitaminc-aead = "0.6.1" +vitaminc-aead = "0.8.0" libfuzzer-sys = "0.4" # Structure-aware inputs for `check_record` and `plan_build`: the mirror # types derive `Arbitrary`, so the fuzzer mutates trees and plans, not bytes. diff --git a/packages/stack-encrypt/src/codes.rs b/packages/stack-encrypt/src/codes.rs index 5cf19530a..2e136ed56 100644 --- a/packages/stack-encrypt/src/codes.rs +++ b/packages/stack-encrypt/src/codes.rs @@ -78,7 +78,7 @@ mod tests { ])); errors.extend(boxed(variants![ TermError::Prf(_) => TermError::Prf(cause()), - TermError::Ore(_) => TermError::Ore(cllw_ore::Error), + TermError::Ore(_) => TermError::Ore(clww_ore::Error), TermError::OreBlockTooLong => TermError::OreBlockTooLong, TermError::OreBlockTrailingNul => TermError::OreBlockTrailingNul, TermError::OreBlock(_) => TermError::OreBlock(cause()), diff --git a/packages/stack-encrypt/src/dynamic/kind.rs b/packages/stack-encrypt/src/dynamic/kind.rs index 039d47b7e..c0451d4e6 100644 --- a/packages/stack-encrypt/src/dynamic/kind.rs +++ b/packages/stack-encrypt/src/dynamic/kind.rs @@ -60,7 +60,7 @@ use crate::target::IndexSpec; /// no order term: over so small a domain it would reveal which rows are /// `true`, or each row's rank among 256 values. /// A decimal, a date and a timestamp have none yet: their order encodings -/// wait for new cllw-ore and ore-rs releases (#1236), and [`not_admitted`] +/// wait for new clww-ore and ore-rs releases (#1236), and [`not_admitted`] /// names that reason. A composite (`array`, `object`) has no term. Only the /// index's kind matters: a match index's options do not change what it /// applies to. @@ -87,7 +87,7 @@ pub fn admits(kind: ValueKind, index: &IndexSpec) -> bool { /// plan that declares the pair is refused with. /// /// [`Reason::OrderTermPending`] for an order index on a decimal, date -/// or timestamp, whose order terms wait for new cllw-ore and ore-rs +/// or timestamp, whose order terms wait for new clww-ore and ore-rs /// releases (#1236). [`Reason::IndexNotAdmitted`] for every other pair /// [`admits`] refuses. /// diff --git a/packages/stack-encrypt/src/dynamic/mod.rs b/packages/stack-encrypt/src/dynamic/mod.rs index 7ccaabf08..9be9ab20c 100644 --- a/packages/stack-encrypt/src/dynamic/mod.rs +++ b/packages/stack-encrypt/src/dynamic/mod.rs @@ -530,10 +530,10 @@ reasons! { /// equality or an order index on a boolean, any index on a composite. IndexNotAdmitted => "index_not_admitted", "the declared type has no such index"; /// The field declares an ORE or OPE index on a decimal, date or - /// timestamp. Their order terms wait for cllw-ore and ore-rs + /// timestamp. Their order terms wait for clww-ore and ore-rs /// releases that encode them the ADR-0002 way (#1236); equality on /// them works today. - OrderTermPending => "order_term_pending", "an order index on a decimal, date or timestamp waits for new cllw-ore and ore-rs releases (#1236)"; + OrderTermPending => "order_term_pending", "an order index on a decimal, date or timestamp waits for new clww-ore and ore-rs releases (#1236)"; /// Two fields are keyed under one identity. SharedIdentity => "shared_identity", "two fields are keyed under one identity"; /// The plan has no field of the name asked for. diff --git a/packages/stack-encrypt/src/dynamic/term.rs b/packages/stack-encrypt/src/dynamic/term.rs index 48f360461..89794b575 100644 --- a/packages/stack-encrypt/src/dynamic/term.rs +++ b/packages/stack-encrypt/src/dynamic/term.rs @@ -16,14 +16,14 @@ //! a domain of its own. A boolean has none. //! - **Match** takes text only, cut in Unicode 16 NFC. //! - **ORE, OPE and block ORE** take an integer of 16 bits or wider, a -//! float, text or bytes, each handed to cllw-ore (ORE, OPE) or ore-rs +//! float, text or bytes, each handed to clww-ore (ORE, OPE) or ore-rs //! (block ORE) as the Rust type the typed path would have named: an `i16` //! as an `i16`, a `u128` as a `u128`. A boolean, a `u8` and an `i8` have //! no order term: over a domain that small (two values, or 256) it would //! tell anyone holding the column which rows are `true`, or rank every //! row among 256. A decimal, a date and a timestamp -//! have none yet: cllw-ore 0.5 does not encode them the ADR-0002 way, and -//! their order terms wait for new cllw-ore and ore-rs releases (#1236). +//! have none yet: clww-ore 0.5 does not encode them the ADR-0002 way, and +//! their order terms wait for new clww-ore and ore-rs releases (#1236). //! //! # These are the query-probe path //! @@ -38,9 +38,10 @@ use std::marker::PhantomData; use super::ValueFrame; use stack_kms::DataKeySource; use vitaminc_aead::plaintext::{ - Error as SinkError, Float, Int, Logical, MapSink, Physical, SeqSink, Sink, SourceError, + Error as SinkError, FixedType, Float, Int, Logical, MapSink, Physical, SeqSink, Sink, + SourceError, }; -use vitaminc_normalize::{domain_of, normalize, NormalizeError}; +use vitaminc_normalize::{domain, domain_of, normalize, NormalizeError}; use serde::{Deserialize, Serialize, Serializer}; @@ -149,8 +150,10 @@ impl IndexSpec { /// The table [`defines`](Self::defines) reads, over one scalar. pub(super) fn takes(&self, ty: Option, value: &Physical<'_>) -> bool { match self { - // vitaminc's table: a kind with an equality domain. - IndexSpec::Equality => domain_of(ty, value).is_some(), + // vitaminc's table: a kind with an equality domain. A null has + // one from `vitaminc-normalize` 0.8, and no term here, as before: + // see `sem::normalized`. + IndexSpec::Equality => domain_of(ty, value).is_some_and(|d| d != domain::NULL), IndexSpec::Match(_) => ty.is_none() && matches!(value, Physical::Text(_)), IndexSpec::Ore | IndexSpec::Ope | IndexSpec::OreBlock => ty.is_none() && ordered(value), } @@ -604,6 +607,12 @@ where (self.0)(ty, value).map_err(Refused) } + /// A typed null is a null to a term: its type hides its length when + /// sealed, which a term does not seal. + fn typed_null(self, _: FixedType) -> Result { + self.scalar(None, Physical::Null) + } + fn seq(self, _: Option) -> Result, Refused> { Err(Refused(None)) } @@ -643,6 +652,10 @@ impl Sink for NoContainer { self.unreachable() } + fn typed_null(self, _: FixedType) -> Result { + self.unreachable() + } + fn seq(self, _: Option) -> Result { self.unreachable() } @@ -1333,8 +1346,8 @@ mod tests { /// A decimal, a date and a timestamp have an equality term, from /// vitaminc, and no order term yet: their order encodings wait for - /// new cllw-ore and ore-rs releases (#1236), and the engine does not - /// shim around cllw-ore 0.5. + /// new clww-ore and ore-rs releases (#1236), and the engine does not + /// shim around clww-ore 0.5. #[tokio::test] async fn a_decimal_date_or_timestamp_has_no_order_term_yet() { let cipher = cipher().await; diff --git a/packages/stack-encrypt/src/dynamic/test_frame.rs b/packages/stack-encrypt/src/dynamic/test_frame.rs index 4c4129041..2f57c7f06 100644 --- a/packages/stack-encrypt/src/dynamic/test_frame.rs +++ b/packages/stack-encrypt/src/dynamic/test_frame.rs @@ -9,8 +9,8 @@ use vitaminc_aead::frame::{FrameError, FrameWriteError}; use vitaminc_aead::plaintext::{ - visit_map, visit_seq, Error as _, Float, Int, Logical, MapSink, Physical, SeqSink, Sink, - SourceError, + visit_map, visit_seq, Error as _, FixedType, Float, Int, Logical, MapSink, Physical, SeqSink, + Sink, SourceError, }; use vitaminc_aead::{to_frame, DecodeError, Decrypt, Encrypt, Frame}; use vitaminc_protected::{Controlled, Protected}; @@ -271,6 +271,10 @@ impl Sink for TreeSink { Ok(self.0.put(value)) } + fn typed_null(self, _: FixedType) -> Result { + Ok(self.0.put(Tree::Null)) + } + fn seq(self, _: Option) -> Result, DecodeError> { Ok(TreeSeq { out: self.0, diff --git a/packages/stack-encrypt/src/dynamic/value_frame.rs b/packages/stack-encrypt/src/dynamic/value_frame.rs index e0c0ff6d8..c1cb607a0 100644 --- a/packages/stack-encrypt/src/dynamic/value_frame.rs +++ b/packages/stack-encrypt/src/dynamic/value_frame.rs @@ -33,7 +33,8 @@ use std::sync::Arc; use vitaminc_aead::frame::{Frame, FrameError, FrameMap, FrameSeq, FrameWriteError, FrameWriter}; use vitaminc_aead::plaintext::kinds::timestamp_nanos; use vitaminc_aead::plaintext::{ - Error as _, Float, Int, Logical, MapSink, Physical, SeqSink, Sink, SourceError, TimeUnit, + Error as _, FixedType, Float, Int, Logical, MapSink, Physical, SeqSink, Sink, SourceError, + TimeUnit, Width, }; use vitaminc_aead::{DecodeError, Decrypt, Encrypt}; use vitaminc_protected::{Controlled, OpaqueDebug, Protected}; @@ -200,6 +201,12 @@ impl Sink for Check { .ok_or(DecodeError::Expected(EXPECTED)) } + fn typed_null(self, ty: FixedType) -> Result<(), DecodeError> { + model_null(ty) + .map(drop) + .ok_or(DecodeError::Expected(EXPECTED)) + } + fn seq(self, _: Option) -> Result { Ok(Check) } @@ -331,6 +338,20 @@ fn model(ty: Option, value: Physical<'_>) -> Option<(Option, P }) } +/// A typed null in the value model: a timestamp's as a nanosecond +/// timestamp's, as [`model`] reads the timestamp it stands in for, every +/// other type of the model as it is, or `None` for a type outside the model +/// (a uuid, or a logical type this crate does not know). +fn model_null(ty: FixedType) -> Option { + match ty.logical() { + None | Some(Logical::Date | Logical::Decimal { .. }) => Some(ty), + Some(Logical::Timestamp(_)) => { + FixedType::new(Some(Logical::Timestamp(TimeUnit::Nanos)), Width::I128) + } + _ => None, + } +} + /// A frame writer that holds the [value model](ValueFrame#the-value-model): /// each scalar is read through the model before it is written, and every /// error is a [`DecodeError`], the error a [`Decrypt`] target reports. A @@ -420,6 +441,16 @@ impl<'o> Sink for Modeled> { .map_err(|error| Modeled { inner: (), field }.written(error)) } + fn typed_null(self, ty: FixedType) -> Result<(), DecodeError> { + let Some(ty) = model_null(ty) else { + return Err(self.fault(DecodeError::Expected(EXPECTED))); + }; + let Self { inner, field } = self; + inner + .typed_null(ty) + .map_err(|error| Modeled { inner: (), field }.written(error)) + } + fn seq(self, len: Option) -> Result { let Self { inner, field } = self; let at = Modeled { inner: (), field }; @@ -542,6 +573,15 @@ impl Sink for ModelOnly { } } + fn typed_null(self, ty: FixedType) -> Result { + match model_null(ty) { + Some(ty) => self.0.typed_null(ty), + None => Err(S::Error::source(SourceError::new(DecodeError::Expected( + EXPECTED, + )))), + } + } + fn seq(self, len: Option) -> Result { self.0.seq(len).map(ModelOnly) } @@ -629,6 +669,11 @@ impl Sink for Split { Ok(Parts::Scalar) } + fn typed_null(self, ty: FixedType) -> Result { + let _ = model_null(ty).ok_or(DecodeError::Expected(EXPECTED))?; + Ok(Parts::Scalar) + } + fn seq(self, _: Option) -> Result, DecodeError> { Ok(Children::new(false, parts)) } @@ -748,6 +793,10 @@ impl Sink for Opening { write(|writer| Modeled::new(writer).scalar(ty, value)) } + fn typed_null(self, ty: FixedType) -> Result { + write(|writer| Modeled::new(writer).typed_null(ty)) + } + fn seq(self, _: Option) -> Result, DecodeError> { Ok(Children::new(false, join)) } @@ -835,6 +884,10 @@ impl Sink for Skip { self.done() } + fn typed_null(self, _: FixedType) -> Result { + self.done() + } + fn seq(self, _: Option) -> Result { Ok(self) } @@ -899,6 +952,11 @@ impl Sink for KindOf { Ok(scalar_kind(ty, &value)) } + /// A typed null is a null, which has no kind. + fn typed_null(self, _: FixedType) -> Result { + self.scalar(None, Physical::Null) + } + fn seq(self, _: Option) -> Result { Ok(Skip::ending(Some(ValueKind::Array), false)) } @@ -1006,6 +1064,10 @@ impl Sink for RowsSink { Ok(SourceRows::One(None)) } + fn typed_null(self, _: FixedType) -> Result { + Ok(SourceRows::One(None)) + } + fn seq(self, _: Option) -> Result { Ok(BatchSink(Vec::new())) } @@ -1054,6 +1116,11 @@ impl<'s> Sink for RowSink<'s> { Ok(()) } + fn typed_null(self, _: FixedType) -> Result<(), DecodeError> { + self.0.put(None); + Ok(()) + } + fn seq(self, _: Option) -> Result, DecodeError> { Ok(NotARow(self.0)) } @@ -1173,6 +1240,111 @@ mod tests { ]) } + /// A null that says what it stands in for, as vitaminc walks a `None` + /// of a fixed-width type and as a host may send one in a frame. + struct TypedNull(FixedType); + + impl Encrypt for TypedNull { + fn visit(self, sink: S) -> Result { + sink.typed_null(self.0) + } + } + + fn fixed(ty: Option, width: Width) -> FixedType { + FixedType::new(ty, width).expect("a fixed-width type") + } + + /// A typed null of each kind of type the value model holds: a plain + /// int and float, and the three logical types, a timestamp of another + /// unit than the model's among them. + fn typed_nulls_in_the_model() -> Vec { + vec![ + fixed(None, Width::I64), + fixed(None, Width::F32), + fixed(Some(Logical::Date), Width::I32), + fixed(Some(Logical::Decimal { scale: 2 }), Width::I128), + fixed(Some(Logical::Timestamp(TimeUnit::Micros)), Width::I64), + fixed(Some(Logical::Timestamp(TimeUnit::Nanos)), Width::I128), + ] + } + + /// A uuid has a typed null, and no place in the value model. + fn uuid_null() -> FixedType { + fixed(Some(Logical::Uuid), Width::Bytes16) + } + + /// The frame a host sends for a typed null: the leaf alone. + fn typed_null_frame(ty: FixedType) -> Vec { + let mut out = Vec::new(); + vitaminc_aead::leaf::write_typed_null(ty, &mut out); + out + } + + /// A typed null of a type in the model is a null in a frame: written, + /// read from a host's bytes, or opened. Its padding belongs to a sealed + /// leaf, not to a frame (vitaminc-aead 0.8), and a null has no kind. + #[test] + fn a_typed_null_in_the_model_is_a_null_in_its_frame() { + let null = frame_of(&Tree::Null); + for ty in typed_nulls_in_the_model() { + let written = ValueFrame::of(TypedNull(ty)).expect("in the model"); + assert_eq!(written.risky_ref(), null.risky_ref(), "{ty:?} written"); + let bytes = typed_null_frame(ty); + assert!(ValueFrame::check(&bytes).is_ok(), "{ty:?} checks"); + let read = ValueFrame::from_bytes(&bytes).expect("reads"); + assert_eq!(read.risky_ref(), null.risky_ref(), "{ty:?} read"); + let opened = TypedNull(ty).visit(Opening).expect("opens"); + assert_eq!(opened.risky_ref(), null.risky_ref(), "{ty:?} opened"); + assert_eq!(read.kind(), None, "{ty:?} has no kind"); + } + } + + /// A typed null of a type outside the model is refused wherever a + /// value of that type is. + #[test] + fn a_typed_null_outside_the_model_is_refused() { + let uuid = uuid_null(); + assert!(matches!( + ValueFrame::of(TypedNull(uuid)), + Err(DecodeError::Expected(EXPECTED)) + )); + let bytes = typed_null_frame(uuid); + for refused in [ + ValueFrame::check(&bytes).map(drop), + ValueFrame::from_bytes(&bytes).map(drop), + ] { + assert!( + matches!( + refused, + Err(FromFrameError::Value(DecodeError::Expected(EXPECTED))) + ), + "{refused:?}" + ); + } + assert!(matches!( + TypedNull(uuid).visit(Opening), + Err(DecodeError::Expected(EXPECTED)) + )); + } + + /// A record source that is a typed null, or holds one as a batch + /// element, is a row that is not a map, as a null is. + #[test] + fn a_typed_null_record_source_is_no_row() { + let ty = fixed(Some(Logical::Date), Width::I32); + let one = typed_null_frame(ty); + let one = Frame::parse(&one).expect("a frame"); + assert!(matches!(split_rows(one), Ok(SourceRows::One(None)))); + let mut batch = vec![vitaminc_aead::frame::ARRAY, 2, 0, 0, 0]; + batch.extend(typed_null_frame(ty)); + batch.extend(typed_null_frame(ty)); + let batch = Frame::parse(&batch).expect("a frame"); + assert!(matches!( + split_rows(batch), + Ok(SourceRows::Batch(rows)) if rows.len() == 2 && rows.iter().all(Option::is_none) + )); + } + /// A value's frame is the frame vitaminc writes for it, byte for byte, /// and reads back as the value. #[test] diff --git a/packages/stack-encrypt/src/op/mod.rs b/packages/stack-encrypt/src/op/mod.rs index 8e849f80a..0ec303432 100644 --- a/packages/stack-encrypt/src/op/mod.rs +++ b/packages/stack-encrypt/src/op/mod.rs @@ -343,7 +343,7 @@ impl Input for (S, S) { /// [`Between`]) are answered over: the integers of 16 bits and wider, the /// floats (`f32` and `f64`) and text (`String`). Not `u8` or `i8`, which /// have no order term ([`Orderable`] says why), as `bool` has none. Each is -/// encoded as its [`Orderable`] target and its terms order as cllw-ore +/// encoded as its [`Orderable`] target and its terms order as clww-ore /// orders that encoding: integers as numbers; floats as Postgres's `float8` /// does, `-0.0` tied with `0.0` and every NaN one value above `+Infinity`, /// an `f32` as the `f64` it widens to; text by the system ADR-0002's fold, diff --git a/packages/stack-encrypt/src/sem/mod.rs b/packages/stack-encrypt/src/sem/mod.rs index 8910dcda2..5da726cd7 100644 --- a/packages/stack-encrypt/src/sem/mod.rs +++ b/packages/stack-encrypt/src/sem/mod.rs @@ -135,13 +135,13 @@ use std::marker::PhantomData; // Re-exported because they appear in this module's public signatures // ([`KeysetCipher::ore_term`], [`OreTerm::inner`], ...): a caller can name -// the ciphertext types without depending on `cllw-ore` directly. -use cllw_ore::vitaminc::{Ope, Ore}; -pub use cllw_ore::{OpeCllw8VariableV1, OreCllw8VariableV1}; +// the ciphertext types without depending on `clww-ore` directly. +use clww_ore::{ClwwOpe, ClwwOre}; +pub use clww_ore::{OpeClww8VariableV1, OreClww8VariableV1}; use vitaminc_aead::Encrypt; use vitaminc_hmac::HmacSha256Prf; -use vitaminc_normalize::{terms, NormalizeError, Normalized}; -use vitaminc_ore::{OrderColumn, OrderEncrypt, OrderError, OrderKeyInit, OrderScheme, OrderTarget}; +use vitaminc_normalize::{domain, terms, NormalizeError, Normalized}; +use vitaminc_ore::{OrderEncrypt, OrderError, OrderKeyInit, OrderScheme, OrderTarget}; use vitaminc_prf::{ BlockVisitor, Context, IntoPrfContext, MapAccess, PrfError, PrfValue, PrfVisitor, PrfVisitorError, SeqAccess, @@ -174,9 +174,9 @@ const EQUALITY_DOMAIN: &[u8] = b"stack-encrypt/sem/equality/v2"; const MATCH_DOMAIN: &[u8] = b"stack-encrypt/sem/match/v2"; /// PAE domain for ORE key derivation. /// -/// `v2`: the key keys cllw-ore's vitaminc ORE scheme, which encrypts the +/// `v2`: the key keys clww-ore's vitaminc ORE scheme, which encrypts the /// value's `vitaminc-ore` order encoding at its [`Orderable`] target, where -/// `v1` keyed cllw-ore's own per-type encryption. +/// `v1` keyed clww-ore's own per-type encryption. const ORE_KEY_DOMAIN: &[u8] = b"stack-encrypt/sem/ore-key/v2"; /// PAE domain for OPE key derivation (distinct from ORE: OPE ciphertexts are /// encrypt-only, so the two schemes must never share a key). `v2` as for @@ -200,11 +200,11 @@ pub enum TermError { #[error("PRF failed")] #[diagnostic(code(stack_encrypt::prf_failed))] Prf(#[source] Box), - /// CLLW ORE/OPE encryption failed. (`cllw_ore::Error` is deliberately + /// CLLW ORE/OPE encryption failed. (`clww_ore::Error` is deliberately /// contentless, so its message is fixed text.) #[error("ORE/OPE encryption failed: {0}")] #[diagnostic(code(stack_encrypt::ore_failed))] - Ore(#[from] cllw_ore::Error), + Ore(#[from] clww_ore::Error), /// Block ORE ([`OreBlockTerm`]) orders text and bytes of at most 1023 /// bytes, counted after the order encoding (text folded): the chained /// scheme's 1024-byte ceiling, less the one marker byte it puts in @@ -341,7 +341,7 @@ pub enum TermBytesError { filter_size: u32, }, /// The buffer's length is not one this CLLW ciphertext shape can have. - /// (The length is all there is to report: `cllw_ore::Error` is + /// (The length is all there is to report: `clww_ore::Error` is /// deliberately contentless, so its message would say strictly less.) #[error("{0} bytes do not fit this CLLW ciphertext shape")] #[diagnostic(code(stack_encrypt::cllw_ciphertext_length))] @@ -505,9 +505,16 @@ pub(crate) fn normalized(value: T) -> Result })?; match (terms.pop(), terms.is_empty()) { // One term, and at the root: the value is that scalar. A container - // with one indexable scalar inside is not a scalar, and a null or a - // boolean produces no term at all. - (Some(term), true) if term.path.steps().is_empty() => Ok(term.normalized), + // with one indexable scalar inside is not a scalar, and a boolean + // produces no term at all. A null has one under `vitaminc-normalize` + // 0.8, and it is dropped here: an absent value keeps a SQL `NULL` + // in its equality column until a null's index terms are decided + // (#1298). + (Some(term), true) + if term.path.steps().is_empty() && term.normalized.domain != domain::NULL => + { + Ok(term.normalized) + } _ => Err(TermError::NoEqualityTerm), } } @@ -1137,7 +1144,7 @@ where /// A plaintext type an order term ([`OreTerm`], [`OpeTerm`]) is derived /// over, and the `vitaminc-ore` order target its values are encoded as. /// This crate is the layer above the order schemes: it names each type's -/// target, and cllw-ore encodes the value as that target and encrypts it. +/// target, and clww-ore encodes the value as that target and encrypts it. /// The encoding (integer width, the canonical float, text's fold) is the /// scheme's, through `vitaminc-ore`, and never this crate's. The value goes /// to the scheme as a `vitaminc-aead` [`Encrypt`] source, by reference, so @@ -1161,9 +1168,8 @@ where /// one of 256 ranks, which a few known rows resolve to the values. So /// `OreTerm`, `OreTerm` and `OreTerm` do not compile (nor /// the `OpeTerm`s), as the dynamic path refuses the same scalars -/// (`dynamic::admits`); each keeps its equality term. `vitaminc-ore` still -/// offers the one-byte targets; their removal is tracked at -/// . +/// (`dynamic::admits`); each keeps its equality term. `vitaminc-ore` has +/// no one-byte target either, since 0.7. /// /// ```compile_fail /// use stack_encrypt::sem::OreTerm; @@ -1192,18 +1198,18 @@ pub trait Orderable: sealed::Sealed + Zeroize + Send + 'static { } mod sealed { - use vitaminc_ore::{OrderColumn, OrderError, OrderScheme}; + use vitaminc_ore::{OrderError, OrderScheme, OrderSpace, OrderTarget, Supports}; - /// Hands `&self` to the column as the `vitaminc-aead` `Encrypt` source + /// Hands `&self` to the space as the `vitaminc-aead` `Encrypt` source /// it is (`&String`, `&i32`, ...), so the owner keeps the one copy and /// wipes it. Not public, and one body for every type: it is here, and /// not a `&Self: Encrypt` bound on `Orderable`, because such a bound is /// not implied at the trait's use sites and would have to be repeated on /// each. pub trait Sealed { - fn encrypt_in( + fn encrypt_in>( &self, - column: &OrderColumn<'_, S>, + space: &OrderSpace<'_, S>, ) -> Result>; } } @@ -1211,11 +1217,11 @@ mod sealed { macro_rules! orderable { ($($ty:ty => $target:ident),* $(,)?) => {$( impl sealed::Sealed for $ty { - fn encrypt_in( + fn encrypt_in>( &self, - column: &OrderColumn<'_, S>, + space: &vitaminc_ore::OrderSpace<'_, S>, ) -> Result> { - column.encrypt(self) + space.encrypt_checked(self).map(vitaminc_ore::OrderTerm::into_raw) } } impl Orderable for $ty { @@ -1230,33 +1236,33 @@ orderable!( String => Text, Vec => Bytes, ); -/// Why cllw-ore produced no order term, as a [`TermError`]: the value's -/// encoding refused it, or the scheme failed. `cllw_ore::Error` carries +/// Why clww-ore produced no order term, as a [`TermError`]: the value's +/// encoding refused it, or the scheme failed. `clww_ore::Error` carries /// nothing, so a scheme failure is that one value whichever way it /// arrives. A scalar of an [`Orderable`] type is never a container and /// never unsupported by a CLLW scheme, so those refusals cannot occur; /// they read as a scheme failure rather than a panic. -fn order_error(error: OrderError) -> TermError { +fn order_error(error: OrderError) -> TermError { match error { OrderError::Term(error) => TermError::Normalize(error), - _ => TermError::Ore(cllw_ore::Error), + _ => TermError::Ore(clww_ore::Error), } } /// An order-revealing (CLLW ORE) index term for a source value of type `T`: -/// cllw-ore's encryption of the value's `vitaminc-ore` order encoding at +/// clww-ore's encryption of the value's `vitaminc-ore` order encoding at /// `T`'s [`Orderable`] target. Comparisons order like the plaintexts, within /// one index. /// /// The type parameter is the *source* type: `OreTerm` in a record type /// declares "this field is the ORE term of a `u64`". Every source type's -/// term is the same ciphertext type, [`OreCllw8VariableV1`]. -pub struct OreTerm(OreCllw8VariableV1, PhantomData T>); +/// term is the same ciphertext type, [`OreClww8VariableV1`]. +pub struct OreTerm(OreClww8VariableV1, PhantomData T>); /// An order-preserving (CLLW OPE) index term for a source value of type `T` -/// (see [`OreTerm`]): [`OpeCllw8VariableV1`], which compares with plain +/// (see [`OreTerm`]): [`OpeClww8VariableV1`], which compares with plain /// lexicographic byte order. -pub struct OpeTerm(OpeCllw8VariableV1, PhantomData T>); +pub struct OpeTerm(OpeClww8VariableV1, PhantomData T>); /// Index terms are one-way: decryption passes over them. `Decryptable` and /// `DecryptField` say so, which is how a derived record finds its ciphertext @@ -1377,8 +1383,8 @@ macro_rules! term_wrapper { }; } -term_wrapper!(OreTerm, OreCllw8VariableV1); -term_wrapper!(OpeTerm, OpeCllw8VariableV1); +term_wrapper!(OreTerm, OreClww8VariableV1); +term_wrapper!(OpeTerm, OpeClww8VariableV1); /// A block ORE index term for a source value of type `T`: ore-rs's 6-bit /// block ORE encryption of the value's `vitaminc-ore` order encoding at @@ -1417,13 +1423,6 @@ term_wrapper!(OpeTerm, OpeCllw8VariableV1); /// of their common prefix in six-bit blocks. pub struct OreBlockTerm(Vec, PhantomData T>); -/// Which of ore-rs's 6-bit schemes encrypts a target's terms: the -/// fixed-width scheme for a target of at most ten bytes, the chained one -/// for the rest, text and bytes among them. -fn ore_block_is_bit6(target: OrderTarget) -> bool { - target.width().is_some_and(|width| width <= 10) -} - /// The order of two block ORE ciphertexts, by the comparator of the scheme /// their header names; `None` if either is not a well-formed ciphertext of /// that scheme, if they name different schemes, or (chained) if they were @@ -1433,14 +1432,8 @@ fn ore_block_is_bit6(target: OrderTarget) -> bool { /// with. ore-rs's `bit2_w6` module is its 6-bit scheme; the legacy 8-bit /// scheme (`BlockOre`, module `bit2`) is not used here. fn ore_block_compare(a: &[u8], b: &[u8]) -> Option { - use ore_rs::scheme::bit2_w6::OreAes128Bit6ChaCha20; - use ore_rs::scheme::chained::OreAes128Bit6ChainedChaCha20; - use ore_rs::OreCipher; - match (a.get(..2)?, b.get(..2)?) { - ([0x02, 0x02], [0x02, 0x02]) => OreAes128Bit6ChaCha20::compare_raw_slices(a, b), - ([0x02, 0x03], [0x02, 0x03]) => OreAes128Bit6ChainedChaCha20::compare_raw_slices(a, b), - _ => None, - } + use ore_rs::{BlockOre, Term}; + BlockOre::compare(&Term::from_bytes(a.to_vec()), &Term::from_bytes(b.to_vec())) } impl OreBlockTerm { @@ -1531,7 +1524,7 @@ impl PartialOrd for OreBlockTerm { } /// A [`PrfVisitor`] that carries the plaintext in and hands the CLLW ORE -/// ciphertext out. The PRF block keys cllw-ore's vitaminc ORE scheme +/// ciphertext out. The PRF block keys clww-ore's vitaminc ORE scheme /// *inside* `visit_block` and dies there: the block arrives by value, is /// copied into the scheme's key (wiped when the scheme drops) and wiped /// here, the value is encrypted, and only the ciphertext leaves. No key is @@ -1555,7 +1548,7 @@ impl PartialOrd for OreBlockTerm { /// /// The plaintext is held in a [`Zeroizing`], so it is wiped when the /// visitor drops: after `visit_block`, or unvisited if the PRF fails first. -/// `encrypt_in` reads it by reference and cllw-ore copies nothing out of it +/// `encrypt_in` reads it by reference and clww-ore copies nothing out of it /// unwiped, so that drop is the last place its bytes live. struct OreVisitor(Zeroizing); @@ -1564,13 +1557,13 @@ where T: Orderable, P: Send + 'static, { - type Value = Result; + type Value = Result; fn visit_block(self, mut block: [u8; 32]) -> Result { - let scheme = Ore::new(Protected::new(block)); + let scheme = ClwwOre::new(Protected::new(block)); block.zeroize(); - let column = scheme.column(T::TARGET, ()); - Ok(sealed::Sealed::encrypt_in(&*self.0, &column).map_err(order_error)) + let space = scheme.target(T::TARGET); + Ok(sealed::Sealed::encrypt_in(&*self.0, &space).map_err(order_error)) } } @@ -1583,20 +1576,20 @@ where T: Orderable, P: Send + 'static, { - type Value = Result; + type Value = Result; fn visit_block(self, mut block: [u8; 32]) -> Result { - let scheme = Ope::new(Protected::new(block)); + let scheme = ClwwOpe::new(Protected::new(block)); block.zeroize(); - let column = scheme.column(T::TARGET, ()); - Ok(sealed::Sealed::encrypt_in(&*self.0, &column).map_err(order_error)) + let space = scheme.target(T::TARGET); + Ok(sealed::Sealed::encrypt_in(&*self.0, &space).map_err(order_error)) } } /// The block ORE twin of [`OreVisitor`]: same key handling, under its own -/// domain, and the scheme chosen by the target ([`ore_block_is_bit6`]). -/// Both schemes are keyed from the one block; ore-rs derives each one's -/// ORE key from it under a label of its own. The plaintext is held in a +/// domain. ore-rs's `BlockOre` routes the space to its 6-bit or chained +/// engine by the target's width, and derives the one ORE key both use from +/// the block under a label of its own. The plaintext is held in a /// [`Zeroizing`], as [`OreVisitor`]'s is: ore-rs reads it by reference and /// works on scrubbed copies, so that drop is the last place its bytes live. struct OreBlockVisitor(Zeroizing); @@ -1609,18 +1602,10 @@ where type Value = Result, TermError>; fn visit_block(self, mut block: [u8; 32]) -> Result { - use ore_rs::vitaminc::{Bit6BlockOre, ChainedBlockOre}; - let key = Protected::new(block); + let scheme = ore_rs::BlockOre::new(Protected::new(block)); block.zeroize(); - let term = if ore_block_is_bit6(T::TARGET) { - let scheme = Bit6BlockOre::new(key); - sealed::Sealed::encrypt_in(&*self.0, &scheme.column(T::TARGET, ())) - .map(|term| term.as_ref().to_vec()) - } else { - let scheme = ChainedBlockOre::new(key); - sealed::Sealed::encrypt_in(&*self.0, &scheme.column(T::TARGET, ())) - .map(|term| term.as_ref().to_vec()) - }; + let term = sealed::Sealed::encrypt_in(&*self.0, &scheme.target(T::TARGET)) + .map(ore_rs::Term::into_bytes); Ok(term.map_err(ore_block_error)) } } @@ -1628,9 +1613,8 @@ where /// Why ore-rs produced no block ORE term, as a [`TermError`]: the value's /// encoding refused it, the value is too long, text ends in NUL, or the /// scheme failed. ore-rs's errors name no part of the value. A target the -/// scheme does not take cannot occur ([`ore_block_is_bit6`] sends every -/// other target to the chained scheme, which takes them all), and reads as -/// a scheme failure rather than a panic. +/// scheme does not take cannot occur (`BlockOre` takes every target), and +/// reads as a scheme failure rather than a panic. fn ore_block_error(error: OrderError) -> TermError { use ore_rs::OreError; match error { @@ -1710,26 +1694,27 @@ fn ore_block( .map(|bytes| OreBlockTerm(bytes, PhantomData)) } -/// Whether block ORE takes `text` as order text: its fold (the order -/// encoding a [`OreBlockTerm`] encrypts) must exist, fit the chained -/// scheme's 1023 bytes, and not end in NUL. The refusals derivation makes, +/// Whether block ORE takes `text` as order text: its order encoding (the +/// marker byte, then the fold, which a [`OreBlockTerm`] encrypts) must +/// exist, fit the chained scheme's 1024 bytes, and not end in NUL. The refusals derivation makes, /// stated without a key, so a binding can refuse a query at its boundary. #[cfg_attr(not(feature = "dynamic"), allow(dead_code))] pub(crate) fn ore_block_text(text: &str) -> Result<(), TermError> { - let folded = vitaminc_ore::text(text)?; - let folded = vitaminc_protected::Controlled::risky_ref(&folded); - if folded.len() > ORE_BLOCK_MAX_BYTES { + let encoded = vitaminc_ore::text(text)?; + let encoded = vitaminc_protected::Controlled::risky_ref(&encoded); + if encoded.len() > ORE_BLOCK_MAX_BYTES { return Err(TermError::OreBlockTooLong); } - if folded.last() == Some(&0) { + if encoded.last() == Some(&0) { return Err(TermError::OreBlockTrailingNul); } Ok(()) } /// The longest text or bytes order encoding block ORE takes: ore-rs's -/// chained ceiling (1024 bytes) less the marker byte it puts in front. -const ORE_BLOCK_MAX_BYTES: usize = ore_rs::scheme::chained::DEFAULT_MAX_STR_BYTES - 1; +/// chained ceiling, 1024 bytes, which counts the marker byte `vitaminc-ore` +/// puts in front of the fold, so the fold itself is at most 1023. +const ORE_BLOCK_MAX_BYTES: usize = ore_rs::scheme::chained::DEFAULT_MAX_STR_BYTES.get(); /// An ORE term of any [`Orderable`] source. Under the local HMAC /// backend, derived during the synchronous build — the returned [`Pending`] @@ -1953,7 +1938,7 @@ impl KeysetCipher<'_, K> { &self, value: T, descriptor: NonEmpty>, - ) -> Pending<'_, OreCllw8VariableV1, K> { + ) -> Pending<'_, OreClww8VariableV1, K> { let term = ore(self.prf(), value, descriptor.into_prf_context()).map(OreTerm::into_inner); Pending::ready(self, term.map_err(Error::from)) } @@ -1966,7 +1951,7 @@ impl KeysetCipher<'_, K> { &self, value: T, descriptor: NonEmpty>, - ) -> Pending<'_, OpeCllw8VariableV1, K> { + ) -> Pending<'_, OpeClww8VariableV1, K> { let term = ope(self.prf(), value, descriptor.into_prf_context()).map(OpeTerm::into_inner); Pending::ready(self, term.map_err(Error::from)) } diff --git a/packages/stack-encrypt/tests/fixtures/README.md b/packages/stack-encrypt/tests/fixtures/README.md index 6fb6ac18c..d75cc2be5 100644 --- a/packages/stack-encrypt/tests/fixtures/README.md +++ b/packages/stack-encrypt/tests/fixtures/README.md @@ -131,7 +131,7 @@ file changes only when a derivation does: regenerate it with form `QueryTerm::to_value` writes, the bytes in hex: one term, or for `between` the low bound's then the high's. An input is JSON, read as the field's declared type, so `40` queries the `uint32` field `age` and - `1.5` the `float64` field `score`, whose terms are cllw-ore's + `1.5` the `float64` field `score`, whose terms are clww-ore's encryption of the float's ADR-0002 order key. - **`verify`.** A page of decrypted values, null for an empty field, and the boolean `verify` answers for each, which is what the typed `MatchQuery` diff --git a/packages/stack-encrypt/tests/fixtures/query_operators.json b/packages/stack-encrypt/tests/fixtures/query_operators.json index d0630eba4..cb850311e 100644 --- a/packages/stack-encrypt/tests/fixtures/query_operators.json +++ b/packages/stack-encrypt/tests/fixtures/query_operators.json @@ -86,7 +86,7 @@ "fidelity": "exact", "index": "ore", "operator": "lt", - "term": "758821c792265d942f89fa1dad016fb71b326f756e62950367e5d12f636d8b78" + "term": "f18256adef15adefb7ed6dea76d0de5418257a7406b06cb9b73fbd5bd75a8d17" } }, { @@ -98,7 +98,7 @@ "fidelity": "exact", "index": "ore", "operator": "lte", - "term": "758821c792265d942f89fa1dad016fb71b326f756e62950367e5d12f636d8b78" + "term": "f18256adef15adefb7ed6dea76d0de5418257a7406b06cb9b73fbd5bd75a8d17" } }, { @@ -110,7 +110,7 @@ "fidelity": "exact", "index": "ore", "operator": "gt", - "term": "758821c792265d942f89fa1dad016fb71b326f756e62950367e5d060dbfcceb5" + "term": "f18256adef15adefb7ed6dea76d0de5418257a7406b06cb9b73fbcbb958af97f" } }, { @@ -122,7 +122,7 @@ "fidelity": "exact", "index": "ore", "operator": "gte", - "term": "758821c792265d942f89fa1dad016fb71b326f756e62950367e5d060dbfcceb5" + "term": "f18256adef15adefb7ed6dea76d0de5418257a7406b06cb9b73fbcbb958af97f" } }, { @@ -138,8 +138,8 @@ "index": "ore", "operator": "between", "term": [ - "758821c792265d942f89fa1dad016fb71b326f756e62950367e5d060dbfcceb5", - "758821c792265d942f89fa1dad016fb71b326f756e62950367e6377200eec06b" + "f18256adef15adefb7ed6dea76d0de5418257a7406b06cb9b73fbcbb958af97f", + "f18256adef15adefb7ed6dea76d0de5418257a7406b06cb9b7404de8dd94a9f9" ] } }, @@ -176,7 +176,7 @@ "fidelity": "exact", "index": "ore", "operator": "lt", - "term": "d86769e4203df9a878dfb084014ea9df2ac9e74b1cef394f5042a6a88e4b81ab7d678eb59f8d27089e5e988fe8130bf9ea2707ab35e341d60c19c9836360eb21" + "term": "9129fe70c2594324aa169a5a9b5a5cbb6069d6574e65017fd005c8bd524bc9d72b923c40c2ec4b3b0e7505ebe58dc929288e836aade49c2680591d17ca9c9989" } }, { @@ -192,8 +192,8 @@ "index": "ore", "operator": "between", "term": [ - "d73ffdebc829eff390b70c5e169f58bf4b2aa664817584cc01f5e114eb7d91d2b6fe729db0f85f0df93d0487a2888f0a1865ca8946912ec33493cb18c5abb183", - "d8688e0201b46fefe8147f16e4011433e428361b12b70e40fed58a526bcdad72208619a7f90e617d22ddda3df8de4ccc224672bc0ea650ad64e30fb253851039" + "90a140c66cc77328cd49e57126a8802c821b5a85713adc8aa79f5ceb311703b3cb788a110494d03fa232c37a2da71ba7f0c20c1f67265dd39b770131ff52ef69", + "912aa94b90269735f38220cfde3773a20658a7990105503ac2d01974a3fb247193566f5cca1bad36337511634befbf6068bd264336df7ea45bf3665bfbe0c124" ] } } diff --git a/packages/stack-encrypt/tests/fixtures/record_lowering.json b/packages/stack-encrypt/tests/fixtures/record_lowering.json index 45ec0cca3..ad2033a38 100644 --- a/packages/stack-encrypt/tests/fixtures/record_lowering.json +++ b/packages/stack-encrypt/tests/fixtures/record_lowering.json @@ -125,12 +125,12 @@ "records": { "lowering": { "age": { - "c": "01000000000000000000000000000000004d5626148f77c4c6d9da0ddbdf7663a2200021162641133485216f389886cbd7c6e9b25afa0f5f166f985b23384e81ffcfac02ec48f08e1f2c79b55251885601527a0226a754a797eaa77131f9c7f2d6157f2098", + "c": "01000000000000000000000000000000004d5626148f77c4c6d9da0ddbdf7663a2200021162641133485216f389886cbd7c6e9b25afa0f5f166f985b23384e81ffcfac02b8a4ba034bed62ff824a3fe900c54478386f337ae9d2c48fef5d0e3b8038b50a47", "eq": "cc854fd5c7e3f4bb28cb15cae47d866b65b7012c06df43b4b9a6c51adff4710a", - "ore": "758821c792265d942f89fa1dad016fb71b326f756e62950367e5d12f62824807" + "ore": "f18256adef15adefb7ed6dea76d0de5418257a7406b06cb9b73fbd5bd6b95899" }, "email": { - "c": "0100000000000000000000000000000000b2afa77357a61488146c0edaa0246f65200043956c4f4bba857028c28165dfce9c63d904b738bbb039b6e11c805112d4a1ee025de4969eb5509d9cb7d2ef0ea827c2b6bf09d7b73ff165ad68d6fe1136f254f9accc930118490a162a1f829b", + "c": "0100000000000000000000000000000000b2afa77357a61488146c0edaa0246f65200043956c4f4bba857028c28165dfce9c63d904b738bbb039b6e11c805112d4a1ee02d5caa00b343d83eb68dc193f7a8c078ecef211cd2761ed97b15579147bfc0937d2c9f59a5bbacd7ce72a5167", "eq": "0cf708c07acaaa169e84e4adf7081f0433d87760bd7e9c63bd7a58c000b8d33b", "match": "030005000900100012001a001c0027002a002e003000340042004b0068006d007100750083009200a800b200b400b700ba00c200c500dc00e500ea00f200f300f900fe00" }, @@ -138,17 +138,17 @@ "passthrough": 42 }, "notes": { - "c": "0100000000000000000000000000000000723f7a7f14b07197168aa13bc52010b3200072a73194b45af604cc6201b5a57554b05cc7ed6ad22b9102cbcb71bd90678496021b7a7da71f40bec0f7d93f6bb3a8f32da41d7eac589e1063c90e7d18e397a81b88d966861810b8" + "c": "0100000000000000000000000000000000723f7a7f14b07197168aa13bc52010b3200072a73194b45af604cc6201b5a57554b05cc7ed6ad22b9102cbcb71bd9067849602fd852f9aa4e30c6a3d583c8c5283ec1210b53c274c3e037cd13b0462c79694f2ca4153cd59d959" } }, "typed_chain": { "age": { - "c": "010000000000000000000000000000000092e427c5e176b60261add6ce80fd02df20008d231453c97fdec97a0b6559ac8f509129d20163f262d40ce5d77cf1ebe0cad50248c801def074dfd0d34b7f34a04479875a7df403a3b12bd8ca475d4f377a86394f", + "c": "010000000000000000000000000000000092e427c5e176b60261add6ce80fd02df20008d231453c97fdec97a0b6559ac8f509129d20163f262d40ce5d77cf1ebe0cad5022075c95245d04dd7b21c1130d28607d36857b296b75ee506a84df8ef2bd9b73336", "eq": "cc854fd5c7e3f4bb28cb15cae47d866b65b7012c06df43b4b9a6c51adff4710a", - "ore": "758821c792265d942f89fa1dad016fb71b326f756e62950367e5d12f62824807" + "ore": "f18256adef15adefb7ed6dea76d0de5418257a7406b06cb9b73fbd5bd6b95899" }, "email": { - "c": "0100000000000000000000000000000000cf92191950409f9fe82a2b11888ffc1d2000ca4d5bbafbff919af4d3a95c7cc046d632fd4c28785b238f4b6f7ea3aa08482902a278c63260694db784fbb3361b95717b08851fa7bf6cce35e45ac115dbaffb9f93dac5cd53939eae0cba0832", + "c": "0100000000000000000000000000000000cf92191950409f9fe82a2b11888ffc1d2000ca4d5bbafbff919af4d3a95c7cc046d632fd4c28785b238f4b6f7ea3aa08482902b82f3961528a67647fb28f394328c2025a2d170fb16ef83779b0478f1e2649c87be3c5953dfac5a9688244c8", "eq": "0cf708c07acaaa169e84e4adf7081f0433d87760bd7e9c63bd7a58c000b8d33b", "match": "030005000900100012001a001c0027002a002e003000340042004b0068006d007100750083009200a800b200b400b700ba00c200c500dc00e500ea00f200f300f900fe00" }, @@ -156,7 +156,7 @@ "passthrough": 42 }, "notes": { - "c": "0100000000000000000000000000000000562a41e032316ff2d1264a9e9f5c3b842000de33c8d1f2caaab8b90f691161a57eeb1328f7f1c9b5be76dec83e8a53765f1102bdeeaf5aa37fa829e7519021baaa76584778ece652b6b881054d4f5c9203662309001de93e044a" + "c": "0100000000000000000000000000000000562a41e032316ff2d1264a9e9f5c3b842000de33c8d1f2caaab8b90f691161a57eeb1328f7f1c9b5be76dec83e8a53765f1102ef67a5276edc137d864f7ddc443911539b36bc6b9209bcc1dc0a8f25dec298557c6ed356901642" } } } diff --git a/packages/stack-encrypt/tests/fixtures/stored_rows_v1.json b/packages/stack-encrypt/tests/fixtures/stored_rows_v1.json index 75c77df16..cb231e0aa 100644 --- a/packages/stack-encrypt/tests/fixtures/stored_rows_v1.json +++ b/packages/stack-encrypt/tests/fixtures/stored_rows_v1.json @@ -485,7 +485,7 @@ [ "ore", { - "passthrough": "0b280000008bb663d8b4c006682148c9277bc5e57d411fba769c6414c115d538247d2949371e0c5aad377dc8a7" + "passthrough": "0b280000009a8ad7f813cc32d1fb89fe1c14a45d57655c0e52d6c3677801a1c80abffcff0e2ce64d6622f740e0" } ] ] @@ -498,7 +498,7 @@ [ "ope", { - "passthrough": "0b290000000060d402259cb39497228b893f5e0a87a0c7800b2a0fa773b681dea30ac939d570cd945da2ec1f7c44" + "passthrough": "0b29000000000bbe8e366aaefdf2ba27bdef9176db2d23f7f50a22d6b39d0b5fa83a5e369f80f3af1d31cc294f62" } ] ] @@ -548,7 +548,7 @@ [ "ore", { - "passthrough": "0bc0000000e4596b725e0c386758533cd6e735152740b9af9bd6e96019ac18a724e079479d43caad7e83ce14f737ca246ae6ba5ad0c0a2e5f7f0a2101c1831bc6aee4ccc2a22292816e36cc8938536d59d689be229b0d0210e0354900ba200b04f93545a06098d2edb7531e590da3dc5cd393261d54f60574a127e198bfc752099b1cfd5f4fe44666963b4e5b3e0c8e7623c8eae478d05c0513e5554be89ca7f1248fd52e23e23974da8052807e49f4782d6d42e0d5690c37d1242ba62fdc4200434be1593" + "passthrough": "0bc00000000cdf4b4c993712153fe8007ccd5f4f3e495a9041d31bc68604f2b73aad04160d7924ce0cd737ca11ce3cb781c035b03a666e8f3972ed867fdd41a2b79eab6a9879e9e54ea22c0e2c25f6bd508e5d145d41d23470a4285bccfbaf2d48f024dd5888038175cd65324640f080b9c45bed2e95f08d9033707b88fb45b41014b7ec9196a05aa7ac3376b9d85b0577f8cac62e26d259dfa55d1a471c69ee454be8dc9007cdecae62f2b4995a353d6d7a36aceba19c2d1987309633cad0c39ea9c8c095" } ] ] @@ -561,7 +561,7 @@ [ "ope", { - "passthrough": "0bc100000000849552987a983ba140e5c8fa0eac802885238b8fcd80f3e55e95f286f24ba7b93c67dfc7501c82b3bad61452b7a8e3b1adbeb99526f990ea8f8e0570666ba91ce7be424ecd14712dd2f96518e26605f14440805a241dd14b28497fb3ed6cf0bfabab60848d2871bdb87377deae6a313c0f6485ce91f103c7f309044f8cf03a3a8aca48dce15500126d1dd2de74674f6e11fc02cf46075ef6c6f09d8b797ade427d3bbd5807e3e066dfee5a3eff31b6698c5a6e6640d70987838d373c39ce7df3" + "passthrough": "0bc100000000b68f3ecc27ba3c18dd2b9443ac9ef6738ee9f0a8cf0ac940da750e708206b2deece11785edc533afed8c3933402115be70afedb2e8c9a63c9b73dff7df85eca922db44e52832a73634b9bcc8bd25090695e540f3acf5902fd064fa246a3b868e126dd2b56e34898b9c22131e2d3e80cc5f2dcb066ba67ff3f1cb9a00e14d41c9930105ae716b1edb449b0891f08eabd6e0aac2ec58fe59067b1e619214f7355df280b5ff2b9f091a465a765805d31714cb25b3ddcc4c43f55166f0f2782d48b8" } ] ] @@ -586,7 +586,7 @@ [ "ore", { - "passthrough": "0b400000003a83168a330a190579e7a0dce23066fc5bf762b1b10a0fd4b5add6be7f76c09f027a39deaaf81c35050751ef258433a5e79bb0835ffa705b1660cf0439ae4813" + "passthrough": "0b40000000ae483a7f5defe9fd696a1ebd1d1a927e94f16542b2434eaacd81aa389bb5993f09c4a56fb21c9d6d2cb598cd11fea4ccd646dbb596543126f79840afd62bcdd5" } ] ] @@ -599,7 +599,7 @@ [ "ope", { - "passthrough": "0b41000000010713d30a44fad510839aa637489c19b56062ffb692d964261640079e31e321728559526c51454b6d827518b8b47c64f9875b6864e62edc62e328d0e0598f1f10" + "passthrough": "0b4100000000f7c004b44504216d9907bf9e1e72cab855bded9848a49430427b1b93c88b0400728c4d67a9a4455c66a37e0915fc2b49690481e6208534f01b6df0ec04eaf71a" } ] ] @@ -624,7 +624,7 @@ [ "ore", { - "passthrough": "0b40000000bdcc3110154be791c3148934d9a7b2bb1082581099dcd46dd44719e6db2b192cb455bec8ee6c2632e0e1b1b322fe419ba72a4c34aec7a543fd93e67fd553f763" + "passthrough": "0b40000000f0420be99f95a537de3161a6cee6c390c7d3ba87d8bd9af602e9a31135d914f3d9f3206d80f44d040631d6971f05975683fd01f783be096a2c9bb29d40c0ba6c" } ] ] @@ -637,7 +637,7 @@ [ "ope", { - "passthrough": "0b4100000000c8228ef43865b325619e4992b56db2acd73e6305a23db7b01c1087c865c6a921ff4b8439def81446aae4e1852ed4e38bbe194701b5d2924ac50c9407f3159a52" + "passthrough": "0b410000000152284d4a6f5a77d5c623651887ba617a05a6b5e9dda3224c244fcde2f6aa1c07261a406a66225484333e23559ab2c36a2f689f8757f484687efcf5932ff80c0b" } ] ] @@ -675,7 +675,7 @@ [ "ore", { - "passthrough": "0b80000000515b9aa9f37d24e2f041da7e424739cc232b81f85e6c6ef07829cea2434ff599f0d83ba6cad9cd71909d8b6d5bbe3bfcb61a234edac0b41ff728e98e9ab633f1d6ccecf4aa5ab288e74eaddd2b899c8952a025f7097117654c3d0eadd7278f5bd770689692b810f1c0de8d2f7ad9def60dc124d78f5360ebd2aee7a028aa4c0d" + "passthrough": "0b80000000d07b956b59e55e4fe46de19da96a9f46342bf2c8c5185632579fc09c35927f7de262f0c0dd2811add117fb73e752e4310c1012c9e1ce9d0263491bd43e78b3d8ac8f9130626327d49bcd341a061ac24d3fb540542b7527d5427b57cdd6038b125f7aaa23fb62d8ee34b91118a06262cc2a32cc102da823f0a3d49927bc04037e" } ] ] @@ -688,7 +688,7 @@ [ "ope", { - "passthrough": "0b81000000007f3e0dbb3cb4371fee47438dd52f3f96c5395a75a8c6f97500af1feae03fc587960db5137bc84733c3e26c6cece4572b5068ffbd237b7959edd8b1a7ca5d317ff1869f73b29e157eeb4a0e12cc20f148c2f0f9fd00c127fe6e392f047f0f4ae84d5f03c29340cce05cd83e9baa7b5e78d4e0933ab9c943ffe49d62d5e6ba8727" + "passthrough": "0b8100000000fcd75a25f22a0f976fb0691700c111679d9ae5807b7bdd69be6c5154437190b9f327efaeaf95b6f7279c3fc1a5f71fa4298984bddfcec1eeb3ce7f10bed6a459089d5de948fc9e236e4f179cdc5bebd22590ee097df0c1eb16de6acc85181f42e5c6d005b2ab1f97d2b8d5861804815b22b9d2da17ee7c428c6208ed12ac05b3" } ] ] @@ -713,7 +713,7 @@ [ "ore", { - "passthrough": "0b10000000be1fd669d8a2cae089e62262c8f163f8" + "passthrough": "0b1000000076beb2c335e8d902eceac35139e55eda" } ] ] @@ -726,7 +726,7 @@ [ "ope", { - "passthrough": "0b11000000003f039dde79c7dd4ccffd191d5544c2ed" + "passthrough": "0b11000000003abd4e8ece83ec95aafd466a98d30fa4" } ] ] @@ -751,7 +751,7 @@ [ "ore", { - "passthrough": "0b20000000f366ce2845fadc799d60dd73190baaa1e79444a558aeb2454490483c76cdfc01" + "passthrough": "0b20000000a3183396975476acc1d0f11df0d5de324f4feb8d9a5f8ed00d963732a9ef418f" } ] ] @@ -764,7 +764,7 @@ [ "ope", { - "passthrough": "0b2100000000c61f2fc35629dcad1b5b22bd86c54a908409b2921d7362d2fe21c2a93c604916" + "passthrough": "0b2100000000c0b07e08ab5a32002b85c4b5f6f7772c14f653452f186ea13c371815983a7a75" } ] ] @@ -789,7 +789,7 @@ [ "ore", { - "passthrough": "0b4000000076f1db359db6b05234937ef37330e9b839c9b5653d16602b7871b1277981065ade1de6ee1ce10dd832f0affcd3b92ddaf75e1db9c619ee8cea18cd89425113a4" + "passthrough": "0b40000000cdf3883765bac44a78dab78be97cac096c219645e64b4718a0efc8ec12740eca2523b7e68d14878b35d2f084845025d94eb5c033fe97f0be5fe410f755e6d29c" } ] ] @@ -802,7 +802,7 @@ [ "ope", { - "passthrough": "0b41000000006e4cb9aaf3e0ed8761ffd0b74ccf91aeabfccabc8f5fc8b4deb29d757dcaba7c063006eb92a5b572dc86349f270ab3e1d3f08bd4372d8660f37ea5725d7a159e" + "passthrough": "0b4100000000925deb04bf2246c26ca7fa3deac9a51bfe24b1d37730225d73dba7169aa6845c486aa397714c58e9954a39ca4bf6532be6b0af020b7f936b9a679856ea0ca7d5" } ] ] @@ -946,7 +946,7 @@ [ "ore", { - "passthrough": "0b800000008e3c2cd1cb101f207b6ff8e0c736294fd32c7c9d8a27532cb8629d31d923c9b04e43c711c3e6a7a25758e6a2e957743d407c29a0944421a3d9e259d0b180a019c008e9f339a6db877ba8245ea8f3964db0f4f866e8f19cc0d6351e772aebe54d2ab6fe33efd6f8a0655edc64f1d1c6263294bbb39e27fda896aa1c09273afa30" + "passthrough": "0b800000004b813a291f8e04f8567e18a4e2aaeef57902dde07827bf115844d18d36de06d172697e0c0163517e0b421e2730667039de012175f31b111e50f084c480b8ea8e3a3b0833e12e7a5488f9ec0d73b22ac23998aaf05e7644e55f6acff6d9d19ae8c1cad515177bc1448a7d05d2d3e51894107085b3f09976e8f306e8072f6efcef" } ] ] @@ -959,7 +959,7 @@ [ "ope", { - "passthrough": "0b8100000000dc8f1d8a4159d905191e10403e38ba67be0dd69bc3f15471400e72115d4224f61674727ab8bac56ad6e99f309ba95f8886fa085f81e5647f2aeb5a5d2142fa087fee560c7d8df14bf85699eb34236cd8b2e6fc83f2ed7b6dd17f05978ad09bdeb6ccf1efc1afb975ccd49fa52b00b844bee0341b115f03b8d427cfe9399320b8" + "passthrough": "0b8100000000a824e89c4282c329a4d96069f158cdbef67de3e449b01363b50f1ceb166703a2c58decef5c3a765c3b7508049feb63adff64b36b739cd22143f4eee6c8aa5f173c8075b94ea8644174106a29608bd60655df143b36c7a20012beddce41d7fbb8954ee66d4bcc42000456cbaa168b2ccb788bdb29714a31f74566999989506d15" } ] ] @@ -984,7 +984,7 @@ [ "ore", { - "passthrough": "0b10000000a082c2300d1f28ce56a8d1388100342a" + "passthrough": "0b1000000049cf67d1f40428bf49576be3e3df43ce" } ] ] @@ -997,7 +997,7 @@ [ "ope", { - "passthrough": "0b1100000000fd45295f100d24e193e7c3b4a3afe6a4" + "passthrough": "0b110000000149691c6a3367ee8478c871c9f4cf4c15" } ] ] @@ -1022,7 +1022,7 @@ [ "ore", { - "passthrough": "0b20000000c3d8d9e15a3c67b2e7b050406e424c86c4427ddc55cd7e94beccf06d4e1aa3af" + "passthrough": "0b20000000fb88f2e243b1334a797a06ebea79b15a820dc5ae1668344bfa58d758f880fd17" } ] ] @@ -1035,7 +1035,7 @@ [ "ope", { - "passthrough": "0b21000000013910babdb9df995bf6cd8b8c3809ff96c20ce7272170cbf4a2e6f192df48ae94" + "passthrough": "0b21000000014d0e72ec6d02fc43651247bd9ca84c5323bc1813a4c68bc69aa8d1acef496c71" } ] ] @@ -1060,7 +1060,7 @@ [ "ore", { - "passthrough": "0b4000000024581d4b396284a673cc04e73d565077e3f6a56e9c178e95fc41a8665e910c0a1ece9482a38b82beee4d17d8b82639cd68390dc14fc03900f57f47023ebcdb36" + "passthrough": "0b40000000da9451a858c81d33242f92cd4b71b93d35661645e793298ae127defe2648db050e0b9bb3509a018f84f4266bc0020f26813c76fc764953da64e734c40659ae9d" } ] ] @@ -1073,7 +1073,7 @@ [ "ope", { - "passthrough": "0b4100000000c65d9da62cb7b3a4841db8ff0fa6304ab8117e40683d26f02557379f122be04b674dafce8618496ee2fe39aa3b5d3ad12f1d8c2230d100078aa11defc16e0867" + "passthrough": "0b410000000137677c48013326e34edee99462e9927217b3b2c63029db38ce33034fd6ed28e9687f1726a49a2a046638f88b9998c62a689a5334b5d198a72a6523aa1053522b" } ] ] @@ -1235,7 +1235,7 @@ [ "ore", { - "passthrough": "0b200000003b66bacffee6b5c0633c4623c3845f7344545bb4c7d02ecaa5bcd9b5f87eca41" + "passthrough": "0b20000000beca9415e2d54831e6daf42acef5bed3bdcd8b5b669061bccab1491a70954fd3" } ] ] @@ -1334,7 +1334,7 @@ [ "ore", { - "passthrough": "0b2000000031a055cf0ff7e82d73fc9711b26536ea18f8ea4be2328cd0c3b17c94b3d39c9d" + "passthrough": "0b200000003c0639c42b4bc6198d8c0f6d0c1020cc257af118db43564bcefd87d3440ea180" } ] ] @@ -1421,7 +1421,7 @@ [ "ore", { - "passthrough": "0b2000000056a202f641a9a81c5f9c179ae587fa6fb846342ba97fe605bc3bb4d55068e23f" + "passthrough": "0b20000000e35fc7559e7ae9856a8e6438987a9fc176e5b14000eef0bbdca5332b138689e7" } ] ] @@ -1517,7 +1517,7 @@ [ "ore", { - "passthrough": "0b20000000758821c792265d942f89fa1dad016fb71b326f756e62950367e5d060dcbc3be9" + "passthrough": "0b20000000f18256adef15adefb7ed6dea76d0de5418257a7406b06cb9b73fbcbb967139c2" } ] ] @@ -1571,7 +1571,7 @@ [ "ore", { - "passthrough": "0b20000000758821c792265d942f89fa1dad016fb71b326f756e62950367e5d130a8115eff" + "passthrough": "0b20000000f18256adef15adefb7ed6dea76d0de5418257a7406b06cb9b73fbd5c5b36f775" } ] ] diff --git a/packages/stack-encrypt/tests/fixtures/value_kinds.json b/packages/stack-encrypt/tests/fixtures/value_kinds.json index fc98e70b6..77459ed77 100644 --- a/packages/stack-encrypt/tests/fixtures/value_kinds.json +++ b/packages/stack-encrypt/tests/fixtures/value_kinds.json @@ -128,43 +128,43 @@ ], "record": { "amount": { - "c": "01000000000000000000000000000000007a4428d606d70760a6ab09137b7998952000aa5c98df7b5db708dec28195dbfa196953ce941a9404e7c315e14856139917c702fa91de3a39604b362861966bda65a4e16e141bc7046d59627ff4f9e9c24114cca0afcf08713a2d350e1c06ebf6", + "c": "01000000000000000000000000000000007a4428d606d70760a6ab09137b7998952000aa5c98df7b5db708dec28195dbfa196953ce941a9404e7c315e14856139917c70272c8dd6e66ca1aebf1bda57062842a1f595b44e43f77add307090df793ac67fef91ff48822172d43744a613b6e", "eq": "93a9395ae5d9581921a3fc2cdd9e0f3cc731d37e8f39f516f3dc3e3a6f0e8514" }, "at": { - "c": "01000000000000000000000000000000003df5051c44f189118ff062fc589189362000c144eccd9336ad2098131bc1ccebd36780eafd132f5d9a7900964b441fbedd240238762eca5b766e057a875482b286a420c4df7d043545869c76ca56f829638f723e412b58915cb8a63e", + "c": "01000000000000000000000000000000003df5051c44f189118ff062fc589189362000c144eccd9336ad2098131bc1ccebd36780eafd132f5d9a7900964b441fbedd2402318d67a00b552d3ffb67264c13652700bc974d4e36962448bc944fed7fea3eb87bfd0297be8cc51e37", "eq": "448bc4271a535ec475e50404c800746fb71cbac46567396bc0873546e5498f4a" }, "date": { - "c": "010000000000000000000000000000000081a52593eddb4ccba009332c41f7173d200048bbb91aa1c0c890d54de6fcd6b404e91d6a8272390ab807c78820543d49ef86025f781af6120f255debe98eaf4c53b4d5915d3702e8b97562b5e3f10ee2fea810ff", + "c": "010000000000000000000000000000000081a52593eddb4ccba009332c41f7173d200048bbb91aa1c0c890d54de6fcd6b404e91d6a8272390ab807c78820543d49ef8602115918d12a10db2ff74868d6a6c52dd8350aacfaaaf3138680210728b2670388b0", "eq": "03226ad4425267b31f8316c513d7155cfc2fd33bbf8992d14ea26cfc64311481" }, "i128": { - "c": "0100000000000000000000000000000000f5bdd6ce34bc69330093fa760c6f6d8120001a9f80b14abd281d94e5139ba66a8744314abdde415fa182d4ad961c4dbf1dc002a391e960daff92e0968960819cd41c2f8ef67887f8395e3d0aae1e968d74bf8af5c7e092e7461e332b019c8eed", + "c": "0100000000000000000000000000000000f5bdd6ce34bc69330093fa760c6f6d8120001a9f80b14abd281d94e5139ba66a8744314abdde415fa182d4ad961c4dbf1dc002a6675c402fefbff35039c68dfad19349a5cb056b9b6ed569bcad642a115f9424d878fc8276ee13f512c712ba05", "eq": "19fb32f017fe269cb2703fe732acd8c1673e49174e5492ea8c372c487d08ce2f", - "ore": "eed82f673c37aac97130e682bffa8fedda8f50a6adbaaf22b995fe84050870ce82de1dc185d9280cab61088b382a6d297ace288376e87b222ba9580bc9235643c35333131a01da66205fc770bbfa5fd84171034d75c4952231c1652cd0b8545c80a55907f2813cf4330528bca3cca7efce20ebe69eec29ec5bf6439c236d69c8" + "ore": "3f76e777c16d34f916957007b50af4aa1d75d991bdc6b341f2115b6293fdff630c0529b8cea701a9a8d42b1fd7eafb142db7b1145ba19b244bbf121fb43af47f8ef86f8a99384afb3412e97c69bbc0c76ea8b10a2d505a5720ba38591fada1a4decbec19b7932ed5275d317d58974eea640237f94cfba032715f97c641dd6a7a" }, "i16": { - "c": "0100000000000000000000000000000000b1739f40d4486c2af05aac240fae06e72000a9313873aaecad5b7a40ed810a0dd870304d8fb8d4ea88949606dce6384dbb660293761ddd2d762e68068488cec8f049f106623550927d770552f9a2c3610508", + "c": "0100000000000000000000000000000000b1739f40d4486c2af05aac240fae06e72000a9313873aaecad5b7a40ed810a0dd870304d8fb8d4ea88949606dce6384dbb66028e2aacdd7526cd36c4219d479ac8e026f9a9d782cb3e14b1140d25067f5474", "eq": "b902e228c35b328eef12f0b8df397d48ee63b81e944e3dfb0855b6006426e012", - "ore": "83bcefa8b71d264f84ac4f346c9427ae" + "ore": "2db94b40090bf95b461165503e3d7890" }, "i8": { - "c": "01000000000000000000000000000000005151a6cfdd1a51bf3a1ea0e85de41428200008a7fb000a5365b240cb064def02dedb57434897a756ae6216259ae26419f45d02da466dd320e4afd377fc28edda0282feb6be40f896dbd6334bcb881925d0", + "c": "01000000000000000000000000000000005151a6cfdd1a51bf3a1ea0e85de41428200008a7fb000a5365b240cb064def02dedb57434897a756ae6216259ae26419f45d023c5ec5b04c5ac5c332af086f71feecb4b960635f505b6573fb39307bfa9a", "eq": "15e37adf2fa39067953df8988ef98fb5ca354599495b23230133d525e62e6768" }, "u128": { - "c": "010000000000000000000000000000000095b0c11aba5068ed6e8b76bcf85967a92000b74f8acb3cdefa94b9fdea95725157aad875dfdb1f567c293638e84dc7872c42022d2c6fa96ddcaa15ec1b96f7e23807d47595491c0bb036791048ec4eb99fe41a7c7958b707ed9c284896af5e82", + "c": "010000000000000000000000000000000095b0c11aba5068ed6e8b76bcf85967a92000b74f8acb3cdefa94b9fdea95725157aad875dfdb1f567c293638e84dc7872c4202ac3b26bb1a24bb6ddc55fcb32275406299464bc0278d8daa3a929203abf1972a4c87cecfc8fded5ef80e22eca9", "eq": "761458346368c5f42c19a00ec9d8849021dfb28d6d6768c75d4290fef986bb9f", - "ope": "00deb76379b2d69b53e21b4468419eec6f1fd3a6338232d3f8acfb94779c95e9751d084cc759f92744b2389e1fc60b93ab3566bf061a00a9dd103329c5ad003628129935ab04d1b586ec506e986f4529f2b33f339b22aa8355971814735f9ebd6d48965546739e193cdfd5b0c6d0f550049f552698b39bbea76fc03527d775a28e" + "ope": "00ba8bbfe22d11c1fe973af9e0f10a54cabca5a5f822ac01283178975a61f6e899ce926cc10058fced231ce768887509a78b43ab08ae170b2becd7856de2e3df69c133357c64fd23535d2098a6b741fbd2d7c30b2de27c3f4bccb97064684b2aa441eee9c93aa3e653490fa907d8e0dd5691867382c13fdfad3628bab0301a2e1d" }, "u16": { - "c": "0100000000000000000000000000000000c40545f440c7f3e3f81f3fa4bbdc13152000c1aa04095f495b7cf8e1022d2e73a5d653616c157249914dc212e5c2c9eed16402aed0aa5806118a7ab9278e6e621f621b8daf665c3f97cc112a6a97c8d234e1", + "c": "0100000000000000000000000000000000c40545f440c7f3e3f81f3fa4bbdc13152000c1aa04095f495b7cf8e1022d2e73a5d653616c157249914dc212e5c2c9eed1640249c170478f583195b0f455fd8f532b321b26548e98adbbcb7fd073d28caf9d", "eq": "f9ec131d5dcf5739ac3a928108e1b50fc51e9f87bcd92f9e6e052b19b5f6b86d", - "ope": "008dd5395c0f5a63bc69d2c01d8ea32e3a" + "ope": "009011bc88ee527a131504f2f495ed03d7" }, "u8": { - "c": "0100000000000000000000000000000000bf3b588776242c390761ddd7097e0ae22000fd2f9eb1bb2712deff3805ba2af81cb31ea5c1fc8ef8e0f058c256e3b170e5d302af00af685f24c50ef4e7df040a92e4aa5d5093567923e759dce513e57116", + "c": "0100000000000000000000000000000000bf3b588776242c390761ddd7097e0ae22000fd2f9eb1bb2712deff3805ba2af81cb31ea5c1fc8ef8e0f058c256e3b170e5d302d3c582ab3b26f8fe22b9de6d9fac079b9a91f1cb5a8f67d654675e5cbb3c", "eq": "ce2278b04c84191451e85ffcbe67f1e7c8585f86583cdbcef68d2dd466fa7b0e" } }, diff --git a/packages/stack-encrypt/tests/frozen_bytes.rs b/packages/stack-encrypt/tests/frozen_bytes.rs index 12c629c1e..d5f63e7f6 100644 --- a/packages/stack-encrypt/tests/frozen_bytes.rs +++ b/packages/stack-encrypt/tests/frozen_bytes.rs @@ -470,7 +470,7 @@ async fn ore_term_encoding_is_the_raw_cllw_bytes() { // differ (see the `sem` module docs). assert_eq!( hex(term.as_bytes()), - "b8291f846d8028ad4e3a67ef95e541ca3c6d1a2b145f49af3135876ae75c5d7b" + "1ba4d59ccb15d505519ad854229ec0c106644fa8b8944ec54c68a1f324499d82" ); assert_eq!(term.to_bytes(), term.as_bytes()); assert_eq!(term.as_ref(), term.as_bytes()); @@ -496,7 +496,7 @@ async fn ope_term_encoding_is_the_raw_cllw_bytes() { assert_eq!( hex(term.as_bytes()), - "00d7a25b801c909f3cb9d177315ba4da7802b9e62eba8c07aab2ad9d64e1a0cfa7" + "00a77ed973ff1af2e5d5e3779471df246d17a515f0131eb87e35e02e7a80aa5292" ); assert_eq!( OpeTerm::::from_bytes(term.as_bytes()).expect("decode ope term"), @@ -510,7 +510,7 @@ async fn ope_term_encoding_is_the_raw_cllw_bytes() { #[test] fn ore_term_from_bytes_rejects_wrong_length() { - // Every order term is cllw-ore's variable-length ciphertext: ORE is + // Every order term is clww-ore's variable-length ciphertext: ORE is // one byte per plaintext bit (a multiple of 8, a u32's 32 here), OPE // that plus a leading carry byte. The length checks are structural: // the type parameter names the source, and nothing in the bytes does. @@ -530,9 +530,9 @@ fn ore_term_from_bytes_rejects_wrong_length() { #[tokio::test] async fn variable_length_ore_and_ope_terms_decode() { - // Text is encoded behind cllw-ore's one marker byte, so `alice` is six + // Text is encoded behind vitaminc-ore's one marker byte, so `alice` is six // plaintext bytes: 48 ORE bytes, and 49 for OPE with its leading carry - // byte. The decode path is the length-validating TryFrom in cllw-ore. + // byte. The decode path is the length-validating TryFrom in clww-ore. let cipher = cipher().await; let keyset = cipher.default_keyset(); let ore: OreTerm = "alice" diff --git a/packages/stack-encrypt/tests/ore_block.rs b/packages/stack-encrypt/tests/ore_block.rs index 2168cf10c..4f252774c 100644 --- a/packages/stack-encrypt/tests/ore_block.rs +++ b/packages/stack-encrypt/tests/ore_block.rs @@ -325,9 +325,9 @@ async fn left_halves_are_pinned() { ); } -const PINNED_I32: &str = "020200060c0a0a1f37375535b8d860bd115a46292e8aac8ef6571e4ab59087b3b4c68d4621980b5633ca7f5a6d0da5d7d9d683003c2bfcc4630697cbce320a75f61b0875bc8d63c530d74c515d0ee6fc1b5303f5ff16e767ad905a95a1e5fbfebfb047d2f959b91b9b3d"; -const PINNED_F64: &str = "0202000b1501163b2a0a33341205014148b5ed0af663b698a1e4727de4a2f9749c116d8be814ed51540319016cc48b5c9ca000d776bf2aa438a615f84fe4c8856567731aebe1d043dcee1cf0a62e1995e3247033d370b0c7b24e6c043d33ecff732552dacfd13cad5b7b11f5c90f6480e05c5d75b04d605a7522c5102491999f35690dcd5ae228b08e812766bf35f8622307ffce17091ad737af98f1c82a9caa2fa556156c52ee7caee7b97d2b6a8f6e0e1ac247e006dae5d61fee390b39e2"; -const PINNED_TEXT: &str = "0203001601001039201c002d22313e3625260c211a36351e3507391835d9cec533ab14188edbe7bb248118b82ff3a1635b1469dd20ab6021b66d5d957893d251ad85f93322d5d445a149f4cea13a7be3692c56241a6cf438a1b6f3353bac005c4eabbeb193ee467a15d7b5cf6d171d8347f4fe2a9d87694bcc86db61747b9e4a1f76c078331be8e57291969b4c6a9e38d6efa1500d921c712888fa953fc94099f0cc0a5852c1decc45563122685a3c07184f4f49ed2b98abb2682e22fcb42140d0a0ff51cca79c678a0b0077c7de2f6690b6e63957e433a96e4f42b2f6e8eb15180349c8d3a4aa9e3663e11e90267b22428407a5f051095113a0ac0bbcbf99e0c4fc41fe2f1c233cf27af369a5f956f29813a6a153f78ab56af7e60f06f3a8fc7a637e6749d44218c0a58d5541944c85a970aff3ca00dbe3bc6be3fdd1944ccab358071e8baac6aeec381c2a2fdac3ba2d69b3c09f7694abf699f6a652da1a2510df98ac20716dd7c25f834d412c0617d195922952942187e399bb6b6d"; +const PINNED_I32: &str = "020200062422373e222f96362b6599fc5183c20804eeddd52d41890dc85341958dc7329d18a521c1d74f76fed42c7517b4e8cdfc74cbc6f9e521a72658dc177b73e9fa5a2d8a661bf3ef7117ecef8aeca900b3465c3640ebddfc8d5887729387bcdc64486801f99d2dda"; +const PINNED_F64: &str = "0202000b0b033912381600140628353cede9c0b7d2aebfd0b81f922c34bb5faa5cd0f3723ab63db491c0f20f47873e7a28d2cde32d31b9ddc8ffb2708429b2432d25b6c806a06cd6efe7021e9c965388064ca5493283cc499209b81c212593869c9baca7cf007f21a318ba7c3932ea23448843d69cb7f79c952cf4bb986a42ddb795a01b558f97fcf9ef5eba7efe87bcb51c10fbe80a7997aa55963596e851c858f014c9408b15ad2762c2a02b32db5bd58e5d3f85651ee7d2d43869d3b09d"; +const PINNED_TEXT: &str = "02030016010010172510373d14172510363017212d163e161a10341620b9ce74f6d4e48df255a31928333790bb04fffdcf1c73688b642c450bfd649429589029e048f81f6b746af7306d8c88833d5e3cd1dca9d109b48203a44e1be8cad4717a7072aeb2c694c4c7952bb117fc89635665a8c4023aed2b84e8652849986c7a4b6fd64d22012154868ba39ac5a7f55cfb26fee81c0b419ab238dc435cb5ac7475b496bb6fae32b60aa38855d425126a44fa59342dfb2d114e74d059399ab0b526d856e0f96f59a7740eef99a787001ebc2d1b6ca5d9bf600bc43f1452250ce58dd8f1e0590f1030c9bbacc31b9f2d984d19bbe6a35a0fd156871d39ff9d55e05f3b497efbfa358f17e32a7b96e3585f3d8a83308693ce3ed3d2dac7268c4570b10910fc73d0937f100ef31a7c7b70c1469984fad0be135ca4e00dcedc4242d1327c73746d3e90db658f48561f4f0572dc65dff246102e9875d98aa0dbdc5e079e76e3d3999f8a10766fcb034119794e333d82ba81db0692dbc93745204b"; /// The block ORE key is the index's own: its terms share no left half with /// another context's, and none with CLLW ORE's key (a CLLW term is a diff --git a/packages/stack-encrypt/tests/roundtrip.rs b/packages/stack-encrypt/tests/roundtrip.rs index def78a5a3..5677d7bb6 100644 --- a/packages/stack-encrypt/tests/roundtrip.rs +++ b/packages/stack-encrypt/tests/roundtrip.rs @@ -122,6 +122,54 @@ async fn option_none_roundtrips() { assert_eq!(pt, None); } +/// A sealed `None` of a fixed-width type is as long as a sealed `Some`: +/// vitaminc 0.8 seals it as a typed null padded to the type's leaf, so the +/// length of a ciphertext does not say whether its value was there. It opens +/// as `None`. Text has no fixed width, so its `None` stays the short null. +#[tokio::test] +async fn a_fixed_width_none_is_as_long_as_a_some() { + let cipher = cipher().await; + let keyset = cipher.default_keyset(); + async fn sealed_len( + keyset: &stack_encrypt::KeysetCipher<'_, FakeDataKeySource>, + value: T, + ) -> usize + where + T: Encrypt + Send + 'static, + { + match keyset.encrypt(value, ()).await.expect("encrypt") { + CipherText::Single(leaf) => leaf.to_bytes().len(), + other => panic!("a scalar seals as one leaf: {other:?}"), + } + } + assert_eq!( + sealed_len(&keyset, Option::::None).await, + sealed_len(&keyset, Some(-7i64)).await, + "i64" + ); + assert_eq!( + sealed_len(&keyset, Option::::None).await, + sealed_len(&keyset, Some(7u32)).await, + "u32" + ); + assert_eq!( + sealed_len(&keyset, Option::::None).await, + sealed_len(&keyset, Some(1.5f64)).await, + "f64" + ); + assert!( + sealed_len(&keyset, Option::::None).await + < sealed_len(&keyset, Some("x".to_string())).await, + "text has no width to pad to" + ); + let ct = keyset + .encrypt(Option::::None, ()) + .await + .expect("encrypt"); + let pt: Option = cipher.decrypt(ct, ()).await.expect("decrypt"); + assert_eq!(pt, None); +} + #[tokio::test] async fn protected_roundtrip() { // Exercises the `Protected` Decrypt impl, which builds the value inside diff --git a/packages/stack-encrypt/tests/term_bytes.rs b/packages/stack-encrypt/tests/term_bytes.rs index e4c2c1d05..98d72cb82 100644 --- a/packages/stack-encrypt/tests/term_bytes.rs +++ b/packages/stack-encrypt/tests/term_bytes.rs @@ -32,6 +32,14 @@ //! these (the CHANGELOG says so). Floats are ordered by the same path: //! `F64`'s encoding folds `-0.0` into `0.0` and every NaN into one, which //! cllw-ore's own float encoding did not. +//! +//! The ORE and OPE pins moved again, with no label of this crate's moving, +//! when cllw-ore became `clww-ore` 0.6 on vitaminc 0.8. Its keystream was +//! fixed and its schemes' names, which every term's salt binds, became +//! `clww-ore` and `clww-ope`, so every order term changed. The marker byte +//! in front of text moved from the scheme to `vitaminc-ore` without +//! changing the bytes encrypted. As with vitaminc 0.5, nothing of this +//! crate's own derivation moved, so the `/v2` suffixes stay. use stack_encrypt::nonempty; use stack_encrypt::sem::{DefaultMatch, MatchConfig, MatchOptions}; @@ -124,7 +132,7 @@ async fn ore_term_bytes_are_pinned() { assert_eq!( hex(term.as_ref()), - "b8291f846d8028ad4e3a67ef95e541ca3c6d1a2b145f49af3135876ae75c5d7b" + "1ba4d59ccb15d505519ad854229ec0c106644fa8b8944ec54c68a1f324499d82" ); } @@ -142,7 +150,7 @@ async fn ope_term_bytes_are_pinned() { assert_eq!( hex(term.as_ref()), - "00d7a25b801c909f3cb9d177315ba4da7802b9e62eba8c07aab2ad9d64e1a0cfa7" + "00a77ed973ff1af2e5d5e3779471df246d17a515f0131eb87e35e02e7a80aa5292" ); } @@ -181,7 +189,7 @@ async fn match_term_positions_are_pinned_for_a_wide_filter() { } /// Text orders by the system ADR-0002's fold (`Ab` is encoded as `ab`, -/// behind cllw-ore's marker byte, so three bytes), under the column salt +/// behind `vitaminc-ore`'s marker byte, so three bytes), under the column salt /// of the `Text` target. Pins the fold, the salt and the CLLW encryption /// together. #[tokio::test] @@ -198,11 +206,11 @@ async fn text_order_term_bytes_are_pinned() { .unwrap(); assert_eq!( hex(ore.as_ref()), - "bc164005ea4d0f86e537d6829de90b2809ac20f460beffeb" + "b05ac63e0d2816d83868f90110b5226ad3c976f75e3a4b24" ); assert_eq!( hex(ope.as_ref()), - "00ff16eecb69b4f14c05a50b5a1249b8ad7cb63f376cbbb998" + "00bfac54f18ed40b78b19468df90f4e3550a5c046f3f283e89" ); } @@ -256,7 +264,7 @@ async fn text_with_no_fold_has_no_order_term() { .is_err()); } -/// A float's order term: cllw-ore's encryption of its ADR-0002 order key, +/// A float's order term: clww-ore's encryption of its ADR-0002 order key, /// the `f64` with zero signs and NaN payloads folded, under the column salt /// of the `F64` target. Pins the key, the salt and the encryption. #[tokio::test] @@ -271,8 +279,8 @@ async fn float_order_term_bytes_are_pinned() { .ope_term(1.5f64, nonempty!("users/score")) .await .unwrap(); - assert_eq!(hex(ore.as_ref()), "f591a4bf7663b9ffcaf021d87de0d10dad925b7663e33de47966c05dab4f76ff1e8bc5537162088c01be03b4db4d3fe980b111f46e7d4da445ec19d2f7445ef0"); - assert_eq!(hex(ope.as_ref()), "01501c6dd5f9a769811461eadfd54631ea58f3f051e7603117396add6c79e5fe4fd2f549c92f0afeaf94cd6c49fc33a9a0657c812132bea46779b2f19f10ce36ae"); + assert_eq!(hex(ore.as_ref()), "6c487f77b33ab3b4e0d37e79f84b24b92843d9cb591d492fd8d092afebba96e50e7d6733935a6e94faa8e7945f04471385553a35aa00ca30fb77d0b7a7a9a9a3"); + assert_eq!(hex(ope.as_ref()), "00836260f898d58c06c8e23b8754e05d7d352c676b714e8523582c930f9e83640ad87d56aa35b7c3ecdc44dfb29a7378fb95738bca93f5ee9ca2a066c63ecb6aaf"); } /// Floats order as Postgres's `float8` does: `-0.0` ties `0.0`, every NaN is diff --git a/packages/stack-encrypt/tests/ui/order_term_of_an_8_bit_integer.stderr b/packages/stack-encrypt/tests/ui/order_term_of_an_8_bit_integer.stderr index dee586b74..4ccf28147 100644 --- a/packages/stack-encrypt/tests/ui/order_term_of_an_8_bit_integer.stderr +++ b/packages/stack-encrypt/tests/ui/order_term_of_an_8_bit_integer.stderr @@ -17,7 +17,7 @@ error[E0277]: the trait bound `u8: Orderable` is not satisfied note: required by a bound in `OreTerm` --> src/sem/mod.rs | - | pub struct OreTerm(OreCllw8VariableV1, PhantomData T>); + | pub struct OreTerm(OreClww8VariableV1, PhantomData T>); | ^^^^^^^^^ required by this bound in `OreTerm` error[E0277]: the trait bound `i8: Orderable` is not satisfied @@ -39,7 +39,7 @@ error[E0277]: the trait bound `i8: Orderable` is not satisfied note: required by a bound in `OpeTerm` --> src/sem/mod.rs | - | pub struct OpeTerm(OpeCllw8VariableV1, PhantomData T>); + | pub struct OpeTerm(OpeClww8VariableV1, PhantomData T>); | ^^^^^^^^^ required by this bound in `OpeTerm` error[E0277]: the trait bound `i8: Orderable` is not satisfied diff --git a/packages/stack-guest-abi/src/value.rs b/packages/stack-guest-abi/src/value.rs index a350c3cde..a08583a73 100644 --- a/packages/stack-guest-abi/src/value.rs +++ b/packages/stack-guest-abi/src/value.rs @@ -10,7 +10,8 @@ //! through a [`Sink`], for the tests that check what a host is given. use vitaminc_aead::plaintext::{ - visit_map, visit_seq, Encrypt, Float, Logical, MapSink, Physical, SeqSink, Sink, SourceError, + visit_map, visit_seq, Encrypt, FixedType, Float, Logical, MapSink, Physical, SeqSink, Sink, + SourceError, }; use vitaminc_aead_frame::{to_frame, Frame, FrameError, FrameWriteError}; use vitaminc_protected::{Controlled, Protected}; @@ -231,6 +232,12 @@ impl Sink for ValueSink { Ok(self.0.put(value)) } + /// A typed null is a null to the host: its type only hides its length + /// once sealed. + fn typed_null(self, _: FixedType) -> Result { + Ok(self.0.put(HostValue::Null)) + } + fn seq(self, _: Option) -> Result, DecodeError> { Ok(ValueSeq { out: self.0, diff --git a/scripts/__tests__/dependabot-eql-inherited-ignores.test.mjs b/scripts/__tests__/dependabot-eql-inherited-ignores.test.mjs index 16d80a139..21fe1dec2 100644 --- a/scripts/__tests__/dependabot-eql-inherited-ignores.test.mjs +++ b/scripts/__tests__/dependabot-eql-inherited-ignores.test.mjs @@ -13,11 +13,11 @@ import { REPO_ROOT } from './lib/repo-root.mjs' * The EQL workspace is a separate Cargo workspace, but not an independent one: * `tests/encryption` depends by path on `stack-kms` and `stack-encrypt`, and * `eql-bindings` on `stack-encrypt` (behind its optional `stack-encrypt` - * feature). Those crates declare `recipher`, `cllw-ore` and `vitaminc-*` as + * feature). Those crates declare `recipher`, `clww-ore` and `vitaminc-*` as * `{ workspace = true }`. Built inside the EQL workspace, those requirements * still come from the ROOT `Cargo.toml`. The root entry ignores these crates - * because they move by hand with cipherstash-suite: the root manifest pins - * `recipher` and `cllw-ore` with `=`, and so does the Go guest. With no + * because they move by hand: the root manifest pins `recipher` with `=`, and + * so does the Go guest. With no * matching ignore, the EQL entry's monthly PR bumped them in the EQL lock and, * to satisfy the exact pins, edited the root `Cargo.toml` without updating the * root `Cargo.lock` or the guest's pin (#1205). Every root `--locked` build and From 0563857cdf2ad0142cd80565197fa9eb0debbc2a Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Wed, 21 Oct 2026 19:32:12 +1100 Subject: [PATCH 2/8] test(stack-encrypt): exclude KindOf::typed_null's equivalent default mutant A typed null has no kind, as any null has none, so KindOf::typed_null's Ok(None) is Ok(Default::default()). The one survivor of cargo mutants --in-diff on the vitaminc 0.8 upgrade; folded into the passthrough exclusion, which is equivalent for the same reason. Claude-Session: https://claude.ai/code/session_01XQN1QpaWVDGjHEg39KEJF3 --- .cargo/mutants.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.cargo/mutants.toml b/.cargo/mutants.toml index 8ef34de7d..59d2ca276 100644 --- a/.cargo/mutants.toml +++ b/.cargo/mutants.toml @@ -85,9 +85,10 @@ exclude_re = [ # the empty list (`dynamic::target::NoTargets`), which a test asserts on # and `resolve` turns into `TargetError::NoTargets`; `vec![]` is the body. 'stack-encrypt/src/dynamic/target\.rs:\d+:\d+: replace ::targets -> Vec with vec!\[\]$', - # A passthrough has no kind: `KindOf::passthrough` returns `Ok(None)`, - # which is `Ok(Default::default())`. `a_frame_names_its_kind` asserts it. - 'stack-encrypt/src/dynamic/value_frame\.rs:\d+:\d+: replace ::passthrough -> Result with Ok\(Default::default\(\)\)$', + # A passthrough, and a typed null as any null, has no kind: + # `KindOf::passthrough` and `KindOf::typed_null` return `Ok(None)`, which + # is `Ok(Default::default())`. `a_frame_names_its_kind` asserts the first. + 'stack-encrypt/src/dynamic/value_frame\.rs:\d+:\d+: replace ::(passthrough|typed_null) -> Result with Ok\(Default::default\(\)\)$', # `model`'s `admits` guard on a date, decimal or undefined value is checked # again by vitaminc on every path that reaches it: the frame writer behind # `Modeled` and `ModelOnly` refuses an inadmissible logical value From 30a89e5650e37609ce6bd3b40309a35419c443d7 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Fri, 23 Oct 2026 12:17:23 +1100 Subject: [PATCH 3/8] chore(deps): take clww-ore 0.6.0 and ore-rs 0.10.0 from crates.io Both crates are released, so the root manifest pins them exactly instead of taking them from cipherstash/ore.rs at one git revision. A git dependency stopped stack-encrypt publishing; this removes it from every lockfile (root, EQL, the Go guest and the fuzz crate). The releases were cut from a later ore.rs history than the pinned revision, after more review. The frozen order-term fixtures pass unchanged against them, so stored terms derive exactly as before. Exact pins because a new release of either can change every stored order term. AGENTS.md and the Dependabot notes now say that rather than "until released". Refs #1298 Claude-Session: https://claude.ai/code/session_01XQN1QpaWVDGjHEg39KEJF3 --- .github/dependabot.yml | 6 ++---- AGENTS.md | 8 ++++---- Cargo.lock | 9 +++++---- Cargo.toml | 10 ++++------ languages/golang/encrypt/guest/Cargo.lock | 9 +++++---- packages/eql/Cargo.lock | 11 ++++++----- packages/stack-encrypt/fuzz/Cargo.lock | 9 +++++---- 7 files changed, 31 insertions(+), 31 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3f77563cd..e224891e0 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -227,8 +227,7 @@ updates: # declare these `{ workspace = true }`, so their requirements come from # the root Cargo.toml even when built here. The root entry below ignores # them because they move by hand: the root manifest pins recipher with - # `=`, and so does the Go guest, and takes clww-ore and ore-rs from - # cipherstash/ore.rs at one revision until they are released. + # `=`, and so does the Go guest, and pins clww-ore and ore-rs with `=`. # Without these lines this entry bumped them in this lockfile and, to # satisfy the exact pins, rewrote the root Cargo.toml without touching # the root Cargo.lock or the guest's pin, breaking every root `--locked` @@ -300,8 +299,7 @@ updates: - dependency-name: "zerokms-protocol" - dependency-name: "recipher" # The order schemes, from cipherstash/ore.rs, moved by hand with - # vitaminc: the root Cargo.toml takes them from git at one revision - # until clww-ore 0.6 and ore-rs 0.10 are released. + # vitaminc: a new release can change every stored order term. - dependency-name: "clww-ore" - dependency-name: "ore-rs" # vitaminc is pinned at 0.8.0 across the crates and the guests; the diff --git a/AGENTS.md b/AGENTS.md index c0cf10b4d..3d2527481 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -687,10 +687,10 @@ monorepo, which is where the silent failures are. The stack-* crates came from `cipherstash/cipherstash-suite`, which still owns `cipherstash-client`, `cts-common`, `zerokms-protocol` and `recipher`. Here those come from crates.io, and `Cargo.lock` holds their exact versions. In the -root `Cargo.toml`, `recipher` is pinned with `=`. The order schemes, `clww-ore` -(formerly `cllw-ore`) and `ore-rs`, live in `cipherstash/ore.rs`; until -clww-ore 0.6 and ore-rs 0.10 are released, the root `Cargo.toml` takes them -from git at one revision, which also stops `stack-encrypt` publishing. `cts-common` and `zerokms-protocol` take caret +root `Cargo.toml`, `recipher` is pinned with `=`, and so are the order +schemes `clww-ore` (formerly `cllw-ore`) and `ore-rs`, which live in +`cipherstash/ore.rs`: a new release of either can change every stored order +term. `cts-common` and `zerokms-protocol` take caret requirements, because the published `stack-auth` inherits them, and an exact pin would stop the suite sharing one `cts-common` with it. diff --git a/Cargo.lock b/Cargo.lock index 79b6a621f..946a9fc37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -523,13 +523,13 @@ dependencies = [ [[package]] name = "clww-ore" version = "0.6.0" -source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95747f5724666cb973b2ca0659e10b6083c11f99877c4727b4c9f534a591c74" dependencies = [ "blake3", "hex", "subtle", "thiserror 1.0.69", - "unicode-normalization", "vitaminc-ore", "vitaminc-protected 0.8.0", "zeroize", @@ -2259,8 +2259,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "ore-rs" -version = "0.9.0" -source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd65962ec1409c09d20e1e016f4fe1b4ae2e2e58dba38c155538b2c0801a185" dependencies = [ "aes", "block-modes", diff --git a/Cargo.toml b/Cargo.toml index 20a9ccda9..5cc0f2dca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,12 +86,10 @@ recipher = "=0.3.1" # `clww-ore` (cllw-ore renamed) for CLWW ORE and OPE, and ore-rs for block # ORE, `Bit6BlockOre` (fixed width up to ten bytes) and `ChainedBlockOre` # (variable length), the 6-bit schemes EQL v4's `_ord_ore` domains store. -# vitaminc is a plain dependency of both from here, not a feature. -# UNRELEASED: both come from cipherstash/ore.rs#132 (stacked on #131 and -# #130) until clww-ore 0.6.0 and ore-rs 0.10.0 reach crates.io; then these -# become exact version pins. -clww-ore = { git = "https://github.com/cipherstash/ore.rs", rev = "6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4", default-features = false } -ore-rs = { git = "https://github.com/cipherstash/ore.rs", rev = "6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4", default-features = false } +# vitaminc is a plain dependency of both from here, not a feature. Both are +# pinned exactly: a new release can change every stored order term. +clww-ore = { version = "=0.6.0", default-features = false } +ore-rs = { version = "=0.10.0", default-features = false } # External dependencies, with the suite's feature lists. base64 = "0.22.0" diff --git a/languages/golang/encrypt/guest/Cargo.lock b/languages/golang/encrypt/guest/Cargo.lock index ffd0125f1..6570262d8 100644 --- a/languages/golang/encrypt/guest/Cargo.lock +++ b/languages/golang/encrypt/guest/Cargo.lock @@ -352,13 +352,13 @@ dependencies = [ [[package]] name = "clww-ore" version = "0.6.0" -source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95747f5724666cb973b2ca0659e10b6083c11f99877c4727b4c9f534a591c74" dependencies = [ "blake3", "hex", "subtle", "thiserror 1.0.69", - "unicode-normalization", "vitaminc-ore", "vitaminc-protected 0.8.0", "zeroize", @@ -1458,8 +1458,9 @@ dependencies = [ [[package]] name = "ore-rs" -version = "0.9.0" -source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd65962ec1409c09d20e1e016f4fe1b4ae2e2e58dba38c155538b2c0801a185" dependencies = [ "aes", "block-modes", diff --git a/packages/eql/Cargo.lock b/packages/eql/Cargo.lock index 265c16b21..63773fcc4 100644 --- a/packages/eql/Cargo.lock +++ b/packages/eql/Cargo.lock @@ -660,13 +660,13 @@ dependencies = [ [[package]] name = "clww-ore" version = "0.6.0" -source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95747f5724666cb973b2ca0659e10b6083c11f99877c4727b4c9f534a591c74" dependencies = [ "blake3", "hex", "subtle", "thiserror 1.0.69", - "unicode-normalization", "vitaminc-ore", "vitaminc-protected 0.8.0", "zeroize", @@ -2690,8 +2690,9 @@ dependencies = [ [[package]] name = "ore-rs" -version = "0.9.0" -source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd65962ec1409c09d20e1e016f4fe1b4ae2e2e58dba38c155538b2c0801a185" dependencies = [ "aes", "block-modes", @@ -4260,7 +4261,7 @@ dependencies = [ "base64ct", "clww-ore", "miette", - "ore-rs 0.9.0", + "ore-rs 0.10.0", "serde", "serde_json", "stack-encrypt-derive", diff --git a/packages/stack-encrypt/fuzz/Cargo.lock b/packages/stack-encrypt/fuzz/Cargo.lock index e36effd00..cde185181 100644 --- a/packages/stack-encrypt/fuzz/Cargo.lock +++ b/packages/stack-encrypt/fuzz/Cargo.lock @@ -361,13 +361,13 @@ dependencies = [ [[package]] name = "clww-ore" version = "0.6.0" -source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95747f5724666cb973b2ca0659e10b6083c11f99877c4727b4c9f534a591c74" dependencies = [ "blake3", "hex", "subtle", "thiserror 1.0.69", - "unicode-normalization", "vitaminc-ore", "vitaminc-protected 0.8.0", "zeroize", @@ -1469,8 +1469,9 @@ dependencies = [ [[package]] name = "ore-rs" -version = "0.9.0" -source = "git+https://github.com/cipherstash/ore.rs?rev=6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4#6e2a7e1c2b09ad0e43cbeccaf5b313a943aa9ba4" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd65962ec1409c09d20e1e016f4fe1b4ae2e2e58dba38c155538b2c0801a185" dependencies = [ "aes", "block-modes", From 2ed8e17b22e6647cadf7c531e067dc3f13d0fa72 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Fri, 23 Oct 2026 12:52:04 +1100 Subject: [PATCH 4/8] chore(eql): build the block ORE timing harness on ore-rs 0.10 ctgen still pinned ore-rs 0.9.0 while its manifest said it matched the root lockfile, which #1327 moved to 0.10.0. ore-rs 0.10 no longer exposes its engines directly: a value reaches them only through vitaminc-ore. So ctgen now opens `BlockOre` spaces for a u64 and for text and encrypts through them, as stack-encrypt does. vitaminc-ore puts a marker byte in front of text, so the prefix rows drop one padding NUL to keep the byte offsets the README describes. The rows keep their block counts (11 fixed, 43 chained, 22 against 43 for prefix), and ctgen still asserts ore-rs's comparator agrees with the plaintext order on every row before writing it. The README's recorded results were measured on 0.9.0; it now says so. Refs #1298 Claude-Session: https://claude.ai/code/session_01XQN1QpaWVDGjHEg39KEJF3 --- .../eql/tests/timing/ore_block_v2/README.md | 21 +- .../timing/ore_block_v2/ctgen/Cargo.lock | 662 +++++++++++++++++- .../timing/ore_block_v2/ctgen/Cargo.toml | 10 +- .../timing/ore_block_v2/ctgen/src/main.rs | 62 +- 4 files changed, 698 insertions(+), 57 deletions(-) diff --git a/packages/eql/tests/timing/ore_block_v2/README.md b/packages/eql/tests/timing/ore_block_v2/README.md index f90bbc6f1..4d1c8594b 100644 --- a/packages/eql/tests/timing/ore_block_v2/README.md +++ b/packages/eql/tests/timing/ore_block_v2/README.md @@ -49,17 +49,21 @@ that schema already exists, it refuses to run rather than touch it. ## Method -`ctgen` produces real ore-rs 0.9.0 ciphertexts, one term per side, in four -kinds of two classes each, plus a correctness set: +`ctgen` produces real ore-rs ciphertexts, one term per side, in four kinds +of two classes each, plus a correctness set. It encrypts through ore-rs's +`BlockOre` and vitaminc-ore, as stack-encrypt does, so text is encoded as a +marker byte and then the text: - **fixed**: `u64` terms of the fixed-width scheme (11 blocks), differing in the first block against differing only in the last; - **equal**: a `u64` against a second encryption of the same value (a different nonce, no block differs), against a first-block difference; -- **chained**: 31-byte text of the chained scheme (a 32-byte bucket, 43 - blocks), differing in the first character against only the last; -- **prefix**: 10-byte text (a 16-byte bucket, 22 blocks) against 26-byte - text (a 32-byte bucket, 43 blocks) whose first 22 blocks equal it, so the +- **chained**: 31-character text of the chained scheme (32 bytes encoded, + a 32-byte bucket, 43 blocks), differing in the first character against + only the last; +- **prefix**: 10-character text (11 bytes encoded, a 16-byte bucket, 22 + blocks) against 26 encoded bytes (a 32-byte bucket, 43 blocks) whose first + 22 blocks equal it, so the block counts settle the order, against the same shapes differing in the first block; - **checks**: 1,500 random pairs of either scheme with shared prefixes of @@ -84,6 +88,11 @@ counts as no detectable difference. ## Results +These were measured with ore-rs 0.9.0's ciphertexts, before `ctgen` moved to +0.10. The wire format the comparator reads (the headers, the block counts, +the halves) did not change, and the text shapes above give the same block +counts as they did. + PostgreSQL 17.5 run natively on macOS, Apple silicon, 100,000 samples per kind, two runs. The machine was shared with other builds, which shows in the difference between the runs' means; classes are drawn at random per diff --git a/packages/eql/tests/timing/ore_block_v2/ctgen/Cargo.lock b/packages/eql/tests/timing/ore_block_v2/ctgen/Cargo.lock index 16d2dfbc8..a600d1a03 100644 --- a/packages/eql/tests/timing/ore_block_v2/ctgen/Cargo.lock +++ b/packages/eql/tests/timing/ore_block_v2/ctgen/Cargo.lock @@ -10,7 +10,7 @@ checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", - "cpufeatures", + "cpufeatures 0.2.17", "zeroize", ] @@ -20,34 +20,95 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +[[package]] +name = "bitvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", + "zeroize", +] + [[package]] name = "block-modes" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e2211b0817f061502a8dd9f11a37e879e79763e3c698d2418cf824d8cb2f21e" +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +dependencies = [ + "serde", +] + [[package]] name = "cfg-if" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "rand_core 0.10.1", + "zeroize", +] + [[package]] name = "cipher" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "inout", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -57,6 +118,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + [[package]] name = "crypto-common" version = "0.1.7" @@ -67,6 +137,73 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12218662ccac37d9714f2191252553d67585b97df8c839cbe49e0bde278dc865" +dependencies = [ + "cmov", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common 0.2.2", + "ctutils", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -88,12 +225,60 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "rand_core 0.10.1", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest", +] + +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "inout" version = "0.1.4" @@ -103,12 +288,34 @@ dependencies = [ "generic-array", ] +[[package]] +name = "js-sys" +version = "0.3.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.191" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "mutants" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ac067452ff1aca8c5002111bd6b1c895baee6e45fcbc44e0193aea17be56" + [[package]] name = "num" version = "0.4.3" @@ -182,10 +389,10 @@ dependencies = [ ] [[package]] -name = "orderable-bytes" -version = "0.2.1" +name = "once_cell" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7d30b72ffca73d9936fe5fc80a9c9520c73f5b4f64839a810211903d5ace3c" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "ore-block-v2-timing-ctgen" @@ -193,28 +400,40 @@ version = "0.0.0" dependencies = [ "hex", "ore-rs", - "rand", + "rand 0.8.8", + "vitaminc-ore", + "vitaminc-protected", ] [[package]] name = "ore-rs" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1d6cb8c1249643266bd60269547c93d3cd263d5385f1262902bbb295ff9a5e" +checksum = "8bd65962ec1409c09d20e1e016f4fe1b4ae2e2e58dba38c155538b2c0801a185" dependencies = [ "aes", "block-modes", "byteorder", "hex", "num", - "orderable-bytes", - "rand", - "rand_chacha", + "rand 0.10.3", "subtle-ng", - "thiserror", + "thiserror 1.0.69", + "vitaminc-context", + "vitaminc-hmac", + "vitaminc-ore", + "vitaminc-prf", + "vitaminc-protected", + "vitaminc-random", "zeroize", ] +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -224,6 +443,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.107" @@ -242,6 +470,18 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.8" @@ -250,7 +490,18 @@ checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", ] [[package]] @@ -260,7 +511,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -269,9 +520,84 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "sha2" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d7069beb7d6ac7b9acd1039986e73443f24234f41074da099d6f994ac9ad19" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest", ] +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "subtle-ng" version = "2.5.0" @@ -289,13 +615,39 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "thiserror" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl 2.0.21", ] [[package]] @@ -306,7 +658,54 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + +[[package]] +name = "toml_datetime" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.17+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" +dependencies = [ + "winnow", ] [[package]] @@ -315,24 +714,249 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "unicode-general-category" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b993bddc193ae5bd0d623b49ec06ac3e9312875fdae725a975c51db1cc1677f" + [[package]] name = "unicode-ident" version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" +[[package]] +name = "unicode-normalization" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75cd3fb03d5288b3ba9a1ee103ac7e9cbb59f0b03d64f8ddfcc04dd42758a85d" +dependencies = [ + "tinyvec", +] + [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vitaminc-aead" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9bb97fd543ee6a2b168e257ec69d0d274a775b1eaa3f856b5ac2941b01891c1" +dependencies = [ + "bytes", + "futures-util", + "serde", + "thiserror 2.0.21", + "vitaminc-aead-derive", + "vitaminc-context", + "vitaminc-protected", + "vitaminc-random", + "zeroize", +] + +[[package]] +name = "vitaminc-aead-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0845a44c07ddc882ed47a0e92e04fc83496220f054b589ad0cbd215c5009e5b7" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "vitaminc-context" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a630079ba2d50680ee5048addd430eda30613559809dd6d383551e6d3d299826" +dependencies = [ + "mutants", + "vitaminc-protected", +] + +[[package]] +name = "vitaminc-hmac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5fa0ae8bbad85ae30fb5c91b0b72b694d59bf2c2c1e7ad799eda66fdbd67e7c" +dependencies = [ + "hmac", + "sha2", + "vitaminc-prf", + "vitaminc-protected", + "zeroize", +] + +[[package]] +name = "vitaminc-normalize" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5a2d8875e0b8b35b7a4f9dd698bbd13c989837cea564b5a4cbb5371b78fa937" +dependencies = [ + "thiserror 2.0.21", + "unicode-general-category", + "unicode-normalization", + "vitaminc-aead", + "vitaminc-protected", +] + +[[package]] +name = "vitaminc-ore" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05518b4d35cb0c592dad59afb11b8e883ea252449b9ae47ff5ddeff0ed49f75" +dependencies = [ + "thiserror 2.0.21", + "unicode-general-category", + "unicode-normalization", + "vitaminc-aead", + "vitaminc-context", + "vitaminc-normalize", + "vitaminc-protected", + "zeroize", +] + +[[package]] +name = "vitaminc-prf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916688478273ca3e5c6805b355534ce9263688391cd4ab23b08bef760039d325" +dependencies = [ + "mutants", + "thiserror 2.0.21", + "vitaminc-context", + "vitaminc-protected", +] + +[[package]] +name = "vitaminc-protected" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6edc22562a9bbff0ba9704a2c43670b2c7cb1637524c045c3ba6436ed00917f" +dependencies = [ + "bitvec", + "digest", + "libc", + "serde", + "serde_bytes", + "subtle", + "thiserror 2.0.21", + "vitaminc-protected-derive", + "zeroize", +] + +[[package]] +name = "vitaminc-protected-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cce3a7d0ce6f57c0e82345f20e87f3737cccd3a70aec2a2ab49f68a3a5e24a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "vitaminc-random" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bb253f783ce6f31a55a92f5a9f0526109b8caa6a465edb94244fd344a078c11" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand 0.10.3", + "thiserror 2.0.21", + "vitaminc-protected", + "vitaminc-random-derives", + "zeroize", +] + +[[package]] +name = "vitaminc-random-derives" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0b3615936d6dded4b775856f4b0fa229d745d183f0b3754ac80035f16c27d9" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasm-bindgen" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.9", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "zerocopy" version = "0.8.63" @@ -350,7 +974,7 @@ checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -370,5 +994,5 @@ checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] diff --git a/packages/eql/tests/timing/ore_block_v2/ctgen/Cargo.toml b/packages/eql/tests/timing/ore_block_v2/ctgen/Cargo.toml index c9a31f8ff..b5e23206e 100644 --- a/packages/eql/tests/timing/ore_block_v2/ctgen/Cargo.toml +++ b/packages/eql/tests/timing/ore_block_v2/ctgen/Cargo.toml @@ -12,9 +12,13 @@ edition = "2021" publish = false [dependencies] -# The 6-bit fixed-width and chained schemes behind EQL v4's `ore_block_v2`; -# the same version as the root Cargo.lock. -ore-rs = { version = "=0.9.0", default-features = false } +# ore-rs's `BlockOre`, whose 6-bit fixed-width and chained engines are what +# EQL v4's `ore_block_v2` compares; the same version as the root Cargo.lock. +# Since 0.10 a value reaches the engines only through vitaminc-ore, as it +# does in stack-encrypt. +ore-rs = { version = "=0.10.0", default-features = false } +vitaminc-ore = "=0.8.0" +vitaminc-protected = "=0.8.0" rand = "0.8" hex = "0.4" diff --git a/packages/eql/tests/timing/ore_block_v2/ctgen/src/main.rs b/packages/eql/tests/timing/ore_block_v2/ctgen/src/main.rs index 203fbef0e..79b37daa9 100644 --- a/packages/eql/tests/timing/ore_block_v2/ctgen/src/main.rs +++ b/packages/eql/tests/timing/ore_block_v2/ctgen/src/main.rs @@ -3,22 +3,26 @@ //! //! fixed u64, 11 blocks; differ in block 0 / only block 10 //! equal u64; a second encryption of a / differ in block 0 -//! chained 31-byte text, 43 blocks; differ in the first -//! character / only the last +//! chained 31-character text (32 bytes encoded), 43 blocks; +//! differ in the first character / only the last //! prefix text in a 16-byte bucket against text in a //! 32-byte bucket: every block a has equals b's //! (the block counts settle it) / the first differs -//! check random pairs of either scheme with shared +//! check random pairs of either engine with shared //! prefixes; expected = sign(a cmp b) //! +//! `BlockOre` sends a `u64` to the fixed-width engine and text to the chained +//! one. vitaminc-ore encodes text as a marker byte and then the text (lower +//! case ASCII folds to itself), so the byte offsets below count the marker. +//! //! Every expected sign is the plaintext order, and ore-rs's own comparator //! is asserted to agree before a row is written. use std::cmp::Ordering; -use ore_rs::scheme::bit2_w6::OreAes128Bit6ChaCha20; -use ore_rs::scheme::chained::OreAes128Bit6ChainedChaCha20; -use ore_rs::{OreCipher, OreEncrypt, OreOutput}; +use ore_rs::{BlockOre, Term}; use rand::Rng; +use vitaminc_ore::{OrderEncrypt, OrderKeyInit, OrderScheme, OrderTarget}; +use vitaminc_protected::Protected; fn sign(o: Ordering) -> i32 { match o { @@ -34,11 +38,20 @@ fn lower(rng: &mut impl Rng, n: usize) -> String { fn main() { let mut rng = rand::thread_rng(); - let key: [u8; 16] = rng.gen(); - let fixed = OreAes128Bit6ChaCha20::init(&key).unwrap(); - let chained = OreAes128Bit6ChainedChaCha20::init(&key).unwrap(); - let ct = |x: u64| x.encrypt(&fixed).unwrap().to_bytes(); - let st = |s: &str| chained.encrypt_str(s).unwrap().to_bytes(); + let key: [u8; 32] = rng.gen(); + let scheme = BlockOre::new(Protected::new(key)); + let fixed = scheme.target(OrderTarget::U64); + let text = scheme.target(OrderTarget::Text); + let ct = |x: u64| fixed.encrypt_checked(&x).unwrap().into_raw().into_bytes(); + let st = |s: &str| { + text.encrypt_checked(&s.to_owned()) + .unwrap() + .into_raw() + .into_bytes() + }; + let compare = |a: &[u8], b: &[u8]| { + BlockOre::compare(&Term::from_bytes(a.to_vec()), &Term::from_bytes(b.to_vec())) + }; let pairs: usize = std::env::args() .nth(1) .map(|s| s.parse().unwrap()) @@ -71,18 +84,15 @@ fn main() { &st(std::str::from_utf8(&last).unwrap()), ); - // 10 bytes pads with NULs to a 16-byte bucket: 22 blocks, the last - // holding two bits of byte 15 and four of byte 16. The longer text - // repeats the padding and puts a byte whose top four bits are clear - // at 16, so all 22 of the shorter text's blocks match it, and its - // 26 bytes take a 32-byte bucket. + // 10 characters encode as 11 bytes, padded with NULs to a 16-byte + // bucket: 22 blocks, the last holding two bits of byte 15 and four + // of byte 16. The longer text repeats the padding and puts a byte + // whose top four bits are clear at 16, so all 22 of the shorter + // text's blocks match it, and its 26 bytes take a 32-byte bucket. let short = lower(&mut rng, 10); - let long = format!("{short}\0\0\0\0\0\0\u{5}{}", lower(&mut rng, 9)); + let long = format!("{short}\0\0\0\0\0\u{5}{}", lower(&mut rng, 9)); let (a, b) = (st(&short), st(&long)); - assert_eq!( - OreAes128Bit6ChainedChaCha20::compare_raw_slices(&a, &b), - Some(Ordering::Less) - ); + assert_eq!(compare(&a, &b), Some(Ordering::Less)); row("prefix", "prefix", &a, &b); let mut other = long.clone().into_bytes(); other[0] = b'a' + (other[0] - b'a' + 1) % 26; @@ -109,10 +119,7 @@ fn main() { }; let (a, b) = (ct(x), ct(y)); let expected = x.cmp(&y); - assert_eq!( - OreAes128Bit6ChaCha20::compare_raw_slices(&a, &b), - Some(expected) - ); + assert_eq!(compare(&a, &b), Some(expected)); println!( "check\t{}\t{}\t{}", sign(expected), @@ -131,10 +138,7 @@ fn main() { }; let (a, b) = (st(&s), st(&t)); let expected = s.as_bytes().cmp(t.as_bytes()); - assert_eq!( - OreAes128Bit6ChainedChaCha20::compare_raw_slices(&a, &b), - Some(expected) - ); + assert_eq!(compare(&a, &b), Some(expected)); println!( "check\t{}\t{}\t{}", sign(expected), From e88d6b8ccfb7c163bf8cbd47f3b69d4ed5239730 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Fri, 23 Oct 2026 12:52:04 +1100 Subject: [PATCH 5/8] docs(stack-encrypt): correct what the ORE upgrade made false Review of #1327 found docs and one message that the move to clww-ore 0.6 and ore-rs 0.10 left wrong: - Block ORE docs named `Bit6BlockOre` and `ChainedBlockOre` and said `BlockOre` was the unused legacy scheme. `BlockOre` is now the one scheme, routing to its `OreAes128Bit6` and `OreAes128Bit6Chained` engines. The marker byte is vitaminc-ore's, not the scheme's. - The `order_term_pending` refusal, and the docs beside it in Rust and Go, said decimal, date and timestamp order indexes wait for new clww-ore and ore-rs releases. Those releases are here; what remains is #1236. The message now says the index is not supported yet (#1236). - Two comments named a clww-ore 0.5 that never existed. It also documents that `ValueFrame::from_bytes` reads a host's typed null as a plain null: a frame writer keeps no padding, and padding an absent value is for the field's plan to declare (#1298), not the host. Refs #1298 Claude-Session: https://claude.ai/code/session_01XQN1QpaWVDGjHEg39KEJF3 --- Cargo.toml | 7 ++++--- languages/golang/cmd/stashgen/README.md | 2 +- languages/golang/encrypt/doc.go | 4 ++-- .../golang/stashgen/enginetest/enginetest.go | 4 ++-- packages/stack-encrypt/src/dynamic/kind.rs | 8 ++++---- packages/stack-encrypt/src/dynamic/mod.rs | 2 +- packages/stack-encrypt/src/dynamic/term.rs | 11 +++++------ .../stack-encrypt/src/dynamic/value_frame.rs | 12 +++++++++++- packages/stack-encrypt/src/sem/mod.rs | 17 +++++++++-------- 9 files changed, 39 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5cc0f2dca..0d0ec9100 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,9 +83,10 @@ zerokms-protocol = "0.12.31" recipher = "=0.3.1" # The two order-preserving schemes Stack Encrypt's order terms encrypt # through. Both implement vitaminc-ore's `OrderScheme` against vitaminc 0.8: -# `clww-ore` (cllw-ore renamed) for CLWW ORE and OPE, and ore-rs for block -# ORE, `Bit6BlockOre` (fixed width up to ten bytes) and `ChainedBlockOre` -# (variable length), the 6-bit schemes EQL v4's `_ord_ore` domains store. +# `clww-ore` (cllw-ore renamed) for CLWW ORE and OPE, and ore-rs's +# `BlockOre` for block ORE, which routes a value to its 6-bit fixed-width +# engine (up to ten bytes) or its chained one (wider, or variable length), +# the terms EQL v4's `_ord_ore` domains store. # vitaminc is a plain dependency of both from here, not a feature. Both are # pinned exactly: a new release can change every stored order term. clww-ore = { version = "=0.6.0", default-features = false } diff --git a/languages/golang/cmd/stashgen/README.md b/languages/golang/cmd/stashgen/README.md index 36788edd3..3162fe90f 100644 --- a/languages/golang/cmd/stashgen/README.md +++ b/languages/golang/cmd/stashgen/README.md @@ -256,7 +256,7 @@ An `opaque` struct crosses as one JSON document and is one column, decoded back A float in an opaque struct must be finite: `encoding/json` refuses NaN and the infinities, so `Encrypt` fails for the batch with `encrypt.ErrEncoding`. A sealed float field outside an opaque struct carries them. A sealed field outside an opaque struct is one scalar, or a type defined over one; a struct, slice or map field seals only inside an opaque struct. The scalars are `string`, `[]byte`, `bool`, every integer type (each sealed at its own width, `int` and `uint` as 64-bit), `encrypt.Int128` and `encrypt.Uint128`, `float32`, `float64`, `encrypt.Decimal`, `encrypt.Date` and `time.Time` (a timestamp). The wire type `stashgen` writes for each is the field's own: `int8` is `gensupport.Int8`, `time.Time` is `gensupport.Timestamp`, and so on. -An order index (`ore`, `ope`) on a decimal, date or timestamp is refused: those order terms wait for new cllw-ore and ore-rs releases (#1236). +An order index (`ore`, `ope`) on a decimal, date or timestamp is refused: those order terms are not supported yet (#1236). The zero `encrypt.Date` is not a date: a date field must be set, and `Encrypt` refuses a zero one with `encrypt.ErrEncoding`, naming the field. A sealed field cannot be a pointer (`*encrypt.Date` is refused as a composite), so an optional date has no sealed form yet: keep it in an opaque struct, or store a sentinel date. A nil `[]byte` in a sealed field, or a nil slice of a type defined over `[]byte`, comes back from `Decrypt` as an empty, non-nil slice; inside an opaque struct, nil comes back as nil. A protobuf message with a `oneof` cannot be generated from a policy: protoc-gen-go puts its members in wrapper types, not in the message struct, and `Generate` refuses it. diff --git a/languages/golang/encrypt/doc.go b/languages/golang/encrypt/doc.go index e29d052b6..59b534c8c 100644 --- a/languages/golang/encrypt/doc.go +++ b/languages/golang/encrypt/doc.go @@ -124,8 +124,8 @@ // time.Time (a timestamp), or a type defined over one of the built-in types. // Each integer seals at its own width. Equality applies to every one but a // bool; ORE and OPE to the integers, text, bytes and floats, and not yet to a -// decimal, date or timestamp, whose order terms wait for new cllw-ore and -// ore-rs releases (#1236). +// decimal, date or timestamp, whose order terms are not supported yet +// (#1236). // // Passthrough fields never cross the binding: the engine does nothing to a // passthrough value that a program could observe, and the FFI codec cannot diff --git a/languages/golang/stashgen/enginetest/enginetest.go b/languages/golang/stashgen/enginetest/enginetest.go index 44f5e97b8..9b0793f01 100644 --- a/languages/golang/stashgen/enginetest/enginetest.go +++ b/languages/golang/stashgen/enginetest/enginetest.go @@ -241,7 +241,7 @@ func eightBit(t stashgen.GoType) bool { // floats, text and bytes. Not over a boolean or an 8-bit integer, whose // order term would reveal which rows are true, or each row's rank among 256 // values; and not yet over a decimal, date or timestamp, whose order terms -// wait for new clww-ore and ore-rs releases (#1236). The JSON index is not +// are not built yet (#1236). The JSON index is not // in the engine yet. func indexApplies(name stashgen.IndexName, t stashgen.GoType) error { switch name { @@ -263,7 +263,7 @@ func indexApplies(name stashgen.IndexName, t stashgen.GoType) error { case stashgen.KindString, stashgen.KindBytes, stashgen.KindFloat: return nil case stashgen.KindDecimal, stashgen.KindDate, stashgen.KindTimestamp: - return fmt.Errorf("an order index on a decimal, date or timestamp waits for new clww-ore and ore-rs releases (#1236)") + return fmt.Errorf("an order index on a decimal, date or timestamp is not supported yet (#1236)") } if integer(t) && !eightBit(t) { return nil diff --git a/packages/stack-encrypt/src/dynamic/kind.rs b/packages/stack-encrypt/src/dynamic/kind.rs index c0451d4e6..3606b9c3a 100644 --- a/packages/stack-encrypt/src/dynamic/kind.rs +++ b/packages/stack-encrypt/src/dynamic/kind.rs @@ -59,8 +59,8 @@ use crate::target::IndexSpec; /// wider, both floats, text and bytes. A boolean and an 8-bit integer have /// no order term: over so small a domain it would reveal which rows are /// `true`, or each row's rank among 256 values. -/// A decimal, a date and a timestamp have none yet: their order encodings -/// wait for new clww-ore and ore-rs releases (#1236), and [`not_admitted`] +/// A decimal, a date and a timestamp have none yet: their order terms are +/// tracked in #1236, and [`not_admitted`] /// names that reason. A composite (`array`, `object`) has no term. Only the /// index's kind matters: a match index's options do not change what it /// applies to. @@ -87,8 +87,8 @@ pub fn admits(kind: ValueKind, index: &IndexSpec) -> bool { /// plan that declares the pair is refused with. /// /// [`Reason::OrderTermPending`] for an order index on a decimal, date -/// or timestamp, whose order terms wait for new clww-ore and ore-rs -/// releases (#1236). [`Reason::IndexNotAdmitted`] for every other pair +/// or timestamp, whose order terms are not built yet (#1236). +/// [`Reason::IndexNotAdmitted`] for every other pair /// [`admits`] refuses. /// /// ``` diff --git a/packages/stack-encrypt/src/dynamic/mod.rs b/packages/stack-encrypt/src/dynamic/mod.rs index 9be9ab20c..66d45fc19 100644 --- a/packages/stack-encrypt/src/dynamic/mod.rs +++ b/packages/stack-encrypt/src/dynamic/mod.rs @@ -533,7 +533,7 @@ reasons! { /// timestamp. Their order terms wait for clww-ore and ore-rs /// releases that encode them the ADR-0002 way (#1236); equality on /// them works today. - OrderTermPending => "order_term_pending", "an order index on a decimal, date or timestamp waits for new clww-ore and ore-rs releases (#1236)"; + OrderTermPending => "order_term_pending", "an order index on a decimal, date or timestamp is not supported yet (#1236)"; /// Two fields are keyed under one identity. SharedIdentity => "shared_identity", "two fields are keyed under one identity"; /// The plan has no field of the name asked for. diff --git a/packages/stack-encrypt/src/dynamic/term.rs b/packages/stack-encrypt/src/dynamic/term.rs index 89794b575..bad1e63ba 100644 --- a/packages/stack-encrypt/src/dynamic/term.rs +++ b/packages/stack-encrypt/src/dynamic/term.rs @@ -22,8 +22,8 @@ //! no order term: over a domain that small (two values, or 256) it would //! tell anyone holding the column which rows are `true`, or rank every //! row among 256. A decimal, a date and a timestamp -//! have none yet: clww-ore 0.5 does not encode them the ADR-0002 way, and -//! their order terms wait for new clww-ore and ore-rs releases (#1236). +//! have none yet: their order terms are tracked in #1236, and +//! vitaminc-ore 0.8 and ore-rs's `BlockOre` now support those targets. //! //! # These are the query-probe path //! @@ -166,7 +166,7 @@ impl IndexSpec { /// reveals too much, which rows hold `true`, or each row's rank among 256 /// values, which a few known rows resolve to the values. Not a null. The /// caller has already refused a scalar under a logical type: a decimal, -/// date or timestamp's order term waits for a later release. +/// date or timestamp's order term is not built yet (#1236). fn ordered(value: &Physical<'_>) -> bool { match value { Physical::Int(Int::I8(_) | Int::U8(_)) | Physical::Null | Physical::Bool(_) => false, @@ -1345,9 +1345,8 @@ mod tests { } /// A decimal, a date and a timestamp have an equality term, from - /// vitaminc, and no order term yet: their order encodings wait for - /// new clww-ore and ore-rs releases (#1236), and the engine does not - /// shim around clww-ore 0.5. + /// vitaminc, and no order term yet: their order terms are tracked in + /// #1236. #[tokio::test] async fn a_decimal_date_or_timestamp_has_no_order_term_yet() { let cipher = cipher().await; diff --git a/packages/stack-encrypt/src/dynamic/value_frame.rs b/packages/stack-encrypt/src/dynamic/value_frame.rs index c1cb607a0..4a6098ed3 100644 --- a/packages/stack-encrypt/src/dynamic/value_frame.rs +++ b/packages/stack-encrypt/src/dynamic/value_frame.rs @@ -101,6 +101,14 @@ impl ValueFrame { /// Read one value from frame bytes a host handed over. /// + /// A typed null in the bytes reads as a null. vitaminc-aead 0.8 lets a + /// frame carry one so that a frame sealed as it is pads the host's + /// absent values, but a [`ValueFrame`] is rewritten through the value + /// model first, and a frame writer keeps no padding. Whether an absent + /// value is padded is for the field's plan to declare (#1298), so the + /// host never decides what an absent value shows; a typed null from a + /// host pads nothing on its own. + /// /// # Errors /// /// [`FromFrameError::Frame`] when the @@ -1282,7 +1290,9 @@ mod tests { /// A typed null of a type in the model is a null in a frame: written, /// read from a host's bytes, or opened. Its padding belongs to a sealed - /// leaf, not to a frame (vitaminc-aead 0.8), and a null has no kind. + /// leaf, not to a frame (vitaminc-aead 0.8), and a null has no kind. So + /// a host's typed null is not padded by this path: padding is the + /// plan's decision (#1298). #[test] fn a_typed_null_in_the_model_is_a_null_in_its_frame() { let null = frame_of(&Tree::Null); diff --git a/packages/stack-encrypt/src/sem/mod.rs b/packages/stack-encrypt/src/sem/mod.rs index 5da726cd7..e3f8e1d2f 100644 --- a/packages/stack-encrypt/src/sem/mod.rs +++ b/packages/stack-encrypt/src/sem/mod.rs @@ -207,8 +207,8 @@ pub enum TermError { Ore(#[from] clww_ore::Error), /// Block ORE ([`OreBlockTerm`]) orders text and bytes of at most 1023 /// bytes, counted after the order encoding (text folded): the chained - /// scheme's 1024-byte ceiling, less the one marker byte it puts in - /// front of a variable-width value. The ceiling bounds what one value + /// engine's 1024-byte ceiling, less the one marker byte `vitaminc-ore` + /// puts in front of a variable-width value. The ceiling bounds what one value /// costs: a term of 1023 bytes is already about 34 KB. #[error( "the value is too long for a block ORE term: its order encoding is longer than 1023 bytes" @@ -1391,13 +1391,14 @@ term_wrapper!(OpeTerm, OpeClww8VariableV1); /// `T`'s [`Orderable`] target, the scheme EQL v4's `_ord_ore` domains /// store (`ob`). Comparisons order like the plaintexts, within one index. /// -/// Which of ore-rs's two 6-bit schemes encrypts it is fixed by the target: +/// ore-rs's one scheme, `BlockOre`, routes the target to one of its two +/// 6-bit engines when the space is opened: /// -/// - **`Bit6BlockOre`** for a target of at most ten bytes: the integers to +/// - **`OreAes128Bit6`** for a target of at most ten bytes: the integers to /// 64 bits and floats (as the `f64` they widen to). Wire header /// `02 02`, then the block count; one block per six bits of the /// encoding, so an `i32` is six blocks and an `i64` eleven. -/// - **`ChainedBlockOre`** for text, bytes and the 128-bit integers. Wire +/// - **`OreAes128Bit6Chained`** for text, bytes and the 128-bit integers. Wire /// header `02 03`, the block count, then the padding policy. Text is /// padded with NUL bytes to a power of two of at least 16 bytes, so a /// term reveals its text's length bucket rather than its length; bytes @@ -1428,9 +1429,9 @@ pub struct OreBlockTerm(Vec, PhantomData T>); /// that scheme, if they name different schemes, or (chained) if they were /// padded under different policies. /// -/// These are the comparators `Bit6BlockOre` and `ChainedBlockOre` compare -/// with. ore-rs's `bit2_w6` module is its 6-bit scheme; the legacy 8-bit -/// scheme (`BlockOre`, module `bit2`) is not used here. +/// `BlockOre::compare` reads the header and compares with that engine's +/// comparator, `OreAes128Bit6` or `OreAes128Bit6Chained`. ore-rs's legacy +/// 8-bit engine (module `bit2`) is not used here. fn ore_block_compare(a: &[u8], b: &[u8]) -> Option { use ore_rs::{BlockOre, Term}; BlockOre::compare(&Term::from_bytes(a.to_vec()), &Term::from_bytes(b.to_vec())) From 4cf7a5be3056a0d22a3c6a5833ed75bdec86da63 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Fri, 23 Oct 2026 13:32:04 +1100 Subject: [PATCH 6/8] refactor(golang): take vitaminc only through stack-encrypt's re-exports The Go guest named vitaminc-aead-frame and vitaminc-protected itself (and vitaminc-aead for its tests), with the version kept equal to stack-encrypt's by hand. A second version would not fail loudly: a `ValueFrame` would just stop meeting the other version's `Decrypt` bound. stack-encrypt now re-exports what a binding speaks through: `dynamic::frame` (vitaminc-aead-frame, with `serde`), `dynamic::plaintext` (the value model, for `Encrypt` on a binding's own values, as `dynamic::read` takes them), and `DecodeError`, `Protected` and `Controlled` at the root, since `ValueFrame::into_inner` returns a `Protected`. The guest uses those and drops its own vitaminc dependencies. One trybuild snapshot now names `Protected` by its shorter re-exported path. Refs #1298 Claude-Session: https://claude.ai/code/session_01XQN1QpaWVDGjHEg39KEJF3 --- .github/dependabot.yml | 5 +++-- languages/golang/encrypt/guest/Cargo.lock | 3 --- languages/golang/encrypt/guest/Cargo.toml | 14 +++++--------- languages/golang/encrypt/guest/src/abi.rs | 2 +- languages/golang/encrypt/guest/src/config.rs | 2 +- .../golang/encrypt/guest/src/deterministic.rs | 4 ++-- languages/golang/encrypt/guest/src/io.rs | 2 +- languages/golang/encrypt/guest/src/ops.rs | 11 ++++++----- languages/golang/encrypt/guest/src/options.rs | 2 +- languages/golang/encrypt/guest/src/test_frame.rs | 6 +++--- languages/golang/encrypt/guest/tests/leak.rs | 6 +++--- .../golang/encrypt/guest/tests/native_ops.rs | 4 ++-- .../golang/encrypt/guest/tests/support/mod.rs | 15 ++++++++------- packages/stack-encrypt/CHANGELOG.md | 9 +++++++++ packages/stack-encrypt/src/dynamic/mod.rs | 13 +++++++++++++ packages/stack-encrypt/src/lib.rs | 8 ++++++-- .../tests/ui/plaintext_needs_encrypt.stderr | 2 +- 17 files changed, 65 insertions(+), 43 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e224891e0..525c939f4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -302,8 +302,9 @@ updates: # vitaminc: a new release can change every stored order term. - dependency-name: "clww-ore" - dependency-name: "ore-rs" - # vitaminc is pinned at 0.8.0 across the crates and the guests; the - # guests' `ValueFrame: Decrypt` bound fails if two versions resolve. + # vitaminc is pinned at 0.8.0 across the crates. The encrypt guest + # takes it only through stack-encrypt's re-exports, so it cannot + # resolve a second version; one would fail at `ValueFrame: Decrypt`. - dependency-name: "vitaminc*" # Major bumps are reviewed and applied manually, not by Dependabot. - dependency-name: "*" diff --git a/languages/golang/encrypt/guest/Cargo.lock b/languages/golang/encrypt/guest/Cargo.lock index 6570262d8..b5903fa5b 100644 --- a/languages/golang/encrypt/guest/Cargo.lock +++ b/languages/golang/encrypt/guest/Cargo.lock @@ -2201,9 +2201,6 @@ dependencies = [ "stack-guest-abi", "stack-kms", "uuid", - "vitaminc-aead 0.8.0", - "vitaminc-aead-frame", - "vitaminc-protected 0.8.0", "zeroize", "zerokms-protocol", ] diff --git a/languages/golang/encrypt/guest/Cargo.toml b/languages/golang/encrypt/guest/Cargo.toml index 4117a0d65..4df0b70ba 100644 --- a/languages/golang/encrypt/guest/Cargo.toml +++ b/languages/golang/encrypt/guest/Cargo.toml @@ -61,13 +61,11 @@ stack-kms = { path = "../../../../packages/stack-kms", default-features = false eql-bindings = { path = "../../../../packages/eql/crates/eql-bindings", features = ["targets"], optional = true } zerokms-protocol = "=0.12.31" -# The transport frame and ciphertext codec, shared with vitaminc's own -# guest — one codec, not a fork. Same vitaminc version stack-encrypt builds -# against (see the comment in packages/stack-encrypt/Cargo.toml). A -# different version here fails at the `ValueFrame: Decrypt` bound, since the -# aead crate would be duplicated. -vitaminc-aead-frame = { version = "0.8.0", features = ["serde"] } -vitaminc-protected = "0.8.0" +# No vitaminc dependency of its own: the transport frame and ciphertext +# codec (`stack_encrypt::dynamic::frame`, vitaminc's own, shared with its +# guest), the value model and `Protected` all come through stack-encrypt's +# re-exports, so the guest cannot build against another vitaminc. Two +# versions would fail only at the `ValueFrame: Decrypt` bound. futures = { version = "0.3", default-features = false, features = ["executor"] } serde = "1" @@ -76,8 +74,6 @@ uuid = "1" zeroize = "1" [dev-dependencies] -# The test tree (`tests/support`) walks values through vitaminc's sinks. -vitaminc-aead = "0.8.0" stack-kms = { path = "../../../../packages/stack-kms", default-features = false, features = ["test-support"] } # For minting a valid client-key fixture in the config tests. recipher = "=0.3.1" diff --git a/languages/golang/encrypt/guest/src/abi.rs b/languages/golang/encrypt/guest/src/abi.rs index 2d6e47e52..e1df6095c 100644 --- a/languages/golang/encrypt/guest/src/abi.rs +++ b/languages/golang/encrypt/guest/src/abi.rs @@ -390,7 +390,7 @@ pub unsafe extern "C" fn se_keyset(sel_ptr: *const u8, sel_len: u32) -> u64 { /// /// The context is one part — a string, bytes, or an `i32`/`i64`/`u32`/`u64` /// — or an array of parts, which may nest as deep as the transport codec -/// allows (`vitaminc_aead_frame::MAX_DEPTH` levels, counted from +/// allows (`stack_encrypt::dynamic::frame::MAX_DEPTH` levels, counted from /// the root of the encoded value; deeper is refused as `STATUS_ENCODING` /// before the context is parsed). [`stack_encrypt::dynamic::context`] is the one home of /// that grammar and of which Rust context each shape spells. diff --git a/languages/golang/encrypt/guest/src/config.rs b/languages/golang/encrypt/guest/src/config.rs index a08f576ce..44f77c218 100644 --- a/languages/golang/encrypt/guest/src/config.rs +++ b/languages/golang/encrypt/guest/src/config.rs @@ -33,10 +33,10 @@ use std::num::NonZeroUsize; use serde::{Deserialize, Deserializer}; +use stack_encrypt::dynamic::frame::serde::from_slice; use stack_guest_abi::last_error::malformed; use stack_kms::{ClientKey, ZeroKmsEndpoint}; use uuid::Uuid; -use vitaminc_aead_frame::serde::from_slice; /// Everything `se_cipher_init` needs to build the cipher. pub struct CipherConfig { diff --git a/languages/golang/encrypt/guest/src/deterministic.rs b/languages/golang/encrypt/guest/src/deterministic.rs index 88a789d51..15567525a 100644 --- a/languages/golang/encrypt/guest/src/deterministic.rs +++ b/languages/golang/encrypt/guest/src/deterministic.rs @@ -13,8 +13,8 @@ pub use stack_kms::DeterministicSource; use serde::Deserialize; +use stack_encrypt::dynamic::frame::serde::from_slice; use stack_guest_abi::last_error::malformed; -use vitaminc_aead_frame::serde::from_slice; use zeroize::Zeroize; /// The `deterministic-kms` build's whole config: the source's 32-byte seed, @@ -57,7 +57,7 @@ impl Seed { mod tests { use super::Seed; use crate::test_frame::{frame, V}; - use vitaminc_aead_frame::serde::from_slice; + use stack_encrypt::dynamic::frame::serde::from_slice; /// A seed is 32 bytes, and only bytes: 32 characters of text are refused. #[test] diff --git a/languages/golang/encrypt/guest/src/io.rs b/languages/golang/encrypt/guest/src/io.rs index 13618e8d2..29206fd83 100644 --- a/languages/golang/encrypt/guest/src/io.rs +++ b/languages/golang/encrypt/guest/src/io.rs @@ -28,9 +28,9 @@ //! copies, and the host wipes the buffers with `se_dealloc`. use serde::{Deserialize, Serialize, Serializer}; +use stack_encrypt::dynamic::frame::serde::{from_slice, to_vec}; use stack_guest_abi::last_error::malformed; use stack_guest_abi::step::{Request, Response}; -use vitaminc_aead_frame::serde::{from_slice, to_vec}; use zeroize::Zeroizing; use crate::status::STATUS_ENCODING; diff --git a/languages/golang/encrypt/guest/src/ops.rs b/languages/golang/encrypt/guest/src/ops.rs index c30b5430b..e08a46696 100644 --- a/languages/golang/encrypt/guest/src/ops.rs +++ b/languages/golang/encrypt/guest/src/ops.rs @@ -45,13 +45,13 @@ //! the output. Control data (a plan, a context, an options object, query //! statistics) carries no secret and is read from its frame with serde. +use stack_encrypt::dynamic::frame::{decode_ciphertext, encode_ciphertext, Frame}; use stack_encrypt::dynamic::{self, Scope, ValueFrame}; use stack_encrypt::sem::MatchOptions; use stack_encrypt::target::IndexSpec; use stack_encrypt::ErrorPayload; use stack_encrypt::{CipherText, KeysetCipher, Label, Node, SealedValue, StackCipherText}; use stack_kms::DataKeySource; -use vitaminc_aead_frame::{decode_ciphertext, encode_ciphertext, Frame}; use zeroize::Zeroizing; use stack_guest_abi::last_error; @@ -86,7 +86,7 @@ type BytesTree = Node>; /// /// The context is one part — a string, bytes, or an `i32`/`i64`/`u32`/`u64` /// — or an array of parts, nested as deep as the transport codec allows -/// ([`MAX_DEPTH`](vitaminc_aead_frame::MAX_DEPTH) levels from the root of the frame; deeper +/// ([`MAX_DEPTH`](stack_encrypt::dynamic::frame::MAX_DEPTH) levels from the root of the frame; deeper /// is [`STATUS_ENCODING`] before the context is read), exactly as a plan /// field's; [`dynamic::context`] is the one home of that grammar. Shape is identity: /// `[x]` is a PAE-framed list and `x` is not, so a probe takes the context @@ -559,8 +559,9 @@ fn not_a_frame() -> u32 { /// is sized as every other output is. A query term's search tokens are /// derived from plaintext, so the staging buffer is wiped once copied. fn encode_answer(answer: &T) -> Result, u32> { - let frame = - Zeroizing::new(vitaminc_aead_frame::serde::to_vec(answer).map_err(|_| STATUS_ENCODING)?); + let frame = Zeroizing::new( + stack_encrypt::dynamic::frame::serde::to_vec(answer).map_err(|_| STATUS_ENCODING)?, + ); let mut out = exact_buffer(Some(frame.len()))?; out.extend_from_slice(&frame); Ok(out) @@ -654,7 +655,7 @@ fn tree_encoded_len(tree: &BytesTree) -> Option { mod tests { use super::*; use crate::support::Tree; - use vitaminc_protected::Controlled; + use stack_encrypt::Controlled; // `tree_encoded_len` re-derives the codec's arithmetic; the codec exports // no `encoded_len` of its own, so this pin is the only thing that fails if diff --git a/languages/golang/encrypt/guest/src/options.rs b/languages/golang/encrypt/guest/src/options.rs index d3bb9f5fb..74dc15c73 100644 --- a/languages/golang/encrypt/guest/src/options.rs +++ b/languages/golang/encrypt/guest/src/options.rs @@ -47,8 +47,8 @@ use stack_kms::{IdentifiedBy, IndexKeySource}; use uuid::Uuid; use zerokms_protocol::Name; +use stack_encrypt::dynamic::frame::serde::from_slice; use stack_guest_abi::last_error::malformed; -use vitaminc_aead_frame::serde::from_slice; use crate::status::fail_error; #[cfg(any(doc, test))] diff --git a/languages/golang/encrypt/guest/src/test_frame.rs b/languages/golang/encrypt/guest/src/test_frame.rs index dc4e77943..58e492663 100644 --- a/languages/golang/encrypt/guest/src/test_frame.rs +++ b/languages/golang/encrypt/guest/src/test_frame.rs @@ -2,7 +2,7 @@ //! send what no writer would (a repeated key, an integer of any width). use serde::{Serialize, Serializer}; -use vitaminc_aead_frame::serde::to_vec; +use stack_encrypt::dynamic::frame::serde::to_vec; /// A test input, written as raw frame bytes by [`frame`]. pub(crate) enum V { @@ -35,7 +35,7 @@ pub(crate) fn frame(v: &V) -> Vec { }; match v { V::Obj(entries) => { - let mut out = container(vitaminc_aead_frame::OBJECT, entries.len()); + let mut out = container(stack_encrypt::dynamic::frame::OBJECT, entries.len()); for (key, value) in entries { out.extend_from_slice(&u32::try_from(key.len()).expect("short").to_le_bytes()); out.extend_from_slice(key.as_bytes()); @@ -44,7 +44,7 @@ pub(crate) fn frame(v: &V) -> Vec { out } V::Arr(items) => { - let mut out = container(vitaminc_aead_frame::ARRAY, items.len()); + let mut out = container(stack_encrypt::dynamic::frame::ARRAY, items.len()); for item in items { out.extend_from_slice(&frame(item)); } diff --git a/languages/golang/encrypt/guest/tests/leak.rs b/languages/golang/encrypt/guest/tests/leak.rs index d16656f38..ffc2aa9d5 100644 --- a/languages/golang/encrypt/guest/tests/leak.rs +++ b/languages/golang/encrypt/guest/tests/leak.rs @@ -24,6 +24,8 @@ use std::future::IntoFuture; use stack_auth::{SecretToken, ServiceToken}; mod support; +use stack_encrypt::dynamic::frame::encode_ciphertext; +use stack_encrypt::dynamic::plaintext::Logical; use stack_encrypt::dynamic::Scope; use stack_encrypt::{CipherText, Descriptor, Node, PassthroughFrame, StackCipher}; use stack_encrypt_guest::options::{parse_options, Side}; @@ -36,8 +38,6 @@ use stack_kms::{ }; use support::Tree; use uuid::Uuid; -use vitaminc_aead::plaintext::Logical; -use vitaminc_aead_frame::encode_ciphertext; use zerokms_protocol::{IdentifiedBy, UnverifiedContext, ViturRequestError}; const PLAINTEXT: &str = "leak-marker-plaintext"; @@ -132,7 +132,7 @@ fn failing() -> StackCipher { // ============================================================================= fn encode(value: Tree) -> Vec { - use vitaminc_protected::Controlled; + use stack_encrypt::Controlled; value.to_frame().expect("encode").risky_unwrap() } diff --git a/languages/golang/encrypt/guest/tests/native_ops.rs b/languages/golang/encrypt/guest/tests/native_ops.rs index 57ba01223..9ab2c4d3a 100644 --- a/languages/golang/encrypt/guest/tests/native_ops.rs +++ b/languages/golang/encrypt/guest/tests/native_ops.rs @@ -19,12 +19,14 @@ use std::future::IntoFuture; mod support; +use stack_encrypt::dynamic::frame::{decode_ciphertext, encode_ciphertext}; use stack_encrypt::dynamic::Scope; use stack_encrypt::sem::DefaultMatch; use stack_encrypt::{ nonempty, CipherText, Label, Node, PassthroughFrame, PendingStackCipherText, SealedValue, StackCipher, }; +use stack_encrypt::{Controlled, Protected}; use stack_encrypt_guest::ops::{self, TERM_EQUALITY, TERM_MATCH, TERM_OPE, TERM_ORE}; use stack_encrypt_guest::status::{ STATUS_AUTH, STATUS_CONTEXT_MISMATCH, STATUS_ENCODING, STATUS_FOREIGN_KEYSET, STATUS_TERM, @@ -35,8 +37,6 @@ use stack_kms::{ }; use support::Tree; use uuid::Uuid; -use vitaminc_aead_frame::{decode_ciphertext, encode_ciphertext}; -use vitaminc_protected::{Controlled, Protected}; use zerokms_protocol::{IdentifiedBy, UnverifiedContext}; /// `futures::executor::block_on` over anything awaitable: the term API diff --git a/languages/golang/encrypt/guest/tests/support/mod.rs b/languages/golang/encrypt/guest/tests/support/mod.rs index 17e0fa4f1..e21c00bcb 100644 --- a/languages/golang/encrypt/guest/tests/support/mod.rs +++ b/languages/golang/encrypt/guest/tests/support/mod.rs @@ -9,13 +9,14 @@ #![allow(dead_code)] -use vitaminc_aead::frame::{FrameError, FrameWriteError}; -use vitaminc_aead::plaintext::{ +use stack_encrypt::dynamic::frame::{to_frame, Frame}; +use stack_encrypt::dynamic::frame::{FrameError, FrameWriteError}; +use stack_encrypt::dynamic::plaintext::{ visit_map, visit_seq, Error as _, FixedType, Float, Int, Logical, MapSink, Physical, SeqSink, Sink, SourceError, }; -use vitaminc_aead::{to_frame, DecodeError, Decrypt, Encrypt, Frame}; -use vitaminc_protected::{Controlled, Protected}; +use stack_encrypt::{Controlled, Protected}; +use stack_encrypt::{DecodeError, Decrypt, Encrypt}; /// A value as a test spells it: each scalar at its own width, a logical /// scalar under its type. Equality is structural and variable-time, which @@ -117,7 +118,7 @@ fn write(value: &Tree, out: &mut Vec) { let count = |len: usize| u32::try_from(len).expect("short").to_le_bytes(); match value { Tree::Object(entries) => { - out.push(vitaminc_aead::frame::OBJECT); + out.push(stack_encrypt::dynamic::frame::OBJECT); out.extend_from_slice(&count(entries.len())); for (key, value) in entries { out.extend_from_slice(&count(key.len())); @@ -126,7 +127,7 @@ fn write(value: &Tree, out: &mut Vec) { } } Tree::Array(items) => { - out.push(vitaminc_aead::frame::ARRAY); + out.push(stack_encrypt::dynamic::frame::ARRAY); out.extend_from_slice(&count(items.len())); for item in items { write(item, out); @@ -139,7 +140,7 @@ fn write(value: &Tree, out: &mut Vec) { /// What a binding reads back from an answer the engine writes: its frame, /// read back. pub(crate) fn value_of(answer: &T) -> Tree { - let frame = vitaminc_aead_frame::serde::to_vec(answer).expect("frames"); + let frame = stack_encrypt::dynamic::frame::serde::to_vec(answer).expect("frames"); Tree::from_frame(&frame).expect("a value") } diff --git a/packages/stack-encrypt/CHANGELOG.md b/packages/stack-encrypt/CHANGELOG.md index e4108a40b..8d812938e 100644 --- a/packages/stack-encrypt/CHANGELOG.md +++ b/packages/stack-encrypt/CHANGELOG.md @@ -9,6 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **The vitaminc a binding speaks through is re-exported.** `dynamic::frame` + is `vitaminc-aead-frame` (the transport frame and ciphertext codec, with + its `serde` module), `dynamic::plaintext` is vitaminc-aead's value model, + for implementing `Encrypt` on a binding's own values, and the crate root + adds `DecodeError`, `Protected` and `Controlled`. A binding that takes + these from stack-encrypt cannot resolve a second vitaminc, which would + fail only at a `ValueFrame: Decrypt` bound. The Go guest now takes + vitaminc only this way. + - **A block ORE index, `OreBlock`** (ADR-0002 and ADR-0009, amended 2026-10-19). It derives ore-rs 0.9.0's 6-bit block ORE under its own key domain, over the same order keys as the CLLW indexes: diff --git a/packages/stack-encrypt/src/dynamic/mod.rs b/packages/stack-encrypt/src/dynamic/mod.rs index 66d45fc19..4d52c4a0f 100644 --- a/packages/stack-encrypt/src/dynamic/mod.rs +++ b/packages/stack-encrypt/src/dynamic/mod.rs @@ -111,6 +111,19 @@ pub use target::{NoTargets, TargetDescriptor, TargetError, TargetResolver}; pub use term::{term, TermBytes}; pub use value_frame::{Children, FromFrameError, Modeled, Opening, ValueFrame}; +/// vitaminc's value model, the sinks and scalar types a value describes +/// itself through. A binding implements [`Encrypt`](crate::Encrypt) for its +/// own values with it, as [`read`] takes them. Re-exported so a binding +/// builds against the vitaminc this crate does. Two versions of vitaminc in +/// one build do not fail loudly: a [`ValueFrame`] stops meeting the other +/// version's `Decrypt` bound. +pub use vitaminc_aead::plaintext; +/// vitaminc's transport frame and ciphertext codec (`vitaminc-aead-frame`, +/// with its `serde` module): the bytes a binding hands this module, and the +/// codec its ciphertexts cross in. Re-exported for the same reason as +/// [`plaintext`]. +pub use vitaminc_aead_frame as frame; + use crate::target::IndexSpec; use crate::{KeysetCipher, StackCipher}; diff --git a/packages/stack-encrypt/src/lib.rs b/packages/stack-encrypt/src/lib.rs index 8d523019a..761c650f8 100644 --- a/packages/stack-encrypt/src/lib.rs +++ b/packages/stack-encrypt/src/lib.rs @@ -311,8 +311,8 @@ pub use target::{ // `IntoAad` and `IntoPrfContext` are vitaminc's blankets over it, so both // derivations see the same bytes. pub use vitaminc_aead::{ - CipherText, Context, ContextPiece, ContextTag, Decrypt, Encrypt, IntoAad, IntoContext, Node, - PassthroughFrame, Unspecified, + CipherText, Context, ContextPiece, ContextTag, DecodeError, Decrypt, Encrypt, IntoAad, + IntoContext, Node, PassthroughFrame, Unspecified, }; // The vitaminc 0.4 names, deprecated there; re-exported for one transition so // a caller that spelled them keeps compiling with a warning. @@ -331,3 +331,7 @@ pub use vitaminc_prf::PrfContext; // checked once); `MaybeEmpty` is what a context type of your own implements // to be wrapped. `#[derive(EncryptFrom)]` names these through this crate. pub use vitaminc_protected::{nonempty, nonempty_bytes, EmptyError, MaybeEmpty, NonEmpty}; + +// And the wrapper plaintext comes back in (`ValueFrame::into_inner`, a +// decrypted `Protected`), with the trait that reads it. +pub use vitaminc_protected::{Controlled, Protected}; diff --git a/packages/stack-encrypt/tests/ui/plaintext_needs_encrypt.stderr b/packages/stack-encrypt/tests/ui/plaintext_needs_encrypt.stderr index a8539066c..d357fbec3 100644 --- a/packages/stack-encrypt/tests/ui/plaintext_needs_encrypt.stderr +++ b/packages/stack-encrypt/tests/ui/plaintext_needs_encrypt.stderr @@ -26,10 +26,10 @@ note: there are multiple different versions of crate `vitaminc_aead` in the depe &&'b T &'a BTreeMap &'a HashMap + &'a Protected &'a Vec &'a [T] &'a std::option::Option - &'a vitaminc_protected::protected::Protected &PassthroughFrame and $N others = note: required for `CipherText` to implement `EncryptFrom` From 3c17e96bb5e1eea962684b6ffc4d91bedaa22ac5 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Fri, 23 Oct 2026 13:45:18 +1100 Subject: [PATCH 7/8] docs: describe the order indexes and a host's typed null for the reader Two review comments on #1327. The encrypt package doc said ORE and OPE apply to "the integers", but an 8-bit integer takes no order index, and it said "not yet" twice. It now says which kinds take an order index and why a bool and an 8-bit integer do not. `ValueFrame::from_bytes` explained a host's typed null through vitaminc's release history and an issue number. It now says only what a caller sees: the null reads as a plain null and is not padded when sealed. Refs #1298 Claude-Session: https://claude.ai/code/session_01XQN1QpaWVDGjHEg39KEJF3 --- languages/golang/encrypt/doc.go | 7 ++++--- packages/stack-encrypt/src/dynamic/value_frame.rs | 15 +++++---------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/languages/golang/encrypt/doc.go b/languages/golang/encrypt/doc.go index 59b534c8c..821937099 100644 --- a/languages/golang/encrypt/doc.go +++ b/languages/golang/encrypt/doc.go @@ -123,9 +123,10 @@ // or [Int128] and [Uint128]), a float32 or float64, a [Decimal], a [Date] or a // time.Time (a timestamp), or a type defined over one of the built-in types. // Each integer seals at its own width. Equality applies to every one but a -// bool; ORE and OPE to the integers, text, bytes and floats, and not yet to a -// decimal, date or timestamp, whose order terms are not supported yet -// (#1236). +// bool. ORE and OPE apply to integers of 16 bits or more, floats, text and +// bytes. A bool or an 8-bit integer takes no order index, since over so few +// values its order terms would show which rows hold which value. Decimals, +// dates and timestamps cannot take an order index yet. // // Passthrough fields never cross the binding: the engine does nothing to a // passthrough value that a program could observe, and the FFI codec cannot diff --git a/packages/stack-encrypt/src/dynamic/value_frame.rs b/packages/stack-encrypt/src/dynamic/value_frame.rs index 4a6098ed3..29618f0c9 100644 --- a/packages/stack-encrypt/src/dynamic/value_frame.rs +++ b/packages/stack-encrypt/src/dynamic/value_frame.rs @@ -101,13 +101,9 @@ impl ValueFrame { /// Read one value from frame bytes a host handed over. /// - /// A typed null in the bytes reads as a null. vitaminc-aead 0.8 lets a - /// frame carry one so that a frame sealed as it is pads the host's - /// absent values, but a [`ValueFrame`] is rewritten through the value - /// model first, and a frame writer keeps no padding. Whether an absent - /// value is padded is for the field's plan to declare (#1298), so the - /// host never decides what an absent value shows; a typed null from a - /// host pads nothing on its own. + /// A typed null in the bytes reads as a plain null: the value this + /// returns does not remember the type, so sealing it does not pad it to + /// the type's length. /// /// # Errors /// @@ -1290,9 +1286,8 @@ mod tests { /// A typed null of a type in the model is a null in a frame: written, /// read from a host's bytes, or opened. Its padding belongs to a sealed - /// leaf, not to a frame (vitaminc-aead 0.8), and a null has no kind. So - /// a host's typed null is not padded by this path: padding is the - /// plan's decision (#1298). + /// leaf, not to a frame, and a null has no kind. So a host's typed null + /// is not padded by this path. #[test] fn a_typed_null_in_the_model_is_a_null_in_its_frame() { let null = frame_of(&Tree::Null); From eb737563f08c560cd729ec5436c4dd276b54abce Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Fri, 23 Oct 2026 17:53:47 +1100 Subject: [PATCH 8/8] fix(stack-encrypt): address review on the ORE upgrade Hold a block ORE term as an ore_rs::Term, so comparing two terms borrows them instead of copying both into new buffers, and decoding copies its input once. Name the 1023-byte block ORE limit by the fold, as the docs elsewhere do, and say the order terms of decimals, dates and timestamps are not supported yet (#1236) rather than waiting on a release. Add the tests the review found missing: a typed null in a guest frame decodes as a host null; a plain null opens as a fixed-width None; a typed null inside a passthrough is held to the value model; and bytes take a block ORE term up to 1023 bytes and no further. Claude-Session: https://claude.ai/code/session_01XQN1QpaWVDGjHEg39KEJF3 --- .github/dependabot.yml | 4 +- packages/stack-encrypt/src/dynamic/mod.rs | 5 +- .../stack-encrypt/src/dynamic/value_frame.rs | 41 +++++++++++++++++ packages/stack-encrypt/src/sem/mod.rs | 46 +++++++++---------- packages/stack-encrypt/tests/ore_block.rs | 18 ++++++++ packages/stack-encrypt/tests/roundtrip.rs | 22 +++++++++ packages/stack-guest-abi/src/value.rs | 20 ++++++++ 7 files changed, 128 insertions(+), 28 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 525c939f4..438ae208c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -226,8 +226,8 @@ updates: # stack-encrypt behind its optional `stack-encrypt` feature. Those crates # declare these `{ workspace = true }`, so their requirements come from # the root Cargo.toml even when built here. The root entry below ignores - # them because they move by hand: the root manifest pins recipher with - # `=`, and so does the Go guest, and pins clww-ore and ore-rs with `=`. + # them because they move by hand: the root manifest pins recipher, + # clww-ore and ore-rs with `=`, and the Go guest pins recipher with `=`. # Without these lines this entry bumped them in this lockfile and, to # satisfy the exact pins, rewrote the root Cargo.toml without touching # the root Cargo.lock or the guest's pin, breaking every root `--locked` diff --git a/packages/stack-encrypt/src/dynamic/mod.rs b/packages/stack-encrypt/src/dynamic/mod.rs index 4d52c4a0f..1cdd8164d 100644 --- a/packages/stack-encrypt/src/dynamic/mod.rs +++ b/packages/stack-encrypt/src/dynamic/mod.rs @@ -543,9 +543,8 @@ reasons! { /// equality or an order index on a boolean, any index on a composite. IndexNotAdmitted => "index_not_admitted", "the declared type has no such index"; /// The field declares an ORE or OPE index on a decimal, date or - /// timestamp. Their order terms wait for clww-ore and ore-rs - /// releases that encode them the ADR-0002 way (#1236); equality on - /// them works today. + /// timestamp. Their order terms are not supported yet (#1236); + /// equality on them works today. OrderTermPending => "order_term_pending", "an order index on a decimal, date or timestamp is not supported yet (#1236)"; /// Two fields are keyed under one identity. SharedIdentity => "shared_identity", "two fields are keyed under one identity"; diff --git a/packages/stack-encrypt/src/dynamic/value_frame.rs b/packages/stack-encrypt/src/dynamic/value_frame.rs index 29618f0c9..453fbc039 100644 --- a/packages/stack-encrypt/src/dynamic/value_frame.rs +++ b/packages/stack-encrypt/src/dynamic/value_frame.rs @@ -1246,6 +1246,7 @@ mod tests { /// A null that says what it stands in for, as vitaminc walks a `None` /// of a fixed-width type and as a host may send one in a frame. + #[derive(Clone)] struct TypedNull(FixedType); impl Encrypt for TypedNull { @@ -1332,6 +1333,46 @@ mod tests { )); } + /// A host's frame of a typed null inside a passthrough. + fn hidden_typed_null_frame(ty: FixedType) -> Vec { + let mut out = vec![vitaminc_aead::frame::PASSTHROUGH]; + out.extend(typed_null_frame(ty)); + out + } + + /// A passthrough holds a typed null to the same rules: one in the model + /// is a null, written or read from a host's bytes, and a uuid's is + /// refused. + #[test] + fn a_typed_null_in_a_passthrough_is_held_to_the_model() { + let null = frame_of(&Tree::Passthrough(Box::new(Tree::Null))); + for ty in typed_nulls_in_the_model() { + let written = ValueFrame::of(Hidden(TypedNull(ty))).expect("in the model"); + assert_eq!(written.risky_ref(), null.risky_ref(), "{ty:?} written"); + let bytes = hidden_typed_null_frame(ty); + assert!(ValueFrame::check(&bytes).is_ok(), "{ty:?} checks"); + let read = ValueFrame::from_bytes(&bytes).expect("reads"); + assert_eq!(read.risky_ref(), null.risky_ref(), "{ty:?} read"); + } + assert!(matches!( + ValueFrame::of(Hidden(TypedNull(uuid_null()))), + Err(DecodeError::Expected(EXPECTED)) + )); + let bytes = hidden_typed_null_frame(uuid_null()); + for refused in [ + ValueFrame::check(&bytes).map(drop), + ValueFrame::from_bytes(&bytes).map(drop), + ] { + assert!( + matches!( + refused, + Err(FromFrameError::Value(DecodeError::Expected(EXPECTED))) + ), + "{refused:?}" + ); + } + } + /// A record source that is a typed null, or holds one as a batch /// element, is a row that is not a map, as a null is. #[test] diff --git a/packages/stack-encrypt/src/sem/mod.rs b/packages/stack-encrypt/src/sem/mod.rs index e3f8e1d2f..70f5e70af 100644 --- a/packages/stack-encrypt/src/sem/mod.rs +++ b/packages/stack-encrypt/src/sem/mod.rs @@ -205,13 +205,13 @@ pub enum TermError { #[error("ORE/OPE encryption failed: {0}")] #[diagnostic(code(stack_encrypt::ore_failed))] Ore(#[from] clww_ore::Error), - /// Block ORE ([`OreBlockTerm`]) orders text and bytes of at most 1023 - /// bytes, counted after the order encoding (text folded): the chained - /// engine's 1024-byte ceiling, less the one marker byte `vitaminc-ore` - /// puts in front of a variable-width value. The ceiling bounds what one value - /// costs: a term of 1023 bytes is already about 34 KB. + /// Block ORE ([`OreBlockTerm`]) orders text whose fold is at most 1023 + /// bytes, and bytes of at most 1023: the chained engine's 1024-byte + /// ceiling, less the one marker byte `vitaminc-ore` puts in front of a + /// variable-width value. The ceiling bounds what one value costs: a term + /// of 1023 bytes is already about 34 KB. #[error( - "the value is too long for a block ORE term: its order encoding is longer than 1023 bytes" + "the value is too long for a block ORE term: it is longer than 1023 bytes, text counted by its fold" )] #[diagnostic( code(stack_encrypt::ore_block_too_long), @@ -1422,7 +1422,7 @@ term_wrapper!(OpeTerm, OpeClww8VariableV1); /// ciphertext carries its deterministic left half, so anyone holding two /// stored terms learns their order and, for the chained scheme, the length /// of their common prefix in six-bit blocks. -pub struct OreBlockTerm(Vec, PhantomData T>); +pub struct OreBlockTerm(ore_rs::Term, PhantomData T>); /// The order of two block ORE ciphertexts, by the comparator of the scheme /// their header names; `None` if either is not a well-formed ciphertext of @@ -1432,9 +1432,8 @@ pub struct OreBlockTerm(Vec, PhantomData T>); /// `BlockOre::compare` reads the header and compares with that engine's /// comparator, `OreAes128Bit6` or `OreAes128Bit6Chained`. ore-rs's legacy /// 8-bit engine (module `bit2`) is not used here. -fn ore_block_compare(a: &[u8], b: &[u8]) -> Option { - use ore_rs::{BlockOre, Term}; - BlockOre::compare(&Term::from_bytes(a.to_vec()), &Term::from_bytes(b.to_vec())) +fn ore_block_compare(a: &ore_rs::Term, b: &ore_rs::Term) -> Option { + ore_rs::BlockOre::compare(a, b) } impl OreBlockTerm { @@ -1445,27 +1444,28 @@ impl OreBlockTerm { /// caller asserts they were generated for this source type `T` and /// under the same context. pub fn from_bytes(bytes: &[u8]) -> Result { - if ore_block_compare(bytes, bytes).is_none() { + let term = ore_rs::Term::from_bytes(bytes.to_vec()); + if ore_block_compare(&term, &term).is_none() { return Err(TermBytesError::MalformedOreBlockCiphertext(bytes.len())); } - Ok(Self(bytes.to_vec(), PhantomData)) + Ok(Self(term, PhantomData)) } /// The frozen byte encoding: the serialised ore-rs ciphertext, header /// first, unframed. EQL v4 stores it hex-encoded as the one element of /// `ob`. pub fn as_bytes(&self) -> &[u8] { - &self.0 + self.0.as_bytes() } /// Owned copy of [`as_bytes`](Self::as_bytes). pub fn to_bytes(&self) -> Vec { - self.0.clone() + self.0.as_bytes().to_vec() } /// Unwrap into the serialised ciphertext. pub fn into_bytes(self) -> Vec { - self.0 + self.0.into_bytes() } /// The order of the two values, by the scheme's comparator. `None` @@ -1490,7 +1490,7 @@ impl TryFrom<&[u8]> for OreBlockTerm { /// The frozen byte encoding — the same bytes as the inherent `as_bytes`. impl AsRef<[u8]> for OreBlockTerm { fn as_ref(&self) -> &[u8] { - &self.0 + self.0.as_bytes() } } @@ -1498,7 +1498,7 @@ impl AsRef<[u8]> for OreBlockTerm { impl fmt::Debug for OreBlockTerm { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OreBlockTerm") - .field("len", &self.0.len()) + .field("len", &self.0.as_bytes().len()) .finish() } } @@ -1600,13 +1600,12 @@ where T: Orderable, P: Send + 'static, { - type Value = Result, TermError>; + type Value = Result; fn visit_block(self, mut block: [u8; 32]) -> Result { let scheme = ore_rs::BlockOre::new(Protected::new(block)); block.zeroize(); - let term = sealed::Sealed::encrypt_in(&*self.0, &scheme.target(T::TARGET)) - .map(ore_rs::Term::into_bytes); + let term = sealed::Sealed::encrypt_in(&*self.0, &scheme.target(T::TARGET)); Ok(term.map_err(ore_block_error)) } } @@ -1692,13 +1691,14 @@ fn ore_block( ) .into_result() .map_err(TermError::from_prf)? - .map(|bytes| OreBlockTerm(bytes, PhantomData)) + .map(|term| OreBlockTerm(term, PhantomData)) } /// Whether block ORE takes `text` as order text: its order encoding (the /// marker byte, then the fold, which a [`OreBlockTerm`] encrypts) must -/// exist, fit the chained scheme's 1024 bytes, and not end in NUL. The refusals derivation makes, -/// stated without a key, so a binding can refuse a query at its boundary. +/// exist, fit the chained scheme's 1024 bytes, and not end in NUL. These +/// are the refusals derivation makes, stated without a key, so a binding +/// can refuse a query at its boundary. #[cfg_attr(not(feature = "dynamic"), allow(dead_code))] pub(crate) fn ore_block_text(text: &str) -> Result<(), TermError> { let encoded = vitaminc_ore::text(text)?; diff --git a/packages/stack-encrypt/tests/ore_block.rs b/packages/stack-encrypt/tests/ore_block.rs index 4f252774c..56bd88d81 100644 --- a/packages/stack-encrypt/tests/ore_block.rs +++ b/packages/stack-encrypt/tests/ore_block.rs @@ -245,6 +245,24 @@ async fn bytes_order_as_bytes() { assert_sorted(&terms, "bytes"); } +/// Bytes take a term up to 1023 bytes, as text's fold does: ore-rs's +/// 1024-byte ceiling counts the marker byte in front of them. +#[tokio::test] +async fn bytes_of_more_than_1023_bytes_have_no_term() { + let cipher = cipher().await; + let keyset = cipher.default_keyset(); + let longest = term(&keyset, vec![7u8; 1023]).await; + assert!(blocks(longest.as_bytes()) > 1023, "every byte is ordered"); + let too_long = keyset + .ore_block_term(vec![7u8; 1024], nonempty!("users/n")) + .await + .unwrap_err(); + assert!( + matches!(too_long, Error::Term(TermError::OreBlockTooLong)), + "{too_long:?}" + ); +} + /// One value encrypts to different bytes each time (the right half's /// nonce), and those terms compare equal; the left half is deterministic. #[tokio::test] diff --git a/packages/stack-encrypt/tests/roundtrip.rs b/packages/stack-encrypt/tests/roundtrip.rs index 5677d7bb6..9afa770e8 100644 --- a/packages/stack-encrypt/tests/roundtrip.rs +++ b/packages/stack-encrypt/tests/roundtrip.rs @@ -122,6 +122,28 @@ async fn option_none_roundtrips() { assert_eq!(pt, None); } +/// A plain null opens as `None` of a fixed-width type too. Before vitaminc +/// 0.8 every `None` was sealed as a plain null, and the dynamic path still +/// seals one, so rows stored that way must keep opening into an `i64` or an +/// `f64` field. +#[tokio::test] +async fn a_plain_null_opens_as_a_fixed_width_none() { + let cipher = cipher().await; + let keyset = cipher.default_keyset(); + let ct = keyset + .encrypt(Option::::None, ()) + .await + .expect("encrypt"); + let pt: Option = cipher.decrypt(ct, ()).await.expect("decrypt"); + assert_eq!(pt, None, "i64"); + let ct = keyset + .encrypt(Option::::None, ()) + .await + .expect("encrypt"); + let pt: Option = cipher.decrypt(ct, ()).await.expect("decrypt"); + assert_eq!(pt, None, "f64"); +} + /// A sealed `None` of a fixed-width type is as long as a sealed `Some`: /// vitaminc 0.8 seals it as a typed null padded to the type's leaf, so the /// length of a ciphertext does not say whether its value was there. It opens diff --git a/packages/stack-guest-abi/src/value.rs b/packages/stack-guest-abi/src/value.rs index a08583a73..7da2ff542 100644 --- a/packages/stack-guest-abi/src/value.rs +++ b/packages/stack-guest-abi/src/value.rs @@ -368,6 +368,26 @@ mod tests { assert!(matches!(back.get("ids"), Some(HostValue::List(items)) if items.len() == 2)); } + /// A typed null (vitaminc's null of a fixed-width type, padded to the + /// type's length) reads as a null: the host has no typed nulls. A guest + /// writes none itself, but a frame may hold one. + #[test] + fn a_typed_null_reads_back_as_a_null() { + use vitaminc_aead::plaintext::Width; + for ty in [ + FixedType::new(None, Width::I64), + FixedType::new(Some(Logical::Date), Width::I32), + ] { + let ty = ty.expect("a fixed-width type"); + let mut frame = Vec::new(); + vitaminc_aead::leaf::write_typed_null(ty, &mut frame); + assert!( + matches!(HostValue::decode(&frame), Ok(HostValue::Null)), + "{ty:?}" + ); + } + } + #[test] fn a_map_with_a_repeated_key_does_not_encode() { let value = HostValue::Map(vec![