jcp-wire: a caller-signed challenge, and endpoint evidence bound to the answer #394

Merged
dcharlot merged 1 commit from feat/jcp-wire-evidence into main 2026-10-21 12:41:10 -04:00

2026-10-21

Transaction Science
jcp-wire: a caller-signed challenge, and endpoint evidence bound to the answer
All checks were successful
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 48s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 5s
standards workspaces build + test / joule-ui-rs (joule-ui/joule-ui-rs, joule-ui-rs, linux) (pull_request) Successful in 1m15s
standards workspaces build + test / jcp-rs (jcp-conformance, jcp/jcp-rs, -p jcp-energy --features nvml, jcp-rs, linux) (pull_request) Successful in 1m38s
standards workspaces build + test / joulehook-rs (joulehook/joulehook-rs, joulehook-rs, linux) (pull_request) Successful in 1m12s
standards workspaces build + test / sandbox-rs (sandbox-conformance, sandbox/sandbox-rs, sandbox-rs, linux) (pull_request) Successful in 2m17s
standards workspaces build + test / jouleclaw-rs (-nodebug, jouleclaw/jouleclaw-rs, -p jouleclaw-energy --features rapl,nvml, jouleclaw-rs, linux-arm64, -C target-feature=+fp16) (pull_request) Successful in 2m53s
standards workspaces build + test / mesh-rs (mesh/mesh-rs, -p mesh-engine-gguf -p mesh-openai --features mesh-engine-gguf/gguf,mesh-openai/server, mesh-rs, linux-arm64) (pull_request) Successful in 1m1s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 4m36s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 9m2s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 2m53s
Sweep 2026-10-19 item #5, wire side. A WireRequest had no challenge slot
and a WireResponse carried no endpoint evidence. Freshness came only from
the caller's `now` stamp, so a caller had no way to ask the platform an
endpoint runs on to vouch for an answer.

jcp-wire (SPEC §11):
- WireRequest.challenge: 32 caller-chosen bytes, covered by the caller's
  signature (challenged_signable_bytes, sign_challenged). It is omitted when
  absent, so a request without one keeps its bytes and its signature.
- WireResponse.evidence { kind, report }, omitted when absent. An endpoint
  configured with_attester answers an authenticated challenged request with
  a report over evidence_report_data = BLAKE3-XOF-64(derive_key "jcp/1 wire
  evidence v1", challenge ‖ BLAKE3(receipt)). The challenge makes it the
  caller's; the receipt makes it this answer's.
- No evidence for a request denied bad-signature, so a forgery cannot make
  the platform produce reports on demand. A repeat gets its first evidence,
  and a restart rebuilds it through respond(), so the attester is
  configured before with_journal.
- WireResponse::verify_evidence checks against the challenge the caller
  SENT, never one read back, through a caller-supplied EvidenceVerifier.
  jcp-wire stays free of any TEE crate, and a transport's own evidence (an
  exported authenticator on TLS) is a profile of the same slot.

SPEC §11: message shapes, the evidence binding and rules, and conformance
class C28 with a C28 check.

Tests: 4 new, plus C28. A challenged request gets evidence bound to its
answer; evidence comes only where asked and able, with an unchallenged
request byte-identical and signed over the old bytes; the challenge is
signed, so swapping or stripping it is refused with no evidence; a repeat
gets its first evidence and a restart rebuilds it. Mutation testing: 9
mutants, all killed.

Verified on the build host: jcp-rs 579 tests (--locked) and every
conformance class; clippy -D warnings (jcp-wire, -conformance, -threshold)
and rustdoc -D warnings (jcp-wire) clean. Repo checks pass, including
lockfiles.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-21 10:26:42 -04:00