@@ -376,51 +376,53 @@ impl MessageEncryption for AES128 {
376376 .and_then (|(eph_pk_x , masked_fields )| {
377377 // With the x-coordinate of the ephemeral public key we can reconstruct the point as we know that the
378378 // y-coordinate must be positive. This may fail however, as not all x-coordinates are on the curve. In
379- // that case, we simply return `Option::none`.
380- point_from_x_coord_and_sign (eph_pk_x , true ).and_then (|eph_pk | {
381- let s_app = get_shared_secret (recipient , eph_pk , contract_address );
382-
383- let unmasked_fields = masked_fields .mapi (|i , field | {
384- let unmasked = unmask_field (s_app , i , field );
385- // If we failed to unmask the field, we are dealing with the random padding. We'll ignore it
386- // later, so we can simply set it to 0
387- unmasked .unwrap_or (0 )
388- });
389- let ciphertext_without_eph_pk_x = decode_bytes_from_fields (unmasked_fields );
390-
391- // Derive symmetric keys:
392- let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret ::<2 >(s_app );
393- let (body_sym_key , body_iv ) = pairs [0 ];
394- let (header_sym_key , header_iv ) = pairs [1 ];
395-
396- // Extract the header ciphertext
397- let header_start = 0 ;
398- let header_ciphertext : [u8 ; HEADER_CIPHERTEXT_SIZE_IN_BYTES ] =
399- array:: subarray (ciphertext_without_eph_pk_x .storage (), header_start );
400- // We need to convert the array to a BoundedVec because the oracle expects a BoundedVec as it's
401- // designed to work with messages with unknown length at compile time. This would not be necessary
402- // here as the header ciphertext length is fixed. But we do it anyway to not have to have duplicate
403- // oracles.
404- let header_ciphertext_bvec =
405- BoundedVec ::<u8 , HEADER_CIPHERTEXT_SIZE_IN_BYTES >::from_array (header_ciphertext );
406-
407- try_aes128_decrypt (header_ciphertext_bvec , header_iv , header_sym_key )
408- // Extract ciphertext length from header (2 bytes, big-endian)
409- .and_then (|header_plaintext | extract_ciphertext_length (header_plaintext ))
410- .filter (|ciphertext_length | ciphertext_length <= MESSAGE_PLAINTEXT_SIZE_IN_BYTES )
411- .map (|ciphertext_length | {
412- // Extract and decrypt main ciphertext
413- let ciphertext_start = header_start + HEADER_CIPHERTEXT_SIZE_IN_BYTES ;
414- let ciphertext_with_padding : [u8 ; MESSAGE_PLAINTEXT_SIZE_IN_BYTES ] =
415- array:: subarray (ciphertext_without_eph_pk_x .storage (), ciphertext_start );
416- BoundedVec ::from_parts (ciphertext_with_padding , ciphertext_length )
417- })
418- // Decrypt main ciphertext and return it
419- .and_then (|ciphertext | try_aes128_decrypt (ciphertext , body_iv , body_sym_key ))
420- // Convert bytes back to fields (32 bytes per field). Returns None if the actual bytes are
421- // not valid.
422- .and_then (|plaintext_bytes | try_decode_fields_from_bytes (plaintext_bytes ))
423- })
379+ // that case, we simply return `Option::none`. Secret derivation may also fail when the PXE does not
380+ // hold the recipient's keys (e.g. when syncing the scope of an address we don't control), in which
381+ // case the message is undecryptable and equally skipped.
382+ point_from_x_coord_and_sign (eph_pk_x , true )
383+ .and_then (|eph_pk | get_shared_secret (recipient , eph_pk , contract_address ))
384+ .and_then (|s_app | {
385+ let unmasked_fields = masked_fields .mapi (|i , field | {
386+ let unmasked = unmask_field (s_app , i , field );
387+ // If we failed to unmask the field, we are dealing with the random padding. We'll ignore it
388+ // later, so we can simply set it to 0
389+ unmasked .unwrap_or (0 )
390+ });
391+ let ciphertext_without_eph_pk_x = decode_bytes_from_fields (unmasked_fields );
392+
393+ // Derive symmetric keys:
394+ let pairs = derive_aes_symmetric_key_and_iv_from_shared_secret ::<2 >(s_app );
395+ let (body_sym_key , body_iv ) = pairs [0 ];
396+ let (header_sym_key , header_iv ) = pairs [1 ];
397+
398+ // Extract the header ciphertext
399+ let header_start = 0 ;
400+ let header_ciphertext : [u8 ; HEADER_CIPHERTEXT_SIZE_IN_BYTES ] =
401+ array:: subarray (ciphertext_without_eph_pk_x .storage (), header_start );
402+ // We need to convert the array to a BoundedVec because the oracle expects a BoundedVec as it's
403+ // designed to work with messages with unknown length at compile time. This would not be
404+ // necessary here as the header ciphertext length is fixed. But we do it anyway to not have to
405+ // have duplicate oracles.
406+ let header_ciphertext_bvec =
407+ BoundedVec ::<u8 , HEADER_CIPHERTEXT_SIZE_IN_BYTES >::from_array (header_ciphertext );
408+
409+ try_aes128_decrypt (header_ciphertext_bvec , header_iv , header_sym_key )
410+ // Extract ciphertext length from header (2 bytes, big-endian)
411+ .and_then (|header_plaintext | extract_ciphertext_length (header_plaintext ))
412+ .filter (|ciphertext_length | ciphertext_length <= MESSAGE_PLAINTEXT_SIZE_IN_BYTES )
413+ .map (|ciphertext_length | {
414+ // Extract and decrypt main ciphertext
415+ let ciphertext_start = header_start + HEADER_CIPHERTEXT_SIZE_IN_BYTES ;
416+ let ciphertext_with_padding : [u8 ; MESSAGE_PLAINTEXT_SIZE_IN_BYTES ] =
417+ array:: subarray (ciphertext_without_eph_pk_x .storage (), ciphertext_start );
418+ BoundedVec ::from_parts (ciphertext_with_padding , ciphertext_length )
419+ })
420+ // Decrypt main ciphertext and return it
421+ .and_then (|ciphertext | try_aes128_decrypt (ciphertext , body_iv , body_sym_key ))
422+ // Convert bytes back to fields (32 bytes per field). Returns None if the actual bytes are
423+ // not valid.
424+ .and_then (|plaintext_bytes | try_decode_fields_from_bytes (plaintext_bytes ))
425+ })
424426 })
425427 }
426428}
0 commit comments