feat(tee-verifier-interface): Borsh DTOs for the verifier contract boundary - #3235
Conversation
5e6fac2 to
b3acde8
Compare
b3acde8 to
820497e
Compare
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.
820497e to
2e70aa9
Compare
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.
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.
2e70aa9 to
dde7dd2
Compare
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.
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.
b731b70 to
c3f7c04
Compare
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.
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.
a288dbd to
b2ff62d
Compare
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.
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.
d392d5c to
198b297
Compare
|
@claude review |
The crate boundary is a cross-contract call (Borsh ABI), the payload is mostly binary (a multi-KB quote plus collateral), and avoiding serde keeps the dependency set minimal. Document that rationale so the absence of serde/JSON support is a recorded decision rather than an apparent omission
…rors land The serde `Collateral` DTO is superseded by `tee_verifier_interface::Collateral` once `mpc-contract` consumes the Borsh mirrors. Add a TODO(#3494) marker so the deferred cleanup is discoverable from the type itself
Good point! Added a note about that here: bb226c3.
Created an issue: #3494 and referenced it in the comment here: 314a535.
Great catch! #3237 (the PR stacked on top of this one) does exactly that: it adds the mpc/crates/tee-verifier/src/conversions.rs Lines 148 to 339 in cf72a5a |
…rors land The serde `Collateral` DTO is superseded by `tee_verifier_interface::Collateral` once `mpc-contract` consumes the Borsh mirrors. Add a TODO(#3494) doc comment so the deferred cleanup is discoverable from the type, and refresh the contract ABI snapshot, which captures the new doc comment as the type's schema description
The TODO(#3494) note on `Collateral` was a `///` doc comment, which `schemars` captures into the contract ABI as the type's schema description. Demote it to a plain `//` comment so it stays visible to maintainers without entering the ABI, and revert the snapshot accordingly
|
@barakeinav1 @netrome I need one more approval. Please re-review when you get a chance. Thanks! 🙏🏼 |
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.
These are the verifier's outcome DTOs: VerificationResult { Verified, Rejected }
carries either a parsed report or a typed VerifierError, returned as the value
of a successful receipt rather than via a failed receipt. An on-chain caller's
#[callback_result] can then tell a rejected quote apart from PromiseError::Failed
(verifier unreachable/crashed), instead of both collapsing to one opaque failure.
Also aligns the design doc's failure-handling control flow with this model.
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.
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.
barakeinav1
left a comment
There was a problem hiding this comment.
Re-reviewed fa44ba9b. The VerificationResult { Verified, Rejected } change resolves the regression cleanly — a rejected quote now resumes immediately with its reason, and only a genuinely unreachable verifier falls through to the timeout, which is the correct behavior. Doc is fully in sync now. Thanks for the quick turnaround. 👍
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.
Closes #3265
Overview
Adds
tee-verifier-interface: the Borsh DTOs spoken at thetee-verifiercontract boundary.They are field-for-field mirrors of the
dcap-qvlinput and output types, owned here so the Borsh wire layout is independent of upstream.This crate is the only DTO crate a consumer (
mpc-contract, future Proximity / Defuse contracts) needs in order to talk to the verifier — without re-linking thedcap-qvl/ring/webpki/x509-certclosure into its own WASM.Prerequisite for the verifier contract in #3266 (PR #3237); part of the stack tracked by #3264.