Skip to content

feat(REQ-26): sign_digest — keyless-sign an arbitrary 32-byte digest (#256) - #263

Merged
avrabe merged 1 commit into
mainfrom
feat/req-26-sign-digest
Aug 21, 2026
Merged

feat(REQ-26): sign_digest — keyless-sign an arbitrary 32-byte digest (#256)#263
avrabe merged 1 commit into
mainfrom
feat/req-26-sign-digest

Conversation

@avrabe

@avrabe avrabe commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Closes the asymmetry varve reported in #256: wsc could verify a bare digest (AirGappedVerifier::verify_signature already takes &[u8; 32]) but could only sign a WASM Module. varve signs layer manifests, whose sha256 is a 32-byte digest.

Change

Adds KeylessSigner::sign_digest(&self, digest: &[u8; 32]) -> Result<KeylessSignature, WSError> as the single keyless signing primitive. sign_module becomes sign_digest(sha256(module)) + the module-embedding step — one signing path, not two.

The digest is signed as an ECDSA P-256 prehash — the exact inverse of the verifier's verify_prehash(module_hash) — so the output verifies offline against the same digest. Behaviour-preserving for sign_module: the old DigestSigner-over-hasher and the new PrehashSigner-over-finalized-digest sign the identical 32-byte SHA-256 with the same key.

Oracle

  • Non-gated (runs in CI): test_sign_digest_prehash_is_verifier_symmetric — the core primitive round-trips for an arbitrary digest and rejects a different one (built-in negative control, so it can't be vacuous).
  • Gated e2e: test_sign_digest_arbitrary_roundtrip signs sha256("test") (a non-module digest) and asserts the signature binds to exactly that digest + carries a Fulcio chain + Rekor entry.
  • The "verifier accepts an arbitrary digest" half is already covered offline by the airgapped::verifier fixture tests (they verify over a synthetic, non-module digest — which is why wsc: keyless signing over an arbitrary digest, not only a WASM Module #256 notes "verification is already general").

Evidence

wsc lib 610 pass/3 ignored (+1 symmetry test); keyless_integration 5 pass/4 ignored (+1 gated). sign_module behaviour unchanged.

Part of the v0.12.0 varve-interop line (plan #261). Refs #256.

🤖 Generated with Claude Code

…256)

varve (#256) can VERIFY a bare digest with wsc (AirGappedVerifier::verify_signature
already takes &[u8;32]) but could only SIGN a WASM Module. It signs layer
manifests, whose sha256 is a 32-byte digest.

Adds KeylessSigner::sign_digest(&self, digest: &[u8;32]) -> KeylessSignature as
the single keyless signing primitive. sign_module is now
sign_digest(sha256(module)) + the module-embedding step, collapsing two signing
paths into one. The digest is signed as an ECDSA P-256 prehash — the exact
inverse of the verifier's verify_prehash(module_hash) — so the output verifies
offline against the same digest. Behaviour-preserving for sign_module: the old
DigestSigner-over-hasher and the new PrehashSigner-over-finalized-digest sign the
identical 32-byte SHA-256 with the same key.

Oracle:
- Non-gated (CI-runnable) test_sign_digest_prehash_is_verifier_symmetric proves
  the core primitive round-trips for an arbitrary digest AND rejects a different
  one (built-in negative control).
- Gated e2e test_sign_digest_arbitrary_roundtrip signs sha256("test") (a
  non-module digest) and asserts the signature binds to exactly that digest.
- The offline "verifier accepts an arbitrary digest" half is already covered by
  the airgapped verifier fixture tests, which verify over a synthetic digest.

Tests: wsc lib 610 pass/3 ignored (was 609; +1 symmetry test); keyless_integration
5 pass/4 ignored (+1 gated). No change to sign_module behaviour.

Refs: #256
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aR3Md1h46K9wAUWMQiESH
@avrabe
avrabe merged commit 25762a1 into main Aug 21, 2026
19 checks passed
@avrabe
avrabe deleted the feat/req-26-sign-digest branch August 21, 2026 19:06
@codecov

codecov Bot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 45.00000% with 22 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/lib/src/signature/keyless/signer.rs 45.00% 22 Missing ⚠️

📢 Thoughts on this report? Let us know!

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