script/dom/webcrypto/subtlecrypto/
turboshake_operation.rs

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 https://mozilla.org/MPL/2.0/. */
4
5use digest::{ExtendableOutput, Update};
6use sha3::{TurboShake128, TurboShake128Core, TurboShake256, TurboShake256Core};
7
8use crate::dom::bindings::error::Error;
9use crate::dom::subtlecrypto::{CryptoAlgorithm, SubtleTurboShakeParams};
10
11/// <https://wicg.github.io/webcrypto-modern-algos/#turboshake-operations-digest>
12pub(crate) fn digest(
13    normalized_algorithm: &SubtleTurboShakeParams,
14    message: &[u8],
15) -> Result<Vec<u8>, Error> {
16    // Step 1. Let outputLength be the outputLength member of normalizedAlgorithm.
17    let output_length = normalized_algorithm.output_length;
18
19    // Step 2. If outputLength is zero or is not a multiple of 8, then throw an OperationError.
20    if output_length == 0 || output_length % 8 != 0 {
21        return Err(Error::Operation(Some(
22            "The outputLength is zero or is not a multiple of 8".to_string(),
23        )));
24    }
25
26    // Step 3. Let domainSeparation be the domainSeparation member of normalizedAlgorithm if
27    // present, or 0x1F otherwise.
28    let domain_separation = normalized_algorithm.domain_separation.unwrap_or(0x1f);
29
30    // Step 4. If domainSeparation is less than 0x01 or greater than 0x7F, then throw an
31    // OperationError.
32    if !(0x01..=0x7f).contains(&domain_separation) {
33        return Err(Error::Operation(Some(
34            "The domainSeparation is less than 0x01 or greater than 0x7F".to_string(),
35        )));
36    }
37
38    // Step 5.
39    // If the name member of normalizedAlgorithm is a case-sensitive string match for
40    // "TurboSHAKE128":
41    //     Let result be the result of performing the TurboSHAKE128 function defined in Section 2
42    //     of [RFC9861] using message as the M input parameter, domainSeparation as the D input
43    //     parameter, and outputLength divided by 8 as the L input parameter.
44    // If the name member of normalizedAlgorithm is a case-sensitive string match for
45    // "TurboSHAKE256":
46    //     Let result be the result of performing the TurboSHAKE256 function defined in Section 2
47    //     of [RFC9861] using message as the M input parameter, domainSeparation as the D input
48    //     parameter, and outputLength divided by 8 as the L input parameter.
49    // Step 6. If performing the operation results in an error, then throw an OperationError.
50    let result = match normalized_algorithm.name {
51        CryptoAlgorithm::TurboShake128 => {
52            let core = TurboShake128Core::new(domain_separation);
53            let mut hasher = TurboShake128::from_core(core);
54            hasher.update(message);
55            hasher.finalize_boxed(output_length as usize / 8).to_vec()
56        },
57        CryptoAlgorithm::TurboShake256 => {
58            let core = TurboShake256Core::new(domain_separation);
59            let mut hasher = TurboShake256::from_core(core);
60            hasher.update(message);
61            hasher.finalize_boxed(output_length as usize / 8).to_vec()
62        },
63        algorithm_name => {
64            return Err(Error::NotSupported(Some(format!(
65                "{} is not a TurboSHAKE algorithm",
66                algorithm_name.as_str()
67            ))));
68        },
69    };
70
71    // Step 7. Return result.
72    Ok(result)
73}