Skip to content

rusty-s3 offers rind - #466

Closed
kixelated wants to merge 1 commit into
mainfrom
quest/m2/adoption/rusty-s3
Closed

kixelated wants to merge 1 commit into
mainfrom
quest/m2/adoption/rusty-s3

Conversation

@kixelated

@kixelated kixelated commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

Claims quest/m2/adoption/rusty-s3.md.

Problem

rusty-s3 picks its SigV4 crypto by feature (rustcrypto, aws-lc-rs, graviola) and has no rind one. The quest's goal is a merged upstream PR adding it.

Approach

The upstream change is prepared and tested but not posted, since it goes outside the moq-dev and kixelated orgs. Nothing lands in rind from this PR.

  • src/crypto.rs gains a rind arm for SHA-256 and HMAC-SHA256 that mirrors the aws-lc-rs arm (rind::digest::digest, rind::hmac::sign), plus the feature, the compile_error! text, the crate docs, and CI clippy and test steps copied from graviola's.
  • rusty-s3 has no CONTRIBUTING or AI policy, and its maintainer's own paolobarbolini/rusty-s3#165 was LLM-driven, so the body below is AI-written and carries the marker.

Choices made without asking:

  • rind ranks last when several backends are on (aws-lc-rs > rustcrypto > graviola > rind), so no existing feature combination changes backend. Ranking it above rustcrypto would let features = ["rind"] win with default features on, but changes nothing for anyone who follows the crate's documented default-features = false.
  • Depends on rind = "0.2", which the published 0.2.0 already satisfies, so posting needn't wait on moq-dev/rind#424.

Validation, on upstream 65535df, with [workspace] added locally only because the clone sat inside rind's workspace:

  • cargo fmt --check; cargo clippy --locked -D warnings for --all-targets, aws-lc-rs,full, graviola,full, rind,full (also --all-targets), and --all-features: clean.
  • cargo test --locked --lib for each backend and rustcrypto,xml: pass.
  • cargo test --locked with rind, rind,full, and rustcrypto, against versitygw 1.8.0 (nixpkgs; docker was unavailable): all integration tests pass, so rind signs requests a real S3 gateway accepts.
  • cargo deny --all-features check licenses bans sources: ok; only duplicate-version warnings (hax-lib, syn, shlex) from rind's armv7 libcrux deps.
  • cargo bench --bench actions on one i7-8700, noisy: rind 10.1 µs, aws-lc-rs 14.0, rustcrypto 14.9, graviola 16.9 per signed GetObject. Not quoted upstream.

Impact

None on rind's API or wire format. Upstream gains an opt-in rind feature; its users need Rust 1.90 (rind's MSRV) against rusty-s3's 1.89, which the upstream msrv job does not build.

Alternatives

  • rind-graviola shim: ruled out by the adoption epic, since [patch] cannot swap in a crate of another name.

Upstream change

Against paolobarbolini/rusty-s3@65535df, excluding Cargo.lock (the build step below records rind in it, about +370 lines):

upstream.diff
diff --git a/.github/workflows/continuos-integration.yml b/.github/workflows/continuos-integration.yml
index 0ad8118..979c7b1 100644
--- a/.github/workflows/continuos-integration.yml
+++ b/.github/workflows/continuos-integration.yml
@@ -58,6 +58,9 @@ jobs:
     - name: Run clippy (graviola)
       run: cargo clippy --locked --no-default-features --features graviola,full
 
+    - name: Run clippy (rind)
+      run: cargo clippy --locked --no-default-features --features rind,full
+
   test:
     strategy:
       fail-fast: false
@@ -95,6 +98,10 @@ jobs:
       if: matrix.platform == 'ubuntu-26.04'
       run: cargo test --locked --no-default-features --features graviola
 
+    - name: Run tests (rind)
+      if: matrix.platform == 'ubuntu-26.04'
+      run: cargo test --locked --no-default-features --features rind
+
     - name: Run tests (default features)
       if: matrix.platform == 'ubuntu-26.04'
       run: cargo test --locked
@@ -115,6 +122,10 @@ jobs:
       if: matrix.platform != 'ubuntu-26.04'
       run: cargo test --locked --lib --no-default-features --features graviola
 
