tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

lib.rs (48327B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 use mls_platform_api::{
      6    ClientIdentifiers, ExporterOutput, GroupDetails, GroupIdEpoch, MlsCommitOutput, Received,
      7 };
      8 use nserror::{nsresult, NS_ERROR_FAILURE, NS_ERROR_INVALID_ARG, NS_OK};
      9 use nsstring::nsACString;
     10 use thin_vec::ThinVec;
     11 
     12 mod storage;
     13 use storage::get_key_path;
     14 use storage::get_storage_key;
     15 use storage::get_storage_path;
     16 
     17 // Access the platform state for the given storage prefix
     18 pub fn state_access(
     19    storage_prefix: &nsACString,
     20 ) -> Result<mls_platform_api::PlatformState, nsresult> {
     21    if storage_prefix.is_empty() {
     22        log::error!("Input storage prefix cannot be empty");
     23        return Err(NS_ERROR_INVALID_ARG);
     24    };
     25 
     26    let db_path = get_storage_path(storage_prefix);
     27    let Ok(db_key) = get_storage_key(storage_prefix) else {
     28        log::error!("Failed to get storage key");
     29        return Err(NS_ERROR_FAILURE);
     30    };
     31 
     32    mls_platform_api::state_access(&db_path, &db_key).map_err(|e| {
     33        log::error!("Failed to access state: {:?}", e);
     34        NS_ERROR_FAILURE
     35    })
     36 }
     37 
     38 #[no_mangle]
     39 pub extern "C" fn mls_state_delete(storage_prefix: &nsACString) -> nsresult {
     40    // Log the function call
     41    log::debug!("Entering mls_state_delete");
     42 
     43    // Retrieve the database path from the caller and retrieve the key
     44    let db_path = get_storage_path(storage_prefix);
     45    let key_path = get_key_path(storage_prefix);
     46 
     47    // Delete the key file which is owned by the storage module
     48    let key_removal_result = match std::fs::remove_file(&key_path) {
     49        Ok(_) => Ok(()),
     50        Err(e) => {
     51            log::error!("{:?}", e);
     52            Err(NS_ERROR_FAILURE)
     53        }
     54    };
     55 
     56    // Delete the database file which is owned by the mls-platform-api library
     57    // Note: we do not check if the key is valid before destructing the database
     58    let db_removal_result = match mls_platform_api::state_delete(&db_path) {
     59        Ok(_) => Ok(()),
     60        Err(e) => {
     61            log::error!("{:?}", e);
     62            Err(NS_ERROR_FAILURE)
     63        }
     64    };
     65 
     66    // Return an error if either operation failed
     67    if key_removal_result.is_err() || db_removal_result.is_err() {
     68        return NS_ERROR_FAILURE;
     69    }
     70 
     71    // Log the name of the database and keys that were deleted
     72    log::debug!(" (input) storage_prefix: {:?}", storage_prefix);
     73    log::info!("State deleted successfully");
     74    NS_OK
     75 }
     76 
     77 #[repr(C)]
     78 pub struct GkGroupIdEpoch {
     79    pub group_id: ThinVec<u8>,
     80    pub group_epoch: ThinVec<u8>,
     81 }
     82 
     83 impl From<GroupIdEpoch> for GkGroupIdEpoch {
     84    fn from(v: GroupIdEpoch) -> Self {
     85        let GroupIdEpoch {
     86            group_id,
     87            group_epoch,
     88        } = v;
     89        Self {
     90            group_id: group_id.into(),
     91            group_epoch: ThinVec::from(group_epoch.to_le_bytes()),
     92        }
     93    }
     94 }
     95 
     96 #[no_mangle]
     97 pub unsafe extern "C" fn mls_state_delete_group(
     98    storage_prefix: &nsACString,
     99    group_id_bytes_ptr: *const u8,
    100    group_id_bytes_len: usize,
    101    identifier_bytes_ptr: *const u8,
    102    identifier_bytes_len: usize,
    103    ret_group_id_epoch: &mut GkGroupIdEpoch,
    104 ) -> nsresult {
    105    // Log the function call
    106    log::debug!("Entering mls_state_delete_group");
    107 
    108    // Validate the inputs
    109    if group_id_bytes_len == 0 {
    110        log::error!("Group Identifier argument cannot be empty");
    111        return NS_ERROR_INVALID_ARG;
    112    }
    113    if identifier_bytes_len == 0 {
    114        log::error!("Identifier argument cannot be empty");
    115        return NS_ERROR_INVALID_ARG;
    116    }
    117 
    118    // Convert the raw pointers to slices
    119    let group_id_bytes: &[u8] =
    120        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
    121    let identifier_bytes: &[u8] =
    122        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
    123 
    124    // Retrieve the platform state based on the storage prefix
    125    let Ok(mut pstate) = state_access(storage_prefix) else {
    126        return NS_ERROR_FAILURE;
    127    };
    128 
    129    // Call the platform API to delete the group for the selected client
    130    let groupid_and_epoch =
    131        match mls_platform_api::state_delete_group(&mut pstate, group_id_bytes, identifier_bytes) {
    132            Ok(gid) => gid,
    133            Err(e) => {
    134                log::error!("{:?}", e);
    135                return NS_ERROR_FAILURE;
    136            }
    137        };
    138 
    139    log::debug!(
    140        " (returns) Group Identifier: {:?}",
    141        hex::encode(&groupid_and_epoch.group_id)
    142    );
    143 
    144    log::debug!(
    145        " (returns) Group Epoch: {:?}",
    146        hex::encode(&groupid_and_epoch.group_epoch.to_le_bytes())
    147    );
    148 
    149    // Write the results
    150    *ret_group_id_epoch = groupid_and_epoch.into();
    151    log::info!("Successfully deleted group");
    152 
    153    NS_OK
    154 }
    155 
    156 #[no_mangle]
    157 pub extern "C" fn mls_generate_identity(
    158    storage_prefix: &nsACString,
    159    ret_identifier: &mut ThinVec<u8>,
    160 ) -> nsresult {
    161    // Log the function call
    162    log::debug!("Entering mls_generate_identity");
    163 
    164    // Retrieve the platform state based on the storage prefix
    165    let Ok(mut pstate) = state_access(storage_prefix) else {
    166        return NS_ERROR_FAILURE;
    167    };
    168 
    169    // Note: We set the GroupConfig to default for now
    170    let default_gc = mls_platform_api::GroupConfig::default();
    171 
    172    // Generate the signature keypair
    173    let identifier =
    174        match mls_platform_api::mls_generate_identity(&mut pstate, default_gc.ciphersuite) {
    175            Ok(id) => id,
    176            Err(e) => {
    177                log::error!("{:?}", e);
    178                return NS_ERROR_FAILURE;
    179            }
    180        };
    181 
    182    // Log the identifier
    183    log::debug!(
    184        " (returns) Client Identifier: {:?}",
    185        hex::encode(&identifier)
    186    );
    187 
    188    // Write the result to ret_val
    189    ret_identifier.extend_from_slice(&identifier);
    190 
    191    log::info!("Successfully generated signature keypair");
    192 
    193    NS_OK
    194 }
    195 
    196 #[no_mangle]
    197 pub unsafe extern "C" fn mls_generate_credential_basic(
    198    cred_content_bytes_ptr: *const u8,
    199    cred_content_bytes_len: usize,
    200    ret_credential: &mut ThinVec<u8>,
    201 ) -> nsresult {
    202    // Log the function call
    203    log::debug!("Entering mls_generate_credential_basic");
    204 
    205    // Validate the inputs
    206    if cred_content_bytes_len == 0 {
    207        log::error!("Credential content argument cannot be empty");
    208        return NS_ERROR_INVALID_ARG;
    209    }
    210 
    211    // Convert the raw pointers to slices
    212    let cred_content_bytes: &[u8] =
    213        unsafe { std::slice::from_raw_parts(cred_content_bytes_ptr, cred_content_bytes_len) };
    214 
    215    // Generate the basic credential
    216    let credential_bytes = match mls_platform_api::mls_generate_credential_basic(cred_content_bytes)
    217    {
    218        Ok(cred) => cred,
    219        Err(e) => {
    220            log::error!("{:?}", e);
    221            return NS_ERROR_FAILURE;
    222        }
    223    };
    224 
    225    // Log the credential
    226    log::debug!(
    227        " (returns) Credential: {:?}",
    228        hex::encode(&credential_bytes)
    229    );
    230 
    231    // Write the result to ret_val
    232    ret_credential.extend_from_slice(&credential_bytes);
    233 
    234    log::info!("Successfully generated basic credential");
    235    NS_OK
    236 }
    237 
    238 #[no_mangle]
    239 pub unsafe extern "C" fn mls_generate_keypackage(
    240    storage_prefix: &nsACString,
    241    identifier_bytes_ptr: *const u8,
    242    identifier_bytes_len: usize,
    243    credential_bytes_ptr: *const u8,
    244    credential_bytes_len: usize,
    245    ret_keypackage: &mut ThinVec<u8>,
    246 ) -> nsresult {
    247    // Log the function call
    248    log::debug!("Entering mls_generate_keypackage");
    249 
    250    // Validate the inputs
    251    if identifier_bytes_len == 0 {
    252        log::error!("Identifier argument cannot be empty");
    253        return NS_ERROR_INVALID_ARG;
    254    }
    255    if credential_bytes_len == 0 {
    256        log::error!("Credential argument cannot be empty");
    257        return NS_ERROR_INVALID_ARG;
    258    }
    259 
    260    // Convert the raw pointers to slices
    261    let identifier_bytes: &[u8] =
    262        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
    263    let credential_bytes: &[u8] =
    264        unsafe { std::slice::from_raw_parts(credential_bytes_ptr, credential_bytes_len) };
    265 
    266    // Retrieve the platform state based on the storage prefix
    267    let Ok(pstate) = state_access(storage_prefix) else {
    268        return NS_ERROR_FAILURE;
    269    };
    270 
    271    // Generate the key package
    272    let key_package = match mls_platform_api::mls_generate_key_package(
    273        &pstate,
    274        identifier_bytes,
    275        credential_bytes,
    276        &Default::default(),
    277    ) {
    278        Ok(kp) => kp,
    279        Err(e) => {
    280            log::error!("{:?}", e);
    281            return NS_ERROR_FAILURE;
    282        }
    283    };
    284 
    285    let key_package_bytes = match key_package.to_bytes() {
    286        Ok(kp) => kp,
    287        Err(e) => {
    288            log::error!("{:?}", e);
    289            return NS_ERROR_FAILURE;
    290        }
    291    };
    292 
    293    // Write the result
    294    ret_keypackage.extend_from_slice(&key_package_bytes);
    295 
    296    log::debug!(
    297        " (returns) Key Package: {:?}",
    298        hex::encode(&key_package_bytes)
    299    );
    300 
    301    log::info!("Successfully generated key package");
    302 
    303    NS_OK
    304 }
    305 
    306 #[repr(C)]
    307 pub struct GkClientIdentifiers {
    308    pub identity: ThinVec<u8>,
    309    pub credential: ThinVec<u8>,
    310 }
    311 
    312 impl From<ClientIdentifiers> for GkClientIdentifiers {
    313    fn from(v: ClientIdentifiers) -> Self {
    314        let ClientIdentifiers {
    315            identity,
    316            credential,
    317        } = v;
    318        Self {
    319            identity: identity.into(),
    320            credential: credential.into(),
    321        }
    322    }
    323 }
    324 
    325 #[repr(C)]
    326 pub struct GkGroupDetails {
    327    pub group_id: ThinVec<u8>,
    328    pub group_epoch: ThinVec<u8>,
    329    pub group_members: ThinVec<GkClientIdentifiers>,
    330 }
    331 
    332 impl From<GroupDetails> for GkGroupDetails {
    333    fn from(v: GroupDetails) -> Self {
    334        let GroupDetails {
    335            group_id,
    336            group_epoch,
    337            group_members,
    338        } = v;
    339        Self {
    340            group_id: group_id.into(),
    341            group_epoch: ThinVec::from(group_epoch.to_le_bytes()),
    342            group_members: group_members.into_iter().map(Into::into).collect(),
    343        }
    344    }
    345 }
    346 
    347 #[no_mangle]
    348 pub unsafe extern "C" fn mls_group_details(
    349    storage_prefix: &nsACString,
    350    group_id_bytes_ptr: *const u8,
    351    group_id_bytes_len: usize,
    352    identifier_bytes_ptr: *const u8,
    353    identifier_bytes_len: usize,
    354    ret_group_details: &mut GkGroupDetails,
    355 ) -> nsresult {
    356    // Log the function call
    357    log::debug!("Entering mls_group_details");
    358 
    359    // Validate the inputs
    360    if group_id_bytes_len == 0 {
    361        log::error!("Group Identifier argument cannot be empty");
    362        return NS_ERROR_INVALID_ARG;
    363    }
    364    if identifier_bytes_len == 0 {
    365        log::error!("Identifier argument cannot be empty");
    366        return NS_ERROR_INVALID_ARG;
    367    }
    368 
    369    // Convert the raw pointers to slices
    370    let group_id_bytes: &[u8] =
    371        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
    372    let identifier_bytes: &[u8] =
    373        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
    374 
    375    // Retrieve the platform state based on the storage prefix
    376    let Ok(mut pstate) = state_access(storage_prefix) else {
    377        return NS_ERROR_FAILURE;
    378    };
    379 
    380    // Retrieve the group details (includes members)
    381    let Ok(group_details) =
    382        mls_platform_api::mls_group_details(&mut pstate, group_id_bytes, identifier_bytes)
    383    else {
    384        log::error!("Failed to retrieve group details");
    385        return NS_ERROR_FAILURE;
    386    };
    387 
    388    // Log the result
    389    log::debug!(" (returns) Group Details: {:?}", group_details);
    390 
    391    // Write the result
    392    *ret_group_details = group_details.into();
    393 
    394    NS_OK
    395 }
    396 
    397 #[no_mangle]
    398 pub unsafe extern "C" fn mls_group_create(
    399    storage_prefix: &nsACString,
    400    identifier_bytes_ptr: *const u8,
    401    identifier_bytes_len: usize,
    402    credential_bytes_ptr: *const u8,
    403    credential_bytes_len: usize,
    404    opt_group_id_bytes_ptr: *const u8,
    405    opt_group_id_bytes_len: usize,
    406    ret_group_id_epoch: &mut GkGroupIdEpoch,
    407 ) -> nsresult {
    408    // Log the function call
    409    log::debug!("Entering mls_group_create");
    410 
    411    // Validate the inputs
    412    if identifier_bytes_len == 0 {
    413        log::error!("Identifier argument cannot be empty");
    414        return NS_ERROR_INVALID_ARG;
    415    }
    416    if credential_bytes_len == 0 {
    417        log::error!("Credential argument cannot be empty");
    418        return NS_ERROR_INVALID_ARG;
    419    }
    420 
    421    // Convert the raw pointers to slices
    422    let identifier_bytes: &[u8] =
    423        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
    424    let credential_bytes: &[u8] =
    425        unsafe { std::slice::from_raw_parts(credential_bytes_ptr, credential_bytes_len) };
    426    let opt_group_id_bytes: &[u8] =
    427        unsafe { std::slice::from_raw_parts(opt_group_id_bytes_ptr, opt_group_id_bytes_len) };
    428 
    429    // Retrieve the platform state based on the storage prefix
    430    let Ok(mut pstate) = state_access(storage_prefix) else {
    431        return NS_ERROR_FAILURE;
    432    };
    433 
    434    // Note: we implicitely require a 32 bytes identifier
    435    let gid_opt_vec: Vec<u8> = opt_group_id_bytes.to_vec();
    436    let gid_opt_res = if opt_group_id_bytes_len != 32 {
    437        log::debug!(
    438            "Optional group identifier provided has incorrect length, generating a random GID..."
    439        );
    440        None
    441    } else {
    442        Some(gid_opt_vec.as_ref())
    443    };
    444 
    445    // Retrieve the group membership
    446    let gide = match mls_platform_api::mls_group_create(
    447        &mut pstate,
    448        identifier_bytes,
    449        credential_bytes,
    450        gid_opt_res,
    451        None,
    452        &Default::default(),
    453    ) {
    454        Ok(v) => v,
    455        Err(e) => {
    456            log::error!("{:?}", e);
    457            return NS_ERROR_FAILURE;
    458        }
    459    };
    460 
    461    // Log the result
    462    log::debug!(
    463        " (returns) Group Identifier created: {:?}",
    464        hex::encode(&gide.group_id)
    465    );
    466 
    467    // Write the result to ret_val
    468    *ret_group_id_epoch = gide.into();
    469 
    470    log::info!("Successfully created group");
    471    NS_OK
    472 }
    473 
    474 #[no_mangle]
    475 pub unsafe extern "C" fn mls_group_add(
    476    storage_prefix: &nsACString,
    477    group_id_bytes_ptr: *const u8,
    478    group_id_bytes_len: usize,
    479    identifier_bytes_ptr: *const u8,
    480    identifier_bytes_len: usize,
    481    keypackage_bytes_ptr: *const u8,
    482    keypackage_bytes_len: usize,
    483    ret_commit_output: &mut GkMlsCommitOutput,
    484 ) -> nsresult {
    485    // Log the function call
    486    log::debug!("Entering mls_group_add");
    487 
    488    // Validate the inputs
    489    if group_id_bytes_len == 0 {
    490        log::error!("Group Identifier argument cannot be empty");
    491        return NS_ERROR_INVALID_ARG;
    492    }
    493    if identifier_bytes_len == 0 {
    494        log::error!("Identifier argument cannot be empty");
    495        return NS_ERROR_INVALID_ARG;
    496    }
    497    if keypackage_bytes_len == 0 {
    498        log::error!("Key Package argument cannot be empty");
    499        return NS_ERROR_INVALID_ARG;
    500    }
    501 
    502    // Convert the raw pointers to slices
    503    let group_id_bytes: &[u8] =
    504        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
    505    let identifier_bytes: &[u8] =
    506        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
    507    let keypackage_bytes: &[u8] =
    508        unsafe { std::slice::from_raw_parts(keypackage_bytes_ptr, keypackage_bytes_len) };
    509 
    510    // Retrieve the platform state based on the storage prefix
    511    let Ok(mut pstate) = state_access(storage_prefix) else {
    512        return NS_ERROR_FAILURE;
    513    };
    514 
    515    // Retrieve the key_package from the caller
    516    let key_package = match mls_platform_api::MlsMessage::from_bytes(&keypackage_bytes) {
    517        Ok(kp) => kp,
    518        Err(e) => {
    519            log::error!("{:?}", e);
    520            return NS_ERROR_INVALID_ARG;
    521        }
    522    };
    523 
    524    let Ok(commit_output) = mls_platform_api::mls_group_add(
    525        &mut pstate,
    526        group_id_bytes,
    527        identifier_bytes,
    528        vec![key_package],
    529    ) else {
    530        log::error!("Failed to add client to the group");
    531        return NS_ERROR_FAILURE;
    532    };
    533 
    534    // Log the result
    535    log::debug!(" (returns) Commit: {:?}", &commit_output.commit);
    536    log::debug!(" (returns) Welcome: {:?}", &commit_output.welcome);
    537    log::debug!(" (returns) Identity: {:?}", &commit_output.identity);
    538 
    539    // Write the result
    540    *ret_commit_output = commit_output.into();
    541 
    542    log::info!("Successfully added client to the group");
    543 
    544    NS_OK
    545 }
    546 
    547 #[no_mangle]
    548 pub unsafe extern "C" fn mls_group_propose_add(
    549    storage_prefix: &nsACString,
    550    group_id_bytes_ptr: *const u8,
    551    group_id_bytes_len: usize,
    552    identifier_bytes_ptr: *const u8,
    553    identifier_bytes_len: usize,
    554    keypackage_bytes_ptr: *const u8,
    555    keypackage_bytes_len: usize,
    556    ret_proposal: &mut ThinVec<u8>,
    557 ) -> nsresult {
    558    // Log the function call
    559    log::debug!("Entering mls_group_propose_add");
    560 
    561    // Validate the inputs
    562    if group_id_bytes_len == 0 {
    563        log::error!("Group Identifier argument cannot be empty");
    564        return NS_ERROR_INVALID_ARG;
    565    }
    566    if identifier_bytes_len == 0 {
    567        log::error!("Identifier argument cannot be empty");
    568        return NS_ERROR_INVALID_ARG;
    569    }
    570    if keypackage_bytes_len == 0 {
    571        log::error!("Key Package argument cannot be empty");
    572        return NS_ERROR_INVALID_ARG;
    573    }
    574 
    575    // Convert the raw pointers to slices
    576    let group_id_bytes: &[u8] =
    577        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
    578    let identifier_bytes: &[u8] =
    579        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
    580    let keypackage_bytes: &[u8] =
    581        unsafe { std::slice::from_raw_parts(keypackage_bytes_ptr, keypackage_bytes_len) };
    582 
    583    // Retrieve the platform state based on the storage prefix
    584    let Ok(mut pstate) = state_access(storage_prefix) else {
    585        return NS_ERROR_FAILURE;
    586    };
    587 
    588    // Retrieve the key_package from the caller
    589    let key_package = match mls_platform_api::MlsMessage::from_bytes(&keypackage_bytes) {
    590        Ok(kp) => kp,
    591        Err(e) => {
    592            log::error!("{:?}", e);
    593            return NS_ERROR_INVALID_ARG;
    594        }
    595    };
    596 
    597    // Retrieve the group membership
    598    let proposal = match mls_platform_api::mls_group_propose_add(
    599        &mut pstate,
    600        group_id_bytes,
    601        identifier_bytes,
    602        key_package,
    603    ) {
    604        Ok(m) => m,
    605        Err(e) => {
    606            log::error!("{:?}", e);
    607            return NS_ERROR_FAILURE;
    608        }
    609    };
    610 
    611    // Log the result
    612    log::debug!(
    613        " (returns) Add Proposal: {:?}",
    614        hex::encode(&proposal.to_bytes().unwrap())
    615    );
    616 
    617    // Write the result to ret_val
    618    ret_proposal.extend_from_slice(&proposal.to_bytes().unwrap());
    619 
    620    log::info!("Successfully proposed adding client to the group");
    621    NS_OK
    622 }
    623 
    624 #[no_mangle]
    625 pub unsafe extern "C" fn mls_group_remove(
    626    storage_prefix: &nsACString,
    627    group_id_bytes_ptr: *const u8,
    628    group_id_bytes_len: usize,
    629    identifier_bytes_ptr: *const u8,
    630    identifier_bytes_len: usize,
    631    rem_identifier_bytes_ptr: *const u8,
    632    rem_identifier_bytes_len: usize,
    633    ret_commit_output: &mut GkMlsCommitOutput,
    634 ) -> nsresult {
    635    // Log the function call
    636    log::debug!("Entering mls_group_remove");
    637 
    638    // Validate the inputs
    639    if group_id_bytes_len == 0 {
    640        log::error!("Group Identifier argument cannot be empty");
    641        return NS_ERROR_INVALID_ARG;
    642    }
    643    if identifier_bytes_len == 0 {
    644        log::error!("Identifier argument cannot be empty");
    645        return NS_ERROR_INVALID_ARG;
    646    }
    647    if rem_identifier_bytes_len == 0 {
    648        log::error!("Identifier to remove argument cannot be empty");
    649        return NS_ERROR_INVALID_ARG;
    650    }
    651 
    652    // Convert the raw pointers to slices
    653    let group_id_bytes: &[u8] =
    654        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
    655    let identifier_bytes: &[u8] =
    656        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
    657    let rem_identifier_bytes: &[u8] =
    658        unsafe { std::slice::from_raw_parts(rem_identifier_bytes_ptr, rem_identifier_bytes_len) };
    659 
    660    // Retrieve the platform state based on the storage prefix
    661    let Ok(mut pstate) = state_access(storage_prefix) else {
    662        return NS_ERROR_FAILURE;
    663    };
    664 
    665    // Retrieve the group membership
    666    let commit_output = match mls_platform_api::mls_group_remove(
    667        &mut pstate,
    668        group_id_bytes,
    669        identifier_bytes,
    670        rem_identifier_bytes,
    671    ) {
    672        Ok(gid) => gid,
    673        Err(e) => {
    674            log::error!("{:?}", e);
    675            return NS_ERROR_FAILURE;
    676        }
    677    };
    678 
    679    // Log the result
    680    log::debug!(" (returns) Commit: {:?}", &commit_output.commit);
    681    log::debug!(" (returns) Welcome: {:?}", &commit_output.welcome);
    682    log::debug!(" (returns) Identity: {:?}", &commit_output.identity);
    683 
    684    // Write the result
    685    *ret_commit_output = commit_output.into();
    686 
    687    log::info!("Successfully removed client from the group");
    688 
    689    NS_OK
    690 }
    691 
    692 #[no_mangle]
    693 pub unsafe extern "C" fn mls_group_propose_remove(
    694    storage_prefix: &nsACString,
    695    group_id_bytes_ptr: *const u8,
    696    group_id_bytes_len: usize,
    697    identifier_bytes_ptr: *const u8,
    698    identifier_bytes_len: usize,
    699    rem_identifier_bytes_ptr: *const u8,
    700    rem_identifier_bytes_len: usize,
    701    ret_proposal: &mut ThinVec<u8>,
    702 ) -> nsresult {
    703    // Log the function call
    704    log::info!("Entering mls_group_propose_remove");
    705 
    706    // Validate the inputs
    707    if group_id_bytes_len == 0 {
    708        log::error!("Group Identifier argument cannot be empty");
    709        return NS_ERROR_INVALID_ARG;
    710    }
    711    if identifier_bytes_len == 0 {
    712        log::error!("Identifier argument cannot be empty");
    713        return NS_ERROR_INVALID_ARG;
    714    }
    715    if rem_identifier_bytes_len == 0 {
    716        log::error!("Identifier to remove argument cannot be empty");
    717        return NS_ERROR_INVALID_ARG;
    718    }
    719 
    720    // Convert the raw pointers to slices
    721    let group_id_bytes: &[u8] =
    722        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
    723    let identifier_bytes: &[u8] =
    724        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
    725    let rem_identifier_bytes: &[u8] =
    726        unsafe { std::slice::from_raw_parts(rem_identifier_bytes_ptr, rem_identifier_bytes_len) };
    727 
    728    // Retrieve the platform state based on the storage prefix
    729    let Ok(mut pstate) = state_access(storage_prefix) else {
    730        return NS_ERROR_FAILURE;
    731    };
    732 
    733    // Retrieve the group membership
    734    let proposal = match mls_platform_api::mls_group_propose_remove(
    735        &mut pstate,
    736        group_id_bytes,
    737        identifier_bytes,
    738        rem_identifier_bytes,
    739    ) {
    740        Ok(gid) => gid,
    741        Err(e) => {
    742            log::error!("{:?}", e);
    743            return NS_ERROR_FAILURE;
    744        }
    745    };
    746 
    747    let proposal_bytes = match proposal.to_bytes() {
    748        Ok(gid) => gid,
    749        Err(e) => {
    750            log::error!("{:?}", e);
    751            return NS_ERROR_FAILURE;
    752        }
    753    };
    754 
    755    // Log the result
    756    log::info!(
    757        " (returns) Remove Proposal: {:?}",
    758        hex::encode(&proposal_bytes)
    759    );
    760 
    761    // Write the result
    762    ret_proposal.extend_from_slice(&proposal_bytes);
    763 
    764    log::info!("Successfully proposed removing client from the group");
    765 
    766    NS_OK
    767 }
    768 
    769 #[no_mangle]
    770 pub unsafe extern "C" fn mls_group_join(
    771    storage_prefix: &nsACString,
    772    identifier_bytes_ptr: *const u8,
    773    identifier_bytes_len: usize,
    774    welcome_bytes_ptr: *const u8,
    775    welcome_bytes_len: usize,
    776    ret_group_id_epoch: &mut GkGroupIdEpoch,
    777 ) -> nsresult {
    778    // Log the function call
    779    log::debug!("Entering mls_group_join");
    780 
    781    // Validate the inputs
    782    if identifier_bytes_len == 0 {
    783        log::error!("Identifier argument cannot be empty");
    784        return NS_ERROR_INVALID_ARG;
    785    }
    786    if welcome_bytes_len == 0 {
    787        log::error!("Welcome message argument cannot be empty");
    788        return NS_ERROR_INVALID_ARG;
    789    }
    790 
    791    // Convert the raw pointers to slices
    792    let identifier_bytes: &[u8] =
    793        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
    794    let welcome_bytes: &[u8] =
    795        unsafe { std::slice::from_raw_parts(welcome_bytes_ptr, welcome_bytes_len) };
    796 
    797    // Retrieve the platform state based on the storage prefix
    798    let Ok(pstate) = state_access(storage_prefix) else {
    799        return NS_ERROR_FAILURE;
    800    };
    801 
    802    // Retrieve the welcome message from the caller
    803    let welcome = match mls_platform_api::MlsMessage::from_bytes(&welcome_bytes) {
    804        Ok(kp) => kp,
    805        Err(e) => {
    806            log::error!("{:?}", e);
    807            return NS_ERROR_INVALID_ARG;
    808        }
    809    };
    810 
    811    // Retrieve the group membership
    812    let gide = match mls_platform_api::mls_group_join(&pstate, identifier_bytes, &welcome, None) {
    813        Ok(gid) => gid,
    814        Err(e) => {
    815            log::error!("{:?}", e);
    816            return NS_ERROR_FAILURE;
    817        }
    818    };
    819 
    820    // Log the result
    821    log::debug!(
    822        " (returns) Group Identifier joined: {:?}",
    823        hex::encode(&gide.group_id)
    824    );
    825 
    826    // Write the result to ret_val
    827    *ret_group_id_epoch = gide.into();
    828 
    829    log::info!("Successfully joined group");
    830    NS_OK
    831 }
    832 
    833 #[no_mangle]
    834 pub unsafe extern "C" fn mls_group_close(
    835    storage_prefix: &nsACString,
    836    group_id_bytes_ptr: *const u8,
    837    group_id_bytes_len: usize,
    838    identifier_bytes_ptr: *const u8,
    839    identifier_bytes_len: usize,
    840    ret_commit_output: &mut GkMlsCommitOutput,
    841 ) -> nsresult {
    842    // Log the function call
    843    log::debug!("Entering mls_group_close");
    844 
    845    // Validate the inputs
    846    if group_id_bytes_len == 0 {
    847        log::error!("Group Identifier argument cannot be empty");
    848        return NS_ERROR_INVALID_ARG;
    849    }
    850    if identifier_bytes_len == 0 {
    851        log::error!("Identifier argument cannot be empty");
    852        return NS_ERROR_INVALID_ARG;
    853    }
    854 
    855    // Convert the raw pointers to slices
    856    let group_id_bytes: &[u8] =
    857        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
    858    let identifier_bytes: &[u8] =
    859        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
    860 
    861    // Retrieve the platform state based on the storage prefix
    862    let Ok(mut pstate) = state_access(storage_prefix) else {
    863        return NS_ERROR_FAILURE;
    864    };
    865 
    866    // Retrieve the commit output
    867    let commit_output =
    868        match mls_platform_api::mls_group_close(&mut pstate, group_id_bytes, identifier_bytes) {
    869            Ok(gid) => gid,
    870            Err(e) => {
    871                log::error!("{:?}", e);
    872                return NS_ERROR_FAILURE;
    873            }
    874        };
    875 
    876    // Log the result
    877    log::debug!(" (returns) Commit: {:?}", &commit_output.commit);
    878    log::debug!(" (returns) Welcome: {:?}", &commit_output.welcome);
    879    log::debug!(" (returns) Identity: {:?}", &commit_output.identity);
    880 
    881    // Write the result
    882    *ret_commit_output = commit_output.into();
    883 
    884    log::info!("Successfully closed group");
    885 
    886    NS_OK
    887 }
    888 
    889 #[repr(C)]
    890 pub struct GkMlsCommitOutput {
    891    pub commit: ThinVec<u8>,
    892    pub welcome: ThinVec<u8>,
    893    pub group_info: ThinVec<u8>,
    894    pub ratchet_tree: ThinVec<u8>,
    895    pub identity: ThinVec<u8>,
    896 }
    897 
    898 impl From<MlsCommitOutput> for GkMlsCommitOutput {
    899    fn from(v: MlsCommitOutput) -> Self {
    900        let MlsCommitOutput {
    901            commit,
    902            welcome,
    903            group_info,
    904            ratchet_tree,
    905            identity,
    906        } = v;
    907        Self {
    908            commit: commit.to_bytes().unwrap_or_default().into(),
    909            welcome: welcome
    910                .first()
    911                .and_then(|f| f.to_bytes().ok())
    912                .map_or(ThinVec::new(), |b| b.into()),
    913            group_info: group_info
    914                .and_then(|gi| gi.to_bytes().ok())
    915                .map_or(ThinVec::new(), |b| b.into()),
    916            ratchet_tree: ratchet_tree.unwrap_or_default().into(),
    917            identity: identity.unwrap_or_default().into(),
    918        }
    919    }
    920 }
    921 
    922 #[repr(C)]
    923 /// cbindgen:derive-constructor=false
    924 /// cbindgen:derive-tagged-enum-copy-constructor=false
    925 /// cbindgen:derive-tagged-enum-copy-assignment=false
    926 pub enum GkReceived {
    927    None,
    928    ApplicationMessage(ThinVec<u8>),
    929    GroupIdEpoch(GkGroupIdEpoch),
    930    CommitOutput(GkMlsCommitOutput),
    931 }
    932 
    933 #[no_mangle]
    934 pub unsafe extern "C" fn mls_receive(
    935    storage_prefix: &nsACString,
    936    identifier_bytes_ptr: *const u8,
    937    identifier_bytes_len: usize,
    938    message_bytes_ptr: *const u8,
    939    message_bytes_len: usize,
    940    ret_group_id: &mut ThinVec<u8>,
    941    ret_received: &mut GkReceived,
    942 ) -> nsresult {
    943    // Log the function call
    944    log::debug!("Entering mls_receive");
    945 
    946    // Validate the inputs
    947    if identifier_bytes_len == 0 {
    948        log::error!("Identifier argument cannot be empty");
    949        return NS_ERROR_INVALID_ARG;
    950    }
    951    if message_bytes_len == 0 {
    952        log::error!("Message argument cannot be empty");
    953        return NS_ERROR_INVALID_ARG;
    954    }
    955 
    956    // Convert the raw pointers to slices
    957    let identifier_bytes: &[u8] =
    958        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
    959    let message_bytes: &[u8] =
    960        unsafe { std::slice::from_raw_parts(message_bytes_ptr, message_bytes_len) };
    961 
    962    // Retrieve the platform state based on the storage prefix
    963    let Ok(pstate) = state_access(storage_prefix) else {
    964        return NS_ERROR_FAILURE;
    965    };
    966 
    967    // Retrieve the message from the caller
    968    let message = match mls_platform_api::MlsMessage::from_bytes(&message_bytes) {
    969        Ok(kp) => kp,
    970        Err(e) => {
    971            log::error!("{:?}", e);
    972            return NS_ERROR_INVALID_ARG;
    973        }
    974    };
    975 
    976    // Retrieve the received output and the group identifier
    977    let (gid, received) = match mls_platform_api::mls_receive(
    978        &pstate,
    979        identifier_bytes,
    980        &mls_platform_api::MessageOrAck::MlsMessage(message),
    981    ) {
    982        Ok(recv) => recv,
    983        Err(e) => {
    984            log::error!("Failed to receive message: {:?}", e);
    985            return NS_ERROR_FAILURE;
    986        }
    987    };
    988 
    989    // Log the result
    990    log::debug!(" (returns) Group Identifier: {:?}", hex::encode(&gid));
    991 
    992    // Write the group id to ret_group_id
    993    ret_group_id.extend_from_slice(&gid);
    994    *ret_received = match received {
    995        Received::ApplicationMessage(message) => {
    996            log::info!("Received an ApplicationMessage");
    997            log::debug!(
    998                " (returns) Received Application Message: {:?}",
    999                hex::encode(&message)
   1000            );
   1001            GkReceived::ApplicationMessage(message.into())
   1002        }
   1003        Received::GroupIdEpoch(epoch) => {
   1004            log::info!("Received a GroupIdEpoch");
   1005            log::debug!(" (returns) Received GroupIdEpoch: {:?}", epoch);
   1006            GkReceived::GroupIdEpoch(epoch.into())
   1007        }
   1008        Received::CommitOutput(commit_output) => {
   1009            log::info!("Received a CommitOutput");
   1010            log::debug!(" (returns) Received CommitOutput: {:?}", commit_output);
   1011            GkReceived::CommitOutput(commit_output.into())
   1012        }
   1013        Received::None => {
   1014            log::info!("Received None");
   1015            GkReceived::None
   1016        }
   1017    };
   1018 
   1019    log::info!("Successfully received message");
   1020 
   1021    NS_OK
   1022 }
   1023 
   1024 #[no_mangle]
   1025 pub unsafe extern "C" fn mls_has_pending_proposals(
   1026    storage_prefix: &nsACString,
   1027    group_id_bytes_ptr: *const u8,
   1028    group_id_bytes_len: usize,
   1029    identifier_bytes_ptr: *const u8,
   1030    identifier_bytes_len: usize,
   1031    ret_has_pending_proposals: &mut bool,
   1032 ) -> nsresult {
   1033    // Log the function call
   1034    log::debug!("Entering mls_has_pending_proposals");
   1035 
   1036    // Validate the inputs
   1037    if group_id_bytes_len == 0 {
   1038        log::error!("Group Identifier argument cannot be empty");
   1039        return NS_ERROR_INVALID_ARG;
   1040    }
   1041    if identifier_bytes_len == 0 {
   1042        log::error!("Identifier argument cannot be empty");
   1043        return NS_ERROR_INVALID_ARG;
   1044    }
   1045 
   1046    // Convert the raw pointers to slices
   1047    let group_id_bytes: &[u8] =
   1048        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
   1049    let identifier_bytes: &[u8] =
   1050        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
   1051 
   1052    // Retrieve the platform state based on the storage prefix
   1053    let Ok(pstate) = state_access(storage_prefix) else {
   1054        return NS_ERROR_FAILURE;
   1055    };
   1056 
   1057    // Retrieve whether there are pending proposals
   1058    let has_pending_proposals = match mls_platform_api::mls_has_pending_proposals(
   1059        &pstate,
   1060        group_id_bytes,
   1061        identifier_bytes,
   1062    ) {
   1063        Ok(result) => result,
   1064        Err(e) => {
   1065            log::error!("{:?}", e);
   1066            return NS_ERROR_FAILURE;
   1067        }
   1068    };
   1069 
   1070    // Write whether there are pending proposals to ret_has_pending_proposals
   1071    *ret_has_pending_proposals = has_pending_proposals;
   1072 
   1073    log::info!("Successfully retrieved has pending proposals");
   1074    NS_OK
   1075 }
   1076 
   1077 #[no_mangle]
   1078 pub unsafe extern "C" fn mls_clear_pending_proposals(
   1079    storage_prefix: &nsACString,
   1080    group_id_bytes_ptr: *const u8,
   1081    group_id_bytes_len: usize,
   1082    identifier_bytes_ptr: *const u8,
   1083    identifier_bytes_len: usize,
   1084    ret_cleared_pending_proposals: &mut bool,
   1085 ) -> nsresult {
   1086    // Log the function call
   1087    log::debug!("Entering mls_clear_pending_proposals");
   1088 
   1089    // Validate the inputs
   1090    if group_id_bytes_len == 0 {
   1091        log::error!("Group Identifier argument cannot be empty");
   1092        return NS_ERROR_INVALID_ARG;
   1093    }
   1094    if identifier_bytes_len == 0 {
   1095        log::error!("Identifier argument cannot be empty");
   1096        return NS_ERROR_INVALID_ARG;
   1097    }
   1098 
   1099    // Convert the raw pointers to slices
   1100    let group_id_bytes: &[u8] =
   1101        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
   1102    let identifier_bytes: &[u8] =
   1103        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
   1104 
   1105    // Retrieve the platform state based on the storage prefix
   1106    let Ok(pstate) = state_access(storage_prefix) else {
   1107        return NS_ERROR_FAILURE;
   1108    };
   1109 
   1110    // Retrieve the result of clearing pending proposals
   1111    let has_cleared_pending_proposals = match mls_platform_api::mls_clear_pending_proposals(
   1112        &pstate,
   1113        group_id_bytes,
   1114        identifier_bytes,
   1115    ) {
   1116        Ok(result) => result,
   1117        Err(e) => {
   1118            log::error!("{:?}", e);
   1119            return NS_ERROR_FAILURE;
   1120        }
   1121    };
   1122 
   1123    // Write the result of clearing pending proposals to ret_cleared_pending_proposals
   1124    *ret_cleared_pending_proposals = has_cleared_pending_proposals;
   1125 
   1126    log::info!("Successfully cleared pending proposals");
   1127    NS_OK
   1128 }
   1129 
   1130 #[no_mangle]
   1131 pub unsafe extern "C" fn mls_has_pending_commit(
   1132    storage_prefix: &nsACString,
   1133    group_id_bytes_ptr: *const u8,
   1134    group_id_bytes_len: usize,
   1135    identifier_bytes_ptr: *const u8,
   1136    identifier_bytes_len: usize,
   1137    ret_has_pending_commit: &mut bool,
   1138 ) -> nsresult {
   1139    // Log the function call
   1140    log::debug!("Entering mls_has_pending_commit");
   1141 
   1142    // Validate the inputs
   1143    if group_id_bytes_len == 0 {
   1144        log::error!("Group Identifier argument cannot be empty");
   1145        return NS_ERROR_INVALID_ARG;
   1146    }
   1147    if identifier_bytes_len == 0 {
   1148        log::error!("Identifier argument cannot be empty");
   1149        return NS_ERROR_INVALID_ARG;
   1150    }
   1151 
   1152    // Convert the raw pointers to slices
   1153    let group_id_bytes: &[u8] =
   1154        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
   1155    let identifier_bytes: &[u8] =
   1156        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
   1157 
   1158    // Retrieve the platform state based on the storage prefix
   1159    let Ok(pstate) = state_access(storage_prefix) else {
   1160        return NS_ERROR_FAILURE;
   1161    };
   1162 
   1163    // Retrieve whether there is pending commit
   1164    let has_pending_commit =
   1165        match mls_platform_api::mls_has_pending_commit(&pstate, group_id_bytes, identifier_bytes) {
   1166            Ok(result) => result,
   1167            Err(e) => {
   1168                log::error!("{:?}", e);
   1169                return NS_ERROR_FAILURE;
   1170            }
   1171        };
   1172 
   1173    // Write whether there is pending commit to ret_has_pending_commit
   1174    *ret_has_pending_commit = has_pending_commit;
   1175 
   1176    log::info!("Successfully retrieved has pending commit");
   1177    NS_OK
   1178 }
   1179 
   1180 #[no_mangle]
   1181 pub unsafe extern "C" fn mls_clear_pending_commit(
   1182    storage_prefix: &nsACString,
   1183    group_id_bytes_ptr: *const u8,
   1184    group_id_bytes_len: usize,
   1185    identifier_bytes_ptr: *const u8,
   1186    identifier_bytes_len: usize,
   1187    ret_cleared_pending_commit: &mut bool,
   1188 ) -> nsresult {
   1189    // Log the function call
   1190    log::debug!("Entering mls_clear_pending_commit");
   1191 
   1192    // Validate the inputs
   1193    if group_id_bytes_len == 0 {
   1194        log::error!("Group Identifier argument cannot be empty");
   1195        return NS_ERROR_INVALID_ARG;
   1196    }
   1197    if identifier_bytes_len == 0 {
   1198        log::error!("Identifier argument cannot be empty");
   1199        return NS_ERROR_INVALID_ARG;
   1200    }
   1201 
   1202    // Convert the raw pointers to slices
   1203    let group_id_bytes: &[u8] =
   1204        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
   1205    let identifier_bytes: &[u8] =
   1206        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
   1207 
   1208    // Retrieve the platform state based on the storage prefix
   1209    let Ok(pstate) = state_access(storage_prefix) else {
   1210        return NS_ERROR_FAILURE;
   1211    };
   1212 
   1213    // Retrieve the result of clearing the pending commit
   1214    let has_cleared_pending_commit =
   1215        match mls_platform_api::mls_clear_pending_commit(&pstate, group_id_bytes, identifier_bytes)
   1216        {
   1217            Ok(result) => result,
   1218            Err(e) => {
   1219                log::error!("{:?}", e);
   1220                return NS_ERROR_FAILURE;
   1221            }
   1222        };
   1223 
   1224    // Write the result of clearing the pending commit to ret_has_pending_proposals
   1225    *ret_cleared_pending_commit = has_cleared_pending_commit;
   1226 
   1227    log::info!("Successfully cleared pending commit");
   1228    NS_OK
   1229 }
   1230 
   1231 #[no_mangle]
   1232 pub unsafe extern "C" fn mls_apply_pending_commit(
   1233    storage_prefix: &nsACString,
   1234    group_id_bytes_ptr: *const u8,
   1235    group_id_bytes_len: usize,
   1236    identifier_bytes_ptr: *const u8,
   1237    identifier_bytes_len: usize,
   1238    ret_received: &mut GkReceived,
   1239 ) -> nsresult {
   1240    // Log the function call
   1241    log::debug!("Entering mls_apply_pending_commit");
   1242 
   1243    // Validate the inputs
   1244    if group_id_bytes_len == 0 {
   1245        log::error!("Group Identifier argument cannot be empty");
   1246        return NS_ERROR_INVALID_ARG;
   1247    }
   1248    if identifier_bytes_len == 0 {
   1249        log::error!("Identifier argument cannot be empty");
   1250        return NS_ERROR_INVALID_ARG;
   1251    }
   1252 
   1253    // Convert the raw pointers to slices
   1254    let group_id_bytes: &[u8] =
   1255        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
   1256    let identifier_bytes: &[u8] =
   1257        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
   1258 
   1259    // Retrieve the platform state based on the storage prefix
   1260    let Ok(pstate) = state_access(storage_prefix) else {
   1261        return NS_ERROR_FAILURE;
   1262    };
   1263 
   1264    // Retrieve the received output and the group identifier
   1265    let (gid, received) = match mls_platform_api::mls_receive(
   1266        &pstate,
   1267        identifier_bytes,
   1268        &mls_platform_api::MessageOrAck::Ack(group_id_bytes.to_vec()),
   1269    ) {
   1270        Ok(recv) => recv,
   1271        Err(e) => {
   1272            log::error!("{:?}", e);
   1273            return NS_ERROR_FAILURE;
   1274        }
   1275    };
   1276 
   1277    // Log the result
   1278    log::debug!(" (returns) Group Identifier: {:?}", hex::encode(&gid));
   1279 
   1280    // Write the group id to ret_group_id
   1281    *ret_received = match received {
   1282        Received::GroupIdEpoch(epoch) => {
   1283            log::info!("Received a GroupIdEpoch");
   1284            log::debug!(" (returns) Received GroupIdEpoch: {:?}", epoch);
   1285            GkReceived::GroupIdEpoch(epoch.into())
   1286        }
   1287        _ => {
   1288            log::info!("Unexpected received type for mls_receive_ack");
   1289            GkReceived::None
   1290        }
   1291    };
   1292 
   1293    log::info!("Successfully received ack message");
   1294 
   1295    NS_OK
   1296 }
   1297 
   1298 #[no_mangle]
   1299 pub unsafe extern "C" fn mls_send(
   1300    storage_prefix: &nsACString,
   1301    group_id_bytes_ptr: *const u8,
   1302    group_id_bytes_len: usize,
   1303    identifier_bytes_ptr: *const u8,
   1304    identifier_bytes_len: usize,
   1305    message_bytes_ptr: *const u8,
   1306    message_bytes_len: usize,
   1307    ret_encrypted: &mut ThinVec<u8>,
   1308 ) -> nsresult {
   1309    // Log the function call
   1310    log::debug!("Entering mls_send");
   1311 
   1312    // Validate the inputs
   1313    if group_id_bytes_len == 0 {
   1314        log::error!("Group Identifier argument cannot be empty");
   1315        return NS_ERROR_INVALID_ARG;
   1316    }
   1317    if identifier_bytes_len == 0 {
   1318        log::error!("Identifier argument cannot be empty");
   1319        return NS_ERROR_INVALID_ARG;
   1320    }
   1321    // Note: We allow empty messages as they could be used as control
   1322 
   1323    // Convert the raw pointers to slices
   1324    let group_id_bytes: &[u8] =
   1325        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
   1326    let identifier_bytes: &[u8] =
   1327        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
   1328    let message_bytes: &[u8] =
   1329        unsafe { std::slice::from_raw_parts(message_bytes_ptr, message_bytes_len) };
   1330 
   1331    // Retrieve the platform state based on the storage prefix
   1332    let Ok(pstate) = state_access(storage_prefix) else {
   1333        return NS_ERROR_FAILURE;
   1334    };
   1335 
   1336    // Retrieve the ciphertext
   1337    let ciphertext = match mls_platform_api::mls_send(
   1338        &pstate,
   1339        group_id_bytes,
   1340        identifier_bytes,
   1341        message_bytes,
   1342    ) {
   1343        Ok(ctx) => ctx,
   1344        Err(e) => {
   1345            log::error!("{:?}", e);
   1346            return NS_ERROR_FAILURE;
   1347        }
   1348    };
   1349 
   1350    // Retrieve the message from the caller
   1351    let ciphertext_bytes = match mls_platform_api::MlsMessage::to_bytes(&ciphertext) {
   1352        Ok(ctx) => ctx,
   1353        Err(e) => {
   1354            log::error!("{:?}", e);
   1355            return NS_ERROR_FAILURE;
   1356        }
   1357    };
   1358 
   1359    // Log the result
   1360    log::debug!(" (input) Message: {:?}", hex::encode(&message_bytes));
   1361    log::debug!(
   1362        " (returns) Ciphertext: {:?}",
   1363        hex::encode(&ciphertext_bytes)
   1364    );
   1365 
   1366    // Write the result to ret_val
   1367    ret_encrypted.extend_from_slice(&ciphertext_bytes);
   1368 
   1369    log::info!("Successfully encrypted message");
   1370    NS_OK
   1371 }
   1372 
   1373 #[repr(C)]
   1374 pub struct GkExporterOutput {
   1375    pub group_id: ThinVec<u8>,
   1376    pub group_epoch: ThinVec<u8>,
   1377    pub label: ThinVec<u8>,
   1378    pub context: ThinVec<u8>,
   1379    pub exporter: ThinVec<u8>,
   1380 }
   1381 
   1382 impl From<ExporterOutput> for GkExporterOutput {
   1383    fn from(v: ExporterOutput) -> Self {
   1384        let ExporterOutput {
   1385            group_id,
   1386            group_epoch,
   1387            label,
   1388            context,
   1389            exporter,
   1390        } = v;
   1391        Self {
   1392            group_id: group_id.into(),
   1393            group_epoch: ThinVec::from(group_epoch.to_le_bytes()),
   1394            label: label.into(),
   1395            context: context.into(),
   1396            exporter: exporter.into(),
   1397        }
   1398    }
   1399 }
   1400 
   1401 #[no_mangle]
   1402 pub unsafe extern "C" fn mls_derive_exporter(
   1403    storage_prefix: &nsACString,
   1404    group_id_bytes_ptr: *const u8,
   1405    group_id_bytes_len: usize,
   1406    identifier_bytes_ptr: *const u8,
   1407    identifier_bytes_len: usize,
   1408    label_bytes_ptr: *const u8,
   1409    label_bytes_len: usize,
   1410    context_bytes_ptr: *const u8,
   1411    context_bytes_len: usize,
   1412    len: u64,
   1413    ret_exporter_output: &mut GkExporterOutput,
   1414 ) -> nsresult {
   1415    // Log the function call
   1416    log::debug!("Entering mls_derive_exporter");
   1417 
   1418    // Validate the inputs
   1419    if group_id_bytes_len == 0 {
   1420        log::error!("Group Identifier argument cannot be empty");
   1421        return NS_ERROR_INVALID_ARG;
   1422    }
   1423    if identifier_bytes_len == 0 {
   1424        log::error!("Identifier argument cannot be empty");
   1425        return NS_ERROR_INVALID_ARG;
   1426    }
   1427    if label_bytes_len == 0 {
   1428        log::error!("Label argument cannot be empty");
   1429        return NS_ERROR_INVALID_ARG;
   1430    }
   1431    if len == 0 {
   1432        log::error!("Length argument cannot be zero");
   1433        return NS_ERROR_INVALID_ARG;
   1434    }
   1435 
   1436    // Convert the raw pointers to slices
   1437    let group_id_bytes: &[u8] =
   1438        unsafe { std::slice::from_raw_parts(group_id_bytes_ptr, group_id_bytes_len) };
   1439    let identifier_bytes: &[u8] =
   1440        unsafe { std::slice::from_raw_parts(identifier_bytes_ptr, identifier_bytes_len) };
   1441    let label_bytes: &[u8] =
   1442        unsafe { std::slice::from_raw_parts(label_bytes_ptr, label_bytes_len) };
   1443    let context_bytes: &[u8] =
   1444        unsafe { std::slice::from_raw_parts(context_bytes_ptr, context_bytes_len) };
   1445 
   1446    // Retrieve the platform state based on the storage prefix
   1447    let Ok(pstate) = state_access(storage_prefix) else {
   1448        return NS_ERROR_FAILURE;
   1449    };
   1450 
   1451    // Retrieve the exporter output
   1452    let exporter_output = match mls_platform_api::mls_derive_exporter(
   1453        &pstate,
   1454        group_id_bytes,
   1455        identifier_bytes,
   1456        label_bytes,
   1457        context_bytes,
   1458        len,
   1459    ) {
   1460        Ok(exp) => exp,
   1461        Err(e) => {
   1462            log::error!("{:?}", e);
   1463            return NS_ERROR_FAILURE;
   1464        }
   1465    };
   1466 
   1467    log::debug!(
   1468        " (returns) Exporter: {:?}",
   1469        hex::encode(&exporter_output.exporter)
   1470    );
   1471 
   1472    // Handle group identifier
   1473    *ret_exporter_output = exporter_output.into();
   1474 
   1475    log::info!("Successfully derived exporter");
   1476    NS_OK
   1477 }
   1478 
   1479 #[no_mangle]
   1480 pub unsafe extern "C" fn mls_get_group_id(
   1481    message_bytes_ptr: *const u8,
   1482    message_bytes_len: usize,
   1483    ret_group_id: &mut ThinVec<u8>,
   1484 ) -> nsresult {
   1485    // Log the function call
   1486    log::debug!("Entering mls_get_group_id");
   1487 
   1488    // Validate the inputs
   1489    if message_bytes_len == 0 {
   1490        log::error!("Message argument cannot be empty");
   1491        return NS_ERROR_INVALID_ARG;
   1492    }
   1493 
   1494    let message_bytes: &[u8] =
   1495        unsafe { std::slice::from_raw_parts(message_bytes_ptr, message_bytes_len) };
   1496 
   1497    // Retrieve the message from the caller
   1498    let message = match mls_platform_api::MlsMessage::from_bytes(&message_bytes) {
   1499        Ok(kp) => kp,
   1500        Err(e) => {
   1501            log::error!("{:?}", e);
   1502            return NS_ERROR_INVALID_ARG;
   1503        }
   1504    };
   1505 
   1506    // Retrieve the group identifier
   1507    let gid = match mls_platform_api::mls_get_group_id(&mls_platform_api::MessageOrAck::MlsMessage(
   1508        message,
   1509    )) {
   1510        Ok(recv) => recv,
   1511        Err(e) => {
   1512            log::error!("{:?}", e);
   1513            return NS_ERROR_FAILURE;
   1514        }
   1515    };
   1516 
   1517    // Write the group id to ret_group_id
   1518    ret_group_id.extend_from_slice(&gid);
   1519 
   1520    // Log the result
   1521    log::debug!(" (returns) Group Identifier: {:?}", hex::encode(&gid));
   1522    log::info!("Successfully retrieved group id");
   1523 
   1524    NS_OK
   1525 }
   1526 
   1527 #[no_mangle]
   1528 pub unsafe extern "C" fn mls_get_group_epoch(
   1529    message_bytes_ptr: *const u8,
   1530    message_bytes_len: usize,
   1531    ret_group_epoch: &mut ThinVec<u8>,
   1532 ) -> nsresult {
   1533    // Log the function call
   1534    log::debug!("Entering mls_get_group_epoch");
   1535 
   1536    // Validate the inputs
   1537    if message_bytes_len == 0 {
   1538        log::error!("Message argument cannot be empty");
   1539        return NS_ERROR_INVALID_ARG;
   1540    }
   1541 
   1542    let message_bytes: &[u8] =
   1543        unsafe { std::slice::from_raw_parts(message_bytes_ptr, message_bytes_len) };
   1544 
   1545    // Retrieve the message from the caller
   1546    let message = match mls_platform_api::MlsMessage::from_bytes(&message_bytes) {
   1547        Ok(kp) => kp,
   1548        Err(e) => {
   1549            log::error!("{:?}", e);
   1550            return NS_ERROR_INVALID_ARG;
   1551        }
   1552    };
   1553 
   1554    // Retrieve the group epoch
   1555    let group_epoch = match mls_platform_api::mls_get_group_epoch(
   1556        &mls_platform_api::MessageOrAck::MlsMessage(message),
   1557    ) {
   1558        Ok(epoch) => epoch,
   1559        Err(e) => {
   1560            log::error!("{:?}", e);
   1561            return NS_ERROR_FAILURE;
   1562        }
   1563    };
   1564 
   1565    // Write the group epoch to ret_group_epoch
   1566    // Convert the u64 group_epoch to little-endian bytes
   1567    let epoch_bytes = group_epoch.to_le_bytes();
   1568    ret_group_epoch.extend_from_slice(&epoch_bytes);
   1569 
   1570    log::info!(" (returns) Group Epoch: {:?}", group_epoch);
   1571    log::info!("Successfully retrieved group epoch");
   1572    NS_OK
   1573 }