Skip to content

perf(xmldsig): execute each signed Reference's transforms once - #369

Merged
polaz merged 3 commits into
mainfrom
perf/#367-single-transform-run
Nov 2, 2026
Merged

polaz merged 3 commits into
mainfrom
perf/#367-single-transform-run

Conversation

@polaz

@polaz polaz commented Nov 2, 2026

Copy link
Copy Markdown
Member

Summary

  • Signing executes each Reference's transform chain once: dependency analysis digests an output it proves independent of every value signing fills, and the digest pass reuses that digest. References that read another digest are still executed after it is filled.
  • On an XSLT Reference over 16384 items, signing now costs about as much as verification instead of twice as much; signed output is byte-identical.

Changes

  • The analysis terminal digests the final output when the settled dependencies are empty and no step may read character data outside its input; otherwise it discards the output without charging it.
  • XSLT and Base64 references are analyzed on the current tree, like subtree-selecting transforms, without a parse of a placeholder copy of the document.
  • The writer's KeyInfo is spliced before the speculative analysis: a KeyInfo that may add an ID or a namespace scope is committed first and analyzed once after; an inert one keeps the analysis plan across the commit, as does generated canonicalization.
  • A spent resource limit in the speculative analysis ends the operation instead of being retried after the commit.
  • The aggregate external-resource test admits one dereference at an allowance equal to the resource size and refuses one byte less.

Testing

Workspace tests with all features (including the xmlsec1 and libxslt oracles), the PKCS#11 suite, Clippy, feature-profile lints, the no-std target, the fuzz build and the compatibility ledgers pass on macOS; Linux and Windows run in CI.

Stacked on #366.

Closes #367

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T11:30:04.653892Z 50f52d6 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 7 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between 35ad6c7 and 50f52d6.

Files selected for processing: 5
  • src/xmldsig/mutation.rs
  • src/xmldsig/sign.rs
  • src/xmldsig/sign/single_execution_tests.rs
  • src/xmldsig/transforms.rs
  • tests/donor_interop_suite.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aef391a099

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/sign.rs Resolved
Comment thread src/xmldsig/sign.rs Resolved
@polaz
polaz force-pushed the perf/#367-single-transform-run branch from aef391a to 714f52d Compare November 2, 2026 10:47
Base automatically changed from perf/#313-xslt-16384 to main November 2, 2026 11:05
polaz added 3 commits November 2, 2026 13:08
Signing ran every Reference's transform chain twice: dependency analysis
executed it to learn which mutable values reach its output and discarded
the result, then the digest pass executed it again.

- The analysis terminal digests the output when the settled dependencies
  are empty and no step may read character data outside its input; the
  digest pass takes that value instead of executing the chain again
- The speculative analysis made before committing generated
  canonicalization keeps its plan after that commit, since the commit
  only changes nodes it tracks; a KeyInfo commit, which may add an ID,
  still triggers a full analysis
- The aggregate external resource test now admits one dereference at an
  allowance equal to the resource size and refuses one byte less

Closes #367
XSLT reads only its input octets and its own stylesheet, and Base64
decodes the text of the nodes it is given, so a DigestValue element is
in their input exactly when its future text is. References using them
no longer need a parse of the document with placeholder values to find
their dependencies.

With the analysis now producing digests, an analysis made before the
writer's KeyInfo could spend the operation's allowances on a result
that is discarded:

- The KeyInfo is spliced before the analysis; one that is not inert
  (it may add an ID or a namespace scope) is committed first and the
  analysis runs once after it, and the splice is reused by that commit
- An inert KeyInfo keeps the analysis plan across the commit
- A spent resource limit in the speculative analysis ends the
  operation instead of being retried after the commit
- Dependency analysis stops a chain once it is known to depend on a
  value signing fills: before an octet-consuming step (XSLT, Base64)
  whose input already holds a tracked node, or after a dependency lost
  its provenance. The output was discarded anyway; a stylesheet no
  longer runs on a DigestValue not yet filled, where it could fail
  although the digest pass after the fill succeeds
- A writer KeyInfo that removes an element carrying an ID is not inert:
  the plan made before the splice is no longer kept across its commit
  and the splice is not deferred, so a Reference to the removed ID is
  refused instead of keeping a digest of a target the signed document
  lacks

Regression tests cover a Manifest stylesheet that refuses an empty
DigestValue and a KeyName ID dropped by the writer, committed and
deferred.
@polaz
polaz force-pushed the perf/#367-single-transform-run branch from 714f52d to 50f52d6 Compare November 2, 2026 11:27
@polaz
polaz enabled auto-merge (squash) November 2, 2026 11:42
@polaz
polaz merged commit eba7dc9 into main Nov 2, 2026
29 checks passed
@polaz
polaz deleted the perf/#367-single-transform-run branch November 2, 2026 11:59
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.

perf(xmldsig): execute each signed Reference's transforms once

1 participant