+    - name: Run tests (rind)
+      if: matrix.platform != 'ubuntu-26.04'
+      run: cargo test --locked --lib --no-default-features --features rind
+
     - name: Run tests (default features)
       if: matrix.platform != 'ubuntu-26.04'
       run: cargo test --locked --lib
diff --git a/Cargo.toml b/Cargo.toml
index a5e4fef..eae4cdc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -23,6 +23,7 @@ graviola = { version = "0.4", optional = true }
 hmac = { version = "0.13", optional = true }
 jiff = { version = "0.2", default-features = false, features = ["std"] }
 percent-encoding = "2.1.0"
+rind = { version = "0.2", optional = true }
 sha2 = { version = "0.11", default-features = false, optional = true }
 url = "2.2.0"
 zeroize = "1"
@@ -39,6 +40,7 @@ default = ["rustcrypto", "full"]
 aws-lc-rs = ["dep:aws-lc-rs"]
 rustcrypto = ["dep:hmac", "dep:sha2"]
 graviola = ["dep:graviola"]
+rind = ["dep:rind"]
 wasm_bindgen = ["jiff/js"]
 xml = ["dep:instant-xml"]
 full = ["xml", "dep:base64", "dep:md-5", "dep:serde", "dep:serde_json", "jiff/serde"]
diff --git a/src/crypto.rs b/src/crypto.rs
index 7a9df35..31d009c 100644
--- a/src/crypto.rs
+++ b/src/crypto.rs
@@ -1,6 +1,11 @@
-#[cfg(not(any(feature = "aws-lc-rs", feature = "rustcrypto", feature = "graviola")))]
+#[cfg(not(any(
+    feature = "aws-lc-rs",
+    feature = "rustcrypto",
+    feature = "graviola",
+    feature = "rind"
+)))]
 compile_error!(
-    "enable at least one of `aws-lc-rs`, `rustcrypto`, or `graviola` to provide a crypto backend"
+    "enable at least one of `aws-lc-rs`, `rustcrypto`, `graviola`, or `rind` to provide a crypto backend"
 );
 
 /// Compute the SHA-256 digest of `data`.
@@ -17,7 +22,10 @@ pub(crate) fn sha256(data: &[u8]) -> [u8; 32] {
         sha2::Sha256::digest(data).into()
     }
 
-    #[cfg(not(any(feature = "aws-lc-rs", feature = "rustcrypto")))]
+    #[cfg(all(
+        feature = "graviola",
+        not(any(feature = "aws-lc-rs", feature = "rustcrypto"))
+    ))]
     {
         use graviola::hashing::Hash as _;
         graviola::hashing::Sha256::hash(data)
@@ -25,6 +33,12 @@ pub(crate) fn sha256(data: &[u8]) -> [u8; 32] {
             .try_into()
             .unwrap()
     }
+
+    #[cfg(not(any(feature = "aws-lc-rs", feature = "rustcrypto", feature = "graviola")))]
+    {
+        use rind::digest::{SHA256, digest};
+        digest(&SHA256, data).as_ref().try_into().unwrap()
+    }
 }
 
 /// Compute the SHA-256 HMAC digest of `data`.
@@ -47,10 +61,22 @@ pub(crate) fn hmac_sha256(key: &[u8], data: &[u8]) -> [u8; 32] {
         hmac.finalize().into_bytes().into()
     }
 
-    #[cfg(not(any(feature = "aws-lc-rs", feature = "rustcrypto")))]
+    #[cfg(all(
+        feature = "graviola",
+        not(any(feature = "aws-lc-rs", feature = "rustcrypto"))
+    ))]
     {
         let mut hmac = graviola::hashing::hmac::Hmac::<graviola::hashing::Sha256>::new(key);
         hmac.update(data);
         hmac.finish().as_ref().try_into().unwrap()
     }
+
+    #[cfg(not(any(feature = "aws-lc-rs", feature = "rustcrypto", feature = "graviola")))]
+    {
+        use rind::hmac::{self, HMAC_SHA256, Key};
+        hmac::sign(&Key::new(&HMAC_SHA256, key), data)
+            .as_ref()
+            .try_into()
+            .unwrap()
+    }
 }
