summaryrefslogtreecommitdiffstats
path: root/vendor/orion/src/hazardous
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /vendor/orion/src/hazardous
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/orion/src/hazardous')
-rw-r--r--vendor/orion/src/hazardous/aead/chacha20poly1305.rs6
-rw-r--r--vendor/orion/src/hazardous/cae/chacha20poly1305blake2b.rs262
-rw-r--r--vendor/orion/src/hazardous/cae/mod.rs33
-rw-r--r--vendor/orion/src/hazardous/cae/xchacha20poly1305blake2b.rs246
-rw-r--r--vendor/orion/src/hazardous/ecc/x25519.rs71
-rw-r--r--vendor/orion/src/hazardous/hash/mod.rs3
-rw-r--r--vendor/orion/src/hazardous/hash/sha2/sha256.rs8
-rw-r--r--vendor/orion/src/hazardous/hash/sha2/sha384.rs8
-rw-r--r--vendor/orion/src/hazardous/hash/sha2/sha512.rs8
-rw-r--r--vendor/orion/src/hazardous/hash/sha3/mod.rs558
-rw-r--r--vendor/orion/src/hazardous/hash/sha3/sha3_224.rs274
-rw-r--r--vendor/orion/src/hazardous/hash/sha3/sha3_256.rs336
-rw-r--r--vendor/orion/src/hazardous/hash/sha3/sha3_384.rs274
-rw-r--r--vendor/orion/src/hazardous/hash/sha3/sha3_512.rs274
-rw-r--r--vendor/orion/src/hazardous/kem/mod.rs25
-rw-r--r--vendor/orion/src/hazardous/kem/x25519_hkdf_sha256.rs289
-rw-r--r--vendor/orion/src/hazardous/mac/poly1305.rs38
-rw-r--r--vendor/orion/src/hazardous/mod.rs7
18 files changed, 2658 insertions, 62 deletions
diff --git a/vendor/orion/src/hazardous/aead/chacha20poly1305.rs b/vendor/orion/src/hazardous/aead/chacha20poly1305.rs
index bc1175809..821125381 100644
--- a/vendor/orion/src/hazardous/aead/chacha20poly1305.rs
+++ b/vendor/orion/src/hazardous/aead/chacha20poly1305.rs
@@ -123,10 +123,10 @@ use core::convert::TryInto;
use zeroize::Zeroizing;
/// The initial counter used for encryption and decryption.
-const ENC_CTR: u32 = 1;
+pub(crate) const ENC_CTR: u32 = 1;
/// The initial counter used for Poly1305 key generation.
-const AUTH_CTR: u32 = 0;
+pub(crate) const AUTH_CTR: u32 = 0;
/// The maximum size of the plaintext (see [RFC 8439](https://www.rfc-editor.org/rfc/rfc8439#section-2.8)).
pub const P_MAX: u64 = (u32::MAX as u64) * 64;
@@ -147,7 +147,7 @@ pub(crate) fn poly1305_key_gen(
}
/// Authenticates the ciphertext, ad and their lengths.
-fn process_authentication(
+pub(crate) fn process_authentication(
auth_ctx: &mut Poly1305,
ad: &[u8],
ciphertext: &[u8],
diff --git a/vendor/orion/src/hazardous/cae/chacha20poly1305blake2b.rs b/vendor/orion/src/hazardous/cae/chacha20poly1305blake2b.rs
new file mode 100644
index 000000000..19cef00fa
--- /dev/null
+++ b/vendor/orion/src/hazardous/cae/chacha20poly1305blake2b.rs
@@ -0,0 +1,262 @@
+// MIT License
+
+// Copyright (c) 2023 The orion Developers
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! # About
+//! This provides a fully committing AEAD, using the CTX construction proposed by Chan and Rogaway,
+//! in the ["On Committing Authenticated Encryption"] paper. Specifically, CTX is instantiated with BLAKE2b-256.
+//!
+//! A fully committing AEAD is important if attacks like the [partitioning oracle attack] are a part of the threat model.
+//!
+//! # Parameters:
+//! - `secret_key`: The secret key.
+//! - `nonce`: The nonce value.
+//! - `ad`: Additional data to authenticate (this is not encrypted and can be [`None`]).
+//! - `ciphertext_with_tag`: The encrypted data with the corresponding 32 byte
+//! BLAKE2b tag appended to it.
+//! - `plaintext`: The data to be encrypted.
+//! - `dst_out`: Destination array that will hold the
+//! `ciphertext_with_tag`/`plaintext` after encryption/decryption.
+//!
+//! `ad`: "A typical use for these data is to authenticate version numbers,
+//! timestamps or monotonically increasing counters in order to discard previous
+//! messages and prevent replay attacks." See [libsodium docs] for more information.
+//!
+//! `nonce`: "Counters and LFSRs are both acceptable ways of generating unique
+//! nonces, as is encrypting a counter using a block cipher with a 64-bit block
+//! size such as DES. Note that it is not acceptable to use a truncation of a
+//! counter encrypted with block ciphers with 128-bit or 256-bit blocks,
+//! because such a truncation may repeat after a short time." See [RFC] for more information.
+//!
+//! `dst_out`: The output buffer may have a capacity greater than the input. If this is the case,
+//! only the first input length amount of bytes in `dst_out` are modified, while the rest remain untouched.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - The length of `dst_out` is less than `plaintext` + [`TAG_SIZE`] when calling [`seal()`].
+//! - The length of `dst_out` is less than `ciphertext_with_tag` - [`TAG_SIZE`] when
+//! calling [`open()`].
+//! - The length of `ciphertext_with_tag` is not at least [`TAG_SIZE`].
+//! - The received tag does not match the calculated tag when calling [`open()`].
+//! - `plaintext.len()` + [`TAG_SIZE`] overflows when calling [`seal()`].
+//! - Converting `usize` to `u64` would be a lossy conversion.
+//! - `plaintext.len() >` [`P_MAX`]
+//! - `ad.len() >` [`A_MAX`]
+//! - `ciphertext_with_tag.len() >` [`C_MAX`]
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - More than `2^32-1 * 64` bytes of data are processed.
+//!
+//! # Security:
+//! - It is critical for security that a given nonce is not re-used with a given
+//! key. Should this happen, the security of all data that has been encrypted
+//! with that given key is compromised.
+//! - Only a nonce for XChaCha20Poly1305 is big enough to be randomly generated
+//! using a CSPRNG.
+//! - To securely generate a strong key, use [`SecretKey::generate()`].
+//! - The length of the `plaintext` is not hidden, only its contents.
+//!
+//! # Recommendation:
+//! - It is recommended to use [`XChaCha20Poly1305-BLAKE2b`] when possible.
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::hazardous::cae;
+//!
+//! let secret_key = cae::chacha20poly1305blake2b::SecretKey::generate();
+//!
+//! // WARNING: This nonce is only meant for demonstration and should not
+//! // be repeated. Please read the security section.
+//! let nonce = cae::chacha20poly1305blake2b::Nonce::from([0u8; 12]);
+//! let ad = "Additional data".as_bytes();
+//! let message = "Data to protect".as_bytes();
+//!
+//! // Length of the above message is 15 and then we accommodate 32 for the BLAKE2b
+//! // tag.
+//!
+//! let mut dst_out_ct = [0u8; 15 + 32];
+//! let mut dst_out_pt = [0u8; 15];
+//! // Encrypt and place ciphertext + tag in dst_out_ct
+//! cae::chacha20poly1305blake2b::seal(&secret_key, &nonce, message, Some(&ad), &mut dst_out_ct)?;
+//! // Verify tag, if correct then decrypt and place message in dst_out_pt
+//! cae::chacha20poly1305blake2b::open(&secret_key, &nonce, &dst_out_ct, Some(&ad), &mut dst_out_pt)?;
+//!
+//! assert_eq!(dst_out_pt.as_ref(), message.as_ref());
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`SecretKey::generate()`]: super::stream::chacha20::SecretKey::generate
+//! [`XChaCha20Poly1305-BLAKE2b`]: xchacha20poly1305blake2b
+//! [`TAG_SIZE`]: chacha20poly1305blake2b::TAG_SIZE
+//! [`seal()`]: chacha20poly1305blake2b::seal
+//! [`open()`]: chacha20poly1305blake2b::open
+//! [RFC]: https://tools.ietf.org/html/rfc8439#section-3
+//! [libsodium docs]: https://download.libsodium.org/doc/secret-key_cryptography/aead#additional-data
+//! [`P_MAX`]: chacha20poly1305blake2b::P_MAX
+//! [`A_MAX`]: chacha20poly1305blake2b::A_MAX
+//! [`C_MAX`]: chacha20poly1305blake2b::C_MAX
+//! ["On Committing Authenticated Encryption"]: https://eprint.iacr.org/2022/1260
+//! [partitioning oracle attack]: https://www.usenix.org/conference/usenixsecurity21/presentation/len
+
+use crate::errors::UnknownCryptoError;
+use crate::hazardous::aead;
+use crate::hazardous::aead::chacha20poly1305::{poly1305_key_gen, process_authentication, ENC_CTR};
+use crate::hazardous::hash::blake2::blake2b::Blake2b;
+use crate::hazardous::mac::poly1305::Poly1305;
+use crate::hazardous::mac::poly1305::POLY1305_OUTSIZE;
+use crate::hazardous::stream::chacha20::{self, ChaCha20, CHACHA_BLOCKSIZE};
+use crate::util;
+use zeroize::Zeroizing;
+
+pub use crate::hazardous::aead::chacha20poly1305::A_MAX;
+pub use crate::hazardous::aead::chacha20poly1305::P_MAX;
+pub use crate::hazardous::stream::chacha20::{Nonce, SecretKey};
+
+/// The size of the BLAKE2b authentication tag.
+pub const TAG_SIZE: usize = 32;
+
+/// The maximum size of the ciphertext.
+pub const C_MAX: u64 = P_MAX + (TAG_SIZE as u64);
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// CTX ChaCha20Poly1305 with BLAKE2b-256.
+pub fn seal(
+ secret_key: &SecretKey,
+ nonce: &Nonce,
+ plaintext: &[u8],
+ ad: Option<&[u8]>,
+ dst_out: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ if u64::try_from(plaintext.len()).map_err(|_| UnknownCryptoError)? > P_MAX {
+ return Err(UnknownCryptoError);
+ }
+
+ let ad = ad.unwrap_or(&[0u8; 0]);
+ #[allow(clippy::absurd_extreme_comparisons)]
+ if u64::try_from(ad.len()).map_err(|_| UnknownCryptoError)? > A_MAX {
+ return Err(UnknownCryptoError);
+ }
+
+ match plaintext.len().checked_add(TAG_SIZE) {
+ Some(out_min_len) => {
+ if dst_out.len() < out_min_len {
+ return Err(UnknownCryptoError);
+ }
+ }
+ None => return Err(UnknownCryptoError),
+ };
+
+ aead::chacha20poly1305::seal(
+ secret_key,
+ nonce,
+ plaintext,
+ Some(ad),
+ &mut dst_out[..plaintext.len() + POLY1305_OUTSIZE],
+ )?;
+
+ let mut blake2b = Blake2b::new(32)?;
+ blake2b.update(secret_key.unprotected_as_bytes())?;
+ blake2b.update(nonce.as_ref())?;
+ blake2b.update(ad)?;
+ blake2b.update(&dst_out[plaintext.len()..plaintext.len() + POLY1305_OUTSIZE])?;
+ let tag = blake2b.finalize()?;
+
+ dst_out[plaintext.len()..plaintext.len() + TAG_SIZE].copy_from_slice(tag.as_ref());
+
+ Ok(())
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// CTX ChaCha20Poly1305 with BLAKE2b-256.
+pub fn open(
+ secret_key: &SecretKey,
+ nonce: &Nonce,
+ ciphertext_with_tag: &[u8],
+ ad: Option<&[u8]>,
+ dst_out: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ if u64::try_from(ciphertext_with_tag.len()).map_err(|_| UnknownCryptoError)? > C_MAX {
+ return Err(UnknownCryptoError);
+ }
+ let ad = ad.unwrap_or(&[0u8; 0]);
+ #[allow(clippy::absurd_extreme_comparisons)]
+ if u64::try_from(ad.len()).map_err(|_| UnknownCryptoError)? > A_MAX {
+ return Err(UnknownCryptoError);
+ }
+ if ciphertext_with_tag.len() < TAG_SIZE {
+ return Err(UnknownCryptoError);
+ }
+ if dst_out.len() < ciphertext_with_tag.len() - TAG_SIZE {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut blake2b = Blake2b::new(32)?;
+ blake2b.update(secret_key.unprotected_as_bytes())?;
+ blake2b.update(nonce.as_ref())?;
+ blake2b.update(ad)?;
+
+ let mut dec_ctx =
+ ChaCha20::new(secret_key.unprotected_as_bytes(), nonce.as_ref(), true).unwrap();
+ let mut tmp = Zeroizing::new([0u8; CHACHA_BLOCKSIZE]);
+ let mut auth_ctx = Poly1305::new(&poly1305_key_gen(&mut dec_ctx, &mut tmp));
+
+ let ciphertext_len = ciphertext_with_tag.len() - TAG_SIZE;
+ process_authentication(&mut auth_ctx, ad, &ciphertext_with_tag[..ciphertext_len])?;
+
+ blake2b.update(auth_ctx.finalize()?.unprotected_as_bytes())?;
+
+ util::secure_cmp(
+ blake2b.finalize()?.as_ref(),
+ &ciphertext_with_tag[ciphertext_len..],
+ )?;
+
+ if ciphertext_len != 0 {
+ dst_out[..ciphertext_len].copy_from_slice(&ciphertext_with_tag[..ciphertext_len]);
+ chacha20::xor_keystream(
+ &mut dec_ctx,
+ ENC_CTR,
+ tmp.as_mut(),
+ &mut dst_out[..ciphertext_len],
+ )?;
+ }
+
+ Ok(())
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+mod public {
+ use super::*;
+ use crate::test_framework::aead_interface::{test_diff_params_err, AeadTestRunner};
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ fn prop_aead_interface(input: Vec<u8>, ad: Vec<u8>) -> bool {
+ let secret_key = SecretKey::generate();
+ let nonce = Nonce::from_slice(&[0u8; chacha20::IETF_CHACHA_NONCESIZE]).unwrap();
+ AeadTestRunner(seal, open, secret_key, nonce, &input, None, TAG_SIZE, &ad);
+ test_diff_params_err(&seal, &open, &input, TAG_SIZE);
+ true
+ }
+}
diff --git a/vendor/orion/src/hazardous/cae/mod.rs b/vendor/orion/src/hazardous/cae/mod.rs
new file mode 100644
index 000000000..270821b61
--- /dev/null
+++ b/vendor/orion/src/hazardous/cae/mod.rs
@@ -0,0 +1,33 @@
+// MIT License
+
+// Copyright (c) 2023 The orion Developers
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+#![cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
+
+/// Fully-committing ChaCha20-Poly1305 with BLAKE2b based on the [CTX] construction by John Chan & Phillip Rogaway.
+///
+/// [CTX]: https://eprint.iacr.org/2022/1260
+pub mod chacha20poly1305blake2b;
+
+/// Fully-committing XChaCha20-Poly1305 with BLAKE2b based on the [CTX] construction by John Chan & Phillip Rogaway.
+///
+/// [CTX]: https://eprint.iacr.org/2022/1260
+pub mod xchacha20poly1305blake2b;
diff --git a/vendor/orion/src/hazardous/cae/xchacha20poly1305blake2b.rs b/vendor/orion/src/hazardous/cae/xchacha20poly1305blake2b.rs
new file mode 100644
index 000000000..25d3c32ef
--- /dev/null
+++ b/vendor/orion/src/hazardous/cae/xchacha20poly1305blake2b.rs
@@ -0,0 +1,246 @@
+// MIT License
+
+// Copyright (c) 2023 The orion Developers
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! # About
+//! This provides a fully committing AEAD, using the CTX construction proposed by Chan and Rogaway,
+//! in the ["On Committing Authenticated Encryption"] paper. Specifically, CTX is instantiated with BLAKE2b-256.
+//!
+//! A fully committing AEAD is important if attacks like the [partitioning oracle attack] are a part of the threat model.
+//!
+//! # Parameters:
+//! - `secret_key`: The secret key.
+//! - `nonce`: The nonce value.
+//! - `ad`: Additional data to authenticate (this is not encrypted and can be [`None`]).
+//! - `ciphertext_with_tag`: The encrypted data with the corresponding 32 byte
+//! BLAKE2b tag appended to it.
+//! - `plaintext`: The data to be encrypted.
+//! - `dst_out`: Destination array that will hold the
+//! `ciphertext_with_tag`/`plaintext` after encryption/decryption.
+//!
+//! `ad`: "A typical use for these data is to authenticate version numbers,
+//! timestamps or monotonically increasing counters in order to discard previous
+//! messages and prevent replay attacks." See [libsodium docs] for more information.
+//!
+//! `dst_out`: The output buffer may have a capacity greater than the input. If this is the case,
+//! only the first input length amount of bytes in `dst_out` are modified, while the rest remain untouched.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - The length of `dst_out` is less than `plaintext` + [`TAG_SIZE`] when calling [`seal()`].
+//! - The length of `dst_out` is less than `ciphertext_with_tag` - [`TAG_SIZE`] when
+//! calling [`open()`].
+//! - The length of `ciphertext_with_tag` is not at least [`TAG_SIZE`].
+//! - The received tag does not match the calculated tag when calling [`open()`].
+//! - `plaintext.len()` + [`TAG_SIZE`] overflows when calling [`seal()`].
+//! - Converting `usize` to `u64` would be a lossy conversion.
+//! - `plaintext.len() >` [`P_MAX`]
+//! - `ad.len() >` [`A_MAX`]
+//! - `ciphertext_with_tag.len() >` [`C_MAX`]
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - More than `2^32-1 * 64` bytes of data are processed.
+//!
+//! # Security:
+//! - It is critical for security that a given nonce is not re-used with a given
+//! key. Should this happen, the security of all data that has been encrypted
+//! with that given key is compromised.
+//! - Only a nonce for XChaCha20Poly1305 is big enough to be randomly generated
+//! using a CSPRNG. [`Nonce::generate()`] can be used for this.
+//! - To securely generate a strong key, use [`SecretKey::generate()`].
+//! - The length of the `plaintext` is not hidden, only its contents.
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::hazardous::cae;
+//!
+//! let secret_key = cae::xchacha20poly1305blake2b::SecretKey::generate();
+//! let nonce = cae::xchacha20poly1305blake2b::Nonce::generate();
+//! let ad = "Additional data".as_bytes();
+//! let message = "Data to protect".as_bytes();
+//!
+//! // Length of the above message is 15 and then we accommodate 32 for the BLAKE2b
+//! // tag.
+//!
+//! let mut dst_out_ct = [0u8; 15 + 32];
+//! let mut dst_out_pt = [0u8; 15];
+//! // Encrypt and place ciphertext + tag in dst_out_ct
+//! cae::xchacha20poly1305blake2b::seal(&secret_key, &nonce, message, Some(&ad), &mut dst_out_ct)?;
+//! // Verify tag, if correct then decrypt and place message in dst_out_pt
+//! cae::xchacha20poly1305blake2b::open(&secret_key, &nonce, &dst_out_ct, Some(&ad), &mut dst_out_pt)?;
+//!
+//! assert_eq!(dst_out_pt.as_ref(), message.as_ref());
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`SecretKey::generate()`]: super::stream::chacha20::SecretKey::generate
+//! [`Nonce::generate()`]: super::stream::xchacha20::Nonce::generate
+//! [`TAG_SIZE`]: xchacha20poly1305blake2b::TAG_SIZE
+//! [`seal()`]: xchacha20poly1305blake2b::seal
+//! [`open()`]: xchacha20poly1305blake2b::open
+//! [RFC]: https://tools.ietf.org/html/rfc8439#section-3
+//! [libsodium docs]: https://download.libsodium.org/doc/secret-key_cryptography/aead#additional-data
+//! [`P_MAX`]: xchacha20poly1305blake2b::P_MAX
+//! [`A_MAX`]: xchacha20poly1305blake2b::A_MAX
+//! [`C_MAX`]: xchacha20poly1305blake2b::C_MAX
+//! ["On Committing Authenticated Encryption"]: https://eprint.iacr.org/2022/1260
+//! [partitioning oracle attack]: https://www.usenix.org/conference/usenixsecurity21/presentation/len
+
+use crate::errors::UnknownCryptoError;
+use crate::hazardous::aead;
+pub use crate::hazardous::aead::chacha20poly1305::A_MAX;
+pub use crate::hazardous::aead::chacha20poly1305::P_MAX;
+use crate::hazardous::aead::chacha20poly1305::{poly1305_key_gen, process_authentication, ENC_CTR};
+pub use crate::hazardous::cae::chacha20poly1305blake2b::{C_MAX, TAG_SIZE};
+use crate::hazardous::hash::blake2::blake2b::Blake2b;
+use crate::hazardous::mac::poly1305::{Poly1305, POLY1305_OUTSIZE};
+use crate::hazardous::stream::chacha20::{self, ChaCha20, CHACHA_BLOCKSIZE};
+use crate::hazardous::stream::xchacha20::subkey_and_nonce;
+pub use crate::hazardous::stream::{chacha20::SecretKey, xchacha20::Nonce};
+use crate::util;
+use zeroize::Zeroizing;
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// CTX XChaCha20Poly1305 with BLAKE2b-256.
+pub fn seal(
+ secret_key: &SecretKey,
+ nonce: &Nonce,
+ plaintext: &[u8],
+ ad: Option<&[u8]>,
+ dst_out: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ if u64::try_from(plaintext.len()).map_err(|_| UnknownCryptoError)? > P_MAX {
+ return Err(UnknownCryptoError);
+ }
+
+ let ad = ad.unwrap_or(&[0u8; 0]);
+ #[allow(clippy::absurd_extreme_comparisons)]
+ if u64::try_from(ad.len()).map_err(|_| UnknownCryptoError)? > A_MAX {
+ return Err(UnknownCryptoError);
+ }
+
+ match plaintext.len().checked_add(TAG_SIZE) {
+ Some(out_min_len) => {
+ if dst_out.len() < out_min_len {
+ return Err(UnknownCryptoError);
+ }
+ }
+ None => return Err(UnknownCryptoError),
+ };
+
+ let (subkey, ietf_nonce) = subkey_and_nonce(secret_key, nonce);
+ aead::chacha20poly1305::seal(
+ &subkey,
+ &ietf_nonce,
+ plaintext,
+ Some(ad),
+ &mut dst_out[..plaintext.len() + POLY1305_OUTSIZE],
+ )?;
+
+ let mut blake2b = Blake2b::new(32)?;
+ blake2b.update(secret_key.unprotected_as_bytes())?;
+ blake2b.update(nonce.as_ref())?;
+ blake2b.update(ad)?;
+ blake2b.update(&dst_out[plaintext.len()..plaintext.len() + POLY1305_OUTSIZE])?;
+ let tag = blake2b.finalize()?;
+
+ dst_out[plaintext.len()..plaintext.len() + TAG_SIZE].copy_from_slice(tag.as_ref());
+
+ Ok(())
+}
+
+#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+/// CTX XChaCha20Poly1305 with BLAKE2b-256.
+pub fn open(
+ secret_key: &SecretKey,
+ nonce: &Nonce,
+ ciphertext_with_tag: &[u8],
+ ad: Option<&[u8]>,
+ dst_out: &mut [u8],
+) -> Result<(), UnknownCryptoError> {
+ if u64::try_from(ciphertext_with_tag.len()).map_err(|_| UnknownCryptoError)? > C_MAX {
+ return Err(UnknownCryptoError);
+ }
+ let ad = ad.unwrap_or(&[0u8; 0]);
+ #[allow(clippy::absurd_extreme_comparisons)]
+ if u64::try_from(ad.len()).map_err(|_| UnknownCryptoError)? > A_MAX {
+ return Err(UnknownCryptoError);
+ }
+ if ciphertext_with_tag.len() < TAG_SIZE {
+ return Err(UnknownCryptoError);
+ }
+ if dst_out.len() < ciphertext_with_tag.len() - TAG_SIZE {
+ return Err(UnknownCryptoError);
+ }
+
+ let mut blake2b = Blake2b::new(32)?;
+ blake2b.update(secret_key.unprotected_as_bytes())?;
+ blake2b.update(nonce.as_ref())?;
+ blake2b.update(ad)?;
+
+ let (subkey, ietf_nonce) = subkey_and_nonce(secret_key, nonce);
+ let mut dec_ctx =
+ ChaCha20::new(subkey.unprotected_as_bytes(), ietf_nonce.as_ref(), true).unwrap();
+ let mut tmp = Zeroizing::new([0u8; CHACHA_BLOCKSIZE]);
+ let mut auth_ctx = Poly1305::new(&poly1305_key_gen(&mut dec_ctx, &mut tmp));
+
+ let ciphertext_len = ciphertext_with_tag.len() - TAG_SIZE;
+ process_authentication(&mut auth_ctx, ad, &ciphertext_with_tag[..ciphertext_len])?;
+
+ blake2b.update(auth_ctx.finalize()?.unprotected_as_bytes())?;
+
+ util::secure_cmp(
+ blake2b.finalize()?.as_ref(),
+ &ciphertext_with_tag[ciphertext_len..],
+ )?;
+
+ if ciphertext_len != 0 {
+ dst_out[..ciphertext_len].copy_from_slice(&ciphertext_with_tag[..ciphertext_len]);
+ chacha20::xor_keystream(
+ &mut dec_ctx,
+ ENC_CTR,
+ tmp.as_mut(),
+ &mut dst_out[..ciphertext_len],
+ )?;
+ }
+
+ Ok(())
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+mod public {
+ use super::*;
+ use crate::test_framework::aead_interface::{test_diff_params_err, AeadTestRunner};
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ fn prop_aead_interface(input: Vec<u8>, ad: Vec<u8>) -> bool {
+ let secret_key = SecretKey::generate();
+ let nonce = Nonce::generate();
+ AeadTestRunner(seal, open, secret_key, nonce, &input, None, TAG_SIZE, &ad);
+ test_diff_params_err(&seal, &open, &input, TAG_SIZE);
+ true
+ }
+}
diff --git a/vendor/orion/src/hazardous/ecc/x25519.rs b/vendor/orion/src/hazardous/ecc/x25519.rs
index 4bbbbc869..806777feb 100644
--- a/vendor/orion/src/hazardous/ecc/x25519.rs
+++ b/vendor/orion/src/hazardous/ecc/x25519.rs
@@ -68,6 +68,11 @@ use core::ops::{Add, Mul, Sub};
/// Formally verified Curve25519 field arithmetic from: <https://github.com/mit-plv/fiat-crypto>.
use fiat_crypto::curve25519_64 as fiat_curve25519_u64;
+use fiat_curve25519_u64::{
+ fiat_25519_add, fiat_25519_carry, fiat_25519_carry_mul, fiat_25519_carry_scmul_121666,
+ fiat_25519_carry_square, fiat_25519_loose_field_element, fiat_25519_relax, fiat_25519_sub,
+ fiat_25519_tight_field_element,
+};
/// The size of a public key used in X25519.
pub const PUBLIC_KEY_SIZE: usize = 32;
@@ -86,9 +91,9 @@ const BASEPOINT: [u8; 32] = [
/// The result of computing a shared secret with a low order point.
const LOW_ORDER_POINT_RESULT: [u8; 32] = [0u8; 32];
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy)]
/// Represent an element in the curve field.
-struct FieldElement([u64; 5]);
+struct FieldElement(fiat_25519_tight_field_element);
impl Eq for FieldElement {}
@@ -99,15 +104,25 @@ impl PartialEq for FieldElement {
}
}
+impl core::fmt::Debug for FieldElement {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "FieldElement({:?})", &self.0 .0)
+ }
+}
+
/// The function fiat_25519_carry_mul multiplies two field elements and reduces the result.
impl Mul for FieldElement {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
- use fiat_curve25519_u64::fiat_25519_carry_mul;
+ let mut ret = fiat_25519_tight_field_element([0u64; 5]);
+ let mut self_relaxed = fiat_25519_loose_field_element([0u64; 5]);
+ let mut rhs_relaxed = fiat_25519_loose_field_element([0u64; 5]);
+
+ fiat_25519_relax(&mut self_relaxed, &self.0);
+ fiat_25519_relax(&mut rhs_relaxed, &rhs.0);
- let mut ret = [0u64; 5];
- fiat_25519_carry_mul(&mut ret, &self.0, &rhs.0);
+ fiat_25519_carry_mul(&mut ret, &self_relaxed, &rhs_relaxed);
Self(ret)
}
@@ -118,12 +133,11 @@ impl Add for FieldElement {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
- use fiat_curve25519_u64::{fiat_25519_add, fiat_25519_carry};
+ let mut ret = fiat_25519_tight_field_element([0u64; 5]);
+ let mut ret_add = fiat_25519_loose_field_element([0u64; 5]);
- let mut ret = [0u64; 5];
- fiat_25519_add(&mut ret, &self.0, &rhs.0);
- let tmp = ret;
- fiat_25519_carry(&mut ret, &tmp);
+ fiat_25519_add(&mut ret_add, &self.0, &rhs.0);
+ fiat_25519_carry(&mut ret, &ret_add);
Self(ret)
}
@@ -134,12 +148,11 @@ impl Sub for FieldElement {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
- use fiat_curve25519_u64::{fiat_25519_carry, fiat_25519_sub};
+ let mut ret = fiat_25519_tight_field_element([0u64; 5]);
+ let mut ret_sub = fiat_25519_loose_field_element([0u64; 5]);
- let mut ret = [0u64; 5];
- fiat_25519_sub(&mut ret, &self.0, &rhs.0);
- let tmp = ret;
- fiat_25519_carry(&mut ret, &tmp);
+ fiat_25519_sub(&mut ret_sub, &self.0, &rhs.0);
+ fiat_25519_carry(&mut ret, &ret_sub);
Self(ret)
}
@@ -148,12 +161,16 @@ impl Sub for FieldElement {
impl FieldElement {
/// Create a `FieldElement` that is `0`.
fn zero() -> Self {
- Self([0u64, 0u64, 0u64, 0u64, 0u64])
+ Self(fiat_25519_tight_field_element([
+ 0u64, 0u64, 0u64, 0u64, 0u64,
+ ]))
}
/// Create a `FieldElement` that is `1`.
fn one() -> Self {
- Self([1u64, 0u64, 0u64, 0u64, 0u64])
+ Self(fiat_25519_tight_field_element([
+ 1u64, 0u64, 0u64, 0u64, 0u64,
+ ]))
}
/// Serialize the `FieldElement` as a byte-array.
@@ -179,7 +196,7 @@ impl FieldElement {
temp[31] &= 127u8; // See RFC: "When receiving such an array, implementations of X25519
// (but not X448) MUST mask the most significant bit in the final byte."
- let mut ret = [0u64; 5];
+ let mut ret = fiat_25519_tight_field_element([0u64; 5]);
fiat_25519_from_bytes(&mut ret, &temp);
Self(ret)
@@ -196,26 +213,28 @@ impl FieldElement {
let tmp_a = *a;
let tmp_b = *b;
- fiat_25519_selectznz(&mut a.0, swap, &tmp_a.0, &tmp_b.0);
- fiat_25519_selectznz(&mut b.0, swap, &tmp_b.0, &tmp_a.0);
+ fiat_25519_selectznz(&mut a.0 .0, swap, &tmp_a.0 .0, &tmp_b.0 .0);
+ fiat_25519_selectznz(&mut b.0 .0, swap, &tmp_b.0 .0, &tmp_a.0 .0);
}
/// Square the `FieldElement` and reduce the result.
fn square(&self) -> Self {
- use fiat_curve25519_u64::fiat_25519_carry_square;
+ let mut self_relaxed = fiat_25519_loose_field_element([0u64; 5]);
+ let mut ret = fiat_25519_tight_field_element([0u64; 5]);
- let mut ret = [0u64; 5];
- fiat_25519_carry_square(&mut ret, &self.0);
+ fiat_25519_relax(&mut self_relaxed, &self.0);
+ fiat_25519_carry_square(&mut ret, &self_relaxed);
Self(ret)
}
/// Multiply the `FieldElement` by 121666 and reduce the result.
fn mul_121666(&self) -> Self {
- use fiat_curve25519_u64::fiat_25519_carry_scmul_121666;
+ let mut self_relaxed = fiat_25519_loose_field_element([0u64; 5]);
+ let mut ret = fiat_25519_tight_field_element([0u64; 5]);
- let mut ret = [0u64; 5];
- fiat_25519_carry_scmul_121666(&mut ret, &self.0);
+ fiat_25519_relax(&mut self_relaxed, &self.0);
+ fiat_25519_carry_scmul_121666(&mut ret, &self_relaxed);
Self(ret)
}
diff --git a/vendor/orion/src/hazardous/hash/mod.rs b/vendor/orion/src/hazardous/hash/mod.rs
index ad3ac155e..01b04c22f 100644
--- a/vendor/orion/src/hazardous/hash/mod.rs
+++ b/vendor/orion/src/hazardous/hash/mod.rs
@@ -23,5 +23,8 @@
/// SHA2 as specified in the [FIPS PUB 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).
pub mod sha2;
+/// SHA3 as specified in the [FIPS PUB 202](https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf).
+pub mod sha3;
+
/// BLAKE2 hash functions.
pub mod blake2;
diff --git a/vendor/orion/src/hazardous/hash/sha2/sha256.rs b/vendor/orion/src/hazardous/hash/sha2/sha256.rs
index 737660715..720d8053d 100644
--- a/vendor/orion/src/hazardous/hash/sha2/sha256.rs
+++ b/vendor/orion/src/hazardous/hash/sha2/sha256.rs
@@ -89,7 +89,7 @@ use super::w32::WordU32;
/// SHA256 streaming state.
pub(crate) struct V256;
-impl Variant<WordU32, { N_CONSTS }> for V256 {
+impl Variant<WordU32, N_CONSTS> for V256 {
#[rustfmt::skip]
#[allow(clippy::unreadable_literal)]
/// The SHA256 constants as defined in FIPS 180-4.
@@ -144,7 +144,7 @@ impl Variant<WordU32, { N_CONSTS }> for V256 {
#[derive(Clone, Debug)]
/// SHA256 streaming state.
pub struct Sha256 {
- pub(crate) _state: State<WordU32, V256, { SHA256_BLOCKSIZE }, { SHA256_OUTSIZE }, { N_CONSTS }>,
+ pub(crate) _state: State<WordU32, V256, SHA256_BLOCKSIZE, SHA256_OUTSIZE, N_CONSTS>,
}
impl Default for Sha256 {
@@ -157,9 +157,7 @@ impl Sha256 {
/// Initialize a `Sha256` struct.
pub fn new() -> Self {
Self {
- _state:
- State::<WordU32, V256, { SHA256_BLOCKSIZE }, { SHA256_OUTSIZE }, { N_CONSTS }>::_new(
- ),
+ _state: State::<WordU32, V256, SHA256_BLOCKSIZE, SHA256_OUTSIZE, N_CONSTS>::_new(),
}
}
diff --git a/vendor/orion/src/hazardous/hash/sha2/sha384.rs b/vendor/orion/src/hazardous/hash/sha2/sha384.rs
index e4df99d7a..c0430512e 100644
--- a/vendor/orion/src/hazardous/hash/sha2/sha384.rs
+++ b/vendor/orion/src/hazardous/hash/sha2/sha384.rs
@@ -88,7 +88,7 @@ const N_CONSTS: usize = 80;
#[derive(Clone)]
pub(crate) struct V384;
-impl Variant<WordU64, { N_CONSTS }> for V384 {
+impl Variant<WordU64, N_CONSTS> for V384 {
/// The SHA384 constants as defined in FIPS 180-4.
const K: [WordU64; N_CONSTS] = super::sha512::V512::K;
@@ -124,7 +124,7 @@ impl Variant<WordU64, { N_CONSTS }> for V384 {
#[derive(Clone, Debug)]
/// SHA384 streaming state.
pub struct Sha384 {
- pub(crate) _state: State<WordU64, V384, { SHA384_BLOCKSIZE }, { SHA384_OUTSIZE }, { N_CONSTS }>,
+ pub(crate) _state: State<WordU64, V384, SHA384_BLOCKSIZE, SHA384_OUTSIZE, N_CONSTS>,
}
impl Default for Sha384 {
@@ -137,9 +137,7 @@ impl Sha384 {
/// Initialize a `Sha384` struct.
pub fn new() -> Self {
Self {
- _state:
- State::<WordU64, V384, { SHA384_BLOCKSIZE }, { SHA384_OUTSIZE }, { N_CONSTS }>::_new(
- ),
+ _state: State::<WordU64, V384, SHA384_BLOCKSIZE, SHA384_OUTSIZE, N_CONSTS>::_new(),
}
}
diff --git a/vendor/orion/src/hazardous/hash/sha2/sha512.rs b/vendor/orion/src/hazardous/hash/sha2/sha512.rs
index f582f78c2..0e865c57d 100644
--- a/vendor/orion/src/hazardous/hash/sha2/sha512.rs
+++ b/vendor/orion/src/hazardous/hash/sha2/sha512.rs
@@ -88,7 +88,7 @@ const N_CONSTS: usize = 80;
#[derive(Clone)]
pub(crate) struct V512;
-impl Variant<WordU64, { N_CONSTS }> for V512 {
+impl Variant<WordU64, N_CONSTS> for V512 {
#[rustfmt::skip]
#[allow(clippy::unreadable_literal)]
/// The SHA512 constants as defined in FIPS 180-4.
@@ -147,7 +147,7 @@ impl Variant<WordU64, { N_CONSTS }> for V512 {
#[derive(Clone, Debug)]
/// SHA512 streaming state.
pub struct Sha512 {
- pub(crate) _state: State<WordU64, V512, { SHA512_BLOCKSIZE }, { SHA512_OUTSIZE }, { N_CONSTS }>,
+ pub(crate) _state: State<WordU64, V512, SHA512_BLOCKSIZE, SHA512_OUTSIZE, N_CONSTS>,
}
impl Default for Sha512 {
@@ -160,9 +160,7 @@ impl Sha512 {
/// Initialize a `Sha512` struct.
pub fn new() -> Self {
Self {
- _state:
- State::<WordU64, V512, { SHA512_BLOCKSIZE }, { SHA512_OUTSIZE }, { N_CONSTS }>::_new(
- ),
+ _state: State::<WordU64, V512, SHA512_BLOCKSIZE, SHA512_OUTSIZE, N_CONSTS>::_new(),
}
}
diff --git a/vendor/orion/src/hazardous/hash/sha3/mod.rs b/vendor/orion/src/hazardous/hash/sha3/mod.rs
new file mode 100644
index 000000000..28be25deb
--- /dev/null
+++ b/vendor/orion/src/hazardous/hash/sha3/mod.rs
@@ -0,0 +1,558 @@
+// MIT License
+
+// Copyright (c) 2023 The orion Developers
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+/// SHA3-224 as specified in the [FIPS PUB 202](https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf).
+pub mod sha3_224;
+
+/// SHA3-256 as specified in the [FIPS PUB 202](https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf).
+pub mod sha3_256;
+
+/// SHA3-384 as specified in the [FIPS PUB 202](https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf).
+pub mod sha3_384;
+
+/// SHA3-512 as specified in the [FIPS PUB 202](https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf).
+pub mod sha3_512;
+
+use crate::errors::UnknownCryptoError;
+use core::fmt::Debug;
+use zeroize::Zeroize;
+
+/// Round constants. See NIST intermediate test vectors for source.
+const RC: [u64; 24] = [
+ 0x0000000000000001,
+ 0x0000000000008082,
+ 0x800000000000808A,
+ 0x8000000080008000,
+ 0x000000000000808B,
+ 0x0000000080000001,
+ 0x8000000080008081,
+ 0x8000000000008009,
+ 0x000000000000008A,
+ 0x0000000000000088,
+ 0x0000000080008009,
+ 0x000000008000000A,
+ 0x000000008000808B,
+ 0x800000000000008B,
+ 0x8000000000008089,
+ 0x8000000000008003,
+ 0x8000000000008002,
+ 0x8000000000000080,
+ 0x000000000000800A,
+ 0x800000008000000A,
+ 0x8000000080008081,
+ 0x8000000000008080,
+ 0x0000000080000001,
+ 0x8000000080008008,
+];
+
+/// Rho offsets. See NIST intermediate test vectors for source.
+const RHO: [u32; 24] = [
+ 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
+];
+
+/// Indices precomputed based on spec of Pi.
+const PI: [usize; 24] = [
+ 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
+];
+
+fn keccakf<const ROUNDS: usize>(state: &mut [u64; 25]) {
+ for round in 0..ROUNDS {
+ let mut buf = [0u64; 5];
+
+ theta(state, &mut buf);
+ rho_and_pi(state, &mut buf);
+ chi(state, &mut buf);
+ iota(state, round);
+ }
+}
+
+#[allow(clippy::erasing_op)]
+#[allow(clippy::identity_op)]
+// Theta (θ).
+fn theta(state: &mut [u64; 25], buf: &mut [u64; 5]) {
+ buf[0] ^= state[0 + (0 * 5)];
+ buf[0] ^= state[0 + (1 * 5)];
+ buf[0] ^= state[0 + (2 * 5)];
+ buf[0] ^= state[0 + (3 * 5)];
+ buf[0] ^= state[0 + (4 * 5)];
+
+ buf[1] ^= state[1 + (0 * 5)];
+ buf[1] ^= state[1 + (1 * 5)];
+ buf[1] ^= state[1 + (2 * 5)];
+ buf[1] ^= state[1 + (3 * 5)];
+ buf[1] ^= state[1 + (4 * 5)];
+
+ buf[2] ^= state[2 + (0 * 5)];
+ buf[2] ^= state[2 + (1 * 5)];
+ buf[2] ^= state[2 + (2 * 5)];
+ buf[2] ^= state[2 + (3 * 5)];
+ buf[2] ^= state[2 + (4 * 5)];
+
+ buf[3] ^= state[3 + (0 * 5)];
+ buf[3] ^= state[3 + (1 * 5)];
+ buf[3] ^= state[3 + (2 * 5)];
+ buf[3] ^= state[3 + (3 * 5)];
+ buf[3] ^= state[3 + (4 * 5)];
+
+ buf[4] ^= state[4 + (0 * 5)];
+ buf[4] ^= state[4 + (1 * 5)];
+ buf[4] ^= state[4 + (2 * 5)];
+ buf[4] ^= state[4 + (3 * 5)];
+ buf[4] ^= state[4 + (4 * 5)];
+
+ state[(0 * 5) + 0] ^= buf[(0 + 4) % 5] ^ buf[(0 + 1) % 5].rotate_left(1);
+ state[(1 * 5) + 0] ^= buf[(0 + 4) % 5] ^ buf[(0 + 1) % 5].rotate_left(1);
+ state[(2 * 5) + 0] ^= buf[(0 + 4) % 5] ^ buf[(0 + 1) % 5].rotate_left(1);
+ state[(3 * 5) + 0] ^= buf[(0 + 4) % 5] ^ buf[(0 + 1) % 5].rotate_left(1);
+ state[(4 * 5) + 0] ^= buf[(0 + 4) % 5] ^ buf[(0 + 1) % 5].rotate_left(1);
+
+ state[(0 * 5) + 1] ^= buf[(1 + 4) % 5] ^ buf[(1 + 1) % 5].rotate_left(1);
+ state[(1 * 5) + 1] ^= buf[(1 + 4) % 5] ^ buf[(1 + 1) % 5].rotate_left(1);
+ state[(2 * 5) + 1] ^= buf[(1 + 4) % 5] ^ buf[(1 + 1) % 5].rotate_left(1);
+ state[(3 * 5) + 1] ^= buf[(1 + 4) % 5] ^ buf[(1 + 1) % 5].rotate_left(1);
+ state[(4 * 5) + 1] ^= buf[(1 + 4) % 5] ^ buf[(1 + 1) % 5].rotate_left(1);
+
+ state[(0 * 5) + 2] ^= buf[(2 + 4) % 5] ^ buf[(2 + 1) % 5].rotate_left(1);
+ state[(1 * 5) + 2] ^= buf[(2 + 4) % 5] ^ buf[(2 + 1) % 5].rotate_left(1);
+ state[(2 * 5) + 2] ^= buf[(2 + 4) % 5] ^ buf[(2 + 1) % 5].rotate_left(1);
+ state[(3 * 5) + 2] ^= buf[(2 + 4) % 5] ^ buf[(2 + 1) % 5].rotate_left(1);
+ state[(4 * 5) + 2] ^= buf[(2 + 4) % 5] ^ buf[(2 + 1) % 5].rotate_left(1);
+
+ state[(0 * 5) + 3] ^= buf[(3 + 4) % 5] ^ buf[(3 + 1) % 5].rotate_left(1);
+ state[(1 * 5) + 3] ^= buf[(3 + 4) % 5] ^ buf[(3 + 1) % 5].rotate_left(1);
+ state[(2 * 5) + 3] ^= buf[(3 + 4) % 5] ^ buf[(3 + 1) % 5].rotate_left(1);
+ state[(3 * 5) + 3] ^= buf[(3 + 4) % 5] ^ buf[(3 + 1) % 5].rotate_left(1);
+ state[(4 * 5) + 3] ^= buf[(3 + 4) % 5] ^ buf[(3 + 1) % 5].rotate_left(1);
+
+ state[(0 * 5) + 4] ^= buf[(4 + 4) % 5] ^ buf[(4 + 1) % 5].rotate_left(1);
+ state[(1 * 5) + 4] ^= buf[(4 + 4) % 5] ^ buf[(4 + 1) % 5].rotate_left(1);
+ state[(2 * 5) + 4] ^= buf[(4 + 4) % 5] ^ buf[(4 + 1) % 5].rotate_left(1);
+ state[(3 * 5) + 4] ^= buf[(4 + 4) % 5] ^ buf[(4 + 1) % 5].rotate_left(1);
+ state[(4 * 5) + 4] ^= buf[(4 + 4) % 5] ^ buf[(4 + 1) % 5].rotate_left(1);
+}
+
+// Rho (ρ) & Pi (π).
+fn rho_and_pi(state: &mut [u64; 25], buf: &mut [u64; 5]) {
+ let mut prev = state[1];
+
+ buf[0] = state[PI[0]];
+ state[PI[0]] = prev.rotate_left(RHO[0]);
+ prev = buf[0];
+
+ buf[0] = state[PI[1]];
+ state[PI[1]] = prev.rotate_left(RHO[1]);
+ prev = buf[0];
+
+ buf[0] = state[PI[2]];
+ state[PI[2]] = prev.rotate_left(RHO[2]);
+ prev = buf[0];
+
+ buf[0] = state[PI[3]];
+ state[PI[3]] = prev.rotate_left(RHO[3]);
+ prev = buf[0];
+
+ buf[0] = state[PI[4]];
+ state[PI[4]] = prev.rotate_left(RHO[4]);
+ prev = buf[0];
+
+ buf[0] = state[PI[5]];
+ state[PI[5]] = prev.rotate_left(RHO[5]);
+ prev = buf[0];
+
+ buf[0] = state[PI[6]];
+ state[PI[6]] = prev.rotate_left(RHO[6]);
+ prev = buf[0];
+
+ buf[0] = state[PI[7]];
+ state[PI[7]] = prev.rotate_left(RHO[7]);
+ prev = buf[0];
+
+ buf[0] = state[PI[8]];
+ state[PI[8]] = prev.rotate_left(RHO[8]);
+ prev = buf[0];
+
+ buf[0] = state[PI[9]];
+ state[PI[9]] = prev.rotate_left(RHO[9]);
+ prev = buf[0];
+
+ buf[0] = state[PI[10]];
+ state[PI[10]] = prev.rotate_left(RHO[10]);
+ prev = buf[0];
+
+ buf[0] = state[PI[11]];
+ state[PI[11]] = prev.rotate_left(RHO[11]);
+ prev = buf[0];
+
+ buf[0] = state[PI[12]];
+ state[PI[12]] = prev.rotate_left(RHO[12]);
+ prev = buf[0];
+
+ buf[0] = state[PI[13]];
+ state[PI[13]] = prev.rotate_left(RHO[13]);
+ prev = buf[0];
+
+ buf[0] = state[PI[14]];
+ state[PI[14]] = prev.rotate_left(RHO[14]);
+ prev = buf[0];
+
+ buf[0] = state[PI[15]];
+ state[PI[15]] = prev.rotate_left(RHO[15]);
+ prev = buf[0];
+
+ buf[0] = state[PI[16]];
+ state[PI[16]] = prev.rotate_left(RHO[16]);
+ prev = buf[0];
+
+ buf[0] = state[PI[17]];
+ state[PI[17]] = prev.rotate_left(RHO[17]);
+ prev = buf[0];
+
+ buf[0] = state[PI[18]];
+ state[PI[18]] = prev.rotate_left(RHO[18]);
+ prev = buf[0];
+
+ buf[0] = state[PI[19]];
+ state[PI[19]] = prev.rotate_left(RHO[19]);
+ prev = buf[0];
+
+ buf[0] = state[PI[20]];
+ state[PI[20]] = prev.rotate_left(RHO[20]);
+ prev = buf[0];
+
+ buf[0] = state[PI[21]];
+ state[PI[21]] = prev.rotate_left(RHO[21]);
+ prev = buf[0];
+
+ buf[0] = state[PI[22]];
+ state[PI[22]] = prev.rotate_left(RHO[22]);
+ prev = buf[0];
+
+ buf[0] = state[PI[23]];
+ state[PI[23]] = prev.rotate_left(RHO[23]);
+}
+
+#[allow(clippy::identity_op)]
+// Chi (χ).
+fn chi(state: &mut [u64; 25], buf: &mut [u64; 5]) {
+ buf[0] = state[0 + 0];
+ buf[1] = state[0 + 1];
+ buf[2] = state[0 + 2];
+ buf[3] = state[0 + 3];
+ buf[4] = state[0 + 4];
+
+ state[0 + 0] = buf[0] ^ ((!buf[(0 + 1) % 5]) & (buf[(0 + 2) % 5]));
+ state[0 + 1] = buf[1] ^ ((!buf[(1 + 1) % 5]) & (buf[(1 + 2) % 5]));
+ state[0 + 2] = buf[2] ^ ((!buf[(2 + 1) % 5]) & (buf[(2 + 2) % 5]));
+ state[0 + 3] = buf[3] ^ ((!buf[(3 + 1) % 5]) & (buf[(3 + 2) % 5]));
+ state[0 + 4] = buf[4] ^ ((!buf[(4 + 1) % 5]) & (buf[(4 + 2) % 5]));
+
+ buf[0] = state[5 + 0];
+ buf[1] = state[5 + 1];
+ buf[2] = state[5 + 2];
+ buf[3] = state[5 + 3];
+ buf[4] = state[5 + 4];
+
+ state[5 + 0] = buf[0] ^ ((!buf[(0 + 1) % 5]) & (buf[(0 + 2) % 5]));
+ state[5 + 1] = buf[1] ^ ((!buf[(1 + 1) % 5]) & (buf[(1 + 2) % 5]));
+ state[5 + 2] = buf[2] ^ ((!buf[(2 + 1) % 5]) & (buf[(2 + 2) % 5]));
+ state[5 + 3] = buf[3] ^ ((!buf[(3 + 1) % 5]) & (buf[(3 + 2) % 5]));
+ state[5 + 4] = buf[4] ^ ((!buf[(4 + 1) % 5]) & (buf[(4 + 2) % 5]));
+
+ buf[0] = state[10 + 0];
+ buf[1] = state[10 + 1];
+ buf[2] = state[10 + 2];
+ buf[3] = state[10 + 3];
+ buf[4] = state[10 + 4];
+
+ state[10 + 0] = buf[0] ^ ((!buf[(0 + 1) % 5]) & (buf[(0 + 2) % 5]));
+ state[10 + 1] = buf[1] ^ ((!buf[(1 + 1) % 5]) & (buf[(1 + 2) % 5]));
+ state[10 + 2] = buf[2] ^ ((!buf[(2 + 1) % 5]) & (buf[(2 + 2) % 5]));
+ state[10 + 3] = buf[3] ^ ((!buf[(3 + 1) % 5]) & (buf[(3 + 2) % 5]));
+ state[10 + 4] = buf[4] ^ ((!buf[(4 + 1) % 5]) & (buf[(4 + 2) % 5]));
+
+ buf[0] = state[15 + 0];
+ buf[1] = state[15 + 1];
+ buf[2] = state[15 + 2];
+ buf[3] = state[15 + 3];
+ buf[4] = state[15 + 4];
+
+ state[15 + 0] = buf[0] ^ ((!buf[(0 + 1) % 5]) & (buf[(0 + 2) % 5]));
+ state[15 + 1] = buf[1] ^ ((!buf[(1 + 1) % 5]) & (buf[(1 + 2) % 5]));
+ state[15 + 2] = buf[2] ^ ((!buf[(2 + 1) % 5]) & (buf[(2 + 2) % 5]));
+ state[15 + 3] = buf[3] ^ ((!buf[(3 + 1) % 5]) & (buf[(3 + 2) % 5]));
+ state[15 + 4] = buf[4] ^ ((!buf[(4 + 1) % 5]) & (buf[(4 + 2) % 5]));
+
+ buf[0] = state[20 + 0];
+ buf[1] = state[20 + 1];
+ buf[2] = state[20 + 2];
+ buf[3] = state[20 + 3];
+ buf[4] = state[20 + 4];
+
+ state[20 + 0] = buf[0] ^ ((!buf[(0 + 1) % 5]) & (buf[(0 + 2) % 5]));
+ state[20 + 1] = buf[1] ^ ((!buf[(1 + 1) % 5]) & (buf[(1 + 2) % 5]));
+ state[20 + 2] = buf[2] ^ ((!buf[(2 + 1) % 5]) & (buf[(2 + 2) % 5]));
+ state[20 + 3] = buf[3] ^ ((!buf[(3 + 1) % 5]) & (buf[(3 + 2) % 5]));
+ state[20 + 4] = buf[4] ^ ((!buf[(4 + 1) % 5]) & (buf[(4 + 2) % 5]));
+}
+
+// Iota (ι).
+fn iota(state: &mut [u64; 25], round: usize) {
+ debug_assert!(round <= 24);
+ state[0] ^= RC[round];
+}
+
+// <https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KeccakF-1600-IntermediateValues.txt>
+#[test]
+fn test_full_round() {
+ let mut state = [0u64; 25];
+ let expected_state_from_zero = [
+ 0xF1258F7940E1DDE7,
+ 0x84D5CCF933C0478A,
+ 0xD598261EA65AA9EE,
+ 0xBD1547306F80494D,
+ 0x8B284E056253D057,
+ 0xFF97A42D7F8E6FD4,
+ 0x90FEE5A0A44647C4,
+ 0x8C5BDA0CD6192E76,
+ 0xAD30A6F71B19059C,
+ 0x30935AB7D08FFC64,
+ 0xEB5AA93F2317D635,
+ 0xA9A6E6260D712103,
+ 0x81A57C16DBCF555F,
+ 0x43B831CD0347C826,
+ 0x01F22F1A11A5569F,
+ 0x05E5635A21D9AE61,
+ 0x64BEFEF28CC970F2,
+ 0x613670957BC46611,
+ 0xB87C5A554FD00ECB,
+ 0x8C3EE88A1CCF32C8,
+ 0x940C7922AE3A2614,
+ 0x1841F924A2C509E4,
+ 0x16F53526E70465C2,
+ 0x75F644E97F30A13B,
+ 0xEAF1FF7B5CECA249,
+ ];
+ let expected_state_rerun = [
+ 0x2D5C954DF96ECB3C,
+ 0x6A332CD07057B56D,
+ 0x093D8D1270D76B6C,
+ 0x8A20D9B25569D094,
+ 0x4F9C4F99E5E7F156,
+ 0xF957B9A2DA65FB38,
+ 0x85773DAE1275AF0D,
+ 0xFAF4F247C3D810F7,
+ 0x1F1B9EE6F79A8759,
+ 0xE4FECC0FEE98B425,
+ 0x68CE61B6B9CE68A1,
+ 0xDEEA66C4BA8F974F,
+ 0x33C43D836EAFB1F5,
+ 0xE00654042719DBD9,
+ 0x7CF8A9F009831265,
+ 0xFD5449A6BF174743,
+ 0x97DDAD33D8994B40,
+ 0x48EAD5FC5D0BE774,
+ 0xE3B8C8EE55B7B03C,
+ 0x91A0226E649E42E9,
+ 0x900E3129E7BADD7B,
+ 0x202A9EC5FAA3CCE8,
+ 0x5B3402464E1C3DB6,
+ 0x609F4E62A44C1059,
+ 0x20D06CD26A8FBF5C,
+ ];
+
+ keccakf::<24>(&mut state);
+ assert_eq!(&state, &expected_state_from_zero);
+ keccakf::<24>(&mut state);
+ assert_eq!(&state, &expected_state_rerun);
+}
+
+#[derive(Clone)]
+/// SHA3 streaming state.
+pub(crate) struct Sha3<const RATE: usize> {
+ pub(crate) state: [u64; 25],
+ pub(crate) buffer: [u8; RATE],
+ pub(crate) capacity: usize,
+ leftover: usize,
+ is_finalized: bool,
+}
+
+impl<const RATE: usize> Drop for Sha3<RATE> {
+ fn drop(&mut self) {
+ self.state.iter_mut().zeroize();
+ self.buffer.iter_mut().zeroize();
+ self.leftover.zeroize();
+ }
+}
+
+impl<const RATE: usize> Debug for Sha3<RATE> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(
+ f,
+ "State {{ state: [***OMITTED***], buffer: [***OMITTED***], capacity: {:?}, leftover: {:?}, \
+ is_finalized: {:?} }}",
+ self.capacity, self.leftover, self.is_finalized
+ )
+ }
+}
+
+impl<const RATE: usize> Sha3<RATE> {
+ /// Initialize a new state.
+ /// `capacity` should be in bytes.
+ pub(crate) fn _new(capacity: usize) -> Self {
+ Self {
+ state: [0u64; 25],
+ buffer: [0u8; RATE],
+ capacity,
+ leftover: 0,
+ is_finalized: false,
+ }
+ }
+
+ /// Process data in `self.buffer` or optionally `data`.
+ pub(crate) fn process_block(&mut self, data: Option<&[u8]>) {
+ // If `data.is_none()` then we want to process leftover data within `self.buffer`.
+ let data_block = match data {
+ Some(bytes) => {
+ debug_assert_eq!(bytes.len(), RATE);
+ bytes
+ }
+ None => &self.buffer,
+ };
+
+ debug_assert_eq!(data_block.len() % 8, 0);
+
+ // We process data in terms of bitrate, but we need to XOR in an entire Keccak state.
+ // So the 25 - bitrate values will be zero. That's the same as not XORing those values
+ // so we leave it be as this.
+ for (b, s) in data_block
+ .chunks_exact(core::mem::size_of::<u64>())
+ .zip(self.state.iter_mut())
+ {
+ *s ^= u64::from_le_bytes(b.try_into().unwrap());
+ }
+
+ keccakf::<24>(&mut self.state);
+ }
+
+ /// Reset to `new()` state.
+ pub(crate) fn _reset(&mut self) {
+ self.state = [0u64; 25];
+ self.buffer = [0u8; RATE];
+ self.leftover = 0;
+ self.is_finalized = false;
+ }
+
+ /// Update state with `data`. This can be called multiple times.
+ pub(crate) fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ if self.is_finalized {
+ return Err(UnknownCryptoError);
+ }
+ if data.is_empty() {
+ return Ok(());
+ }
+
+ let mut bytes = data;
+
+ if self.leftover != 0 {
+ debug_assert!(self.leftover <= RATE);
+
+ let mut want = RATE - self.leftover;
+ if want > bytes.len() {
+ want = bytes.len();
+ }
+
+ for (idx, itm) in bytes.iter().enumerate().take(want) {
+ self.buffer[self.leftover + idx] = *itm;
+ }
+
+ bytes = &bytes[want..];
+ self.leftover += want;
+
+ if self.leftover < RATE {
+ return Ok(());
+ }
+
+ self.process_block(None);
+ self.leftover = 0;
+ }
+
+ while bytes.len() >= RATE {
+ self.process_block(Some(bytes[..RATE].as_ref()));
+ bytes = &bytes[RATE..];
+ }
+
+ if !bytes.is_empty() {
+ debug_assert_eq!(self.leftover, 0);
+ self.buffer[..bytes.len()].copy_from_slice(bytes);
+ self.leftover = bytes.len();
+ }
+
+ Ok(())
+ }
+
+ /// Finalize the hash and put the final digest into `dest`.
+ pub(crate) fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ if self.is_finalized {
+ return Err(UnknownCryptoError);
+ }
+
+ self.is_finalized = true;
+ // self.leftover should not be greater than SHA3(256/384/512)_RATE
+ // as that would have been processed in the update call
+ debug_assert!(self.leftover < RATE);
+ // Set padding byte and pad with zeroes after
+ self.buffer[self.leftover] = 0x06;
+ self.leftover += 1;
+ for itm in self.buffer.iter_mut().skip(self.leftover) {
+ *itm = 0;
+ }
+
+ self.buffer[self.buffer.len() - 1] |= 0x80;
+ self.process_block(None);
+
+ // The reason we can't work with chunks_exact here is that for SHA3-224
+ // the `dest` is not evenly divisible by 8/`core::mem::size_of::<u64>()`.
+ for (out_chunk, state_value) in dest
+ .chunks_mut(core::mem::size_of::<u64>())
+ .zip(self.state.iter())
+ {
+ // We need to slice the state value in bytes here for same reason as mentioned
+ // above.
+ out_chunk.copy_from_slice(&state_value.to_le_bytes()[..out_chunk.len()]);
+ }
+
+ Ok(())
+ }
+
+ #[cfg(test)]
+ /// Compare two Sha3 state objects to check if their fields
+ /// are the same.
+ pub(crate) fn compare_state_to_other(&self, other: &Self) {
+ for idx in 0..25 {
+ assert_eq!(self.state[idx], other.state[idx]);
+ }
+ assert_eq!(self.buffer, other.buffer);
+ assert_eq!(self.capacity, other.capacity);
+ assert_eq!(self.leftover, other.leftover);
+ assert_eq!(self.is_finalized, other.is_finalized);
+ }
+}
diff --git a/vendor/orion/src/hazardous/hash/sha3/sha3_224.rs b/vendor/orion/src/hazardous/hash/sha3/sha3_224.rs
new file mode 100644
index 000000000..e235f2b65
--- /dev/null
+++ b/vendor/orion/src/hazardous/hash/sha3/sha3_224.rs
@@ -0,0 +1,274 @@
+// MIT License
+
+// Copyright (c) 2023 The orion Developers
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! # Parameters:
+//! - `data`: The data to be hashed.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - [`finalize()`] is called twice without a [`reset()`] in between.
+//! - [`update()`] is called after [`finalize()`] without a [`reset()`] in
+//! between.
+//!
+//! # Example:
+//! ```rust
+//! use orion::hazardous::hash::sha3::sha3_224::Sha3_224;
+//!
+//! // Using the streaming interface
+//! let mut state = Sha3_224::new();
+//! state.update(b"Hello world")?;
+//! let hash = state.finalize()?;
+//!
+//! // Using the one-shot function
+//! let hash_one_shot = Sha3_224::digest(b"Hello world")?;
+//!
+//! assert_eq!(hash, hash_one_shot);
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`update()`]: sha3_224::Sha3_224::update
+//! [`reset()`]: sha3_224::Sha3_224::reset
+//! [`finalize()`]: sha3_224::Sha3_224::finalize
+
+use crate::errors::UnknownCryptoError;
+#[cfg(feature = "safe_api")]
+use std::io;
+
+use super::Sha3;
+
+/// Rate of SHA3-224 (equivalent to blocksize in SHA2).
+pub const SHA3_224_RATE: usize = 144;
+
+/// Output size of SHA3-224 in bytes.
+pub const SHA3_224_OUTSIZE: usize = 28;
+
+construct_public! {
+ /// A type to represent the `Digest` that SHA3-224 returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 28 bytes.
+ (Digest, test_digest, SHA3_224_OUTSIZE, SHA3_224_OUTSIZE)
+}
+
+impl_from_trait!(Digest, SHA3_224_OUTSIZE);
+
+#[derive(Clone, Debug)]
+/// SHA3-224 streaming state.
+pub struct Sha3_224 {
+ pub(crate) _state: Sha3<SHA3_224_RATE>,
+}
+
+impl Default for Sha3_224 {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+/// Example: hashing from a [`Read`](std::io::Read)er with SHA3-224.
+/// ```rust
+/// use orion::{
+/// hazardous::hash::sha3::sha3_224::{Sha3_224, Digest},
+/// errors::UnknownCryptoError,
+/// };
+/// use std::io::{self, Read, Write};
+///
+/// // `reader` could also be a `File::open(...)?`.
+/// let mut reader = io::Cursor::new(b"some data");
+/// let mut hasher = Sha3_224::new();
+/// std::io::copy(&mut reader, &mut hasher)?;
+///
+/// let digest: Digest = hasher.finalize()?;
+///
+/// # Ok::<(), Box<dyn std::error::Error>>(())
+/// ```
+#[cfg(feature = "safe_api")]
+impl io::Write for Sha3_224 {
+ /// Update the hasher's internal state with *all* of the bytes given.
+ /// If this function returns the `Ok` variant, it's guaranteed that it
+ /// will contain the length of the buffer passed to [`Write`](std::io::Write).
+ /// Note that this function is just a small wrapper over
+ /// [`Sha3_224::update`](crate::hazardous::hash::sha3::sha3_224::Sha3_224::update).
+ ///
+ /// ## Errors:
+ /// This function will only ever return the [`std::io::ErrorKind::Other`]()
+ /// variant when it returns an error. Additionally, this will always contain Orion's
+ /// [`UnknownCryptoError`](crate::errors::UnknownCryptoError) type.
+ fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
+ self.update(bytes)
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
+ Ok(bytes.len())
+ }
+
+ /// This type doesn't buffer writes, so flushing is a no-op.
+ fn flush(&mut self) -> Result<(), std::io::Error> {
+ Ok(())
+ }
+}
+
+impl Sha3_224 {
+ /// Initialize a `Sha3_224` struct.
+ pub fn new() -> Self {
+ Self {
+ _state: Sha3::<SHA3_224_RATE>::_new(56),
+ }
+ }
+
+ /// Reset to `new()` state.
+ pub fn reset(&mut self) {
+ self._state._reset();
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Update state with `data`. This can be called multiple times.
+ pub fn update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ self._state._update(data)
+ }
+
+ /// Finalize the hash and put the final digest into `dest`.
+ pub(crate) fn _finalize_internal(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ self._state._finalize(dest)
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Return a SHA3-224 digest.
+ pub fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
+ let mut digest = [0u8; SHA3_224_OUTSIZE];
+ self._finalize_internal(&mut digest)?;
+
+ Ok(Digest::from(digest))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Calculate a SHA3-224 digest of some `data`.
+ pub fn digest(data: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ let mut ctx = Self::new();
+ ctx.update(data)?;
+ ctx.finalize()
+ }
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[test]
+ fn test_default_equals_new() {
+ let new = Sha3_224::new();
+ let default = Sha3_224::default();
+ new._state.compare_state_to_other(&default._state);
+ }
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let initial_state = Sha3_224::new();
+ let debug = format!("{:?}", initial_state);
+ let expected = "Sha3_224 { _state: State { state: [***OMITTED***], buffer: [***OMITTED***], capacity: 56, leftover: 0, is_finalized: false } }";
+ assert_eq!(debug, expected);
+ }
+
+ mod test_streaming_interface {
+ use super::*;
+ use crate::test_framework::incremental_interface::*;
+
+ impl TestableStreamingContext<Digest> for Sha3_224 {
+ fn reset(&mut self) -> Result<(), UnknownCryptoError> {
+ self.reset();
+ Ok(())
+ }
+
+ fn update(&mut self, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ self.update(input)
+ }
+
+ fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
+ self.finalize()
+ }
+
+ fn one_shot(input: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ Sha3_224::digest(input)
+ }
+
+ fn verify_result(expected: &Digest, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ let actual: Digest = Self::one_shot(input)?;
+
+ if &actual == expected {
+ Ok(())
+ } else {
+ Err(UnknownCryptoError)
+ }
+ }
+
+ fn compare_states(state_1: &Sha3_224, state_2: &Sha3_224) {
+ state_1._state.compare_state_to_other(&state_2._state);
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let initial_state: Sha3_224 = Sha3_224::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha3_224>::new(
+ initial_state,
+ SHA3_224_RATE,
+ );
+ test_runner.run_all_tests();
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Related bug: https://github.com/orion-rs/orion/issues/46
+ /// Test different streaming state usage patterns.
+ fn prop_input_to_consistency(data: Vec<u8>) -> bool {
+ let initial_state: Sha3_224 = Sha3_224::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha3_224>::new(
+ initial_state,
+ SHA3_224_RATE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_io_impls {
+ use crate::hazardous::hash::sha3::sha3_224::Sha3_224;
+ use std::io::Write;
+
+ #[quickcheck]
+ fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
+ let mut hasher_a = Sha3_224::new();
+ let mut hasher_b = hasher_a.clone();
+
+ hasher_a.update(&data).unwrap();
+ hasher_b.write_all(&data).unwrap();
+
+ let hash_a = hasher_a.finalize().unwrap();
+ let hash_b = hasher_b.finalize().unwrap();
+
+ hash_a == hash_b
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/hash/sha3/sha3_256.rs b/vendor/orion/src/hazardous/hash/sha3/sha3_256.rs
new file mode 100644
index 000000000..f972db988
--- /dev/null
+++ b/vendor/orion/src/hazardous/hash/sha3/sha3_256.rs
@@ -0,0 +1,336 @@
+// MIT License
+
+// Copyright (c) 2023 The orion Developers
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! # Parameters:
+//! - `data`: The data to be hashed.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - [`finalize()`] is called twice without a [`reset()`] in between.
+//! - [`update()`] is called after [`finalize()`] without a [`reset()`] in
+//! between.
+//!
+//! # Example:
+//! ```rust
+//! use orion::hazardous::hash::sha3::sha3_256::Sha3_256;
+//!
+//! // Using the streaming interface
+//! let mut state = Sha3_256::new();
+//! state.update(b"Hello world")?;
+//! let hash = state.finalize()?;
+//!
+//! // Using the one-shot function
+//! let hash_one_shot = Sha3_256::digest(b"Hello world")?;
+//!
+//! assert_eq!(hash, hash_one_shot);
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`update()`]: sha3_256::Sha3_256::update
+//! [`reset()`]: sha3_256::Sha3_256::reset
+//! [`finalize()`]: sha3_256::Sha3_256::finalize
+
+use crate::errors::UnknownCryptoError;
+#[cfg(feature = "safe_api")]
+use std::io;
+
+use super::Sha3;
+
+/// Rate of SHA3-256 (equivalent to blocksize in SHA2).
+pub const SHA3_256_RATE: usize = 136;
+
+/// Output size of SHA3-256 in bytes.
+pub const SHA3_256_OUTSIZE: usize = 32;
+
+construct_public! {
+ /// A type to represent the `Digest` that SHA3-256 returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 32 bytes.
+ (Digest, test_digest, SHA3_256_OUTSIZE, SHA3_256_OUTSIZE)
+}
+
+impl_from_trait!(Digest, SHA3_256_OUTSIZE);
+
+#[derive(Clone, Debug)]
+/// SHA3-256 streaming state.
+pub struct Sha3_256 {
+ pub(crate) _state: Sha3<SHA3_256_RATE>,
+}
+
+impl Default for Sha3_256 {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+/// Example: hashing from a [`Read`](std::io::Read)er with SHA3-256.
+/// ```rust
+/// use orion::{
+/// hazardous::hash::sha3::sha3_256::{Sha3_256, Digest},
+/// errors::UnknownCryptoError,
+/// };
+/// use std::io::{self, Read, Write};
+///
+/// // `reader` could also be a `File::open(...)?`.
+/// let mut reader = io::Cursor::new(b"some data");
+/// let mut hasher = Sha3_256::new();
+/// std::io::copy(&mut reader, &mut hasher)?;
+///
+/// let digest: Digest = hasher.finalize()?;
+///
+/// # Ok::<(), Box<dyn std::error::Error>>(())
+/// ```
+#[cfg(feature = "safe_api")]
+impl io::Write for Sha3_256 {
+ /// Update the hasher's internal state with *all* of the bytes given.
+ /// If this function returns the `Ok` variant, it's guaranteed that it
+ /// will contain the length of the buffer passed to [`Write`](std::io::Write).
+ /// Note that this function is just a small wrapper over
+ /// [`Sha3_256::update`](crate::hazardous::hash::sha3::sha3_256::Sha3_256::update).
+ ///
+ /// ## Errors:
+ /// This function will only ever return the [`std::io::ErrorKind::Other`]()
+ /// variant when it returns an error. Additionally, this will always contain Orion's
+ /// [`UnknownCryptoError`](crate::errors::UnknownCryptoError) type.
+ fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
+ self.update(bytes)
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
+ Ok(bytes.len())
+ }
+
+ /// This type doesn't buffer writes, so flushing is a no-op.
+ fn flush(&mut self) -> Result<(), std::io::Error> {
+ Ok(())
+ }
+}
+
+impl Sha3_256 {
+ /// Initialize a `Sha3_256` struct.
+ pub fn new() -> Self {
+ Self {
+ _state: Sha3::<{ SHA3_256_RATE }>::_new(64),
+ }
+ }
+
+ /// Reset to `new()` state.
+ pub fn reset(&mut self) {
+ self._state._reset();
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Update state with `data`. This can be called multiple times.
+ pub fn update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ self._state._update(data)
+ }
+
+ /// Finalize the hash and put the final digest into `dest`.
+ pub(crate) fn _finalize_internal(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ self._state._finalize(dest)
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Return a SHA3-256 digest.
+ pub fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
+ let mut digest = [0u8; SHA3_256_OUTSIZE];
+ self._finalize_internal(&mut digest)?;
+
+ Ok(Digest::from(digest))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Calculate a SHA3-256 digest of some `data`.
+ pub fn digest(data: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ let mut ctx = Self::new();
+ ctx.update(data)?;
+ ctx.finalize()
+ }
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[test]
+ fn test_default_equals_new() {
+ let new = Sha3_256::new();
+ let default = Sha3_256::default();
+ new._state.compare_state_to_other(&default._state);
+ }
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let initial_state = Sha3_256::new();
+ let debug = format!("{:?}", initial_state);
+ let expected = "Sha3_256 { _state: State { state: [***OMITTED***], buffer: [***OMITTED***], capacity: 64, leftover: 0, is_finalized: false } }";
+ assert_eq!(debug, expected);
+ }
+
+ #[test]
+ // <https://github.com/ziglang/zig/issues/14851>
+ fn test_zig_cryptofuzz() {
+ let expected_hash: [u8; 32] = [
+ 0x57, 0x80, 0x4, 0x8d, 0xfa, 0x38, 0x1a, 0x1d, 0x1, 0xc7, 0x47, 0x90, 0x6e, 0x4a, 0x8,
+ 0x71, 0x1d, 0xd3, 0x4f, 0xd7, 0x12, 0xec, 0xd7, 0xc6, 0x80, 0x1d, 0xd2, 0xb3, 0x8f,
+ 0xd8, 0x1a, 0x89,
+ ];
+ let msg: [u8; 613] = [
+ 0x97, 0xd1, 0x2d, 0x1a, 0x16, 0x2d, 0x36, 0x4d, 0x20, 0x62, 0x19, 0x0b, 0x14, 0x93,
+ 0xbb, 0xf8, 0x5b, 0xea, 0x04, 0xc2, 0x61, 0x8e, 0xd6, 0x08, 0x81, 0xa1, 0x1d, 0x73,
+ 0x27, 0x48, 0xbf, 0xa4, 0xba, 0xb1, 0x9a, 0x48, 0x9c, 0xf9, 0x9b, 0xff, 0x34, 0x48,
+ 0xa9, 0x75, 0xea, 0xc8, 0xa3, 0x48, 0x24, 0x9d, 0x75, 0x27, 0x48, 0xec, 0x03, 0xb0,
+ 0xbb, 0xdf, 0x33, 0x90, 0xe3, 0x93, 0xed, 0x68, 0x24, 0x39, 0x12, 0xdf, 0xea, 0xee,
+ 0x8c, 0x9f, 0x96, 0xde, 0x42, 0x46, 0x8c, 0x2b, 0x17, 0x83, 0x36, 0xfb, 0xf4, 0xf7,
+ 0xff, 0x79, 0xb9, 0x45, 0x41, 0xc9, 0x56, 0x1a, 0x6b, 0x0c, 0xa4, 0x1a, 0xdd, 0x6b,
+ 0x95, 0xe8, 0x03, 0x0f, 0x09, 0x29, 0x40, 0x1b, 0xea, 0x87, 0xfa, 0xb9, 0x18, 0xa9,
+ 0x95, 0x07, 0x7c, 0x2f, 0x7c, 0x33, 0xfb, 0xc5, 0x11, 0x5e, 0x81, 0x0e, 0xbc, 0xae,
+ 0xec, 0xb3, 0xe1, 0x4a, 0x26, 0x56, 0xe8, 0x5b, 0x11, 0x9d, 0x37, 0x06, 0x9b, 0x34,
+ 0x31, 0x6e, 0xa3, 0xba, 0x41, 0xbc, 0x11, 0xd8, 0xc5, 0x15, 0xc9, 0x30, 0x2c, 0x9b,
+ 0xb6, 0x71, 0xd8, 0x7c, 0xbc, 0x38, 0x2f, 0xd5, 0xbd, 0x30, 0x96, 0xd4, 0xa3, 0x00,
+ 0x77, 0x9d, 0x55, 0x4a, 0x33, 0x53, 0xb6, 0xb3, 0x35, 0x1b, 0xae, 0xe5, 0xdc, 0x22,
+ 0x23, 0x85, 0x95, 0x88, 0xf9, 0x3b, 0xbf, 0x74, 0x13, 0xaa, 0xcb, 0x0a, 0x60, 0x79,
+ 0x13, 0x79, 0xc0, 0x4a, 0x02, 0xdb, 0x1c, 0xc9, 0xff, 0x60, 0x57, 0x9a, 0x70, 0x28,
+ 0x58, 0x60, 0xbc, 0x57, 0x07, 0xc7, 0x47, 0x1a, 0x45, 0x71, 0x76, 0x94, 0xfb, 0x05,
+ 0xad, 0xec, 0x12, 0x29, 0x5a, 0x44, 0x6a, 0x81, 0xd9, 0xc6, 0xf0, 0xb6, 0x9b, 0x97,
+ 0x83, 0x69, 0xfb, 0xdc, 0x0d, 0x4a, 0x67, 0xbc, 0x72, 0xf5, 0x43, 0x5e, 0x9b, 0x13,
+ 0xf2, 0xe4, 0x6d, 0x49, 0xdb, 0x76, 0xcb, 0x42, 0x6a, 0x3c, 0x9f, 0xa1, 0xfe, 0x5e,
+ 0xca, 0x0a, 0xfc, 0xfa, 0x39, 0x27, 0xd1, 0x3c, 0xcb, 0x9a, 0xde, 0x4c, 0x6b, 0x09,
+ 0x8b, 0x49, 0xfd, 0x1e, 0x3d, 0x5e, 0x67, 0x7c, 0x57, 0xad, 0x90, 0xcc, 0x46, 0x5f,
+ 0x5c, 0xae, 0x6a, 0x9c, 0xb2, 0xcd, 0x2c, 0x89, 0x78, 0xcf, 0xf1, 0x49, 0x96, 0x55,
+ 0x1e, 0x04, 0xef, 0x0e, 0x1c, 0xde, 0x6c, 0x96, 0x51, 0x00, 0xee, 0x9a, 0x1f, 0x8d,
+ 0x61, 0xbc, 0xeb, 0xb1, 0xa6, 0xa5, 0x21, 0x8b, 0xa7, 0xf8, 0x25, 0x41, 0x48, 0x62,
+ 0x5b, 0x01, 0x6c, 0x7c, 0x2a, 0xe8, 0xff, 0xf9, 0xf9, 0x1f, 0xe2, 0x79, 0x2e, 0xd1,
+ 0xff, 0xa3, 0x2e, 0x1c, 0x3a, 0x1a, 0x5d, 0x2b, 0x7b, 0x87, 0x25, 0x22, 0xa4, 0x90,
+ 0xea, 0x26, 0x9d, 0xdd, 0x13, 0x60, 0x4c, 0x10, 0x03, 0xf6, 0x99, 0xd3, 0x21, 0x0c,
+ 0x69, 0xc6, 0xd8, 0xc8, 0x9e, 0x94, 0x89, 0x51, 0x21, 0xe3, 0x9a, 0xcd, 0xda, 0x54,
+ 0x72, 0x64, 0xae, 0x94, 0x79, 0x36, 0x81, 0x44, 0x14, 0x6d, 0x3a, 0x0e, 0xa6, 0x30,
+ 0xbf, 0x95, 0x99, 0xa6, 0xf5, 0x7f, 0x4f, 0xef, 0xc6, 0x71, 0x2f, 0x36, 0x13, 0x14,
+ 0xa2, 0x9d, 0xc2, 0x0c, 0x0d, 0x4e, 0xc0, 0x02, 0xd3, 0x6f, 0xee, 0x98, 0x5e, 0x24,
+ 0x31, 0x74, 0x11, 0x96, 0x6e, 0x43, 0x57, 0xe8, 0x8e, 0xa0, 0x8d, 0x3d, 0x79, 0x38,
+ 0x20, 0xc2, 0x0f, 0xb4, 0x75, 0x99, 0x3b, 0xb1, 0xf0, 0xe8, 0xe1, 0xda, 0xf9, 0xd4,
+ 0xe6, 0xd6, 0xf4, 0x8a, 0x32, 0x4a, 0x4a, 0x25, 0xa8, 0xd9, 0x60, 0xd6, 0x33, 0x31,
+ 0x97, 0xb9, 0xb6, 0xed, 0x5f, 0xfc, 0x15, 0xbd, 0x13, 0xc0, 0x3a, 0x3f, 0x1f, 0x2d,
+ 0x09, 0x1d, 0xeb, 0x69, 0x6a, 0xfe, 0xd7, 0x95, 0x3e, 0x8a, 0x4e, 0xe1, 0x6e, 0x61,
+ 0xb2, 0x6c, 0xe3, 0x2b, 0x70, 0x60, 0x7e, 0x8c, 0xe4, 0xdd, 0x27, 0x30, 0x7e, 0x0d,
+ 0xc7, 0xb7, 0x9a, 0x1a, 0x3c, 0xcc, 0xa7, 0x22, 0x77, 0x14, 0x05, 0x50, 0x57, 0x31,
+ 0x1b, 0xc8, 0xbf, 0xce, 0x52, 0xaf, 0x9c, 0x8e, 0x10, 0x2e, 0xd2, 0x16, 0xb6, 0x6e,
+ 0x43, 0x10, 0xaf, 0x8b, 0xde, 0x1d, 0x60, 0xb2, 0x7d, 0xe6, 0x2f, 0x08, 0x10, 0x12,
+ 0x7e, 0xb4, 0x76, 0x45, 0xb6, 0xd8, 0x9b, 0x26, 0x40, 0xa1, 0x63, 0x5c, 0x7a, 0x2a,
+ 0xb1, 0x8c, 0xd6, 0xa4, 0x6f, 0x5a, 0xae, 0x33, 0x7e, 0x6d, 0x71, 0xf5, 0xc8, 0x6d,
+ 0x80, 0x1c, 0x35, 0xfc, 0x3f, 0xc1, 0xa6, 0xc6, 0x1a, 0x15, 0x04, 0x6d, 0x76, 0x38,
+ 0x32, 0x95, 0xb2, 0x51, 0x1a, 0xe9, 0x3e, 0x89, 0x9f, 0x0c, 0x79,
+ ];
+
+ let mut ctx = Sha3_256::new();
+ ctx.update(&msg[..64]).unwrap();
+ ctx.update(&msg[64..]).unwrap();
+
+ assert_eq!(ctx.finalize().unwrap().as_ref(), &expected_hash);
+ }
+
+ mod test_streaming_interface {
+ use super::*;
+ use crate::test_framework::incremental_interface::*;
+
+ impl TestableStreamingContext<Digest> for Sha3_256 {
+ fn reset(&mut self) -> Result<(), UnknownCryptoError> {
+ self.reset();
+ Ok(())
+ }
+
+ fn update(&mut self, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ self.update(input)
+ }
+
+ fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
+ self.finalize()
+ }
+
+ fn one_shot(input: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ Sha3_256::digest(input)
+ }
+
+ fn verify_result(expected: &Digest, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ let actual: Digest = Self::one_shot(input)?;
+
+ if &actual == expected {
+ Ok(())
+ } else {
+ Err(UnknownCryptoError)
+ }
+ }
+
+ fn compare_states(state_1: &Sha3_256, state_2: &Sha3_256) {
+ state_1._state.compare_state_to_other(&state_2._state);
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let initial_state: Sha3_256 = Sha3_256::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha3_256>::new(
+ initial_state,
+ SHA3_256_RATE,
+ );
+ test_runner.run_all_tests();
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Related bug: https://github.com/orion-rs/orion/issues/46
+ /// Test different streaming state usage patterns.
+ fn prop_input_to_consistency(data: Vec<u8>) -> bool {
+ let initial_state: Sha3_256 = Sha3_256::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha3_256>::new(
+ initial_state,
+ SHA3_256_RATE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_io_impls {
+ use crate::hazardous::hash::sha3::sha3_256::Sha3_256;
+ use std::io::Write;
+
+ #[quickcheck]
+ fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
+ let mut hasher_a = Sha3_256::new();
+ let mut hasher_b = hasher_a.clone();
+
+ hasher_a.update(&data).unwrap();
+ hasher_b.write_all(&data).unwrap();
+
+ let hash_a = hasher_a.finalize().unwrap();
+ let hash_b = hasher_b.finalize().unwrap();
+
+ hash_a == hash_b
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/hash/sha3/sha3_384.rs b/vendor/orion/src/hazardous/hash/sha3/sha3_384.rs
new file mode 100644
index 000000000..96ccdb318
--- /dev/null
+++ b/vendor/orion/src/hazardous/hash/sha3/sha3_384.rs
@@ -0,0 +1,274 @@
+// MIT License
+
+// Copyright (c) 2023 The orion Developers
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! # Parameters:
+//! - `data`: The data to be hashed.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - [`finalize()`] is called twice without a [`reset()`] in between.
+//! - [`update()`] is called after [`finalize()`] without a [`reset()`] in
+//! between.
+//!
+//! # Example:
+//! ```rust
+//! use orion::hazardous::hash::sha3::sha3_384::Sha3_384;
+//!
+//! // Using the streaming interface
+//! let mut state = Sha3_384::new();
+//! state.update(b"Hello world")?;
+//! let hash = state.finalize()?;
+//!
+//! // Using the one-shot function
+//! let hash_one_shot = Sha3_384::digest(b"Hello world")?;
+//!
+//! assert_eq!(hash, hash_one_shot);
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`update()`]: sha3_384::Sha3_384::update
+//! [`reset()`]: sha3_384::Sha3_384::reset
+//! [`finalize()`]: sha3_384::Sha3_384::finalize
+
+use crate::errors::UnknownCryptoError;
+#[cfg(feature = "safe_api")]
+use std::io;
+
+use super::Sha3;
+
+/// Rate of SHA3-384 (equivalent to blocksize in SHA2).
+pub const SHA3_384_RATE: usize = 104;
+
+/// Output size of SHA3-384 in bytes.
+pub const SHA3_384_OUTSIZE: usize = 48;
+
+construct_public! {
+ /// A type to represent the `Digest` that SHA3-384 returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 48 bytes.
+ (Digest, test_digest, SHA3_384_OUTSIZE, SHA3_384_OUTSIZE)
+}
+
+impl_from_trait!(Digest, SHA3_384_OUTSIZE);
+
+#[derive(Clone, Debug)]
+/// SHA3-384 streaming state.
+pub struct Sha3_384 {
+ pub(crate) _state: Sha3<SHA3_384_RATE>,
+}
+
+impl Default for Sha3_384 {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+/// Example: hashing from a [`Read`](std::io::Read)er with SHA3-384.
+/// ```rust
+/// use orion::{
+/// hazardous::hash::sha3::sha3_384::{Sha3_384, Digest},
+/// errors::UnknownCryptoError,
+/// };
+/// use std::io::{self, Read, Write};
+///
+/// // `reader` could also be a `File::open(...)?`.
+/// let mut reader = io::Cursor::new(b"some data");
+/// let mut hasher = Sha3_384::new();
+/// std::io::copy(&mut reader, &mut hasher)?;
+///
+/// let digest: Digest = hasher.finalize()?;
+///
+/// # Ok::<(), Box<dyn std::error::Error>>(())
+/// ```
+#[cfg(feature = "safe_api")]
+impl io::Write for Sha3_384 {
+ /// Update the hasher's internal state with *all* of the bytes given.
+ /// If this function returns the `Ok` variant, it's guaranteed that it
+ /// will contain the length of the buffer passed to [`Write`](std::io::Write).
+ /// Note that this function is just a small wrapper over
+ /// [`Sha3_384::update`](crate::hazardous::hash::sha3::sha3_384::Sha3_384::update).
+ ///
+ /// ## Errors:
+ /// This function will only ever return the [`std::io::ErrorKind::Other`]()
+ /// variant when it returns an error. Additionally, this will always contain Orion's
+ /// [`UnknownCryptoError`](crate::errors::UnknownCryptoError) type.
+ fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
+ self.update(bytes)
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
+ Ok(bytes.len())
+ }
+
+ /// This type doesn't buffer writes, so flushing is a no-op.
+ fn flush(&mut self) -> Result<(), std::io::Error> {
+ Ok(())
+ }
+}
+
+impl Sha3_384 {
+ /// Initialize a `Sha3_384` struct.
+ pub fn new() -> Self {
+ Self {
+ _state: Sha3::<SHA3_384_RATE>::_new(96),
+ }
+ }
+
+ /// Reset to `new()` state.
+ pub fn reset(&mut self) {
+ self._state._reset();
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Update state with `data`. This can be called multiple times.
+ pub fn update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ self._state._update(data)
+ }
+
+ /// Finalize the hash and put the final digest into `dest`.
+ pub(crate) fn _finalize_internal(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ self._state._finalize(dest)
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Return a SHA3-384 digest.
+ pub fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
+ let mut digest = [0u8; SHA3_384_OUTSIZE];
+ self._finalize_internal(&mut digest)?;
+
+ Ok(Digest::from(digest))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Calculate a SHA3-384 digest of some `data`.
+ pub fn digest(data: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ let mut ctx = Self::new();
+ ctx.update(data)?;
+ ctx.finalize()
+ }
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[test]
+ fn test_default_equals_new() {
+ let new = Sha3_384::new();
+ let default = Sha3_384::default();
+ new._state.compare_state_to_other(&default._state);
+ }
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let initial_state = Sha3_384::new();
+ let debug = format!("{:?}", initial_state);
+ let expected = "Sha3_384 { _state: State { state: [***OMITTED***], buffer: [***OMITTED***], capacity: 96, leftover: 0, is_finalized: false } }";
+ assert_eq!(debug, expected);
+ }
+
+ mod test_streaming_interface {
+ use super::*;
+ use crate::test_framework::incremental_interface::*;
+
+ impl TestableStreamingContext<Digest> for Sha3_384 {
+ fn reset(&mut self) -> Result<(), UnknownCryptoError> {
+ self.reset();
+ Ok(())
+ }
+
+ fn update(&mut self, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ self.update(input)
+ }
+
+ fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
+ self.finalize()
+ }
+
+ fn one_shot(input: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ Sha3_384::digest(input)
+ }
+
+ fn verify_result(expected: &Digest, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ let actual: Digest = Self::one_shot(input)?;
+
+ if &actual == expected {
+ Ok(())
+ } else {
+ Err(UnknownCryptoError)
+ }
+ }
+
+ fn compare_states(state_1: &Sha3_384, state_2: &Sha3_384) {
+ state_1._state.compare_state_to_other(&state_2._state);
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let initial_state: Sha3_384 = Sha3_384::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha3_384>::new(
+ initial_state,
+ SHA3_384_RATE,
+ );
+ test_runner.run_all_tests();
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Related bug: https://github.com/orion-rs/orion/issues/46
+ /// Test different streaming state usage patterns.
+ fn prop_input_to_consistency(data: Vec<u8>) -> bool {
+ let initial_state: Sha3_384 = Sha3_384::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha3_384>::new(
+ initial_state,
+ SHA3_384_RATE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_io_impls {
+ use crate::hazardous::hash::sha3::sha3_384::Sha3_384;
+ use std::io::Write;
+
+ #[quickcheck]
+ fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
+ let mut hasher_a = Sha3_384::new();
+ let mut hasher_b = hasher_a.clone();
+
+ hasher_a.update(&data).unwrap();
+ hasher_b.write_all(&data).unwrap();
+
+ let hash_a = hasher_a.finalize().unwrap();
+ let hash_b = hasher_b.finalize().unwrap();
+
+ hash_a == hash_b
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/hash/sha3/sha3_512.rs b/vendor/orion/src/hazardous/hash/sha3/sha3_512.rs
new file mode 100644
index 000000000..d1b243233
--- /dev/null
+++ b/vendor/orion/src/hazardous/hash/sha3/sha3_512.rs
@@ -0,0 +1,274 @@
+// MIT License
+
+// Copyright (c) 2023 The orion Developers
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! # Parameters:
+//! - `data`: The data to be hashed.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - [`finalize()`] is called twice without a [`reset()`] in between.
+//! - [`update()`] is called after [`finalize()`] without a [`reset()`] in
+//! between.
+//!
+//! # Example:
+//! ```rust
+//! use orion::hazardous::hash::sha3::sha3_512::Sha3_512;
+//!
+//! // Using the streaming interface
+//! let mut state = Sha3_512::new();
+//! state.update(b"Hello world")?;
+//! let hash = state.finalize()?;
+//!
+//! // Using the one-shot function
+//! let hash_one_shot = Sha3_512::digest(b"Hello world")?;
+//!
+//! assert_eq!(hash, hash_one_shot);
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`update()`]: sha3_512::Sha3_512::update
+//! [`reset()`]: sha3_512::Sha3_512::reset
+//! [`finalize()`]: sha3_512::Sha3_512::finalize
+
+use crate::errors::UnknownCryptoError;
+#[cfg(feature = "safe_api")]
+use std::io;
+
+use super::Sha3;
+
+/// Rate of SHA3-512 (equivalent to blocksize in SHA2).
+pub const SHA3_512_RATE: usize = 72;
+
+/// Output size of SHA3-512 in bytes.
+pub const SHA3_512_OUTSIZE: usize = 64;
+
+construct_public! {
+ /// A type to represent the `Digest` that SHA3-512 returns.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 64 bytes.
+ (Digest, test_digest, SHA3_512_OUTSIZE, SHA3_512_OUTSIZE)
+}
+
+impl_from_trait!(Digest, SHA3_512_OUTSIZE);
+
+#[derive(Clone, Debug)]
+/// SHA3-512 streaming state.
+pub struct Sha3_512 {
+ pub(crate) _state: Sha3<SHA3_512_RATE>,
+}
+
+impl Default for Sha3_512 {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+/// Example: hashing from a [`Read`](std::io::Read)er with SHA3-512.
+/// ```rust
+/// use orion::{
+/// hazardous::hash::sha3::sha3_512::{Sha3_512, Digest},
+/// errors::UnknownCryptoError,
+/// };
+/// use std::io::{self, Read, Write};
+///
+/// // `reader` could also be a `File::open(...)?`.
+/// let mut reader = io::Cursor::new(b"some data");
+/// let mut hasher = Sha3_512::new();
+/// std::io::copy(&mut reader, &mut hasher)?;
+///
+/// let digest: Digest = hasher.finalize()?;
+///
+/// # Ok::<(), Box<dyn std::error::Error>>(())
+/// ```
+#[cfg(feature = "safe_api")]
+impl io::Write for Sha3_512 {
+ /// Update the hasher's internal state with *all* of the bytes given.
+ /// If this function returns the `Ok` variant, it's guaranteed that it
+ /// will contain the length of the buffer passed to [`Write`](std::io::Write).
+ /// Note that this function is just a small wrapper over
+ /// [`Sha3_512::update`](crate::hazardous::hash::sha3::sha3_512::Sha3_512::update).
+ ///
+ /// ## Errors:
+ /// This function will only ever return the [`std::io::ErrorKind::Other`]()
+ /// variant when it returns an error. Additionally, this will always contain Orion's
+ /// [`UnknownCryptoError`](crate::errors::UnknownCryptoError) type.
+ fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
+ self.update(bytes)
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
+ Ok(bytes.len())
+ }
+
+ /// This type doesn't buffer writes, so flushing is a no-op.
+ fn flush(&mut self) -> Result<(), std::io::Error> {
+ Ok(())
+ }
+}
+
+impl Sha3_512 {
+ /// Initialize a `Sha3_512` struct.
+ pub fn new() -> Self {
+ Self {
+ _state: Sha3::<SHA3_512_RATE>::_new(128),
+ }
+ }
+
+ /// Reset to `new()` state.
+ pub fn reset(&mut self) {
+ self._state._reset();
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Update state with `data`. This can be called multiple times.
+ pub fn update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
+ self._state._update(data)
+ }
+
+ /// Finalize the hash and put the final digest into `dest`.
+ pub(crate) fn _finalize_internal(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
+ self._state._finalize(dest)
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Return a SHA3-512 digest.
+ pub fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
+ let mut digest = [0u8; SHA3_512_OUTSIZE];
+ self._finalize_internal(&mut digest)?;
+
+ Ok(Digest::from(digest))
+ }
+
+ #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
+ /// Calculate a SHA3-512 digest of some `data`.
+ pub fn digest(data: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ let mut ctx = Self::new();
+ ctx.update(data)?;
+ ctx.finalize()
+ }
+}
+
+// Testing public functions in the module.
+#[cfg(test)]
+mod public {
+ use super::*;
+
+ #[test]
+ fn test_default_equals_new() {
+ let new = Sha3_512::new();
+ let default = Sha3_512::default();
+ new._state.compare_state_to_other(&default._state);
+ }
+
+ #[test]
+ #[cfg(feature = "safe_api")]
+ fn test_debug_impl() {
+ let initial_state = Sha3_512::new();
+ let debug = format!("{:?}", initial_state);
+ let expected = "Sha3_512 { _state: State { state: [***OMITTED***], buffer: [***OMITTED***], capacity: 128, leftover: 0, is_finalized: false } }";
+ assert_eq!(debug, expected);
+ }
+
+ mod test_streaming_interface {
+ use super::*;
+ use crate::test_framework::incremental_interface::*;
+
+ impl TestableStreamingContext<Digest> for Sha3_512 {
+ fn reset(&mut self) -> Result<(), UnknownCryptoError> {
+ self.reset();
+ Ok(())
+ }
+
+ fn update(&mut self, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ self.update(input)
+ }
+
+ fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
+ self.finalize()
+ }
+
+ fn one_shot(input: &[u8]) -> Result<Digest, UnknownCryptoError> {
+ Sha3_512::digest(input)
+ }
+
+ fn verify_result(expected: &Digest, input: &[u8]) -> Result<(), UnknownCryptoError> {
+ let actual: Digest = Self::one_shot(input)?;
+
+ if &actual == expected {
+ Ok(())
+ } else {
+ Err(UnknownCryptoError)
+ }
+ }
+
+ fn compare_states(state_1: &Sha3_512, state_2: &Sha3_512) {
+ state_1._state.compare_state_to_other(&state_2._state);
+ }
+ }
+
+ #[test]
+ fn default_consistency_tests() {
+ let initial_state: Sha3_512 = Sha3_512::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha3_512>::new(
+ initial_state,
+ SHA3_512_RATE,
+ );
+ test_runner.run_all_tests();
+ }
+
+ #[quickcheck]
+ #[cfg(feature = "safe_api")]
+ /// Related bug: https://github.com/orion-rs/orion/issues/46
+ /// Test different streaming state usage patterns.
+ fn prop_input_to_consistency(data: Vec<u8>) -> bool {
+ let initial_state: Sha3_512 = Sha3_512::new();
+
+ let test_runner = StreamingContextConsistencyTester::<Digest, Sha3_512>::new(
+ initial_state,
+ SHA3_512_RATE,
+ );
+ test_runner.run_all_tests_property(&data);
+ true
+ }
+ }
+
+ #[cfg(feature = "safe_api")]
+ mod test_io_impls {
+ use crate::hazardous::hash::sha3::sha3_512::Sha3_512;
+ use std::io::Write;
+
+ #[quickcheck]
+ fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
+ let mut hasher_a = Sha3_512::new();
+ let mut hasher_b = hasher_a.clone();
+
+ hasher_a.update(&data).unwrap();
+ hasher_b.write_all(&data).unwrap();
+
+ let hash_a = hasher_a.finalize().unwrap();
+ let hash_b = hasher_b.finalize().unwrap();
+
+ hash_a == hash_b
+ }
+ }
+}
diff --git a/vendor/orion/src/hazardous/kem/mod.rs b/vendor/orion/src/hazardous/kem/mod.rs
new file mode 100644
index 000000000..767b65337
--- /dev/null
+++ b/vendor/orion/src/hazardous/kem/mod.rs
@@ -0,0 +1,25 @@
+// MIT License
+
+// Copyright (c) 2023 The orion Developers
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+#[cfg(feature = "safe_api")]
+/// DHKEM(X25519, HKDF-SHA256) as specified in HPKE [RFC 9180](https://www.rfc-editor.org/rfc/rfc9180.html).
+pub mod x25519_hkdf_sha256;
diff --git a/vendor/orion/src/hazardous/kem/x25519_hkdf_sha256.rs b/vendor/orion/src/hazardous/kem/x25519_hkdf_sha256.rs
new file mode 100644
index 000000000..0ea9609f2
--- /dev/null
+++ b/vendor/orion/src/hazardous/kem/x25519_hkdf_sha256.rs
@@ -0,0 +1,289 @@
+// MIT License
+
+// Copyright (c) 2023 The orion Developers
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! # Parameters:
+//! - `public_recipient`: The public X25519 key of the recipient.
+//! - `public_ephemeral`: The ephemeral X25519 key fro this KEM operation.
+//! - `secret_recipient`: The private X25519 of the recipient.
+//! - `secret_sender`: The private X25519 of the sender.
+//!
+//! # Errors:
+//! An error will be returned if:
+//! - If a shared X25519 secret is all-zero.
+//! - If `ikm.len() < 32` when calling [`derive_keypair()`].
+//!
+//! # Panics:
+//! A panic will occur if:
+//! - [`generate()`] panics during [`encap()`], [`auth_encap()`], [`decap()`] or [`auth_decap()`].
+//!
+//! # Security:
+//! - The `ikm` used as input for [`derive_keypair()`] must never be reused.
+//! - This KEM is vulnerable to key-compromise impersonation attacks (KCI), meaning
+//! that if the recipients private key `secret_recipient` is leaked at any point, sender authentication
+//! no longer holds. See [KCI section](https://www.rfc-editor.org/rfc/rfc9180.html#section-9.1.1) of the RFC
+//! on recommendations on how to mitigate this.
+//! - Please refer to the RFC for a detailed description of all security properties provided: <https://www.rfc-editor.org/rfc/rfc9180.html#section-9>.
+//!
+//! # Example:
+//! ```rust
+//! # #[cfg(feature = "safe_api")] {
+//! use orion::hazardous::kem::x25519_hkdf_sha256::DhKem;
+//!
+//! let (sender_secret, sender_public) = DhKem::generate_keypair()?;
+//! let (recipient_secret, recipient_public) = DhKem::generate_keypair()?;
+//!
+//! let (sender_shared_secret, public_eph) =
+//! DhKem::auth_encap(&recipient_public, &sender_secret)?;
+//! let recipient_shared_secret = DhKem::auth_decap(&public_eph, &recipient_secret, &sender_public)?;
+//!
+//! assert_eq!(sender_shared_secret, recipient_shared_secret);
+//! # }
+//! # Ok::<(), orion::errors::UnknownCryptoError>(())
+//! ```
+//! [`encap()`]: x25519_hkdf_sha256::DhKem::encap
+//! [`decap()`]: x25519_hkdf_sha256::DhKem::decap
+//! [`auth_encap()`]: x25519_hkdf_sha256::DhKem::auth_encap
+//! [`auth_decap()`]: x25519_hkdf_sha256::DhKem::auth_decap
+//! [`derive_keypair()`]: x25519_hkdf_sha256::DhKem::derive_keypair
+//! [`generate()`]: crate::hazardous::ecc::x25519::PrivateKey::generate
+
+#![cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
+
+use crate::errors::UnknownCryptoError;
+use crate::hazardous::ecc::x25519;
+use crate::hazardous::kdf::hkdf::sha256;
+use zeroize::Zeroize;
+
+pub use crate::hazardous::ecc::x25519::PrivateKey;
+pub use crate::hazardous::ecc::x25519::PublicKey;
+
+construct_secret_key! {
+ /// A type to represent the `SharedSecret` that DH-KEM(X25519, HKDF-SHA256) produces.
+ ///
+ /// This type simply holds bytes. Creating an instance from slices or similar,
+ /// performs no checks whatsoever.
+ ///
+ /// # Errors:
+ /// An error will be returned if:
+ /// - `slice` is not 32 bytes.
+ (SharedSecret, test_shared_key, 32, 32)
+}
+
+/// DHKEM(X25519, HKDF-SHA256) as specified in HPKE [RFC 9180](https://www.rfc-editor.org/rfc/rfc9180.html).
+pub struct DhKem {}
+
+impl DhKem {
+ /// ID for this DH-KEM. See <https://www.rfc-editor.org/rfc/rfc9180.html#section-7.1>
+ pub const KEM_ID: u16 = 0x0020;
+
+ /// Version of HPKE implemented. See <https://www.rfc-editor.org/rfc/rfc9180.html#section-4-10>.
+ pub const HPKE_VERSION_ID: &'static str = "HPKE-v1";
+
+ /// Length of bytes of a shared secret produced by this KEM. See <https://www.rfc-editor.org/rfc/rfc9180.html#section-4-1>.
+ const N_SECRET: u16 = 32;
+
+ fn labeled_extract(
+ salt: &[u8],
+ label: &[u8; 7],
+ ikm: &[u8],
+ ) -> Result<sha256::Tag, UnknownCryptoError> {
+ let mut labeled_ikm = Vec::<u8>::new();
+ labeled_ikm.extend_from_slice(Self::HPKE_VERSION_ID.as_bytes());
+ labeled_ikm.extend_from_slice(b"KEM");
+ labeled_ikm.extend_from_slice(&Self::KEM_ID.to_be_bytes());
+ labeled_ikm.extend_from_slice(label);
+ labeled_ikm.extend_from_slice(ikm);
+
+ sha256::extract(salt, &labeled_ikm)
+ }
+
+ fn labeled_expand<const L: u16>(
+ prk: &sha256::Tag,
+ label: &[u8],
+ info: &[u8],
+ ) -> Result<Vec<u8>, UnknownCryptoError> {
+ let mut labeled_info = Vec::<u8>::new();
+ labeled_info.extend_from_slice(&L.to_be_bytes());
+ labeled_info.extend_from_slice(Self::HPKE_VERSION_ID.as_bytes());
+ labeled_info.extend_from_slice(b"KEM");
+ labeled_info.extend_from_slice(&Self::KEM_ID.to_be_bytes());
+ labeled_info.extend_from_slice(label);
+ labeled_info.extend_from_slice(info);
+
+ let mut out = vec![0u8; L as usize];
+ sha256::expand(prk, Some(&labeled_info), &mut out)?;
+
+ Ok(out)
+ }
+
+ fn extract_and_expand(dh: &[u8], kem_context: &[u8]) -> Result<Vec<u8>, UnknownCryptoError> {
+ let eae_prk = Self::labeled_extract(b"", b"eae_prk", dh)?;
+ let shared_secret =
+ Self::labeled_expand::<{ Self::N_SECRET }>(&eae_prk, b"shared_secret", kem_context)?;
+
+ Ok(shared_secret)
+ }
+
+ /// Generate random X25519 keypair.
+ pub fn generate_keypair() -> Result<(PrivateKey, PublicKey), UnknownCryptoError> {
+ let sk = PrivateKey::generate();
+ let pk = PublicKey::try_from(&sk)?;
+
+ Ok((sk, pk))
+ }
+
+ /// Deterministically derive a X25519 keyapir from `ikm`.
+ pub fn derive_keypair(ikm: &[u8]) -> Result<(PrivateKey, PublicKey), UnknownCryptoError> {
+ if ikm.len() < 32 {
+ return Err(UnknownCryptoError);
+ }
+
+ let dkp_prk = Self::labeled_extract(b"", b"dkp_prk", ikm)?;
+ let sk = PrivateKey::from_slice(&Self::labeled_expand::<32>(&dkp_prk, b"sk", b"")?)?;
+ let pk = PublicKey::try_from(&sk)?;
+
+ Ok((sk, pk))
+ }
+
+ /// Derive ephemeral shared secret and encapsulation thereof, which can be
+ /// decapsulated by the holder of `public_recipient`.
+ pub fn encap(
+ public_recipient: &PublicKey,
+ ) -> Result<(SharedSecret, PublicKey), UnknownCryptoError> {
+ let secret_ephemeral = PrivateKey::generate();
+ let public_ephemeral = PublicKey::try_from(&secret_ephemeral)?;
+
+ let dh = x25519::key_agreement(&secret_ephemeral, public_recipient)?;
+ let mut kem_context = [0u8; 32 + 32];
+ kem_context[..32].copy_from_slice(&public_ephemeral.to_bytes());
+ kem_context[32..64].copy_from_slice(&public_recipient.to_bytes());
+
+ let shared_secret = Self::extract_and_expand(dh.unprotected_as_bytes(), &kem_context)?;
+
+ Ok((SharedSecret::from_slice(&shared_secret)?, public_ephemeral))
+ }
+
+ /// Decapsulate `public_ephemeral` and return the shared ephemeral secrety,
+ /// using `secret_recipient` private key.
+ pub fn decap(
+ public_ephemeral: &PublicKey,
+ secret_recipient: &PrivateKey,
+ ) -> Result<SharedSecret, UnknownCryptoError> {
+ let dh = x25519::key_agreement(secret_recipient, public_ephemeral)?;
+
+ let mut kem_context = [0u8; 32 + 32];
+ kem_context[..32].copy_from_slice(&public_ephemeral.to_bytes());
+ kem_context[32..64].copy_from_slice(&PublicKey::try_from(secret_recipient)?.to_bytes());
+
+ let shared_secret = Self::extract_and_expand(dh.unprotected_as_bytes(), &kem_context)?;
+
+ SharedSecret::from_slice(&shared_secret)
+ }
+
+ /// Equivalent to [`Self::encap()`], additionally ensuring the holder of `secret_sender` was
+ /// the one to generate the shared secret.
+ pub fn auth_encap(
+ public_recipient: &PublicKey,
+ secret_sender: &PrivateKey,
+ ) -> Result<(SharedSecret, PublicKey), UnknownCryptoError> {
+ let secret_ehemeral = PrivateKey::generate();
+ let public_ephemeral = PublicKey::try_from(&secret_ehemeral)?;
+
+ let mut dh = [0u8; 64];
+ dh[..32].copy_from_slice(
+ x25519::key_agreement(&secret_ehemeral, public_recipient)?.unprotected_as_bytes(),
+ );
+ dh[32..64].copy_from_slice(
+ x25519::key_agreement(secret_sender, public_recipient)?.unprotected_as_bytes(),
+ );
+
+ let mut kem_context = [0u8; 32 * 3];
+ kem_context[..32].copy_from_slice(&public_ephemeral.to_bytes());
+ kem_context[32..64].copy_from_slice(&public_recipient.to_bytes());
+ kem_context[64..96].copy_from_slice(&PublicKey::try_from(secret_sender)?.to_bytes());
+
+ let shared_secret = Self::extract_and_expand(&dh, &kem_context)?;
+ dh.iter_mut().zeroize();
+
+ Ok((SharedSecret::from_slice(&shared_secret)?, public_ephemeral))
+ }
+
+ /// Equivalent to [`Self::decap()`], additionally ensuring the holder of `secret_sender` was
+ /// the one to generate the shared secret.
+ pub fn auth_decap(
+ public_ephemeral: &PublicKey,
+ secret_recipient: &PrivateKey,
+ public_sender: &PublicKey,
+ ) -> Result<SharedSecret, UnknownCryptoError> {
+ let mut dh = [0u8; 64];
+ dh[..32].copy_from_slice(
+ x25519::key_agreement(secret_recipient, public_ephemeral)?.unprotected_as_bytes(),
+ );
+ dh[32..64].copy_from_slice(
+ x25519::key_agreement(secret_recipient, public_sender)?.unprotected_as_bytes(),
+ );
+
+ let mut kem_context = [0u8; 32 * 3];
+ kem_context[..32].copy_from_slice(&public_ephemeral.to_bytes());
+ kem_context[32..64].copy_from_slice(&PublicKey::try_from(secret_recipient)?.to_bytes());
+ kem_context[64..96].copy_from_slice(&public_sender.to_bytes());
+
+ let shared_secret = Self::extract_and_expand(&dh, &kem_context)?;
+ dh.iter_mut().zeroize();
+
+ SharedSecret::from_slice(&shared_secret)
+ }
+}
+
+#[cfg(test)]
+#[cfg(feature = "safe_api")]
+mod public {
+ use crate::hazardous::ecc::x25519::{PrivateKey, PublicKey};
+ use crate::hazardous::kem::x25519_hkdf_sha256::*;
+
+ #[test]
+ fn encap_decap_roundtrip() {
+ let recipient_secret = PrivateKey::generate();
+ let recipient_public = PublicKey::try_from(&recipient_secret).unwrap();
+
+ let (shared_secret_1, public_eph) = DhKem::encap(&recipient_public).unwrap();
+ let shared_secret_2 = DhKem::decap(&public_eph, &recipient_secret).unwrap();
+
+ assert_eq!(shared_secret_1, shared_secret_2);
+ }
+
+ #[test]
+ fn auth_encap_decap_roundtrip() {
+ let sender_secret = PrivateKey::generate();
+ let sender_public = PublicKey::try_from(&sender_secret).unwrap();
+
+ let recipient_secret = PrivateKey::generate();
+ let recipient_public = PublicKey::try_from(&recipient_secret).unwrap();
+
+ let (shared_secret_1, public_eph) =
+ DhKem::auth_encap(&recipient_public, &sender_secret).unwrap();
+ let shared_secret_2 =
+ DhKem::auth_decap(&public_eph, &recipient_secret, &sender_public).unwrap();
+
+ assert_eq!(shared_secret_1, shared_secret_2);
+ }
+}
diff --git a/vendor/orion/src/hazardous/mac/poly1305.rs b/vendor/orion/src/hazardous/mac/poly1305.rs
index 29853f566..b9c974d6e 100644
--- a/vendor/orion/src/hazardous/mac/poly1305.rs
+++ b/vendor/orion/src/hazardous/mac/poly1305.rs
@@ -77,8 +77,8 @@ use crate::{
};
use fiat_crypto::poly1305_32::{
fiat_poly1305_add, fiat_poly1305_carry, fiat_poly1305_carry_mul, fiat_poly1305_from_bytes,
- fiat_poly1305_loose_field_element, fiat_poly1305_selectznz, fiat_poly1305_subborrowx_u26,
- fiat_poly1305_tight_field_element, fiat_poly1305_u1,
+ fiat_poly1305_loose_field_element, fiat_poly1305_relax, fiat_poly1305_selectznz,
+ fiat_poly1305_subborrowx_u26, fiat_poly1305_tight_field_element, fiat_poly1305_u1,
};
/// The blocksize which Poly1305 operates on.
@@ -119,8 +119,8 @@ impl_from_trait!(Tag, POLY1305_OUTSIZE);
#[derive(Clone)]
/// Poly1305 streaming state.
pub struct Poly1305 {
- a: [u32; 5],
- r: [u32; 5],
+ a: fiat_poly1305_tight_field_element,
+ r: fiat_poly1305_loose_field_element,
s: [u32; 4],
leftover: usize,
buffer: [u8; POLY1305_BLOCKSIZE],
@@ -130,8 +130,8 @@ pub struct Poly1305 {
impl Drop for Poly1305 {
fn drop(&mut self) {
use zeroize::Zeroize;
- self.a.zeroize();
- self.r.zeroize();
+ self.a.0.zeroize();
+ self.r.0.zeroize();
self.s.zeroize();
self.buffer.zeroize();
}
@@ -164,11 +164,11 @@ impl Poly1305 {
// One byte is appended to detect trailing zeroes if not last chunk.
// See https://cr.yp.to/mac/poly1305-20050329.pdf, Section 2 "Conversion and padding".
mb[16] = u8::from(!self.is_finalized);
- let mut m: fiat_poly1305_tight_field_element = [0u32; 5];
+ let mut m = fiat_poly1305_tight_field_element([0u32; 5]);
fiat_poly1305_from_bytes(&mut m, &mb);
// h += m
- let mut h: fiat_poly1305_loose_field_element = [0u32; 5];
+ let mut h = fiat_poly1305_loose_field_element([0u32; 5]);
fiat_poly1305_add(&mut h, &self.a, &m);
// h *= r with partial reduction modulo p
fiat_poly1305_carry_mul(&mut self.a, &h, &self.r);
@@ -181,11 +181,13 @@ impl Poly1305 {
/// Remaining processing after all data blocks have been processed.
fn process_end_of_stream(&mut self) {
// full carry h
- let mut buf_h: fiat_poly1305_tight_field_element = [0u32; 5];
- fiat_poly1305_carry(&mut buf_h, &self.a);
+ let mut buf_h = fiat_poly1305_tight_field_element([0u32; 5]);
+ let mut a_relaxed = fiat_poly1305_loose_field_element([0u32; 5]);
+ fiat_poly1305_relax(&mut a_relaxed, &self.a);
+ fiat_poly1305_carry(&mut buf_h, &a_relaxed);
// compute h + -p
- let mut p: fiat_poly1305_tight_field_element = [0u32; 5];
+ let mut p = fiat_poly1305_tight_field_element([0u32; 5]);
fiat_poly1305_from_bytes(&mut p, &Self::PRIME);
let mut carry: fiat_poly1305_u1 = 0;
@@ -197,7 +199,7 @@ impl Poly1305 {
// select h if h < p, or h + -p if h >= p
let mut ret = [0u32; 5];
- fiat_poly1305_selectznz(&mut ret, carry,&[g0, g1, g2, g3, g4], &buf_h);
+ fiat_poly1305_selectznz(&mut ret, carry,&[g0, g1, g2, g3, g4], &buf_h.0);
let mut h0 = ret[0];
let mut h1 = ret[1];
@@ -228,8 +230,8 @@ impl Poly1305 {
/// Initialize a `Poly1305` struct with a given one-time key.
pub fn new(one_time_key: &OneTimeKey) -> Self {
let mut state = Self {
- a: [0u32; 5],
- r: [0u32; 5],
+ a: fiat_poly1305_tight_field_element([0u32; 5]),
+ r: fiat_poly1305_loose_field_element([0u32; 5]),
s: [0u32; 4],
leftover: 0,
buffer: [0u8; POLY1305_BLOCKSIZE],
@@ -280,7 +282,7 @@ impl Poly1305 {
/// Reset to `new()` state.
pub fn reset(&mut self) {
- self.a = [0u32; 5];
+ self.a = fiat_poly1305_tight_field_element([0u32; 5]);
self.leftover = 0;
self.is_finalized = false;
self.buffer = [0u8; POLY1305_BLOCKSIZE];
@@ -358,7 +360,7 @@ impl Poly1305 {
}
self.process_end_of_stream();
- store_u32_into_le(&self.a[0..4], &mut local_buffer);
+ store_u32_into_le(&self.a.0[0..4], &mut local_buffer);
Ok(Tag::from(local_buffer))
}
@@ -455,8 +457,8 @@ mod public {
}
fn compare_states(state_1: &Poly1305, state_2: &Poly1305) {
- assert_eq!(state_1.a, state_2.a);
- assert_eq!(state_1.r, state_2.r);
+ assert_eq!(state_1.a.0, state_2.a.0);
+ assert_eq!(state_1.r.0, state_2.r.0);
assert_eq!(state_1.s, state_2.s);
assert_eq!(state_1.leftover, state_2.leftover);
assert_eq!(state_1.buffer[..], state_2.buffer[..]);
diff --git a/vendor/orion/src/hazardous/mod.rs b/vendor/orion/src/hazardous/mod.rs
index 25a5ae227..ff8c188ae 100644
--- a/vendor/orion/src/hazardous/mod.rs
+++ b/vendor/orion/src/hazardous/mod.rs
@@ -44,3 +44,10 @@ pub mod stream;
/// Elliptic-Curve Cryptography.
pub mod ecc;
+
+#[cfg(feature = "experimental")]
+/// Fully-committing Authenticated Encryption. __WARNING:__ Experimental feature.
+pub mod cae;
+
+/// Key Encapsulation Mechanisms (KEMs).
+pub mod kem;