Skip to content

Fix marvin-toolkit - #776

Merged
tarcieri merged 1 commit into
masterfrom
fix-marvin-toolkit
Nov 6, 2026
Merged

tarcieri merged 1 commit into
masterfrom
fix-marvin-toolkit

Conversation

@tarcieri

@tarcieri tarcieri commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Updates the marvin-toolkit/ subdirectory to pull in the parent workspace and source its dependencies from there. Previously it was pulling in the old rsa v0.9 release series.

Additionally improves the Rust harness for running it and updates the documentation.

Updates the `marvin-toolkit/` subdirectory to pull in the parent
workspace and source its dependencies from there.

Additionally improves the Rust harness for running it and updates the
documentation.
@tarcieri

tarcieri commented Nov 6, 2026 •

Copy link
Copy Markdown
Member Author

After closing out #711, here are the results:

$ ./marvin-toolkit/entrypoint.sh \
  -s 2048 -n 100000 -q \
  -o marvin-toolkit/outputs/long-default

[...]

[i] Calculating confidence intervals of central tendencies
Done: 100.00%, elapsed: 24.45s, speed: 246.99 bootstraps/s, avg speed: 204.48 bootstraps/s, remaining:  0.00s, ETA: 21:07:19 05-11-2026
[i] Confidence intervals of central tendencies done in 24.5s
[i] Start graphing the worst pair data
[i] Worst pair data graphed in 0.933s
Sign test mean p-value: 0.4342, median p-value: 0.3963, min p-value: 0.006806
Friedman test (chisquare approximation) for all samples
p-value: 0.14505489481689438
Worst pair: 8(valid_245), 12(valid_repeated_byte_payload_246_1)
Mean of differences: 9.11231e-08s, 95% CI: -8.23881e-08s, 2.620058e-07s (±1.722e-07s)
Median of differences: 8.30000e-08s, 95% CI: 1.00000e-09s, 1.250000e-07s (±6.200e-08s)
Trimmed mean (5%) of differences: 9.89668e-08s, 95% CI: -2.72189e-08s, 2.240925e-07s (±1.257e-07s)
Trimmed mean (25%) of differences: 8.47634e-08s, 95% CI: -1.60590e-08s, 1.873171e-07s (±1.017e-07s)
Trimmed mean (45%) of differences: 7.55387e-08s, 95% CI: 1.58961e-08s, 1.353464e-07s (±5.973e-08s)
Trimean of differences: 8.32500e-08s, 95% CI: -3.12500e-08s, 1.875000e-07s (±1.094e-07s)
Layperson explanation: Large confidence intervals detected, collecting more data necessary. Side channel leakage smaller than 5.973e-08s is possible
For detailed report see /Users/tony/src/RustCrypto/RSA/marvin-toolkit/outputs/long-default/results/report.csv
Analysis return value: 0
Results: /Users/tony/src/RustCrypto/RSA/marvin-toolkit/outputs/long-default/results/report.txt (analysis exit status: 0)

Curious if this may mean a potential sidechannel remains:

Worst pair: 8(valid_245), 12(valid_repeated_byte_payload_246_1)

Otherwise I think this means things are massively improved, at the very least.

cc @tomato42

@tarcieri
tarcieri merged commit 74c186a into master Nov 6, 2026
14 checks passed
@tarcieri
tarcieri deleted the fix-marvin-toolkit branch November 6, 2026 04:27
kaidokert added a commit to kaidokert/RSA that referenced this pull request Nov 7, 2026
* CI: enable `minimal-versions` job (RustCrypto#762)

Fork adaptation: applied to the fork's workflow. The job runs
unchanged against the fork's manifest.

(cherry picked from commit b19bcff)

* README.md: change encryption example to use OAEP (RustCrypto#721)

PKCS#1 v1.5 encryption is fundamentally broken due to
Bleichenbacher attacks, and `draft-irtf-cfrg-rsa-guidance` suggests we
get rid of it entirely.

At the very least, we can stop using it in the README.md example

Fork adaptation: applied to UPSTREAM_README.md, the fork's copy of the
upstream README. The conflict drops the fork's stale `private-key`
feature wrapper around the example, so the copy is verbatim again. The
upstream message's issue reference is dropped.

(cherry picked from commit 8790e2a)

* README.md: add codecov badge (RustCrypto#765)

Fork adaptation: applied to UPSTREAM_README.md, the fork's copy of the
upstream README.

(cherry picked from commit d3670e7)

* README.md: fix codecov badge link

Fork adaptation: applied to UPSTREAM_README.md, the fork's copy of the
upstream README.

(cherry picked from commit 843dc43)

* README.md cleanups

- Updates status and security sections with latest constant-time
  hardening info
- Removes old status section
- Update MSRV policy

Fork adaptation: applied to UPSTREAM_README.md, the fork's copy of the
upstream README.

(cherry picked from commit 681c285)

* README.md: fix constant-time hardening link

Fork adaptation: applied to UPSTREAM_README.md, the fork's copy of the
upstream README.

(cherry picked from commit 769ffb0)

* README.md: reword text about previous audits

The audit we cite is old and many issues have been uncovered which were
not found when it occurred.

This changes the text to note there was an audit but it probably isn't
really relevant anymore.

Fork adaptation: applied to UPSTREAM_README.md, the fork's copy of the
upstream README.

(cherry picked from commit 2a5b8b8)

* UPSTREAM_README.md: MSRV badge to 1.87

The README hunk of upstream's crypto-bigint 0.7.6 bump, whose manifest
change was skipped. The fork's MSRV is already 1.87, and this makes the
copy match upstream's README at the catch-up target.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Fix `marvin-toolkit` (RustCrypto#776)

Updates the `marvin-toolkit/` subdirectory to pull in the parent
workspace and source its dependencies from there. Previously it was
pulling in the old `rsa` v0.9 release series.

Additionally improves the Rust harness for running it and updates the
documentation.

Fork adaptation: the harness depends on `rsa_heapless` (lib name
`rsa`) by path, and the workspace CI jobs add `-p rsa-marvin` next to
`-p rsa_heapless`. The `Cargo.lock` part is dropped, since the fork does
not track a lockfile.

(cherry picked from commit 74c186a)

* CI: install the RISC-V QEMU package on Ubuntu 26.04

ubuntu-latest moved to 26.04, whose qemu 10 packages no longer include
qemu-system-riscv32 in qemu-system-misc, so the footprint suite failed to
spawn the emulator. Install qemu-system-riscv, falling back to -misc on
older images, and fail the step early if the binary is missing.

* marvin-toolkit: generate Cargo.lock when the checkout has none

The toolkit expects a tracked Cargo.lock: the Dockerfile copies it and
both build paths pass --locked, which cannot create one. The fork does
not track a lockfile, so a fresh checkout could not start either path.
Resolve one first, so the run still records exact versions. The Docker
image also copies examples/, which the fork's manifest declares as
explicit targets.

---------

Co-authored-by: Tony Arcieri <bascule@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@rldyourmnd

Copy link
Copy Markdown

I investigated the returned-length boundary behind the worst-pair question above. A focused qualification patch is available at rldyourmnd/RSA@master...fix/marvin-qualification (base 4a7de12449ac290033b26c64a118acbe8133af0d; commits 8966d38 and 7f956f7). It adds RSA-sized padding drivers and optional --out-lengths PATH metadata to the existing timing driver. It changes no production cryptographic implementation.

For a synthetic RSA-2048 key and 1,000 distinct ciphertexts per stock probe:

Probe Returned lengths Samples returning 245 bytes
valid_245 Always 245 1000/1000
valid_repeated_byte_payload_246_1 0 through 245 4/1000

The second probe has seven PS bytes and takes implicit rejection. The returned-length distribution differs from valid_245. The current API includes the final suffix allocation/copy inside the measured interval. Under draft guidance §7.2, the final returned length may be public; padding validity and buffer selection remain secret. A difference between these classes alone therefore cannot locate a leak before that boundary.

I also ran a diagnostic with all outputs fixed at 245 bytes: four classes, 100,000 repetitions each, fresh default blinding, x86-64 i9-13900K, CPU affinity, rustc 1.99.1/LLVM 23.1.1. The three valid classes had pools of 1,000 ciphertexts each; the invalid class used the four matching ciphertexts above, sampled with replacement. Friedman p=0.47140284127645815. The worst-pair median difference was -74 ns (95% CI about -169 to +35 ns); the smallest reported confidence half-width was 99.19 ns. This remains inconclusive, with a small fixed invalid-input pool and a shared machine. It does not establish absence of leakage. Full raw timing reports were retained, without subtracting an output-length effect.

Patch validation on Linux:

  • BINSEC 0.11.3, cargo-checkct 85271e5, nightly-2026-10-06: all 42 cases secure across x86-64, Thumb-2 and RISC-V with control-flow,memory-access,dividend,divisor, no skip-unknown. The added 256/257/384/512-byte drivers check decoding and full-buffer selection before the returned-length boundary. Raw RSA arithmetic fixtures remain small.
  • Detector control: an injected secret branch restricted to buffers larger than 32 bytes leaves the original 30 cases secure and makes all 12 added cases insecure. This is an intentional coverage control.
  • cargo test --locked -p rsa-marvin passes on Rust 1.87.0, checking the 12 published B.1 vectors in all three blinding modes, metadata order, optional use and refusing to overwrite existing metadata. The new positive test fails on the original CLI. Upstream Clippy and all-target Clippy for rsa-marvin pass. RSA's all-features suite passes 232 tests on Rust 1.99.1.

The metadata is read/written after the timer stops; the original timing CSV format is preserved. Extra I/O can still perturb later measurements, so compared runs should use the same setting. The patch documents this limitation and keeps the complete tlsfuzzer report.

AI assistance was used for source analysis, code, experiment orchestration and this report. Per the request in #711, I am sharing the bounded qualification patch and actual results here for review.

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.

2 participants