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}