Skip to content

refactor(attestation): extract attestation-types crate without dcap-qvl#3245

Draft
pbeza wants to merge 3 commits into
feat/tee-verifier-contractfrom
feat/attestation-types-split
Draft

refactor(attestation): extract attestation-types crate without dcap-qvl#3245
pbeza wants to merge 3 commits into
feat/tee-verifier-contractfrom
feat/attestation-types-split

Conversation

@pbeza
Copy link
Copy Markdown
Contributor

@pbeza pbeza commented May 15, 2026

Closes #3267

Pure crate split, no behaviour change. Stacked on #3237. Sets up the WASM-size win that the follow-up PR (mpc-contract Promise refactor) will land.

What moves into the new attestation-types crate

  • app_compose, measurements, report_data, tcb_info modules — none of these touched dcap-qvl to begin with.
  • The post-DCAP verification helpers — refactored from private methods on DstackAttestation into free functions in attestation_types::verify_post_dcap, taking the tee_verifier_interface::VerifiedReport mirror instead of the dcap_qvl type. Same logic, byte-for-byte.

What stays in attestation

  • DstackAttestation::verify — the one and only dcap_qvl::verify::verify call site. It now converts the upstream report to the Borsh mirror once and calls the free functions on it.
  • The Collateral newtype and QuoteBytes newtype. Their dedup with the tee-verifier-interface mirrors is deferred to a later PR (tee-authority and friends need a migration path).

What this enables (next PR, stacked on this one)

mpc-contract can depend on attestation-types alone — no dcap-qvl — and call the post-DCAP helpers from a Promise callback that receives the verifier-returned VerifiedReport. That is the actual WASM-size win for NEP-509.

Drive-bys

  • Drops the dead TryFrom<dcap_qvl::verify::VerifiedReport> for Measurements impl (no callers anywhere in the codebase).
  • Re-exports the moved modules from attestation::lib.rs so existing consumers (mpc-attestation, tee-authority, attestation-cli, etc.) keep their import paths unchanged.

Part of the verifier breakout described in docs/design/attestation-verifier-contract.md (#3160).

pbeza added 3 commits May 15, 2026 12:20
…undary

Introduces a no_std crate carrying the Borsh-stable types that cross the
`tee-verifier` contract boundary. The crate has no `dcap-qvl` dependency
so it can be linked into consumer contracts (e.g. `mpc-contract`)
without dragging `ring`/`webpki`/X.509 parsing into their WASM.

Types:

- `QuoteBytes`, `Collateral`: standalone mirrors of `dcap_qvl`'s quote
  bytes and `QuoteCollateralV3`.
- `VerifiedReport`, `Report`, `TDReport10`, `TDReport15`, `EnclaveReport`,
  `TcbStatus`, `TcbStatusWithAdvisory`: Borsh mirrors of the corresponding
  `dcap_qvl` types, fields one-to-one for forward-compat.
- `VerifierError`: error type for future use.

Conversions between these mirrors and the `dcap_qvl` types live in the
verifier crate, not here, to avoid the orphan rule and to keep this
crate `dcap-qvl`-free.

Borsh-schema derives are gated behind an optional `borsh-schema` feature,
enabled by the verifier crate when `cargo near build` generates ABI.

Part of the work described in
docs/design/attestation-verifier-contract.md (PR #3160).
Adds the `tee-verifier` contract — a stateless NEAR contract exposing
one method:

    verify_quote(quote: QuoteBytes, collateral: Collateral) -> VerifiedReport

The method reads the current block timestamp inside the contract and
calls `dcap_qvl::verify::verify(quote, collateral, now)`. On success,
the parsed report is converted to the Borsh mirror types from
`tee-verifier-interface` and returned via Borsh. On verification
failure, the method panics with the upstream error rendered as a
string; callers handle this as `PromiseResult::Failed` in their
callback.

The contract has no state and no admin. All policy (allowlists,
report-data binding, RTMR3 replay, app-compose validation, etc.) is
the caller's responsibility — only the cryptographic dcap-qvl part
lives here.

Includes:
- `tee_verifier::TeeVerifier` (empty state struct, one method).
- `tee_verifier::conversions` (free functions converting between
  `dcap_qvl` types and the mirror types in `tee-verifier-interface`;
  free functions rather than `From` impls because of the orphan rule).
- An integration test (`tests/verify_quote.rs`) that calls
  `verify_quote` directly against the real Dstack quote+collateral
  fixture from `test-utils`, asserting the returned `VerifiedReport`
  has status `UpToDate`, no advisory IDs, and a TD10 report.

WASM size (non-reproducible, default release): ~518 KiB.

This is the v1 verifier from
`docs/design/attestation-verifier-contract.md` (#3160). A follow-up
PR will wire `mpc-contract`'s `submit_participant_info` into it via
Promise + callback.

Stacked on #3235.
…-qvl

Pure crate split, no behaviour change. Sets up the WASM-size win that
the follow-up PR (mpc-contract Promise refactor) will land.

What moves:
- `app_compose`, `measurements`, `report_data`, `tcb_info` modules and
  their assets — none of these touched `dcap-qvl` to begin with.
- The post-DCAP verification helpers (`verify_tcb_status`,
  `verify_report_data`, `verify_rtmr3`, `verify_app_compose`,
  `verify_any_measurements`, `verify_static_rtmrs`,
  `verify_key_provider_digest`, `verify_event_log_rtmr3`,
  `validate_app_compose_config`, `compare_hashes`, `compare_hex_hashes`,
  plus the `OrErr` and `GetSingleEvent` traits and `VerificationError`)
  — refactored from private methods on `DstackAttestation` to free
  functions in `attestation_types::verify_post_dcap`, taking the
  `tee_verifier_interface::VerifiedReport` mirror instead of the
  `dcap_qvl` type.

What stays in `attestation`:
- `DstackAttestation::verify` (the one and only `dcap_qvl::verify::verify`
  call site). It now converts the dcap-qvl-returned report to the
  Borsh mirror once and calls the free functions on it.
- The `Collateral` newtype and `QuoteBytes` newtype. Their dedup with
  the `tee-verifier-interface` mirrors is deferred to a later PR.

What this enables (next PR):
- `mpc-contract` can depend on `attestation-types` alone (no `dcap-qvl`)
  and call the post-DCAP helpers from a Promise callback that receives
  the verifier-returned `VerifiedReport`. That is the actual WASM-size
  win for NEP-509.

Drops the dead `TryFrom<dcap_qvl::verify::VerifiedReport> for Measurements`
impl (no callers anywhere in the codebase).

Re-exports the moved modules from `attestation::lib.rs` so existing
consumers (`mpc-attestation`, `tee-authority`, `attestation-cli`, etc.)
keep their import paths unchanged.

Part of the verifier breakout from
docs/design/attestation-verifier-contract.md (#3160). Stacked on #3237.
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