@@ -62,6 +62,7 @@ pub enum ClientCommandCode {
6262 SendBuffer = 4 ,
6363 SendBufferContinued = 5 ,
6464 ReceiveBuffer = 6 ,
65+ StorePageProof = 7 ,
6566}
6667
6768impl TryFrom < u8 > for ClientCommandCode {
@@ -76,12 +77,13 @@ impl TryFrom<u8> for ClientCommandCode {
7677 4 => Ok ( ClientCommandCode :: SendBuffer ) ,
7778 5 => Ok ( ClientCommandCode :: SendBufferContinued ) ,
7879 6 => Ok ( ClientCommandCode :: ReceiveBuffer ) ,
80+ 7 => Ok ( ClientCommandCode :: StorePageProof ) ,
7981 _ => Err ( "Invalid value for ClientCommandCode" ) ,
8082 }
8183 }
8284}
8385
84- #[ derive( Debug , Clone , Copy ) ]
86+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
8587#[ repr( u8 ) ]
8688pub enum SectionKind {
8789 Code = 0 ,
@@ -154,14 +156,33 @@ impl<'a> Message<'a> for GetPageMessage {
154156
155157/// Message sent by client in response to the VM's GetPageProofMessage
156158/// It contains the page's metadata, and the merkle proof of the page (or part of it)
159+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
160+ #[ repr( u8 ) ]
161+ pub enum PageProofKind {
162+ Merkle = 0 ,
163+ Hmac = 1 ,
164+ }
165+
166+ impl TryFrom < u8 > for PageProofKind {
167+ type Error = & ' static str ;
168+ fn try_from ( value : u8 ) -> Result < Self , Self :: Error > {
169+ match value {
170+ 0 => Ok ( PageProofKind :: Merkle ) ,
171+ 1 => Ok ( PageProofKind :: Hmac ) ,
172+ _ => Err ( "Invalid page proof kind" ) ,
173+ }
174+ }
175+ }
176+
157177#[ derive( Debug , Clone ) ]
158178pub struct GetPageResponse < ' a > {
159179 pub page_data : & ' a [ u8 ; PAGE_SIZE ] ,
160- pub is_encrypted : bool , // whether the page is encrypted
161- pub nonce : [ u8 ; 12 ] , // nonce of the page encryption (all zeros if not encrypted)
162- pub n : u8 , // number of element in the proof
163- pub t : u8 , // number of proof elements in this message
164- pub proof : & ' a [ [ u8 ; 32 ] ] , // hashes of the proof
180+ pub is_encrypted : bool ,
181+ pub nonce : [ u8 ; 12 ] ,
182+ pub n : u8 ,
183+ pub t : u8 ,
184+ pub proof_kind : PageProofKind ,
185+ pub proof : & ' a [ [ u8 ; 32 ] ] , // Merkle proof elements OR single HMAC (len()==1)
165186}
166187
167188impl < ' a > GetPageResponse < ' a > {
@@ -172,6 +193,7 @@ impl<'a> GetPageResponse<'a> {
172193 nonce : [ u8 ; 12 ] ,
173194 n : u8 ,
174195 t : u8 ,
196+ proof_kind : PageProofKind ,
175197 proof : & ' a [ [ u8 ; 32 ] ] ,
176198 ) -> Self {
177199 GetPageResponse {
@@ -180,12 +202,14 @@ impl<'a> GetPageResponse<'a> {
180202 nonce,
181203 n,
182204 t,
205+ proof_kind,
183206 proof,
184207 }
185208 }
186209
187210 pub const fn max_proof_size ( ) -> usize {
188- ( MAX_APDU_DATA_SIZE - PAGE_SIZE - 1 - 12 - 1 - 1 ) / 32
211+ // page_data | n | t | is_encrypted | nonce(12) | proof_kind | proof elements
212+ ( MAX_APDU_DATA_SIZE - PAGE_SIZE - 1 - 1 - 1 - 12 - 1 ) / 32
189213 }
190214}
191215
@@ -197,13 +221,14 @@ impl<'a> Message<'a> for GetPageResponse<'a> {
197221 f ( & [ self . t ] ) ;
198222 f ( & [ self . is_encrypted as u8 ] ) ;
199223 f ( & self . nonce ) ;
224+ f ( & [ self . proof_kind as u8 ] ) ;
200225 for p in self . proof {
201226 f ( p) ;
202227 }
203228 }
204229
205230 fn deserialize ( data : & ' a [ u8 ] ) -> Result < Self , MessageDeserializationError > {
206- if data. len ( ) < PAGE_SIZE + 1 + 1 + 1 + 12 {
231+ if data. len ( ) < PAGE_SIZE + 1 + 1 + 1 + 12 + 1 {
207232 return Err ( MessageDeserializationError :: InvalidDataLength ) ;
208233 }
209234 let page_data = data[ 0 ..PAGE_SIZE ] . try_into ( ) . unwrap ( ) ;
@@ -217,13 +242,16 @@ impl<'a> Message<'a> for GetPageResponse<'a> {
217242 } else {
218243 [ 0 ; 12 ]
219244 } ;
220- let proof_len = data. len ( ) - ( PAGE_SIZE + 1 + 1 + 1 + 12 ) ;
245+ let pk_byte = data[ PAGE_SIZE + 15 ] ;
246+ let proof_kind = PageProofKind :: try_from ( pk_byte)
247+ . map_err ( |_| MessageDeserializationError :: InvalidDataLength ) ?;
248+ let proof_len = data. len ( ) - ( PAGE_SIZE + 1 + 1 + 1 + 12 + 1 ) ;
221249 if proof_len % 32 != 0 {
222250 return Err ( MessageDeserializationError :: InvalidDataLength ) ;
223251 }
224252 let slice_len = proof_len / 32 ;
225253 let proof = unsafe {
226- let ptr = data. as_ptr ( ) . add ( PAGE_SIZE + 1 + 1 + 1 + 12 ) as * const [ u8 ; 32 ] ;
254+ let ptr = data. as_ptr ( ) . add ( PAGE_SIZE + 1 + 1 + 1 + 12 + 1 ) as * const [ u8 ; 32 ] ;
227255 core:: slice:: from_raw_parts ( ptr, slice_len)
228256 } ;
229257
@@ -233,10 +261,63 @@ impl<'a> Message<'a> for GetPageResponse<'a> {
233261 nonce,
234262 n,
235263 t,
264+ proof_kind,
236265 proof,
237266 } )
238267 }
239268}
269+ /// Message sent by the VM instructing the host to store a compact HMAC proof for a code page.
270+ #[ derive( Debug , Clone ) ]
271+ pub struct StorePageProofMessage {
272+ pub command_code : ClientCommandCode ,
273+ pub section_kind : SectionKind ,
274+ pub page_index : u32 ,
275+ pub hmac : [ u8 ; 32 ] ,
276+ }
277+
278+ impl StorePageProofMessage {
279+ #[ inline]
280+ pub fn new ( section_kind : SectionKind , page_index : u32 , hmac : [ u8 ; 32 ] ) -> Self {
281+ StorePageProofMessage {
282+ command_code : ClientCommandCode :: StorePageProof ,
283+ section_kind,
284+ page_index,
285+ hmac,
286+ }
287+ }
288+ }
289+
290+ impl < ' a > Message < ' a > for StorePageProofMessage {
291+ #[ inline]
292+ fn serialize_with < F : FnMut ( & [ u8 ] ) > ( & self , mut f : F ) {
293+ f ( & [ self . command_code as u8 ] ) ;
294+ f ( & [ self . section_kind as u8 ] ) ;
295+ f ( & self . page_index . to_be_bytes ( ) ) ;
296+ f ( & self . hmac ) ;
297+ }
298+
299+ fn deserialize ( data : & ' a [ u8 ] ) -> Result < Self , MessageDeserializationError > {
300+ if data. len ( ) != 1 + 1 + 4 + 32 {
301+ return Err ( MessageDeserializationError :: InvalidDataLength ) ;
302+ }
303+ let command_code = ClientCommandCode :: try_from ( data[ 0 ] )
304+ . map_err ( |_| MessageDeserializationError :: InvalidClientCommandCode ) ?;
305+ if !matches ! ( command_code, ClientCommandCode :: StorePageProof ) {
306+ return Err ( MessageDeserializationError :: MismatchingClientCommandCode ) ;
307+ }
308+ let section_kind = SectionKind :: try_from ( data[ 1 ] )
309+ . map_err ( |_| MessageDeserializationError :: InvalidSectionKind ) ?;
310+ let page_index = u32:: from_be_bytes ( [ data[ 2 ] , data[ 3 ] , data[ 4 ] , data[ 5 ] ] ) ;
311+ let mut hmac = [ 0u8 ; 32 ] ;
312+ hmac. copy_from_slice ( & data[ 6 ..38 ] ) ;
313+ Ok ( StorePageProofMessage {
314+ command_code,
315+ section_kind,
316+ page_index,
317+ hmac,
318+ } )
319+ }
320+ }
240321
241322/// Message sent by the VM to request the rest of the proof, if it didn't fit
242323/// in GetPageResponse
0 commit comments