diff --git a/src/lib.rs b/src/lib.rs
index 45555c0..8f3dac9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,11 +37,12 @@
 //!
 //! ## Features
 //!
-//! * `rustcrypto` (enabled by default), `aws-lc-rs` and `graviola`: the
-//!   cryptography used for signing requests. At least one of them must be
+//! * `rustcrypto` (enabled by default), `aws-lc-rs`, `graviola` and `rind`:
+//!   the cryptography used for signing requests. At least one of them must be
 //!   enabled. If more are, `aws-lc-rs` is preferred over `rustcrypto`, which is
-//!   preferred over `graviola`, so to avoid building `rustcrypto` with another
-//!   one, disable the default features and enable `full` again, like with
+//!   preferred over `graviola`, which is preferred over `rind`, so to avoid
+//!   building `rustcrypto` with another one, disable the default features and
+//!   enable `full` again, like with
 //!   `default-features = false, features = ["aws-lc-rs", "full"]`.
 //! * `xml`: the actions which send or receive XML, like `ListObjectsV2`
 //!   and the ones for multipart uploads.

To post it:

gh repo fork paolobarbolini/rusty-s3 --clone && cd rusty-s3
git switch -c rind
git apply upstream.diff        # the diff above
cargo check --no-default-features --features rind,full   # records rind in Cargo.lock
git commit -am "feat: add the rind crypto backend"
git push -u origin rind
gh pr create --repo paolobarbolini/rusty-s3 --title "feat: add the rind crypto backend" --body-file upstream-body.md
upstream-body.md
Adds a `rind` feature that signs requests with [rind](https://github.com/moq-dev/rind), next to `rustcrypto`, `aws-lc-rs`, and `graviola`.

rind is a pure-Rust fork of graviola (no C toolchain needed), and its `digest` and `hmac` modules follow aws-lc-rs's API, so the new arm mirrors the aws-lc-rs one. It ranks last when several backends are enabled, so every existing feature combination keeps its backend. The CI clippy and test steps copy graviola's.

Notes:
- rind's MSRV is 1.90, one above rusty-s3's 1.89. The `msrv` job builds only the default and `aws-lc-rs` features, so it is unaffected; only users who opt into `rind` need 1.90.
- `Cargo.lock` grows by about 370 lines: rind's 32-bit ARM backend (libcrux, fiat-crypto, curve25519-dalek) is recorded for every target. On x86_64 and aarch64 rind pulls in only `cfg-if` and `getrandom`. `cargo deny check` passes.
- Disclosure: I maintain rind.

Tested locally: `cargo fmt --check`, `cargo clippy` for each backend and `--all-features`, and `cargo test --no-default-features --features rind` and `rind,full` against versitygw.

(Written by Claude Opus 5.5 with high)

Follow-ups

  • Rewrite the quest to wait on upstream once posted: plan. After the upstream PR is open, this branch should replace the claim with a quest ## Waiting item (paolobarbolini/rusty-s3: merge the rind feature PR) so it resurfaces in quest waiting rather than sitting as a draft.
  • Deduplicate rind's hax-lib 0.3/0.4 and syn 2/3 on armv7 (libcrux-intrinsics vs core-models, libcrux-macros): drop. They show up only as cargo-deny warnings in consumers' lockfiles and are pinned by libcrux's own releases.

Waiting

  • Maintainer: post the upstream PR with the steps above (an agent may not post outside moq-dev and kixelated without approval). Recommended: post as is. Check: an open PR from your fork on paolobarbolini/rusty-s3.

Models

Size: XS
Implementer: Claude Code, claude-opus-5-5, high effort

Review

Skipped: nothing lands in rind yet; the upstream diff was checked by its own CI-equivalent runs above.

(Written by Claude Opus 5.5 with high)

@kixelated

Copy link
Copy Markdown
Collaborator Author

Closing: the maintainer dropped this quest on 2026-11-07 (let projects pull rind rather than send them patches). moq-dev/rind#471 deletes it with the others.

(Written by Claude Opus 5.5 with high)

@kixelated kixelated closed this Nov 7, 2026
@kixelated
kixelated deleted the quest/m2/adoption/rusty-s3 branch November 7, 2026 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant