quartz_contract_core/msg/execute/
attested.rs1use std::{convert::Into, default::Default};
2
3use cosmwasm_schema::cw_serde;
4use cosmwasm_std::{HexBinary, StdError};
5use quartz_tee_ra::intel_sgx::dcap::{Collateral, Quote3, Quote3Error};
6use serde::Serialize;
7
8pub type Quote = Quote3<Vec<u8>>;
11
12#[cfg(not(feature = "mock-sgx"))]
13pub type DefaultAttestation = DcapAttestation;
14#[cfg(not(feature = "mock-sgx"))]
15pub type RawDefaultAttestation = RawDcapAttestation;
16
17#[cfg(feature = "mock-sgx")]
18pub type DefaultAttestation = MockAttestation;
19#[cfg(feature = "mock-sgx")]
20pub type RawDefaultAttestation = RawMockAttestation;
21
22use crate::{
23 msg::HasDomainType,
24 state::{MrEnclave, UserData},
25};
26
27#[derive(Clone, Debug, PartialEq)]
29pub struct Attested<M, A> {
30 pub msg: M,
31 pub attestation: A,
32}
33
34impl<M, A> Attested<M, A> {
35 pub fn new(msg: M, attestation: A) -> Self {
36 Self { msg, attestation }
37 }
38
39 pub fn into_tuple(self) -> (M, A) {
40 let Attested { msg, attestation } = self;
41 (msg, attestation)
42 }
43
44 pub fn msg(&self) -> &M {
45 &self.msg
46 }
47
48 pub fn attestation(&self) -> &A {
49 &self.attestation
50 }
51}
52
53#[cw_serde]
54pub struct RawAttested<RM, RA> {
55 pub msg: RM,
56 pub attestation: RA,
57}
58
59impl<RM, RA> TryFrom<RawAttested<RM, RA>> for Attested<RM::DomainType, RA::DomainType>
60where
61 RM: HasDomainType,
62 RA: HasDomainType,
63{
64 type Error = StdError;
65
66 fn try_from(value: RawAttested<RM, RA>) -> Result<Self, Self::Error> {
67 Ok(Self {
68 msg: value.msg.try_into()?,
69 attestation: value.attestation.try_into()?,
70 })
71 }
72}
73
74impl<RM, RA> From<Attested<RM::DomainType, RA::DomainType>> for RawAttested<RM, RA>
75where
76 RM: HasDomainType,
77 RA: HasDomainType,
78{
79 fn from(value: Attested<RM::DomainType, RA::DomainType>) -> Self {
80 Self {
81 msg: value.msg.into(),
82 attestation: value.attestation.into(),
83 }
84 }
85}
86
87impl<RM, RA> HasDomainType for RawAttested<RM, RA>
88where
89 RM: HasDomainType,
90 RA: HasDomainType,
91{
92 type DomainType = Attested<RM::DomainType, RA::DomainType>;
93}
94
95pub trait HasUserData {
97 fn user_data(&self) -> UserData;
98}
99
100pub fn user_data_json<T: Serialize>(value: &T) -> UserData {
101 use serde_json::to_string;
102 use sha2::{Digest, Sha256};
103
104 let mut hasher = Sha256::new();
105 hasher.update(to_string(value).expect("infallible serializer"));
106 let digest: [u8; 32] = hasher.finalize().into();
107
108 let mut user_data = [0u8; 64];
109 user_data[0..32].copy_from_slice(&digest);
110 user_data
111}
112
113pub trait Attestation {
114 fn mr_enclave(&self) -> MrEnclave;
115}
116
117#[derive(Clone, Debug, PartialEq, Serialize)]
119pub struct DcapAttestation {
120 quote: Quote,
121 collateral: Collateral,
122}
123
124impl DcapAttestation {
125 pub fn new(quote: Quote, collateral: Collateral) -> Self {
126 Self { quote, collateral }
127 }
128
129 pub fn into_tuple(self) -> (Quote, Collateral) {
130 (self.quote, self.collateral)
131 }
132}
133
134#[cw_serde]
135pub struct RawDcapAttestation {
136 pub quote: HexBinary,
137 pub collateral: HexBinary,
138}
139
140impl TryFrom<RawDcapAttestation> for DcapAttestation {
141 type Error = StdError;
142
143 fn try_from(value: RawDcapAttestation) -> Result<Self, Self::Error> {
144 let quote_bytes: Vec<u8> = value.quote.into();
145 let collateral_bytes: Vec<u8> = value.collateral.into();
146 let quote = quote_bytes
147 .try_into()
148 .map_err(|e: Quote3Error| StdError::parse_err("Quote", e.to_string()))?;
149 let collateral = ciborium::from_reader(collateral_bytes.as_slice())
150 .map_err(|e| StdError::parse_err("Collateral", e.to_string()))?;
151
152 Ok(Self { quote, collateral })
153 }
154}
155
156impl From<DcapAttestation> for RawDcapAttestation {
157 fn from(value: DcapAttestation) -> Self {
158 let mut collateral_serialized = Vec::new();
159 ciborium::into_writer(&value.collateral, &mut collateral_serialized)
160 .expect("infallible serializer");
161
162 Self {
163 quote: value.quote.as_ref().to_vec().into(),
164 collateral: collateral_serialized.into(),
165 }
166 }
167}
168
169impl HasDomainType for RawDcapAttestation {
170 type DomainType = DcapAttestation;
171}
172
173impl HasUserData for DcapAttestation {
174 fn user_data(&self) -> UserData {
175 let report_data = self.quote.app_report_body().report_data();
176 let report_data_slice: &[u8] = report_data.as_ref();
177 report_data_slice
178 .to_owned()
179 .try_into()
180 .expect("fixed size array")
181 }
182}
183
184impl Attestation for DcapAttestation {
185 fn mr_enclave(&self) -> MrEnclave {
186 let mr_enclave = self.quote.app_report_body().mr_enclave();
187 let mr_enclave_slice: &[u8] = mr_enclave.as_ref();
188 mr_enclave_slice
189 .to_owned()
190 .try_into()
191 .expect("fixed size array")
192 }
193}
194
195#[derive(Clone, Debug, PartialEq)]
196pub struct MockAttestation(pub UserData);
197
198impl Default for MockAttestation {
199 fn default() -> Self {
200 Self([0u8; 64])
201 }
202}
203
204#[cw_serde]
205pub struct RawMockAttestation(pub HexBinary);
206
207impl TryFrom<RawMockAttestation> for MockAttestation {
208 type Error = StdError;
209
210 fn try_from(value: RawMockAttestation) -> Result<Self, Self::Error> {
211 Ok(Self(value.0.to_array()?))
212 }
213}
214
215impl From<MockAttestation> for RawMockAttestation {
216 fn from(value: MockAttestation) -> Self {
217 Self(value.0.into())
218 }
219}
220
221impl HasDomainType for RawMockAttestation {
222 type DomainType = MockAttestation;
223}
224
225impl HasUserData for MockAttestation {
226 fn user_data(&self) -> UserData {
227 self.0
228 }
229}
230
231impl Attestation for MockAttestation {
232 fn mr_enclave(&self) -> MrEnclave {
233 Default::default()
234 }
235}
236
237#[derive(Clone, Debug, PartialEq)]
238pub struct Noop<T>(pub T);
239
240#[cw_serde]
241pub struct RawNoop<T>(pub T);
242
243impl<T: Serialize> HasDomainType for RawNoop<T> {
244 type DomainType = Noop<T>;
245}
246
247impl<T> HasUserData for Noop<T>
248where
249 T: HasUserData,
250{
251 fn user_data(&self) -> UserData {
252 self.0.user_data()
253 }
254}
255
256impl<T> TryFrom<RawNoop<T>> for Noop<T> {
257 type Error = StdError;
258
259 fn try_from(value: RawNoop<T>) -> Result<Self, Self::Error> {
260 Ok(Self(value.0))
261 }
262}
263
264impl<T> From<Noop<T>> for RawNoop<T> {
265 fn from(value: Noop<T>) -> Self {
266 Self(value.0)
267 }
268}